1
0
mirror of https://github.com/muety/wakapi.git synced 2023-08-10 21:12:56 +03:00

chore: send notification on successful import

This commit is contained in:
Ferdinand Mütsch
2021-04-10 10:48:06 +02:00
parent 56247b4e1e
commit 2a9fbfdfd7
11 changed files with 262 additions and 32 deletions

View File

@ -11,29 +11,37 @@ import (
)
const (
tplPath = "/views/mail"
tplNamePasswordReset = "reset_password"
subjectPasswordReset = "Wakapi Password Reset"
tplPath = "/views/mail"
tplNamePasswordReset = "reset_password"
tplNameImportNotification = "import_finished"
subjectPasswordReset = "Wakapi Password Reset"
subjectImportNotification = "Wakapi Data Import Finished"
)
type passwordResetLinkTplData struct {
type PasswordResetTplData struct {
ResetLink string
}
type ImportNotificationTplData struct {
PublicUrl string
Duration string
NumHeartbeats int
}
// Factory
func NewMailService() services.IMailService {
config := conf.Get()
if config.Mail.Enabled {
if config.Mail.Provider == conf.MailProviderMailWhale {
return NewMailWhaleService(config.Mail.MailWhale)
return NewMailWhaleService(config.Mail.MailWhale, config.Server.PublicUrl)
} else if config.Mail.Provider == conf.MailProviderSmtp {
return NewSMTPMailService(config.Mail.Smtp)
return NewSMTPMailService(config.Mail.Smtp, config.Server.PublicUrl)
}
}
return &NoopMailService{}
}
func getPasswordResetTemplate(data passwordResetLinkTplData) (*bytes.Buffer, error) {
func getPasswordResetTemplate(data PasswordResetTplData) (*bytes.Buffer, error) {
tpl, err := loadTemplate(tplNamePasswordReset)
if err != nil {
return nil, err
@ -45,6 +53,18 @@ func getPasswordResetTemplate(data passwordResetLinkTplData) (*bytes.Buffer, err
return &rendered, nil
}
func getImportNotificationTemplate(data ImportNotificationTplData) (*bytes.Buffer, error) {
tpl, err := loadTemplate(tplNameImportNotification)
if err != nil {
return nil, err
}
var rendered bytes.Buffer
if err := tpl.Execute(&rendered, data); err != nil {
return nil, err
}
return &rendered, nil
}
func loadTemplate(tplName string) (*template.Template, error) {
tplFile, err := pkger.Open(fmt.Sprintf("%s/%s.tpl.html", tplPath, tplName))
if err != nil {

View File

@ -12,6 +12,7 @@ import (
)
type MailWhaleMailService struct {
publicUrl string
config *conf.MailwhaleMailConfig
httpClient *http.Client
}
@ -25,26 +26,39 @@ type MailWhaleSendRequest struct {
TemplateVars map[string]string `json:"template_vars"`
}
func NewMailWhaleService(config *conf.MailwhaleMailConfig) *MailWhaleMailService {
func NewMailWhaleService(config *conf.MailwhaleMailConfig, publicUrl string) *MailWhaleMailService {
return &MailWhaleMailService{
config: config,
publicUrl: publicUrl,
config: config,
httpClient: &http.Client{
Timeout: 10 * time.Second,
},
}
}
func (s *MailWhaleMailService) SendPasswordResetMail(recipient *models.User, resetLink string) error {
template, err := getPasswordResetTemplate(passwordResetLinkTplData{ResetLink: resetLink})
func (s *MailWhaleMailService) SendPasswordReset(recipient *models.User, resetLink string) error {
template, err := getPasswordResetTemplate(PasswordResetTplData{ResetLink: resetLink})
if err != nil {
return err
}
return s.send(recipient.Email, subjectPasswordReset, template.String(), true)
}
func (s *MailWhaleMailService) SendImportNotification(recipient *models.User, duration time.Duration, numHeartbeats int) error {
template, err := getImportNotificationTemplate(ImportNotificationTplData{
PublicUrl: s.publicUrl,
Duration: fmt.Sprintf("%.0f seconds", duration.Seconds()),
NumHeartbeats: numHeartbeats,
})
if err != nil {
return err
}
return s.send(recipient.Email, subjectImportNotification, template.String(), true)
}
func (s *MailWhaleMailService) send(to, subject, body string, isHtml bool) error {
if to == "" {
return errors.New("no recipient mail address set, cannot send password reset link")
return errors.New("not sending mail as recipient mail address seems to be invalid")
}
sendRequest := &MailWhaleSendRequest{

View File

@ -3,11 +3,17 @@ package mail
import (
"github.com/emvi/logbuch"
"github.com/muety/wakapi/models"
"time"
)
type NoopMailService struct{}
func (n *NoopMailService) SendPasswordResetMail(recipient *models.User, resetLink string) error {
func (n *NoopMailService) SendPasswordReset(recipient *models.User, resetLink string) error {
logbuch.Info("noop mail service doing nothing instead of sending password reset mail to %s", recipient.ID)
return nil
}
func (n *NoopMailService) SendImportNotification(recipient *models.User, duration time.Duration, numHeartbeats int) error {
logbuch.Info("noop mail service doing nothing instead of sending import notification mail to %s", recipient.ID)
return nil
}

View File

@ -2,21 +2,25 @@ package mail
import (
"errors"
"fmt"
"github.com/emersion/go-sasl"
"github.com/emersion/go-smtp"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models"
"io"
"time"
)
type SMTPMailService struct {
config *conf.SMTPMailConfig
auth sasl.Client
publicUrl string
config *conf.SMTPMailConfig
auth sasl.Client
}
func NewSMTPMailService(config *conf.SMTPMailConfig) *SMTPMailService {
func NewSMTPMailService(config *conf.SMTPMailConfig, publicUrl string) *SMTPMailService {
return &SMTPMailService{
config: config,
publicUrl: publicUrl,
config: config,
auth: sasl.NewPlainClient(
"",
config.Username,
@ -25,8 +29,8 @@ func NewSMTPMailService(config *conf.SMTPMailConfig) *SMTPMailService {
}
}
func (s *SMTPMailService) SendPasswordResetMail(recipient *models.User, resetLink string) error {
template, err := getPasswordResetTemplate(passwordResetLinkTplData{ResetLink: resetLink})
func (s *SMTPMailService) SendPasswordReset(recipient *models.User, resetLink string) error {
template, err := getPasswordResetTemplate(PasswordResetTplData{ResetLink: resetLink})
if err != nil {
return err
}
@ -38,14 +42,27 @@ func (s *SMTPMailService) SendPasswordResetMail(recipient *models.User, resetLin
}
mail.WithHTML(template.String())
return s.send(
s.config.ConnStr(),
s.config.TLS,
s.auth,
mail.From.Raw(),
mail.To.RawStrings(),
mail.Reader(),
)
return s.send(s.config.ConnStr(), s.config.TLS, s.auth, mail.From.Raw(), mail.To.RawStrings(), mail.Reader())
}
func (s *SMTPMailService) SendImportNotification(recipient *models.User, duration time.Duration, numHeartbeats int) error {
template, err := getImportNotificationTemplate(ImportNotificationTplData{
PublicUrl: s.publicUrl,
Duration: fmt.Sprintf("%.0f seconds", duration.Seconds()),
NumHeartbeats: numHeartbeats,
})
if err != nil {
return err
}
mail := &models.Mail{
From: models.MailAddress(s.config.Sender),
To: models.MailAddresses([]models.MailAddress{models.MailAddress(recipient.Email)}),
Subject: subjectImportNotification,
}
mail.WithHTML(template.String())
return s.send(s.config.ConnStr(), s.config.TLS, s.auth, mail.From.Raw(), mail.To.RawStrings(), mail.Reader())
}
func (s *SMTPMailService) send(addr string, tls bool, a sasl.Client, from string, to []string, r io.Reader) error {

View File

@ -80,5 +80,6 @@ type IUserService interface {
}
type IMailService interface {
SendPasswordResetMail(recipient *models.User, resetLink string) error
SendPasswordReset(*models.User, string) error
SendImportNotification(*models.User, time.Duration, int) error
}