From c13dd9addbf89f716e4ef5cfdf1d673139ffcb68 Mon Sep 17 00:00:00 2001 From: Mo Tarbin Date: Sun, 30 Jun 2024 21:41:41 -0400 Subject: Move to Donetick Org, first commit --- internal/notifier/service/planner.go | 149 +++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 internal/notifier/service/planner.go (limited to 'internal/notifier/service') diff --git a/internal/notifier/service/planner.go b/internal/notifier/service/planner.go new file mode 100644 index 0000000..22502ab --- /dev/null +++ b/internal/notifier/service/planner.go @@ -0,0 +1,149 @@ +package service + +import ( + "context" + "encoding/json" + "fmt" + "time" + + chModel "donetick.com/core/internal/chore/model" + cModel "donetick.com/core/internal/circle/model" + cRepo "donetick.com/core/internal/circle/repo" + nModel "donetick.com/core/internal/notifier/model" + nRepo "donetick.com/core/internal/notifier/repo" + "donetick.com/core/logging" +) + +type NotificationPlanner struct { + nRepo *nRepo.NotificationRepository + cRepo *cRepo.CircleRepository +} + +func NewNotificationPlanner(nr *nRepo.NotificationRepository, cr *cRepo.CircleRepository) *NotificationPlanner { + return &NotificationPlanner{nRepo: nr, + cRepo: cr, + } +} + +func (n *NotificationPlanner) GenerateNotifications(c context.Context, chore *chModel.Chore) bool { + log := logging.FromContext(c) + circleMembers, err := n.cRepo.GetCircleUsers(c, chore.CircleID) + assignees := make([]*cModel.UserCircleDetail, 0) + for _, member := range circleMembers { + if member.ID == chore.AssignedTo { + assignees = append(assignees, member) + } + } + + if err != nil { + log.Error("Error getting circle members", err) + return false + } + n.nRepo.DeleteAllChoreNotifications(chore.ID) + notifications := make([]*nModel.Notification, 0) + if !chore.Notification || chore.FrequencyType == "trigger" { + + return true + } + var mt *chModel.NotificationMetadata + if err := json.Unmarshal([]byte(*chore.NotificationMetadata), &mt); err != nil { + log.Error("Error unmarshalling notification metadata", err) + return true + } + if mt.DueDate { + notifications = append(notifications, generateDueNotifications(chore, assignees)...) + } + if mt.PreDue { + notifications = append(notifications, generatePreDueNotifications(chore, assignees)...) + } + if mt.Nagging { + notifications = append(notifications, generateOverdueNotifications(chore, assignees)...) + } + + n.nRepo.BatchInsertNotifications(notifications) + return true +} + +func generateDueNotifications(chore *chModel.Chore, users []*cModel.UserCircleDetail) []*nModel.Notification { + var assignee *cModel.UserCircleDetail + notifications := make([]*nModel.Notification, 0) + for _, user := range users { + if user.ID == chore.AssignedTo { + assignee = user + break + } + } + for _, user := range users { + + notification := &nModel.Notification{ + ChoreID: chore.ID, + IsSent: false, + ScheduledFor: *chore.NextDueDate, + CreatedAt: time.Now().UTC(), + TypeID: 1, + UserID: user.ID, + TargetID: fmt.Sprint(user.ChatID), + Text: fmt.Sprintf("📅 Reminder: '%s' is due today and assigned to %s.", chore.Name, assignee.DisplayName), + } + notifications = append(notifications, notification) + } + + return notifications +} + +func generatePreDueNotifications(chore *chModel.Chore, users []*cModel.UserCircleDetail) []*nModel.Notification { + var assignee *cModel.UserCircleDetail + for _, user := range users { + if user.ID == chore.AssignedTo { + assignee = user + break + } + } + notifications := make([]*nModel.Notification, 0) + for _, user := range users { + notification := &nModel.Notification{ + ChoreID: chore.ID, + IsSent: false, + ScheduledFor: *chore.NextDueDate, + CreatedAt: time.Now().UTC().Add(-time.Hour * 3), + TypeID: 3, + UserID: user.ID, + TargetID: fmt.Sprint(user.ChatID), + Text: fmt.Sprintf("📢 Heads up! Chore '%s' is due soon (on %s) and assigned to %s.", chore.Name, chore.NextDueDate.Format("January 2nd"), assignee.DisplayName), + } + notifications = append(notifications, notification) + + } + return notifications + +} + +func generateOverdueNotifications(chore *chModel.Chore, users []*cModel.UserCircleDetail) []*nModel.Notification { + var assignee *cModel.UserCircleDetail + for _, user := range users { + if user.ID == chore.AssignedTo { + assignee = user + break + } + } + notifications := make([]*nModel.Notification, 0) + for _, hours := range []int{24, 48, 72} { + scheduleTime := chore.NextDueDate.Add(time.Hour * time.Duration(hours)) + for _, user := range users { + notification := &nModel.Notification{ + ChoreID: chore.ID, + IsSent: false, + ScheduledFor: scheduleTime, + CreatedAt: time.Now().UTC(), + TypeID: 2, + UserID: user.ID, + TargetID: fmt.Sprint(user.ChatID), + Text: fmt.Sprintf("🚨 '%s' is now %d hours overdue. Please complete it as soon as possible. (Assigned to %s)", chore.Name, hours, assignee.DisplayName), + } + notifications = append(notifications, notification) + } + } + + return notifications + +} -- cgit