package emailLogic import ( "bytes" "context" "encoding/json" "strings" "text/template" "time" "github.com/perfect-panel/server/pkg/logger" "github.com/hibiken/asynq" "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/pkg/email" "github.com/perfect-panel/server/queue/types" ) type SendEmailLogic struct { svcCtx *svc.ServiceContext } func NewSendEmailLogic(svcCtx *svc.ServiceContext) *SendEmailLogic { return &SendEmailLogic{ svcCtx: svcCtx, } } func (l *SendEmailLogic) ProcessTask(ctx context.Context, task *asynq.Task) error { var payload types.SendEmailPayload if err := json.Unmarshal(task.Payload(), &payload); err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] Unmarshal payload failed", logger.Field("error", err.Error()), logger.Field("payload", task.Payload()), ) return nil } messageLog := log.Message{ Platform: l.svcCtx.Config.Email.Platform, To: payload.Email, Subject: payload.Subject, Content: payload.Content, } sender, err := email.NewSender(l.svcCtx.Config.Email.Platform, l.svcCtx.Config.Email.PlatformConfig, l.svcCtx.Config.Site.SiteName) if err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] NewSender failed", logger.Field("error", err.Error())) return nil } var content string switch payload.Type { case types.EmailTypeVerify: if t, ok := payload.Content["Type"].(float64); ok { payload.Content["Type"] = int(t) } else if t, ok := payload.Content["Type"].(int); ok { payload.Content["Type"] = t } typeVal, _ := payload.Content["Type"].(int) scene := resolveVerifyScene(payload.Scene, typeVal) tplStr := selectVerifyTemplate(l.svcCtx.Config.Email.VerifyEmailTemplates, l.svcCtx.Config.Email.VerifyEmailTemplate, scene) tpl, _ := template.New("verify").Parse(tplStr) var result bytes.Buffer err = tpl.Execute(&result, payload.Content) if err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", logger.Field("error", err.Error()), logger.Field("data", payload.Content), ) return nil } content = result.String() case types.EmailTypeDeleteAccount: tplStr := l.svcCtx.Config.Email.DeleteAccountEmailTemplate if tplStr == "" { tplStr = email.DefaultDeleteAccountEmailTemplate } tpl, _ := template.New("delete_account").Parse(tplStr) var result bytes.Buffer err = tpl.Execute(&result, payload.Content) if err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", logger.Field("error", err.Error()), logger.Field("template", l.svcCtx.Config.Email.DeleteAccountEmailTemplate), logger.Field("data", payload.Content), ) return nil } content = result.String() case types.EmailTypeMaintenance: tplStr := l.svcCtx.Config.Email.MaintenanceEmailTemplate if tplStr == "" { tplStr = email.DefaultMaintenanceEmailTemplate } tpl, _ := template.New("maintenance").Parse(tplStr) var result bytes.Buffer err = tpl.Execute(&result, payload.Content) if err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", logger.Field("error", err.Error()), logger.Field("template", l.svcCtx.Config.Email.MaintenanceEmailTemplate), logger.Field("data", payload.Content), ) return nil } content = result.String() case types.EmailTypeExpiration: tplStr := l.svcCtx.Config.Email.ExpirationEmailTemplate if tplStr == "" { tplStr = email.DefaultExpirationEmailTemplate } tpl, _ := template.New("expiration").Parse(tplStr) var result bytes.Buffer err = tpl.Execute(&result, payload.Content) if err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", logger.Field("error", err.Error()), logger.Field("template", l.svcCtx.Config.Email.ExpirationEmailTemplate), logger.Field("data", payload.Content), ) return nil } content = result.String() case types.EmailTypeTrafficExceed: tplStr := l.svcCtx.Config.Email.TrafficExceedEmailTemplate if tplStr == "" { tplStr = email.DefaultTrafficExceedEmailTemplate } tpl, _ := template.New("traffic_exceed").Parse(tplStr) var result bytes.Buffer err = tpl.Execute(&result, payload.Content) if err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", logger.Field("error", err.Error()), logger.Field("template", l.svcCtx.Config.Email.TrafficExceedEmailTemplate), logger.Field("data", payload.Content), ) return nil } content = result.String() case types.EmailTypeCustom: if payload.Content == nil { logger.WithContext(ctx).Error("[SendEmailLogic] Custom email content is empty", logger.Field("payload", payload), ) return nil } if tpl, ok := payload.Content["content"].(string); !ok { logger.WithContext(ctx).Error("[SendEmailLogic] Custom email content is not a string", logger.Field("payload", payload), ) return nil } else { content = tpl } default: logger.WithContext(ctx).Error("[SendEmailLogic] Unsupported email type", logger.Field("type", payload.Type), logger.Field("payload", payload), ) return nil } err = sender.Send([]string{payload.Email}, payload.Subject, content) if err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] Send email failed", logger.Field("error", err.Error())) return nil } messageLog.Status = 1 emailLog, err := messageLog.Marshal() if err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] Marshal message log failed", logger.Field("error", err.Error()), logger.Field("messageLog", messageLog), ) return nil } if err = l.svcCtx.LogModel.Insert(ctx, &log.SystemLog{ Type: log.TypeEmailMessage.Uint8(), Date: time.Now().Format("2006-01-02"), ObjectID: 0, Content: string(emailLog), }); err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] Insert email log failed", logger.Field("error", err.Error()), logger.Field("emailLog", string(emailLog)), ) return nil } return nil } func resolveVerifyScene(scene string, typeVal int) string { scene = strings.ToLower(strings.TrimSpace(scene)) if scene != "" { return scene } return constant.ParseVerifyType(uint8(typeVal)).String() } func selectVerifyTemplate(sceneTemplates map[string]string, legacyTemplate string, scene string) string { if sceneTemplates != nil { if tpl := strings.TrimSpace(sceneTemplates[scene]); tpl != "" { return tpl } if tpl := strings.TrimSpace(sceneTemplates["default"]); tpl != "" { return tpl } } if strings.TrimSpace(legacyTemplate) != "" { return legacyTemplate } return email.DefaultEmailVerifyTemplate }