diff --git a/cli/server.go b/cli/server.go index f76872a78c342..c8c1e9232bbe2 100644 --- a/cli/server.go +++ b/cli/server.go @@ -993,9 +993,10 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. if experiments.Enabled(codersdk.ExperimentNotifications) { cfg := options.DeploymentValues.Notifications metrics := notifications.NewMetrics(options.PrometheusRegistry) + helpers := templateHelpers(options) // The enqueuer is responsible for enqueueing notifications to the given store. - enqueuer, err := notifications.NewStoreEnqueuer(cfg, options.Database, templateHelpers(options), logger.Named("notifications.enqueuer")) + enqueuer, err := notifications.NewStoreEnqueuer(cfg, options.Database, helpers, logger.Named("notifications.enqueuer")) if err != nil { return xerrors.Errorf("failed to instantiate notification store enqueuer: %w", err) } @@ -1004,7 +1005,7 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. // The notification manager is responsible for: // - creating notifiers and managing their lifecycles (notifiers are responsible for dequeueing/sending notifications) // - keeping the store updated with status updates - notificationsManager, err = notifications.NewManager(cfg, options.Database, metrics, logger.Named("notifications.manager")) + notificationsManager, err = notifications.NewManager(cfg, options.Database, helpers, metrics, logger.Named("notifications.manager")) if err != nil { return xerrors.Errorf("failed to instantiate notification manager: %w", err) } @@ -1291,7 +1292,8 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. // We can later use this to inject whitelabel fields when app name / logo URL are overridden. func templateHelpers(options *coderd.Options) map[string]any { return map[string]any{ - "base_url": func() string { return options.AccessURL.String() }, + "base_url": func() string { return options.AccessURL.String() }, + "current_year": func() string { return strconv.Itoa(time.Now().Year()) }, } } diff --git a/coderd/notifications/dispatch/smtp.go b/coderd/notifications/dispatch/smtp.go index 218668e65d02e..e0c1b89f6154e 100644 --- a/coderd/notifications/dispatch/smtp.go +++ b/coderd/notifications/dispatch/smtp.go @@ -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) } diff --git a/coderd/notifications/dispatch/smtp/html.gotmpl b/coderd/notifications/dispatch/smtp/html.gotmpl index 00005179316bf..ac0527b9742d2 100644 --- a/coderd/notifications/dispatch/smtp/html.gotmpl +++ b/coderd/notifications/dispatch/smtp/html.gotmpl @@ -1,27 +1,32 @@ - + -
- - + + +© {{ current_year }} Coder. All rights reserved - {{ base_url }}
+ +