feat(eventEntriesNotification): added email notifications when a user registers for an event or something about his entry was changed
Build and Push Docker image / build-and-push (push) Successful in 3m10s
Details
Build and Push Docker image / build-and-push (push) Successful in 3m10s
Details
This commit is contained in:
parent
50da122f22
commit
aaebaf8b17
|
@ -0,0 +1,87 @@
|
||||||
|
package eventEntriesNotifier
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/logger"
|
||||||
|
"github.com/pocketbase/pocketbase"
|
||||||
|
"github.com/pocketbase/pocketbase/core"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/mailer"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/template"
|
||||||
|
"net/mail"
|
||||||
|
)
|
||||||
|
|
||||||
|
// sendEmailNotification sends an email notification to the user
|
||||||
|
func sendEmailNotification(app *pocketbase.PocketBase, recordId string, STATUS string) error {
|
||||||
|
registry := template.NewRegistry()
|
||||||
|
|
||||||
|
record, err := app.Dao().FindRecordById("eventListSlotEntriesWithUser", recordId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := app.Dao().FindRecordById("users", record.GetString("user"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// render email template
|
||||||
|
html, err := registry.LoadFiles(
|
||||||
|
"html/eventEntryNotification.html",
|
||||||
|
).Render(map[string]any{
|
||||||
|
"STATUS": STATUS,
|
||||||
|
"EVENT_NAME": record.GetString("eventName"),
|
||||||
|
"APP_URL": app.Settings().Meta.AppUrl,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// send email
|
||||||
|
email := &mailer.Message{
|
||||||
|
From: mail.Address{
|
||||||
|
Address: app.Settings().Meta.SenderAddress,
|
||||||
|
Name: app.Settings().Meta.SenderName,
|
||||||
|
},
|
||||||
|
To: []mail.Address{{Address: user.GetString("email")}},
|
||||||
|
Subject: "[StuVe IT] Info zu einer Event Anmeldung",
|
||||||
|
HTML: html,
|
||||||
|
}
|
||||||
|
if err := app.NewMailClient().Send(email); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitEventEntriesNotifier initializes the eventEntriesNotifier email notifier
|
||||||
|
func InitEventEntriesNotifier(app *pocketbase.PocketBase, e *core.ServeEvent) error {
|
||||||
|
|
||||||
|
logger.LogInfoF("Adding eventEntriesNotifier email notifier")
|
||||||
|
|
||||||
|
app.OnModelAfterCreate("eventListSlotEntries").Add(func(e *core.ModelEvent) error {
|
||||||
|
// send email notification
|
||||||
|
err := sendEmailNotification(app, e.Model.GetId(), "created")
|
||||||
|
if err != nil {
|
||||||
|
logger.LogErrorF("Error sending eventEntry email notification: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
app.OnModelAfterCreate("eventListSlotEntries").Add(func(e *core.ModelEvent) error {
|
||||||
|
// send email notification
|
||||||
|
err := sendEmailNotification(app, e.Model.GetId(), "updated")
|
||||||
|
if err != nil {
|
||||||
|
logger.LogErrorF("Error sending eventEntry email notification: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
app.OnModelAfterDelete("eventListSlotEntries").Add(func(e *core.ModelEvent) error {
|
||||||
|
// send email notification
|
||||||
|
err := sendEmailNotification(app, e.Model.GetId(), "deleted")
|
||||||
|
if err != nil {
|
||||||
|
logger.LogErrorF("Error sending eventEntry email notification: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -45,18 +45,29 @@
|
||||||
background-color: #228be6;
|
background-color: #228be6;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="stack">
|
<div class="stack">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="blue-text">Hallo 👋,</h1>
|
<h1 class="blue-text">Hallo 👋,</h1>
|
||||||
<p>Du hast eine neue {{.MESSAGE_TYPE}}! Schau dir die {{.MESSAGE_TYPE}} an, indem du auf den Button klickst:</p>
|
<p>
|
||||||
|
{{if eq .STATUS "created"}}
|
||||||
|
Du hast Dich erfolgreich für das Event {{.EVENT_NAME}} angemeldet!
|
||||||
|
{{else if eq .STATUS "updated"}}
|
||||||
|
Die Daten Deiner Anmeldung für das Event {{.EVENT_NAME}} wurde aktualisiert.
|
||||||
|
{{else if eq .STATUS "deleted"}}
|
||||||
|
Deine Anmeldung für das Event {{.EVENT_NAME}} wurde storniert!
|
||||||
|
{{else}}
|
||||||
|
Schau Dir Deine Anmeldungen für das Event {{.EVENT_NAME}} an!
|
||||||
|
{{end}}
|
||||||
|
</p>
|
||||||
<br/>
|
<br/>
|
||||||
<a class="action-btn" href="{{.ACTION_URL}}" target="_blank" rel="noopener">{{.MESSAGE_TYPE}} anschauen</a>
|
<a class="action-btn" href="{{.APP_URL}}/events/entries" target="_blank" rel="noopener">Deine Anmeldungen</a>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="group">
|
<div class="group">
|
||||||
<svg class="logo" width="100%" height="100%" viewBox="0 0 100 100" version="1.1"
|
<svg class="logo" width="100%" height="100%" viewBox="0 0 100 100"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xml:space="preserve"
|
xml:space="preserve"
|
||||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
|
@ -25,7 +25,7 @@ func LogErrorF(format string, a ...interface{}) {
|
||||||
logger("error", format, a...)
|
logger("error", format, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// logger logger is a helper function to log messages to stdout
|
// logger logger is a helper function to log eventEntriesNotifier to stdout
|
||||||
func logger(level string, format string, a ...interface{}) {
|
func logger(level string, format string, a ...interface{}) {
|
||||||
var c *color.Color
|
var c *color.Color
|
||||||
switch level {
|
switch level {
|
||||||
|
|
18
main/main.go
18
main/main.go
|
@ -2,10 +2,10 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/emailApi"
|
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/emailApi"
|
||||||
|
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/eventEntriesNotifier"
|
||||||
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/ldapApi"
|
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/ldapApi"
|
||||||
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/ldapSync"
|
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/ldapSync"
|
||||||
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/logger"
|
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/logger"
|
||||||
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/messages"
|
|
||||||
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/qrApi"
|
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/qrApi"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
"github.com/pocketbase/pocketbase"
|
"github.com/pocketbase/pocketbase"
|
||||||
|
@ -25,22 +25,16 @@ func main() {
|
||||||
app := pocketbase.New()
|
app := pocketbase.New()
|
||||||
|
|
||||||
// setup ldap sync
|
// setup ldap sync
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
app.OnBeforeServe().Add(func(e *core.ServeEvent) error { return ldapSync.InitLdapSync(app) })
|
||||||
return ldapSync.InitLdapSync(app)
|
|
||||||
})
|
|
||||||
|
|
||||||
// setup ldap login
|
// setup ldap login
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
app.OnBeforeServe().Add(func(e *core.ServeEvent) error { return ldapApi.InitLdapApi(app, e) })
|
||||||
return ldapApi.InitLdapApi(app, e)
|
|
||||||
})
|
|
||||||
|
|
||||||
// setup qr api
|
// setup qr api
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
app.OnBeforeServe().Add(func(e *core.ServeEvent) error { return qrApi.InitQRApi(app, e) })
|
||||||
return qrApi.InitQRApi(app, e)
|
|
||||||
})
|
|
||||||
|
|
||||||
// setup messages email notifications
|
// setup eventEntriesNotifier email notifications
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error { return messages.InitMessages(app, e) })
|
app.OnBeforeServe().Add(func(e *core.ServeEvent) error { return eventEntriesNotifier.InitEventEntriesNotifier(app, e) })
|
||||||
|
|
||||||
// setup email api
|
// setup email api
|
||||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error { return emailApi.InitEmailApi(app, e) })
|
app.OnBeforeServe().Add(func(e *core.ServeEvent) error { return emailApi.InitEmailApi(app, e) })
|
||||||
|
|
154
messages/main.go
154
messages/main.go
|
@ -1,154 +0,0 @@
|
||||||
package messages
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/logger"
|
|
||||||
"github.com/pocketbase/dbx"
|
|
||||||
"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"
|
|
||||||
)
|
|
||||||
|
|
||||||
// sendEmailNotification sends an email notification to the user
|
|
||||||
func sendEmailNotification(app *pocketbase.PocketBase, registry *template.Registry, user *models.Record, message *models.Record) {
|
|
||||||
// check if user and message are set and user is not the sender
|
|
||||||
if user == nil || message == nil || user.GetId() == message.GetString("sender") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't send email notification if user has muted email notifications and message is not an announcement
|
|
||||||
if user.GetBool("muteEmailNotifications") && !message.GetBool("isAnnouncement") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// get user email
|
|
||||||
userEmail := user.GetString("email")
|
|
||||||
|
|
||||||
// check if user has a valid email
|
|
||||||
if len(userEmail) == 0 {
|
|
||||||
logger.LogErrorF("Error sending email notification to user with username '%s': no valid email", user.GetString("username"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// get link to chat and message type (announcement or message)
|
|
||||||
var actionUrl string
|
|
||||||
var messageType string
|
|
||||||
if message.GetBool("isAnnouncement") {
|
|
||||||
actionUrl = app.Settings().Meta.AppUrl + "/chat/announcements"
|
|
||||||
messageType = "Ankündigung"
|
|
||||||
} else {
|
|
||||||
actionUrl = app.Settings().Meta.AppUrl + "/chat/" + message.GetString("eventList")
|
|
||||||
messageType = "Nachricht"
|
|
||||||
}
|
|
||||||
|
|
||||||
// render email template
|
|
||||||
html, err := registry.LoadFiles(
|
|
||||||
"html/emailNotification.html",
|
|
||||||
).Render(map[string]any{
|
|
||||||
"ACTION_URL": actionUrl,
|
|
||||||
"APP_URL": app.Settings().Meta.AppUrl,
|
|
||||||
"MESSAGE_TYPE": messageType,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logger.LogErrorF("Error rendering email notification to user with username '%s': %v", user.GetString("username"), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// send email
|
|
||||||
email := &mailer.Message{
|
|
||||||
From: mail.Address{
|
|
||||||
Address: app.Settings().Meta.SenderAddress,
|
|
||||||
Name: app.Settings().Meta.SenderName,
|
|
||||||
},
|
|
||||||
To: []mail.Address{{Address: userEmail}},
|
|
||||||
Subject: "[StuVe IT] Neue " + messageType,
|
|
||||||
HTML: html,
|
|
||||||
}
|
|
||||||
if err := app.NewMailClient().Send(email); err != nil {
|
|
||||||
logger.LogErrorF("Error sending email notification to user with username '%s': %v", user.GetString("username"), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func messageNotifier(app *pocketbase.PocketBase, createdMessageRecord *models.Record) {
|
|
||||||
registry := template.NewRegistry()
|
|
||||||
|
|
||||||
// expand the createdMessageRecord to get recipient user and send email notification if recipient is set
|
|
||||||
if errs := app.Dao().ExpandRecord(createdMessageRecord, []string{"recipients", "eventList"}, nil); len(errs) > 0 {
|
|
||||||
// return new error with all errors
|
|
||||||
logger.LogErrorF("Error expanding created message record: %v", errs)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
recipients := createdMessageRecord.ExpandedAll("recipients")
|
|
||||||
for _, recipient := range recipients {
|
|
||||||
sendEmailNotification(app, registry, recipient, createdMessageRecord)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get eventList entries to notify and event admins
|
|
||||||
eventList := createdMessageRecord.ExpandedOne("eventList")
|
|
||||||
if eventList != nil {
|
|
||||||
// get all eventListSlotEntries for the eventList
|
|
||||||
listEntryRecords, err := app.Dao().FindRecordsByFilter(
|
|
||||||
"eventListSlotEntries",
|
|
||||||
"eventListsSlot.eventList.id={:listId}",
|
|
||||||
"",
|
|
||||||
-1,
|
|
||||||
0,
|
|
||||||
dbx.Params{"listId": eventList.GetId()},
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.LogErrorF("Error getting eventListSlotEntries for EmailNotifier: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// send messages to all eventListSlotEntries
|
|
||||||
for _, record := range listEntryRecords {
|
|
||||||
// expand the createdMessageRecord to get the user
|
|
||||||
if errs := app.Dao().ExpandRecord(record, []string{"user"}, nil); len(errs) > 0 {
|
|
||||||
logger.LogErrorF("Error expanding user for EmailNotifier: %v", errs)
|
|
||||||
}
|
|
||||||
sendEmailNotification(app, registry, record.ExpandedOne("user"), createdMessageRecord)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get event and eventAdmins
|
|
||||||
if errs := app.Dao().ExpandRecord(eventList, []string{"event"}, nil); len(errs) > 0 {
|
|
||||||
logger.LogErrorF("Error expanding event for EmailNotifier: %v", errs)
|
|
||||||
}
|
|
||||||
event := eventList.ExpandedOne("event")
|
|
||||||
if errs := app.Dao().ExpandRecord(event, []string{"eventAdmins"}, nil); len(errs) > 0 {
|
|
||||||
logger.LogErrorF("Error expanding eventAdmins for EmailNotifier: %v", errs)
|
|
||||||
}
|
|
||||||
eventAdmins := event.ExpandedAll("eventAdmins")
|
|
||||||
|
|
||||||
// send messages to all eventAdmins
|
|
||||||
for _, record := range eventAdmins {
|
|
||||||
sendEmailNotification(app, registry, record, createdMessageRecord)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitMessages initializes the messages email notifier
|
|
||||||
//
|
|
||||||
// the function sends an email notification to all recipients of a message after the message has been created
|
|
||||||
func InitMessages(app *pocketbase.PocketBase, e *core.ServeEvent) error {
|
|
||||||
|
|
||||||
logger.LogInfoF("Adding messages email notifier")
|
|
||||||
|
|
||||||
app.OnModelAfterCreate("messages").Add(func(e *core.ModelEvent) error {
|
|
||||||
|
|
||||||
// get created message record
|
|
||||||
createdMessageRecord, err := app.Dao().FindRecordById("messages", e.Model.GetId())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
go messageNotifier(app, createdMessageRecord)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue