teafolio/page_repository.go

138 lines
4.1 KiB
Go
Raw Normal View History

2022-12-31 00:47:07 +00:00
package main
import (
"bytes"
"errors"
2022-12-31 00:47:07 +00:00
"fmt"
"html"
"log"
2022-12-31 00:47:07 +00:00
"net/http"
"net/url"
"strings"
"teafolio/gitea"
"github.com/yuin/goldmark"
2022-12-31 00:47:07 +00:00
)
func (this *Application) Repopage(w http.ResponseWriter, r *http.Request, repoName string) {
ctx := r.Context()
repoURL := this.cfg.Gitea.URL + url.PathEscape(this.cfg.Gitea.Org) + `/` + url.PathEscape(repoName)
extraHead := ""
2022-12-31 01:06:43 +00:00
readme, err := this.gitea.RepoFile(ctx, repoName, `README.md`)
2022-12-31 00:47:07 +00:00
if err != nil {
log.Printf("%s %s: %s", r.Method, r.URL.Path, err)
http.Redirect(w, r, repoURL, http.StatusTemporaryRedirect)
2022-12-31 00:47:07 +00:00
return
}
lines := strings.Split(string(readme), "\n")
// Check if this repo has the 'article' tag
hasArticleTag := false
this.reposMut.RLock()
for _, rr := range this.reposCache {
if rr.Name != repoName {
continue
}
2022-12-31 01:06:43 +00:00
for _, topic := range rr.Topics {
2022-12-31 00:47:07 +00:00
if topic == "article" {
hasArticleTag = true
break
}
}
}
this.reposMut.RUnlock()
// We add some extra badges based on special text entries
extraBadgesMd := ``
if !hasArticleTag {
extraBadgesMd += ` %%REPLACEME__BADGE%%`
}
extraBadgesMd += ` [![](https://img.shields.io/badge/vcs-git-green?logo=git)](` + repoURL + `)`
// Inject more badges to 3rd line; or, create badges on 3rd line if there are none already
if len(lines) >= 3 && strings.Contains(lines[2], `shields.io`) {
lines[2] += ` ` + extraBadgesMd
} else {
// Push other lines down
lines = append([]string{lines[0], lines[1], extraBadgesMd, ""}, lines[2:]...)
}
2022-12-31 01:06:43 +00:00
readmeHtml, err := this.gitea.RenderMarkdown(ctx, repoName, strings.Join(lines, "\n"))
2022-12-31 00:47:07 +00:00
if err != nil {
if !errors.Is(err, gitea.ErrMarkdownCooldown) {
log.Printf("%s %s: %s", r.Method, r.URL.Path, fmt.Errorf("rendering markdown: %w", err))
}
// Failed to use Gitea's markdown renderer
// HTTP 401 (Unauthorized) started happening with this API sometime
// between Gitea 1.18 -> 1.21, and no authorization token seems
// sufficient to make it work again
// Use our own one instead as a fallback
buff := bytes.Buffer{}
err = goldmark.Convert([]byte(strings.Join(lines, "\n")), &buff)
if err != nil {
// Built-in markdown renderer didn't work either
log.Printf("%s %s: %s", r.Method, r.URL.Path, fmt.Errorf("rendering markdown: %w", err))
http.Redirect(w, r, repoURL, http.StatusTemporaryRedirect)
return
}
// OK
readmeHtml = buff.Bytes()
err = nil
2022-12-31 00:47:07 +00:00
}
readmeHtml = []byte(strings.Replace(string(readmeHtml), `%%REPLACEME__BADGE%%`, `<img src="/static/build_success_brightgreen.svg" style="width:90px;height:20px;">`, 1))
2022-12-31 01:06:43 +00:00
images, err := this.gitea.ImageFilesForRepo(ctx, repoName)
2022-12-31 00:47:07 +00:00
if err != nil {
log.Printf("%s %s: %s", r.Method, r.URL.Path, fmt.Errorf("listing images: %w", err))
http.Redirect(w, r, repoURL, http.StatusTemporaryRedirect)
2022-12-31 00:47:07 +00:00
return
}
// If the Git repository contains a top-level go.mod file, allow vanity imports
2022-12-31 01:06:43 +00:00
if goMod, err := this.gitea.RepoFile(ctx, repoName, `go.mod`); err == nil {
2022-12-31 00:47:07 +00:00
// Check the first line should be `module MODULENAME\n`
firstLine := bytes.SplitN(goMod, []byte("\n"), 2)[0]
if bytes.HasPrefix(firstLine, []byte("module ")) {
moduleName := firstLine[7:]
extraHead = `<meta name="go-import" content="` + html.EscapeString(string(moduleName)) + ` git ` + repoURL + `.git">`
}
}
// De-escalate all headers in rendered markdown to match our style
repl := strings.NewReplacer(`<h1`, `<h2`, `<h2`, `<h3`, `<h3`, `<h4`,
`</h1>`, `</h2>`, `</h2>`, `</h3>`, `</h3>`, `</h4>`)
// Ready for template
this.Templatepage(w, r, repoName, extraHead, func() {
projBodyclass := `projbody`
if len(images) > 0 {
projBodyclass += ` projbody_halfw`
}
fmt.Fprint(w, `<div class="projinfo"><div class="`+projBodyclass+`">`)
repl.WriteString(w, string(readmeHtml))
fmt.Fprint(w, `</div>`)
if len(images) > 0 {
fmt.Fprint(w, `<div class="projimg">`)
for _, img := range images {
fmt.Fprint(w, `<a href="`+html.EscapeString(img.RawURL)+`"><img alt="" class="thumbimage" src="`+html.EscapeString(img.RawURL)+`" /></a>`)
}
fmt.Fprint(w, `</div>`)
}
fmt.Fprint(w, `<div style="clear:both;"></div>`)
fmt.Fprint(w, `</div>`) // projbody
})
}