blob: 911c2c0b6a252b5d698d5ad89bb22a07897dcd87 [file] [log] [blame]
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +02001package main
2
3import (
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +02004 "bytes"
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +02005 "html/template"
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +02006 "net/url"
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +02007 "strings"
8
9 "code.hackerspace.pl/hscloud/devtools/hackdoc/config"
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020010
11 "github.com/golang/glog"
12 "gopkg.in/russross/blackfriday.v2"
13)
14
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020015// renderMarkdown renders markdown to HTML, replacing all relative (intra-hackdoc) links with version that have ref set.
16func renderMarkdown(input []byte, ref string) []byte {
17 r := blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{
18 Flags: blackfriday.CommonHTMLFlags,
19 })
20
21 parser := blackfriday.New(blackfriday.WithRenderer(r), blackfriday.WithExtensions(blackfriday.CommonExtensions))
22 ast := parser.Parse(input)
23
24 var buf bytes.Buffer
25 ast.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
26 if ref != "" && entering && node.Type == blackfriday.Link {
27 dest := string(node.Destination)
28 u, err := url.Parse(dest)
29 if err == nil && !u.IsAbs() {
30 q := u.Query()
31 q["ref"] = []string{ref}
32 u.RawQuery = q.Encode()
33 node.Destination = []byte(u.String())
34 }
35 }
36 return r.RenderNode(&buf, node, entering)
37 })
38 return buf.Bytes()
39}
40
41func (r *request) handleMarkdown(path string, cfg *config.Config) {
42 data, err := r.source.ReadFile(r.ctx, path)
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020043 if err != nil {
44 glog.Errorf("ReadFile(%q): %w", err)
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020045 r.handle500()
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020046 return
47 }
48
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020049 rendered := renderMarkdown([]byte(data), r.ref)
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020050
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020051 r.logRequest("serving markdown at %s, cfg %+v", path, cfg)
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020052
53 // TODO(q3k): allow markdown files to override which template to load
54 tmpl, ok := cfg.Templates["default"]
55 if !ok {
56 glog.Errorf("No default template found for %s", path)
57 // TODO(q3k): implement fallback template
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020058 r.w.Write(rendered)
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020059 return
60 }
61
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020062 pathInDepot := strings.TrimPrefix(path, "//")
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020063 vars := map[string]interface{}{
64 "Rendered": template.HTML(rendered),
65 "Title": path,
66 "Path": path,
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020067 "PathInDepot": pathInDepot,
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020068 "HackdocURL": flagHackdocURL,
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020069 "WebLinks": r.source.WebLinks(pathInDepot),
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020070 }
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020071 err = tmpl.Execute(r.w, vars)
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020072 if err != nil {
73 glog.Errorf("Could not execute template for %s: %v", err)
74 }
75}