Support Reminder events

Move code to schedule to have event independent from NotificationPlatform
This commit is contained in:
Mo Tarbin 2025-02-10 01:44:42 -05:00
parent 04d1894aea
commit 80afab3bc0
7 changed files with 61 additions and 28 deletions

View file

@ -1,6 +1,11 @@
package model
import "time"
import (
"database/sql/driver"
"encoding/json"
"errors"
"time"
)
type Notification struct {
ID int `json:"id" gorm:"primaryKey"`
@ -13,7 +18,7 @@ type Notification struct {
TypeID NotificationPlatform `json:"type" gorm:"column:type"`
ScheduledFor time.Time `json:"scheduled_for" gorm:"column:scheduled_for;index"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
RawEvent interface{} `json:"raw_event" gorm:"column:raw_event;type:jsonb"`
RawEvent JSONB `json:"raw_event" gorm:"column:raw_event;type:jsonb"`
}
type NotificationDetails struct {
Notification
@ -32,3 +37,24 @@ const (
NotificationPlatformTelegram
NotificationPlatformPushover
)
type JSONB map[string]interface{}
func (j JSONB) Value() (driver.Value, error) {
value, err := json.Marshal(j)
if err != nil {
return nil, err
}
return string(value), nil
}
func (j *JSONB) Scan(value interface{}) error {
switch v := value.(type) {
case []byte:
return json.Unmarshal(v, j)
case string:
return json.Unmarshal([]byte(v), j)
default:
return errors.New("type assertion to []byte or string failed")
}
}

View file

@ -45,10 +45,6 @@ func (n *Notifier) SendNotification(c context.Context, notification *nModel.Noti
if err != nil {
log.Error("Failed to send notification", "err", err)
}
if notification.RawEvent != nil && notification.WebhookURL != nil {
// if we have a webhook url, we should send the event to the webhook
n.eventsProducer.NotificaitonEvent(c, *notification.WebhookURL, notification.RawEvent)
}
return nil
}

View file

@ -7,6 +7,7 @@ import (
"donetick.com/core/config"
chRepo "donetick.com/core/internal/chore/repo"
"donetick.com/core/internal/events"
nRepo "donetick.com/core/internal/notifier/repo"
uRepo "donetick.com/core/internal/user/repo"
"donetick.com/core/logging"
@ -23,17 +24,19 @@ type Scheduler struct {
userRepo *uRepo.UserRepository
stopChan chan bool
notifier *Notifier
eventsProducer *events.EventsProducer
notificationRepo *nRepo.NotificationRepository
SchedulerJobs config.SchedulerConfig
}
func NewScheduler(cfg *config.Config, ur *uRepo.UserRepository, cr *chRepo.ChoreRepository, n *Notifier, nr *nRepo.NotificationRepository) *Scheduler {
func NewScheduler(cfg *config.Config, ur *uRepo.UserRepository, cr *chRepo.ChoreRepository, n *Notifier, nr *nRepo.NotificationRepository, ep *events.EventsProducer) *Scheduler {
return &Scheduler{
choreRepo: cr,
userRepo: ur,
stopChan: make(chan bool),
notifier: n,
notificationRepo: nr,
eventsProducer: ep,
SchedulerJobs: cfg.SchedulerJobs,
}
}
@ -72,6 +75,11 @@ func (s *Scheduler) loadAndSendNotificationJob(c context.Context) (time.Duration
log.Error("Error sending notification", err)
continue
}
if notification.RawEvent != nil && notification.WebhookURL != nil {
// if we have a webhook url, we should send the event to the webhook
s.eventsProducer.NotificationEvent(c, *notification.WebhookURL, notification.RawEvent)
}
notification.IsSent = true
}

View file

@ -87,12 +87,13 @@ func generateDueNotifications(chore *chModel.Chore, users []*cModel.UserCircleDe
CreatedAt: time.Now().UTC(),
TypeID: user.NotificationType,
UserID: user.ID,
CircleID: user.CircleID,
TargetID: user.TargetID,
Text: fmt.Sprintf("📅 Reminder: *%s* is due today and assigned to %s.", chore.Name, assignee.DisplayName),
RawEvent: map[string]interface{}{
"id": chore.ID,
"name": chore.Name,
"due_date": chore.NextDueDate.Format("January 2nd"),
"due_date": chore.NextDueDate,
"assignee": assignee.DisplayName,
"assignee_username": assignee.Username,
},
@ -122,12 +123,13 @@ func generatePreDueNotifications(chore *chModel.Chore, users []*cModel.UserCircl
CreatedAt: time.Now().UTC().Add(-time.Hour * 3),
TypeID: user.NotificationType,
UserID: user.ID,
CircleID: user.CircleID,
TargetID: user.TargetID,
Text: fmt.Sprintf("📢 Heads up! *%s* is due soon (on %s) and assigned to %s.", chore.Name, chore.NextDueDate.Format("January 2nd"), assignee.DisplayName),
RawEvent: map[string]interface{}{
"id": chore.ID,
"name": chore.Name,
"due_date": chore.NextDueDate.Format("January 2nd"),
"due_date": chore.NextDueDate,
"assignee": assignee.DisplayName,
"assignee_username": assignee.Username,
},
@ -160,13 +162,14 @@ func generateOverdueNotifications(chore *chModel.Chore, users []*cModel.UserCirc
CreatedAt: time.Now().UTC(),
TypeID: user.NotificationType,
UserID: user.ID,
CircleID: user.CircleID,
TargetID: fmt.Sprint(user.TargetID),
Text: fmt.Sprintf("🚨 *%s* is now %d hours overdue. Please complete it as soon as possible. (Assigned to %s)", chore.Name, hours, assignee.DisplayName),
RawEvent: map[string]interface{}{
"id": chore.ID,
"type": EventTypeOverdue,
"name": chore.Name,
"due_date": chore.NextDueDate.Format("January 2nd"),
"due_date": chore.NextDueDate,
"assignee": assignee.DisplayName,
"assignee_username": assignee.Username,
},