blob: fb46c5d25bf0e3499c0d97e3e6e0a3ce1b031e48 [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
Sergiusz Bazanski8adbd492020-04-10 21:20:53 +020011 "github.com/gabriel-vasile/mimetype"
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020012 "github.com/golang/glog"
13 "gopkg.in/russross/blackfriday.v2"
14)
15
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020016// renderMarkdown renders markdown to HTML, replacing all relative (intra-hackdoc) links with version that have ref set.
17func renderMarkdown(input []byte, ref string) []byte {
18 r := blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{
19 Flags: blackfriday.CommonHTMLFlags,
20 })
21
22 parser := blackfriday.New(blackfriday.WithRenderer(r), blackfriday.WithExtensions(blackfriday.CommonExtensions))
23 ast := parser.Parse(input)
24
25 var buf bytes.Buffer
26 ast.Walk(func(node *blackfriday.Node, entering bool) blackfriday.WalkStatus {
27 if ref != "" && entering && node.Type == blackfriday.Link {
28 dest := string(node.Destination)
29 u, err := url.Parse(dest)
30 if err == nil && !u.IsAbs() {
31 q := u.Query()
32 q["ref"] = []string{ref}
33 u.RawQuery = q.Encode()
34 node.Destination = []byte(u.String())
Sergiusz Bazanski8adbd492020-04-10 21:20:53 +020035 glog.Infof("link fix %q -> %q", dest, u.String())
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020036 }
37 }
38 return r.RenderNode(&buf, node, entering)
39 })
40 return buf.Bytes()
41}
42
Sergiusz Bazanski8adbd492020-04-10 21:20:53 +020043type pathPart struct {
44 Label string
45 Path string
46}
47
48func (r *request) handleFile(path string, cfg *config.Config) {
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020049 data, err := r.source.ReadFile(r.ctx, path)
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020050 if err != nil {
51 glog.Errorf("ReadFile(%q): %w", err)
Sergiusz Bazanskif157b4d2020-04-10 17:39:43 +020052 r.handle500()
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020053 return
54 }
55
Sergiusz Bazanski8adbd492020-04-10 21:20:53 +020056 // TODO(q3k): do MIME detection instead.
57 if strings.HasSuffix(path, ".md") {
58 rendered := renderMarkdown([]byte(data), r.ref)
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020059
Sergiusz Bazanski8adbd492020-04-10 21:20:53 +020060 r.logRequest("serving markdown at %s, cfg %+v", path, cfg)
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +020061
Sergiusz Bazanski8adbd492020-04-10 21:20:53 +020062 // TODO(q3k): allow markdown files to override which template to load
63 tmpl, ok := cfg.Templates["default"]
64 if !ok {
65 glog.Errorf("No default template found for %s", path)
66 // TODO(q3k): implement fallback template
67 r.w.Write(rendered)
68 return
69 }
70
71 pathInDepot := strings.TrimPrefix(path, "//")
72 pathParts := []pathPart{
73 {Label: "//", Path: "/"},
74 }
75 parts := strings.Split(pathInDepot, "/")
76 fullPath := ""
77 for i, p := range parts {
78 label := p
79 if i != len(parts)-1 {
80 label = label + "/"
81 }
82 fullPath += "/" + p
83 pathParts = append(pathParts, pathPart{Label: label, Path: fullPath})
84 }
85
86 vars := map[string]interface{}{
87 "Rendered": template.HTML(rendered),
88 "Title": path,
89 "Path": path,
90 "PathInDepot": pathInDepot,
91 "PathParts": pathParts,
92 "HackdocURL": flagHackdocURL,
93 "WebLinks": r.source.WebLinks(pathInDepot),
94 }
95 err = tmpl.Execute(r.w, vars)
96 if err != nil {
97 glog.Errorf("Could not execute template for %s: %v", err)
98 }
99
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +0200100 return
101 }
102
Sergiusz Bazanski8adbd492020-04-10 21:20:53 +0200103 // Just serve the file.
104 mime := mimetype.Detect(data)
105 r.w.Header().Set("Content-Type", mime.String())
106 r.w.Write(data)
Sergiusz Bazanskic881cf32020-04-08 20:03:12 +0200107}