Yimaru-BackEnd/internal/services/emailtemplates/defaults.go
Yared Yemane 5937c5505a Add admin-managed email templates and use them for OTP delivery
Adds CRUD and preview APIs, RBAC permissions, seeded system templates, and migrates OTP email/SMS to template rendering.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 01:28:48 -07:00

113 lines
4.4 KiB
Go

package emailtemplates
import (
"Yimaru-Backend/internal/domain"
"bytes"
)
var defaultTemplates = map[string]domain.EmailTemplate{
domain.EmailTemplateSlugOTP: {
Slug: domain.EmailTemplateSlugOTP,
Name: "One-Time Password",
Subject: "Yimaru - One Time Password",
BodyText: "Welcome to Yimaru Online Learning Platform{{if .FirstName}}, {{.FirstName}}{{end}}. Your OTP is {{.OTP}}. It expires in {{.ExpiresMinutes}} minutes. Please do not share it with anyone.",
BodyHTML: "<p>Welcome to Yimaru Online Learning Platform{{if .FirstName}}, <strong>{{.FirstName}}</strong>{{end}}.</p><p>Your one-time password is <strong>{{.OTP}}</strong>.</p><p>It expires in {{.ExpiresMinutes}} minutes. Please do not share it with anyone.</p>",
Variables: []string{"OTP", "FirstName", "ExpiresMinutes"},
Status: domain.EmailTemplateStatusActive,
},
domain.EmailTemplateSlugInvitation: {
Slug: domain.EmailTemplateSlugInvitation,
Name: "User Invitation",
Subject: "You are invited to join Yimaru",
BodyText: "Hi{{if .FirstName}} {{.FirstName}}{{end}}, you have been invited{{if .InviterName}} by {{.InviterName}}{{end}} to join Yimaru Online Learning Platform. Accept your invitation: {{.InviteLink}}",
BodyHTML: "<p>Hi{{if .FirstName}} <strong>{{.FirstName}}</strong>{{end}},</p><p>You have been invited{{if .InviterName}} by <strong>{{.InviterName}}</strong>{{end}} to join Yimaru Online Learning Platform.</p><p><a href=\"{{.InviteLink}}\">Accept your invitation</a></p>",
Variables: []string{"FirstName", "InviterName", "InviteLink"},
Status: domain.EmailTemplateStatusActive,
},
domain.EmailTemplateSlugPasswordReset: {
Slug: domain.EmailTemplateSlugPasswordReset,
Name: "Password Reset",
Subject: "Reset your Yimaru password",
BodyText: "Hi{{if .FirstName}} {{.FirstName}}{{end}}, use this link to reset your password: {{.ResetLink}}. The link expires in {{.ExpiresMinutes}} minutes.",
BodyHTML: "<p>Hi{{if .FirstName}} <strong>{{.FirstName}}</strong>{{end}},</p><p>Use the link below to reset your password. It expires in {{.ExpiresMinutes}} minutes.</p><p><a href=\"{{.ResetLink}}\">Reset your password</a></p>",
Variables: []string{"FirstName", "ResetLink", "ExpiresMinutes"},
Status: domain.EmailTemplateStatusActive,
},
domain.EmailTemplateSlugWelcome: {
Slug: domain.EmailTemplateSlugWelcome,
Name: "Welcome Email",
Subject: "Welcome to Yimaru",
BodyText: "Hi{{if .FirstName}} {{.FirstName}}{{end}}, welcome to Yimaru Online Learning Platform! Sign in at {{.LoginURL}} to get started.",
BodyHTML: "<p>Hi{{if .FirstName}} <strong>{{.FirstName}}</strong>{{end}},</p><p>Welcome to Yimaru Online Learning Platform!</p><p><a href=\"{{.LoginURL}}\">Sign in to get started</a></p>",
Variables: []string{"FirstName", "LoginURL"},
Status: domain.EmailTemplateStatusActive,
},
domain.EmailTemplateSlugCustomMessage: {
Slug: domain.EmailTemplateSlugCustomMessage,
Name: "Custom Message",
Subject: "{{.Subject}}",
BodyText: "{{.Message}}",
BodyHTML: "<p>{{.Message}}</p>",
Variables: []string{"Subject", "Message"},
Status: domain.EmailTemplateStatusActive,
},
}
func defaultTemplate(slug string) (domain.EmailTemplate, bool) {
tmpl, ok := defaultTemplates[slug]
return tmpl, ok
}
func renderTemplateFields(tmpl domain.EmailTemplate, data map[string]any) (domain.RenderedEmail, error) {
if data == nil {
data = map[string]any{}
}
subject, err := executeTextTemplate("subject:"+tmpl.Slug, tmpl.Subject, data)
if err != nil {
return domain.RenderedEmail{}, err
}
text, err := executeTextTemplate("text:"+tmpl.Slug, tmpl.BodyText, data)
if err != nil {
return domain.RenderedEmail{}, err
}
html, err := executeHTMLTemplate("html:"+tmpl.Slug, tmpl.BodyHTML, data)
if err != nil {
return domain.RenderedEmail{}, err
}
return domain.RenderedEmail{
Subject: subject,
Text: text,
HTML: html,
}, nil
}
func executeTextTemplate(name, content string, data map[string]any) (string, error) {
tmpl, err := newTextTemplate(name, content)
if err != nil {
return "", err
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
return "", err
}
return buf.String(), nil
}
func executeHTMLTemplate(name, content string, data map[string]any) (string, error) {
tmpl, err := newHTMLTemplate(name, content)
if err != nil {
return "", err
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
return "", err
}
return buf.String(), nil
}