109 lines
2.7 KiB
Go
109 lines
2.7 KiB
Go
package usecase
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"html/template"
|
|
"strings"
|
|
|
|
"apps/backend/internal/module/notification/domain"
|
|
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|
)
|
|
|
|
// Config for notification service.
|
|
type Config struct {
|
|
Sender string
|
|
DevExposeCode bool
|
|
Brand domain.Brand
|
|
Providers []domain.EmailDelivery
|
|
}
|
|
|
|
// Service implements domain.UseCase.
|
|
type Service struct {
|
|
cfg Config
|
|
}
|
|
|
|
func NewService(cfg Config) *Service {
|
|
if cfg.Sender == "" {
|
|
cfg.Sender = "Harbor Desk <noreply@haixun.local>"
|
|
}
|
|
if cfg.Brand.Name == "" {
|
|
cfg.Brand = domain.DefaultBrand(cfg.Brand.Link)
|
|
}
|
|
if len(cfg.Providers) == 0 {
|
|
cfg.Providers = []domain.EmailDelivery{NewLogDelivery()}
|
|
cfg.DevExposeCode = true
|
|
}
|
|
return &Service{cfg: cfg}
|
|
}
|
|
|
|
func (s *Service) SenderFrom() string { return s.cfg.Sender }
|
|
func (s *Service) ExposeCodeInAPI() bool { return s.cfg.DevExposeCode }
|
|
func (s *Service) Brand() domain.Brand { return s.cfg.Brand }
|
|
|
|
func (s *Service) Enabled() bool {
|
|
for _, p := range s.cfg.Providers {
|
|
if p.Name() != "log" {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (s *Service) GetEmailTemplate(kind domain.TemplateKind, lang domain.Language) (*domain.EmailTemplate, error) {
|
|
lang = domain.NormalizeLanguage(string(lang))
|
|
return domain.GetTemplate(kind, lang, s.cfg.Brand)
|
|
}
|
|
|
|
func (s *Service) RenderVerify(kind domain.TemplateKind, lang domain.Language, vars domain.VerifyTemplateVars) (string, string, error) {
|
|
lang = domain.NormalizeLanguage(string(lang))
|
|
tpl, err := s.GetEmailTemplate(kind, lang)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
if vars.Username == "" {
|
|
vars.Username = "there"
|
|
}
|
|
// hermes may leave empty ResetURL button — still OK if placeholder replaced
|
|
t, err := template.New(string(kind)).Parse(tpl.Body)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := t.Execute(&buf, vars); err != nil {
|
|
return "", "", err
|
|
}
|
|
return tpl.Subject, buf.String(), nil
|
|
}
|
|
|
|
func (s *Service) SendEmail(ctx context.Context, req domain.EmailRequest) error {
|
|
if req.SenderEmail == "" {
|
|
req.SenderEmail = s.cfg.Sender
|
|
}
|
|
var last error
|
|
for _, p := range s.cfg.Providers {
|
|
if err := p.SendEmail(ctx, req); err != nil {
|
|
logx.WithContext(ctx).Errorf("notification send via %s failed: %v", p.Name(), err)
|
|
last = err
|
|
continue
|
|
}
|
|
logx.WithContext(ctx).Infof("notification sent via %s to %s subject=%q", p.Name(), maskEmail(req.RecipientEmail), req.Subject)
|
|
return nil
|
|
}
|
|
if last != nil {
|
|
return last
|
|
}
|
|
return fmt.Errorf("no email providers configured")
|
|
}
|
|
|
|
func maskEmail(e string) string {
|
|
e = strings.TrimSpace(e)
|
|
at := strings.IndexByte(e, '@')
|
|
if at <= 1 {
|
|
return "***"
|
|
}
|
|
return e[:1] + "***" + e[at:]
|
|
}
|