1package web
2
3import (
4 "bytes"
5 "context"
6 "html/template"
7
8 "github.com/charmbracelet/soft-serve/git"
9 "github.com/charmbracelet/soft-serve/pkg/backend"
10 "github.com/charmbracelet/soft-serve/pkg/proto"
11 "github.com/microcosm-cc/bluemonday"
12 "github.com/yuin/goldmark"
13 extension "github.com/yuin/goldmark/extension"
14 "github.com/yuin/goldmark/parser"
15 goldmarkhtml "github.com/yuin/goldmark/renderer/html"
16)
17
18// renderMarkdown converts markdown content to sanitized HTML.
19func renderMarkdown(content []byte) (template.HTML, error) {
20 var buf bytes.Buffer
21 md := goldmark.New(
22 goldmark.WithExtensions(extension.GFM),
23 goldmark.WithParserOptions(
24 parser.WithAutoHeadingID(),
25 ),
26 goldmark.WithRendererOptions(
27 goldmarkhtml.WithUnsafe(),
28 ),
29 )
30
31 if err := md.Convert(content, &buf); err != nil {
32 return "", err
33 }
34
35 policy := bluemonday.UGCPolicy()
36 policy.AllowStyling()
37 policy.RequireNoFollowOnLinks(false)
38 policy.AllowElements("center")
39 sanitized := policy.SanitizeBytes(buf.Bytes())
40
41 return template.HTML(sanitized), nil
42}
43
44// getServerReadme loads and renders the README from the .soft-serve repository.
45func getServerReadme(ctx context.Context, be *backend.Backend) (template.HTML, error) {
46 repos, err := be.Repositories(ctx)
47 if err != nil {
48 return "", err
49 }
50
51 for _, r := range repos {
52 if r.Name() == ".soft-serve" {
53 readme, _, err := backend.Readme(r, nil)
54 if err != nil {
55 return "", err
56 }
57 if readme != "" {
58 return renderMarkdown([]byte(readme))
59 }
60 }
61 }
62
63 return "", nil
64}
65
66// openRepository opens a git repository.
67func openRepository(repo proto.Repository) (*git.Repository, error) {
68 return repo.Open()
69}
70
71// getDefaultBranch returns the default branch name, or empty string if none exists.
72func getDefaultBranch(gr *git.Repository) string {
73 head, err := gr.HEAD()
74 if err != nil || head == nil {
75 return ""
76 }
77 return head.Name().Short()
78}