Ajout d'une newsletter basique
La newsletter effectue une collecte des évènements sur une période de temps donné et envoi un récapitulatif à l'ensemble des utilisateurs de Daddy. Actuellement, sont collectés et présentés: - Les créations de groupes de travail - Les créations de dossiers d'aide à la décision - Les dossiers dont le statut à été modifié et prêt à voté
This commit is contained in:
212
internal/task/newsletter.go
Normal file
212
internal/task/newsletter.go
Normal file
@ -0,0 +1,212 @@
|
||||
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,
|
||||
}
|
||||
}
|
6
internal/task/task.go
Normal file
6
internal/task/task.go
Normal file
@ -0,0 +1,6 @@
|
||||
package task
|
||||
|
||||
type Task interface {
|
||||
Name() string
|
||||
Run()
|
||||
}
|
Reference in New Issue
Block a user