stuve-it-backend/emailApi/main.go

147 lines
4.4 KiB
Go
Raw Normal View History

package emailApi
import (
"fmt"
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/logger"
"github.com/microcosm-cc/bluemonday"
"github.com/pocketbase/pocketbase"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/models"
"github.com/pocketbase/pocketbase/tools/mailer"
"github.com/pocketbase/pocketbase/tools/template"
"net/mail"
)
// sendEmailToUser sends an email notification to a recipient of the email record
2024-10-25 14:53:06 +00:00
func sendEmailToUser(app *pocketbase.PocketBase, registry *template.Registry, recipient *models.Record, sender *models.Record, emailRecord *models.Record) error {
// check if recipient and message are set and recipient is not the sender
if recipient == nil || emailRecord == nil || sender == nil {
2024-10-25 14:53:06 +00:00
return fmt.Errorf("unable to send email to recipient: recipient, sender or email record is nil")
}
// sanitize email content
policy := bluemonday.UGCPolicy()
content := emailRecord.GetString("content")
safeContent := policy.Sanitize(content)
// get recipient and sender email
recipientEmail := recipient.GetString("email")
senderEmail := sender.GetString("email")
2024-10-24 20:06:12 +00:00
// get email subject
subject := "[StuVe IT] " + emailRecord.GetString("subject")
// render email template
html, err := registry.LoadFiles(
2024-10-24 17:21:50 +00:00
"html/blankEmail.html",
).Render(map[string]any{
"APP_URL": app.Settings().Meta.AppUrl,
"SENDER_SN": sender.GetString("sn"),
"SENDER_GIVENNAME": sender.GetString("givenName"),
"SENDER_EMAIL": senderEmail,
"CONTENT": safeContent,
2024-10-24 20:06:12 +00:00
"SUBJECT": subject,
})
if err != nil {
2024-10-25 14:53:06 +00:00
return fmt.Errorf("error rendering email template for user with id '%s': %v", recipient.Id, err)
}
// set reply-to header
headers := make(map[string]string)
headers["Reply-To"] = senderEmail
// send email
email := &mailer.Message{
From: mail.Address{
Address: app.Settings().Meta.SenderAddress,
Name: app.Settings().Meta.SenderName,
},
To: []mail.Address{{Address: recipientEmail}},
2024-10-24 20:06:12 +00:00
Subject: subject,
HTML: html,
Headers: headers,
}
if err := app.NewMailClient().Send(email); err != nil {
2024-10-25 14:53:06 +00:00
return fmt.Errorf("error sending email to user with id '%s': %v", recipient.Id, err)
}
2024-10-25 14:53:06 +00:00
return nil
}
// sendEmails sends an email notification to the recipients of the email record@
func sendEmails(app *pocketbase.PocketBase, emailRecord *models.Record) {
registry := template.NewRegistry()
// expand the createdMessageRecord to get recipient user and send email notification if recipient is set
2024-10-24 17:14:45 +00:00
if errs := app.Dao().ExpandRecord(emailRecord, []string{"recipients", "sender"}, nil); len(errs) > 0 {
// return new error with all errors
logger.LogErrorF("Error expanding created email record: %v", errs)
emailRecord.Set("errors", fmt.Sprintf("The email was not sent to anyone due to an error."))
return
}
2024-10-25 14:53:06 +00:00
// get sender and recipients
sender := emailRecord.ExpandedOne("sender")
recipients := emailRecord.ExpandedAll("recipients")
2024-10-25 14:53:06 +00:00
// this is the list of user ids that the email was sent to
sendToIds := make([]string, 0)
// send email to each recipient
for _, recipient := range recipients {
2024-10-25 14:53:06 +00:00
// send email to user
err := sendEmailToUser(app, registry, recipient, sender, emailRecord)
// check if there was an error sending the email
if err != nil {
logger.LogErrorF("%v", err)
continue
}
// add recipient id to sendToIds
sendToIds = append(sendToIds, recipient.Id)
// update email sentTo field, this will be overwritten for each recipient
// we update it for every iteration to provide live feedback on the frontend
emailRecord.Set("sentTo", sendToIds)
// save email record
if err := app.Dao().SaveRecord(emailRecord); err != nil {
logger.LogErrorF("Error saving email record: %v", err)
2024-10-25 14:53:06 +00:00
}
}
// mark email as sent
2024-10-25 14:53:06 +00:00
emailRecord.Set("sentTo", sendToIds)
// save email record
if err := app.Dao().SaveRecord(emailRecord); err != nil {
logger.LogErrorF("Error saving email record: %v", err)
}
return
}
// InitEmailApi initializes the email notifier
//
// the function sends an email notification after it was created
func InitEmailApi(app *pocketbase.PocketBase, _ *core.ServeEvent) error {
logger.LogInfoF("Adding email notifier")
app.OnModelAfterCreate("emails").Add(func(e *core.ModelEvent) error {
// get created message record
createdEmailRecord, err := app.Dao().FindRecordById("emails", e.Model.GetId())
if err != nil {
return err
}
go sendEmails(app, createdEmailRecord)
return nil
})
return nil
}