mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-16 09:53:24 +09:00
enhance: improve e-mail templates (#38396)
Co-authored-by: bircni <bircni@icloud.com>
This commit is contained in:
@@ -4,9 +4,13 @@
|
||||
package devtest
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/templates"
|
||||
"gitea.dev/modules/util"
|
||||
"gitea.dev/services/context"
|
||||
@@ -15,28 +19,67 @@ import (
|
||||
"go.yaml.in/yaml/v4"
|
||||
)
|
||||
|
||||
var mailDarkSchemeQuery = regexp.MustCompile(`@media\s*\(\s*prefers-color-scheme\s*:\s*dark\s*\)`)
|
||||
|
||||
func mailPreviewMockData(tmplName string) (map[string]any, error) {
|
||||
mockData := map[string]any{}
|
||||
mockDataContent, err := templates.AssetFS().ReadFile(tmplName + ".devtest.yml")
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return mockData, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return mockData, yaml.Unmarshal(mockDataContent, &mockData)
|
||||
}
|
||||
|
||||
func MailPreviewRender(ctx *context.Context) {
|
||||
tmplName := ctx.PathParam("*")
|
||||
mockDataContent, err := templates.AssetFS().ReadFile("mail/" + tmplName + ".devtest.yml")
|
||||
mockData := map[string]any{}
|
||||
if err == nil {
|
||||
err = yaml.Unmarshal(mockDataContent, &mockData)
|
||||
if err != nil {
|
||||
http.Error(ctx.Resp, "Failed to parse mock data: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
mockData, err := mailPreviewMockData(tmplName)
|
||||
if err != nil {
|
||||
http.Error(ctx.Resp, "Failed to parse mock data: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
mockData["locale"] = ctx.Locale
|
||||
err = mailer.LoadedTemplates().BodyTemplates.ExecuteTemplate(ctx.Resp, tmplName, mockData)
|
||||
if err != nil {
|
||||
_, _ = ctx.Resp.Write([]byte(err.Error()))
|
||||
var mailBody strings.Builder
|
||||
if err := mailer.LoadedTemplates().BodyTemplates.ExecuteTemplate(&mailBody, tmplName, mockData); err != nil {
|
||||
http.Error(ctx.Resp, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
body := mailBody.String()
|
||||
// emulate mail clients, which resolve "cid:" URIs to the mail's inline attachments
|
||||
body = strings.ReplaceAll(body, `src="cid:`, `src="`+setting.AppSubURL+`/devtest/mail-preview-embed/`)
|
||||
previewStyle := "body {padding: 12px 16px}"
|
||||
// a page can force "color-scheme" on an embedded document but never "prefers-color-scheme"
|
||||
if scheme := ctx.FormString("scheme"); scheme == "light" || scheme == "dark" {
|
||||
body = mailDarkSchemeQuery.ReplaceAllString(body, util.Iif(scheme == "dark", "@media all", "@media not all"))
|
||||
previewStyle += "\n:root {color-scheme: " + scheme + "}"
|
||||
}
|
||||
body = strings.Replace(body, "</head>", "<style>"+previewStyle+"</style></head>", 1)
|
||||
// fragment templates like "mail/base/head" would be sniffed as text/plain otherwise
|
||||
ctx.Resp.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
_, _ = ctx.Resp.Write([]byte(body))
|
||||
}
|
||||
|
||||
func MailPreviewEmbed(ctx *context.Context) {
|
||||
content, err := mailer.LoadMailIcon(ctx.PathParam("*"))
|
||||
if err != nil {
|
||||
ctx.NotFound(err)
|
||||
return
|
||||
}
|
||||
ctx.Resp.Header().Set("Content-Type", "image/png")
|
||||
_, _ = ctx.Resp.Write(content)
|
||||
}
|
||||
|
||||
func prepareMailPreviewRender(ctx *context.Context, tmplName string) {
|
||||
subject := "(default subject)"
|
||||
if mockData, err := mailPreviewMockData(tmplName); err == nil {
|
||||
if mockSubject, ok := mockData["Subject"].(string); ok {
|
||||
subject = util.IfZero(mockSubject, subject)
|
||||
}
|
||||
}
|
||||
tmplSubject := mailer.LoadedTemplates().SubjectTemplates.Lookup(tmplName)
|
||||
// FIXME: MAIL-TEMPLATE-SUBJECT: only "issue" related messages support using subject from templates
|
||||
subject := "(default subject)"
|
||||
if tmplSubject != nil {
|
||||
var buf strings.Builder
|
||||
err := tmplSubject.Execute(&buf, nil)
|
||||
|
||||
@@ -1781,6 +1781,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) {
|
||||
m.Any("/fetch-action-test", devtest.FetchActionTest)
|
||||
m.Any("/mail-preview", devtest.MailPreview)
|
||||
m.Any("/mail-preview/*", devtest.MailPreviewRender)
|
||||
m.Any("/mail-preview-embed/*", devtest.MailPreviewEmbed)
|
||||
m.Any("/{sub}", devtest.TmplCommon)
|
||||
m.Get("/repo-action-view/runs/{run}", devtest.MockActionsView)
|
||||
m.Get("/repo-action-view/runs/{run}/attempts/{attempt}", devtest.MockActionsView)
|
||||
|
||||
Reference in New Issue
Block a user