package task import ( "bytes" "context" "fmt" "text/template" "time" "forge.cadoles.com/Cadoles/daddy/internal/mail" "forge.cadoles.com/Cadoles/daddy/internal/model" "github.com/pkg/errors" "forge.cadoles.com/Cadoles/daddy/internal/orm" "gitlab.com/wpetit/goweb/middleware/container" "gitlab.com/wpetit/goweb/logger" ) type Newsletter struct { ctx context.Context timeRange time.Duration baseURL string contentTemplate string subjectTemplate string from string } func (t *Newsletter) Name() string { return "newsletter" } func (t *Newsletter) Run() { ctx := t.ctx logger.Info(ctx, "preparing newsletter", logger.F("timeRange", t.timeRange)) contentTmpl, err := template.New("").Parse(t.contentTemplate) if err != nil { logger.Error(ctx, "could not parse newsletter content template", logger.E(errors.WithStack(err))) return } subjectTmpl, err := template.New("").Parse(t.subjectTemplate) if err != nil { logger.Error(ctx, "could not parse newsletter subject template", logger.E(errors.WithStack(err))) return } ctn := container.Must(ctx) orm := orm.Must(ctn) db := orm.DB() mailSrv := mail.Must(ctn) eventRepo := model.NewEventRepository(db) to := time.Now() from := to.Add(-t.timeRange) events, err := eventRepo.Search(ctx, &model.EventFilter{ From: &from, To: &to, }) if err != nil { logger.Error(ctx, "could not search events", logger.E(errors.WithStack(err))) return } newWorkgroups := make([]*model.Workgroup, 0) newDecisionSupportFiles := make([]*model.DecisionSupportFile, 0) readyToVote := make([]*model.DecisionSupportFile, 0) voted := make([]*model.DecisionSupportFile, 0) workgroupRepo := model.NewWorkgroupRepository(db) dsfRepo := model.NewDSFRepository(db) for _, evt := range events { switch { case evt.Type == model.EventTypeCreated && evt.ObjectType == model.ObjectTypeWorkgroup: workgroup, err := workgroupRepo.Find(ctx, fmt.Sprintf("%d", evt.ObjectID)) if err != nil { logger.Error( ctx, "could not find workgroup", logger.E(errors.WithStack(err)), logger.F("id", evt.ObjectID), ) return } newWorkgroups = append(newWorkgroups, workgroup) case evt.Type == model.EventTypeCreated && evt.ObjectType == model.ObjectTypeDecisionSupportFile: dsf, err := dsfRepo.Find(ctx, fmt.Sprintf("%d", evt.ObjectID)) if err != nil { logger.Error( ctx, "could not find decision support file", logger.E(errors.WithStack(err)), logger.F("id", evt.ObjectID), ) return } newDecisionSupportFiles = append(newDecisionSupportFiles, dsf) case evt.Type == model.EventTypeStatusChanged && evt.ObjectType == model.ObjectTypeDecisionSupportFile: dsf, err := dsfRepo.Find(ctx, fmt.Sprintf("%d", evt.ObjectID)) if err != nil { logger.Error( ctx, "could not find decision support file", logger.E(errors.WithStack(err)), logger.F("id", evt.ObjectID), ) return } if dsf.Status == model.StatusReady { readyToVote = append(readyToVote, dsf) } if dsf.Status == model.StatusVoted { voted = append(voted, dsf) } } } hasEvents := len(newDecisionSupportFiles) > 0 || len(newWorkgroups) > 0 userRepo := model.NewUserRepository(db) users, err := userRepo.All(ctx) if err != nil { logger.Error(ctx, "could not find users", logger.E(errors.WithStack(err))) return } var ( contentBuff bytes.Buffer subjectBuff bytes.Buffer ) for _, u := range users { tmplData := struct { User *model.User NewWorkgroups []*model.Workgroup NewDecisionSupportFiles []*model.DecisionSupportFile ReadyToVote []*model.DecisionSupportFile Voted []*model.DecisionSupportFile BaseURL string From time.Time To time.Time HasEvents bool }{ User: u, BaseURL: t.baseURL, NewWorkgroups: newWorkgroups, NewDecisionSupportFiles: newDecisionSupportFiles, ReadyToVote: readyToVote, Voted: voted, From: from.Local(), To: to.Local(), HasEvents: hasEvents, } err = contentTmpl.Execute(&contentBuff, tmplData) if err != nil { logger.Error(ctx, "could not execute newsletter content template", logger.E(errors.WithStack(err))) return } err = subjectTmpl.Execute(&subjectBuff, tmplData) if err != nil { logger.Error(ctx, "could not execute newsletter subject template", logger.E(errors.WithStack(err))) return } newsletterContent := contentBuff.String() newsletterSubject := subjectBuff.String() err := mailSrv.Send( mail.WithRecipients(u.Email), mail.WithSubject(newsletterSubject), mail.WithSender(t.from, ""), mail.WithBody(mail.ContentTypeText, newsletterContent, nil), ) if err != nil { logger.Error( ctx, "could not send newsletter", logger.E(errors.WithStack(err)), logger.F("email", u.Email), ) return } contentBuff.Reset() subjectBuff.Reset() } } func NewNewsletter(ctx context.Context, timeRange time.Duration, baseURL, contentTemplate, subjectTemplate, from string) *Newsletter { return &Newsletter{ ctx: ctx, timeRange: timeRange, baseURL: baseURL, contentTemplate: contentTemplate, subjectTemplate: subjectTemplate, from: from, } }