mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
refactor: refactor notification email template (#14208)
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/emersion/go-sasl"
|
||||
@@ -53,10 +54,12 @@ type SMTPHandler struct {
|
||||
log slog.Logger
|
||||
|
||||
loginWarnOnce sync.Once
|
||||
|
||||
helpers template.FuncMap
|
||||
}
|
||||
|
||||
func NewSMTPHandler(cfg codersdk.NotificationsEmailConfig, log slog.Logger) *SMTPHandler {
|
||||
return &SMTPHandler{cfg: cfg, log: log}
|
||||
func NewSMTPHandler(cfg codersdk.NotificationsEmailConfig, helpers template.FuncMap, log slog.Logger) *SMTPHandler {
|
||||
return &SMTPHandler{cfg: cfg, helpers: helpers, log: log}
|
||||
}
|
||||
|
||||
func (s *SMTPHandler) Dispatcher(payload types.MessagePayload, titleTmpl, bodyTmpl string) (DeliveryFunc, error) {
|
||||
@@ -75,12 +78,12 @@ func (s *SMTPHandler) Dispatcher(payload types.MessagePayload, titleTmpl, bodyTm
|
||||
// Then, reuse these strings in the HTML & plain body templates.
|
||||
payload.Labels["_subject"] = subject
|
||||
payload.Labels["_body"] = htmlBody
|
||||
htmlBody, err = render.GoTemplate(htmlTemplate, payload, nil)
|
||||
htmlBody, err = render.GoTemplate(htmlTemplate, payload, s.helpers)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("render full html template: %w", err)
|
||||
}
|
||||
payload.Labels["_body"] = plainBody
|
||||
plainBody, err = render.GoTemplate(plainTemplate, payload, nil)
|
||||
plainBody, err = render.GoTemplate(plainTemplate, payload, s.helpers)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("render full plaintext template: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{{ .Labels._subject }}</title>
|
||||
</head>
|
||||
<body style="font-family: Arial, sans-serif; background-color: #1d1d20; margin: 0; padding: 0;">
|
||||
<div style="max-width: 600px; margin: 20px auto; background-color: #3f556d; border: 1px solid #34495E; padding: 20px; border-radius: 8px;">
|
||||
<div style="text-align: center; padding: 20px 0; border-bottom: 1px solid #34495E;">
|
||||
<img width="215" height="47" src="https://coder.com/logo-wide-white.png"/>
|
||||
</div>
|
||||
<div style="padding: 20px; color: #ECF0F1; line-height: 1.6;">
|
||||
<h1 style="color: #ECF0F1;">{{ .Labels._subject }}</h1>
|
||||
</head>
|
||||
<body style="margin: 0; padding: 0; font-family: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #020617; background: #f8fafc;">
|
||||
<div style="max-width: 600px; margin: 20px auto; padding: 60px; border: 1px solid #e2e8f0; border-radius: 8px; background-color: #fff; text-align: left; font-size: 14px; line-height: 1.5;">
|
||||
<div style="text-align: center;">
|
||||
<img src="https://coder.com/coder-logo-horizontal.png" alt="Coder Logo" style="height: 40px;" />
|
||||
</div>
|
||||
<h1 style="text-align: center; font-size: 24px; font-weight: 400; margin: 8px 0 32px; line-height: 1.5;">
|
||||
{{ .Labels._subject }}
|
||||
</h1>
|
||||
<div style="line-height: 1.5;">
|
||||
{{ .Labels._body }}
|
||||
|
||||
</div>
|
||||
<div style="text-align: center; margin-top: 32px;">
|
||||
{{ range $action := .Actions }}
|
||||
<a href="{{ $action.URL }}" style="display: inline-block; padding: 10px 20px; background-color: #3D74DB; color: #ffffff; text-decoration: none; border-radius: 4px; margin-top: 20px;">{{ $action.Label }}</a><br>
|
||||
<a href="{{ $action.URL }}" style="display: inline-block; padding: 13px 24px; background-color: #020617; color: #f8fafc; text-decoration: none; border-radius: 8px; margin: 0 4px;">
|
||||
{{ $action.Label }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div style="border-top: 1px solid #e2e8f0; color: #475569; font-size: 12px; margin-top: 64px; padding-top: 24px; line-height: 1.6;">
|
||||
<p>© {{ current_year }} Coder. All rights reserved - <a href="{{ base_url }}" style="color: #2563eb; text-decoration: none;">{{ base_url }}</a></p>
|
||||
<p><a href="{{ base_url }}/settings/notifications" style="color: #2563eb; text-decoration: none;">Click here to manage your notification settings</a></p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: center; padding: 10px 0; border-top: 1px solid #34495E; margin-top: 20px; color: #BDC3C7;">
|
||||
<!-- TODO: dynamic copyright -->
|
||||
© 2024 Coder. All rights reserved.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -417,7 +417,11 @@ func TestSMTP(t *testing.T) {
|
||||
require.NoError(t, hp.Set(listen.Addr().String()))
|
||||
tc.cfg.Smarthost = hp
|
||||
|
||||
handler := dispatch.NewSMTPHandler(tc.cfg, logger.Named("smtp"))
|
||||
helpers := map[string]any{
|
||||
"base_url": func() string { return "http://test.com" },
|
||||
"current_year": func() string { return "2024" },
|
||||
}
|
||||
handler := dispatch.NewSMTPHandler(tc.cfg, helpers, logger.Named("smtp"))
|
||||
|
||||
// Start mock SMTP server in the background.
|
||||
var wg sync.WaitGroup
|
||||
|
||||
Reference in New Issue
Block a user