refactor(web): render the issue body and its merge request links in their own helpers
1 file · +38 -22
M internal/adapters/web/issues.go +38 -22
| @@ -290,29 +290,11 @@ func (s *Server) issueShow(ctx context.Context, r *http.Request) (templ.Componen | |||
| 290 | 290 | Number: "#" + strconv.FormatInt(n, 10), Title: visibleText(i.Title.String()), | |
| 291 | 291 | State: string(i.State), Open: i.IsOpen(), | |
| 292 | 292 | } | |
| 293 | - | if body := i.Body.String(); strings.TrimSpace(body) != "" { | |
| 294 | - | var h template.HTML | |
| 295 | - | var err error | |
| 296 | - | if i.External { | |
| 297 | - | // Written by an anonymous visitor: the untrusted policy. | |
| 298 | - | h, err = s.md.renderUntrusted([]byte(body), "issue-desc-", s.numberResolver(ctx, d.name())) | |
| 299 | - | } else { | |
| 300 | - | h, err = s.md.renderIssue([]byte(body), d.name(), d.repo.DefaultBranch, "issue-desc-", s.numberResolver(ctx, d.name())) | |
| 301 | - | } | |
| 302 | - | if err != nil { | |
| 303 | - | return nil, 0, err | |
| 304 | - | } | |
| 305 | - | p.Desc = h | |
| 306 | - | } | |
| 307 | - | if i.ClosedByMergeRequest > 0 { | |
| 308 | - | p.ClosedBy = &Link{Label: "!" + strconv.FormatInt(i.ClosedByMergeRequest, 10), Href: mrHref(d.name(), i.ClosedByMergeRequest)} | |
| 309 | - | } | |
| 310 | - | for _, ref := range res.References { | |
| 311 | - | p.References = append(p.References, IssueRefView{ | |
| 312 | - | Number: "!" + strconv.FormatInt(ref.Number, 10), Title: visibleText(ref.Title.String()), | |
| 313 | - | State: string(ref.State), Href: mrHref(d.name(), ref.Number), Closes: ref.Closes, | |
| 314 | - | }) | |
| 293 | + | if p.Desc, err = s.issueBody(ctx, d, i); err != nil { | |
| 294 | + | return nil, 0, err | |
| 315 | 295 | } | |
| 296 | + | p.ClosedBy = numberLink(d.name(), i.ClosedByMergeRequest) | |
| 297 | + | p.References = issueRefViews(d.name(), res.References) | |
| 316 | 298 | p.Opened.Name = s.who(i.Author) | |
| 317 | 299 | if i.External { | |
| 318 | 300 | // The label is the visitor's, not the owner's: shown as plain text. | |
| @@ -356,6 +338,40 @@ func (s *Server) issueShow(ctx context.Context, r *http.Request) (templ.Componen | |||
| 356 | 338 | return IssueShow(l, p), http.StatusOK, nil | |
| 357 | 339 | } | |
| 358 | 340 | ||
| 341 | + | // issueBody renders the description of an issue; an issue from the public form | |
| 342 | + | // was written by an anonymous visitor and gets the untrusted policy. | |
| 343 | + | func (s *Server) issueBody(ctx context.Context, d *repoData, i domain.Issue) (template.HTML, error) { | |
| 344 | + | body := i.Body.String() | |
| 345 | + | if strings.TrimSpace(body) == "" { | |
| 346 | + | return "", nil | |
| 347 | + | } | |
| 348 | + | numbers := s.numberResolver(ctx, d.name()) | |
| 349 | + | if i.External { | |
| 350 | + | return s.md.renderUntrusted([]byte(body), "issue-desc-", numbers) | |
| 351 | + | } | |
| 352 | + | return s.md.renderIssue([]byte(body), d.name(), d.repo.DefaultBranch, "issue-desc-", numbers) | |
| 353 | + | } | |
| 354 | + | ||
| 355 | + | // numberLink links merge request n of repo; nil for 0. | |
| 356 | + | func numberLink(repo string, n int64) *Link { | |
| 357 | + | if n == 0 { | |
| 358 | + | return nil | |
| 359 | + | } | |
| 360 | + | return &Link{Label: "!" + strconv.FormatInt(n, 10), Href: mrHref(repo, n)} | |
| 361 | + | } | |
| 362 | + | ||
| 363 | + | // issueRefViews are the merge requests that mention an issue. | |
| 364 | + | func issueRefViews(repo string, refs []ports.IssueReference) []IssueRefView { | |
| 365 | + | views := make([]IssueRefView, 0, len(refs)) | |
| 366 | + | for _, ref := range refs { | |
| 367 | + | views = append(views, IssueRefView{ | |
| 368 | + | Number: "!" + strconv.FormatInt(ref.Number, 10), Title: visibleText(ref.Title.String()), | |
| 369 | + | State: string(ref.State), Href: mrHref(repo, ref.Number), Closes: ref.Closes, | |
| 370 | + | }) | |
| 371 | + | } | |
| 372 | + | return views | |
| 373 | + | } | |
| 374 | + | ||
| 359 | 375 | // pageOrRedirect is page(), except that a page that is not found may be the | |
| 360 | 376 | // page of the other kind of the number: target then names where to send the | |
| 361 | 377 | // visitor ("" when there is none). | |
| @@ -290,29 +290,11 @@ func (s *Server) issueShow(ctx context.Context, r *http.Request) (templ.Componen | |||||
| 290 | Number: "#" + strconv.FormatInt(n, 10), Title: visibleText(i.Title.String()), | 290 | Number: "#" + strconv.FormatInt(n, 10), Title: visibleText(i.Title.String()), | ||
| 291 | State: string(i.State), Open: i.IsOpen(), | 291 | State: string(i.State), Open: i.IsOpen(), | ||
| 292 | } | 292 | } | ||
| 293 | - | if body := i.Body.String(); strings.TrimSpace(body) != "" { | 293 | + | if p.Desc, err = s.issueBody(ctx, d, i); err != nil { |
| 294 | - | var h template.HTML | 294 | + | return nil, 0, err |
| 295 | - | var err error | |||
| 296 | - | if i.External { | |||
| 297 | - | // Written by an anonymous visitor: the untrusted policy. | |||
| 298 | - | h, err = s.md.renderUntrusted([]byte(body), "issue-desc-", s.numberResolver(ctx, d.name())) | |||
| 299 | - | } else { | |||
| 300 | - | h, err = s.md.renderIssue([]byte(body), d.name(), d.repo.DefaultBranch, "issue-desc-", s.numberResolver(ctx, d.name())) | |||
| 301 | - | } | |||
| 302 | - | if err != nil { | |||
| 303 | - | return nil, 0, err | |||
| 304 | - | } | |||
| 305 | - | p.Desc = h | |||
| 306 | - | } | |||
| 307 | - | if i.ClosedByMergeRequest > 0 { | |||
| 308 | - | p.ClosedBy = &Link{Label: "!" + strconv.FormatInt(i.ClosedByMergeRequest, 10), Href: mrHref(d.name(), i.ClosedByMergeRequest)} | |||
| 309 | - | } | |||
| 310 | - | for _, ref := range res.References { | |||
| 311 | - | p.References = append(p.References, IssueRefView{ | |||
| 312 | - | Number: "!" + strconv.FormatInt(ref.Number, 10), Title: visibleText(ref.Title.String()), | |||
| 313 | - | State: string(ref.State), Href: mrHref(d.name(), ref.Number), Closes: ref.Closes, | |||
| 314 | - | }) | |||
| 315 | } | 295 | } | ||
| 296 | + | p.ClosedBy = numberLink(d.name(), i.ClosedByMergeRequest) | |||
| 297 | + | p.References = issueRefViews(d.name(), res.References) | |||
| 316 | p.Opened.Name = s.who(i.Author) | 298 | p.Opened.Name = s.who(i.Author) | ||
| 317 | if i.External { | 299 | if i.External { | ||
| 318 | // The label is the visitor's, not the owner's: shown as plain text. | 300 | // The label is the visitor's, not the owner's: shown as plain text. | ||
| @@ -356,6 +338,40 @@ func (s *Server) issueShow(ctx context.Context, r *http.Request) (templ.Componen | |||||
| 356 | return IssueShow(l, p), http.StatusOK, nil | 338 | return IssueShow(l, p), http.StatusOK, nil | ||
| 357 | } | 339 | } | ||
| 358 | 340 | ||||
| 341 | + | // issueBody renders the description of an issue; an issue from the public form | |||
| 342 | + | // was written by an anonymous visitor and gets the untrusted policy. | |||
| 343 | + | func (s *Server) issueBody(ctx context.Context, d *repoData, i domain.Issue) (template.HTML, error) { | |||
| 344 | + | body := i.Body.String() | |||
| 345 | + | if strings.TrimSpace(body) == "" { | |||
| 346 | + | return "", nil | |||
| 347 | + | } | |||
| 348 | + | numbers := s.numberResolver(ctx, d.name()) | |||
| 349 | + | if i.External { | |||
| 350 | + | return s.md.renderUntrusted([]byte(body), "issue-desc-", numbers) | |||
| 351 | + | } | |||
| 352 | + | return s.md.renderIssue([]byte(body), d.name(), d.repo.DefaultBranch, "issue-desc-", numbers) | |||
| 353 | + | } | |||
| 354 | + | ||||
| 355 | + | // numberLink links merge request n of repo; nil for 0. | |||
| 356 | + | func numberLink(repo string, n int64) *Link { | |||
| 357 | + | if n == 0 { | |||
| 358 | + | return nil | |||
| 359 | + | } | |||
| 360 | + | return &Link{Label: "!" + strconv.FormatInt(n, 10), Href: mrHref(repo, n)} | |||
| 361 | + | } | |||
| 362 | + | ||||
| 363 | + | // issueRefViews are the merge requests that mention an issue. | |||
| 364 | + | func issueRefViews(repo string, refs []ports.IssueReference) []IssueRefView { | |||
| 365 | + | views := make([]IssueRefView, 0, len(refs)) | |||
| 366 | + | for _, ref := range refs { | |||
| 367 | + | views = append(views, IssueRefView{ | |||
| 368 | + | Number: "!" + strconv.FormatInt(ref.Number, 10), Title: visibleText(ref.Title.String()), | |||
| 369 | + | State: string(ref.State), Href: mrHref(repo, ref.Number), Closes: ref.Closes, | |||
| 370 | + | }) | |||
| 371 | + | } | |||
| 372 | + | return views | |||
| 373 | + | } | |||
| 374 | + | ||||
| 359 | // pageOrRedirect is page(), except that a page that is not found may be the | 375 | // pageOrRedirect is page(), except that a page that is not found may be the | ||
| 360 | // page of the other kind of the number: target then names where to send the | 376 | // page of the other kind of the number: target then names where to send the | ||
| 361 | // visitor ("" when there is none). | 377 | // visitor ("" when there is none). | ||