213 lines
5.2 KiB
Go
213 lines
5.2 KiB
Go
|
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)
|
||
|
|
||
|
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)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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
|
||
|
BaseURL string
|
||
|
From time.Time
|
||
|
To time.Time
|
||
|
HasEvents bool
|
||
|
}{
|
||
|
User: u,
|
||
|
BaseURL: t.baseURL,
|
||
|
NewWorkgroups: newWorkgroups,
|
||
|
NewDecisionSupportFiles: newDecisionSupportFiles,
|
||
|
ReadyToVote: readyToVote,
|
||
|
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,
|
||
|
}
|
||
|
}
|