1
0

Improve sending overdue task reminders by only sending one for all overdue tasks

This commit is contained in:
kolaente
2021-04-18 15:32:02 +02:00
parent 7ff7b0d743
commit 6e263b6a91
6 changed files with 118 additions and 28 deletions

View File

@ -214,3 +214,37 @@ func (n *UndoneTaskOverdueNotification) ToDB() interface{} {
func (n *UndoneTaskOverdueNotification) Name() string {
return "task.undone.overdue"
}
// UndoneTasksOverdueNotification represents a UndoneTasksOverdueNotification notification
type UndoneTasksOverdueNotification struct {
User *user.User
Tasks []*Task
}
// ToMail returns the mail notification for UndoneTasksOverdueNotification
func (n *UndoneTasksOverdueNotification) ToMail() *notifications.Mail {
overdueLine := ""
for _, task := range n.Tasks {
until := time.Until(task.DueDate).Round(1*time.Hour) * -1
overdueLine += `* [` + task.Title + `](` + config.ServiceFrontendurl.GetString() + "tasks/" + strconv.FormatInt(task.ID, 10) + `), overdue since ` + utils.HumanizeDuration(until) + "\n"
}
return notifications.NewMail().
Subject(`Your overdue tasks`).
Greeting("Hi "+n.User.GetName()+",").
Line("You have the following overdue tasks:").
Line(overdueLine).
Action("Open Vikunja", config.ServiceFrontendurl.GetString()).
Line("Have a nice day!")
}
// ToDB returns the UndoneTasksOverdueNotification notification in a format which can be saved in the db
func (n *UndoneTasksOverdueNotification) ToDB() interface{} {
return nil
}
// Name returns the name of the notification
func (n *UndoneTasksOverdueNotification) Name() string {
return "task.undone.overdue"
}

View File

@ -19,6 +19,8 @@ package models
import (
"time"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/config"
"code.vikunja.io/api/pkg/cron"
"code.vikunja.io/api/pkg/db"
@ -48,6 +50,11 @@ func getUndoneOverdueTasks(s *xorm.Session, now time.Time) (taskIDs []int64, err
return
}
type userWithTasks struct {
user *user.User
tasks []*Task
}
// RegisterOverdueReminderCron registers a function which checks once a day for tasks that are overdue and not done.
func RegisterOverdueReminderCron() {
if !config.ServiceEnableEmailReminders.GetBool() {
@ -76,21 +83,41 @@ func RegisterOverdueReminderCron() {
return
}
uts := make(map[int64]*userWithTasks)
for _, t := range users {
_, exists := uts[t.User.ID]
if !exists {
uts[t.User.ID] = &userWithTasks{
user: t.User,
tasks: []*Task{},
}
}
uts[t.User.ID].tasks = append(uts[t.User.ID].tasks, t.Task)
}
log.Debugf("[Undone Overdue Tasks Reminder] Sending reminders to %d users", len(users))
for _, u := range users {
n := &UndoneTaskOverdueNotification{
User: u.User,
Task: u.Task,
for _, ut := range uts {
var n notifications.Notification = &UndoneTasksOverdueNotification{
User: ut.user,
Tasks: ut.tasks,
}
err = notifications.Notify(u.User, n)
if len(ut.tasks) == 1 {
n = &UndoneTaskOverdueNotification{
User: ut.user,
Task: ut.tasks[0],
}
}
err = notifications.Notify(ut.user, n)
if err != nil {
log.Errorf("[Undone Overdue Tasks Reminder] Could not notify user %d: %s", u.User.ID, err)
log.Errorf("[Undone Overdue Tasks Reminder] Could not notify user %d: %s", ut.user.ID, err)
return
}
log.Debugf("[Undone Overdue Tasks Reminder] Sent reminder email for task %d to user %d", u.Task.ID, u.User.ID)
log.Debugf("[Undone Overdue Tasks Reminder] Sent reminder email for %d tasks to user %d", len(ut.tasks), ut.user.ID)
continue
}
})
if err != nil {