package main import ( "bytes" "errors" "fmt" "html" "log" "net/http" "net/url" "strings" "teafolio/gitea" "github.com/yuin/goldmark" ) 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 := "" readme, err := this.gitea.RepoFile(ctx, repoName, `README.md`) if err != nil { log.Printf("%s %s: %s", r.Method, r.URL.Path, err) http.Redirect(w, r, repoURL, http.StatusTemporaryRedirect) 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 } for _, topic := range rr.Topics { 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:]...) } readmeHtml, err := this.gitea.RenderMarkdown(ctx, repoName, strings.Join(lines, "\n")) 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 } readmeHtml = []byte(strings.Replace(string(readmeHtml), `%%REPLACEME__BADGE%%`, ``, 1)) images, err := this.gitea.ImageFilesForRepo(ctx, repoName) 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) return } // If the Git repository contains a top-level go.mod file, allow vanity imports if goMod, err := this.gitea.RepoFile(ctx, repoName, `go.mod`); err == nil { // 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 = `` } } // De-escalate all headers in rendered markdown to match our style repl := strings.NewReplacer(``, ``, ``, ``, ``, ``) // Ready for template this.Templatepage(w, r, repoName, extraHead, func() { projBodyclass := `projbody` if len(images) > 0 { projBodyclass += ` projbody_halfw` } fmt.Fprint(w, `
`) repl.WriteString(w, string(readmeHtml)) fmt.Fprint(w, `
`) if len(images) > 0 { fmt.Fprint(w, `
`) for _, img := range images { fmt.Fprint(w, ``) } fmt.Fprint(w, `
`) } fmt.Fprint(w, `
`) fmt.Fprint(w, `
`) // projbody }) }