From ab1d58959f75e4ec0ea45b5e1771f8e695d4e311 Mon Sep 17 00:00:00 2001 From: konrad Date: Sat, 13 Jun 2020 21:32:31 +0000 Subject: [PATCH] Ensure task dates are in the future if a task has a repeating interval (#586) Ensure task dates are in the future if a task has a repeating interval Co-authored-by: kolaente Reviewed-on: https://kolaente.dev/vikunja/api/pulls/586 --- pkg/models/tasks.go | 17 ++++++++++++- pkg/models/tasks_test.go | 52 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/pkg/models/tasks.go b/pkg/models/tasks.go index faf2fc4faf..4260e09e10 100644 --- a/pkg/models/tasks.go +++ b/pkg/models/tasks.go @@ -800,20 +800,35 @@ func updateDone(oldTask *Task, newTask *Task) { // assuming we'll merge the new task over the old task if oldTask.DueDate > 0 { + // Always add one instance of the repeating interval to catch cases where a due date is already in the future + // but not the repeating interval newTask.DueDate = timeutil.FromTime(oldTask.DueDate.ToTime().Add(repeatDuration)) + // Add the repeating interval until the new due date is in the future + for !newTask.DueDate.ToTime().After(time.Now()) { + newTask.DueDate = timeutil.FromTime(newTask.DueDate.ToTime().Add(repeatDuration)) + } } newTask.Reminders = oldTask.Reminders for in, r := range oldTask.Reminders { newTask.Reminders[in] = timeutil.FromTime(r.ToTime().Add(repeatDuration)) + for !newTask.Reminders[in].ToTime().After(time.Now()) { + newTask.Reminders[in] = timeutil.FromTime(newTask.Reminders[in].ToTime().Add(repeatDuration)) + } } if oldTask.StartDate > 0 { newTask.StartDate = timeutil.FromTime(oldTask.StartDate.ToTime().Add(repeatDuration)) + for !newTask.StartDate.ToTime().After(time.Now()) { + newTask.StartDate = timeutil.FromTime(newTask.StartDate.ToTime().Add(repeatDuration)) + } } if oldTask.EndDate > 0 { newTask.EndDate = timeutil.FromTime(oldTask.EndDate.ToTime().Add(repeatDuration)) + for !newTask.EndDate.ToTime().After(time.Now()) { + newTask.EndDate = timeutil.FromTime(newTask.EndDate.ToTime().Add(repeatDuration)) + } } newTask.Done = false @@ -892,7 +907,7 @@ func (t *Task) updateReminders(reminders []timeutil.TimeStamp) (err error) { } } - // Loop through our users and add them + // Loop through our reminders and add them for _, r := range reminders { // Check if the reminder already exists and only inserts it if not if oldReminders[r] != nil { diff --git a/pkg/models/tasks_test.go b/pkg/models/tasks_test.go index 8bce9a1251..65520d1ad6 100644 --- a/pkg/models/tasks_test.go +++ b/pkg/models/tasks_test.go @@ -22,6 +22,7 @@ import ( "code.vikunja.io/api/pkg/user" "github.com/stretchr/testify/assert" "testing" + "time" ) func TestTask_Create(t *testing.T) { @@ -150,7 +151,13 @@ func TestUpdateDone(t *testing.T) { Done: true, } updateDone(oldTask, newTask) - assert.Equal(t, timeutil.TimeStamp(1550008600), newTask.DueDate) + + var expected int64 = 1550008600 + for expected < time.Now().Unix() { + expected += oldTask.RepeatAfter + } + + assert.Equal(t, timeutil.TimeStamp(expected), newTask.DueDate) }) t.Run("don't update if due date is zero", func(t *testing.T) { oldTask := &Task{ @@ -178,9 +185,19 @@ func TestUpdateDone(t *testing.T) { Done: true, } updateDone(oldTask, newTask) + + var expected1 int64 = 1550008600 + var expected2 int64 = 1555008600 + for expected1 < time.Now().Unix() { + expected1 += oldTask.RepeatAfter + } + for expected2 < time.Now().Unix() { + expected2 += oldTask.RepeatAfter + } + assert.Len(t, newTask.Reminders, 2) - assert.Equal(t, timeutil.TimeStamp(1550008600), newTask.Reminders[0]) - assert.Equal(t, timeutil.TimeStamp(1555008600), newTask.Reminders[1]) + assert.Equal(t, timeutil.TimeStamp(expected1), newTask.Reminders[0]) + assert.Equal(t, timeutil.TimeStamp(expected2), newTask.Reminders[1]) }) t.Run("update start date", func(t *testing.T) { oldTask := &Task{ @@ -192,7 +209,13 @@ func TestUpdateDone(t *testing.T) { Done: true, } updateDone(oldTask, newTask) - assert.Equal(t, timeutil.TimeStamp(1550008600), newTask.StartDate) + + var expected int64 = 1550008600 + for expected < time.Now().Unix() { + expected += oldTask.RepeatAfter + } + + assert.Equal(t, timeutil.TimeStamp(expected), newTask.StartDate) }) t.Run("update end date", func(t *testing.T) { oldTask := &Task{ @@ -204,7 +227,26 @@ func TestUpdateDone(t *testing.T) { Done: true, } updateDone(oldTask, newTask) - assert.Equal(t, timeutil.TimeStamp(1550008600), newTask.EndDate) + + var expected int64 = 1550008600 + for expected < time.Now().Unix() { + expected += oldTask.RepeatAfter + } + + assert.Equal(t, timeutil.TimeStamp(expected), newTask.EndDate) + }) + t.Run("ensure due date is repeated even if the original one is in the future", func(t *testing.T) { + oldTask := &Task{ + Done: false, + RepeatAfter: 8600, + DueDate: timeutil.FromTime(time.Now().Add(time.Hour)), + } + newTask := &Task{ + Done: true, + } + updateDone(oldTask, newTask) + expected := int64(oldTask.DueDate) + oldTask.RepeatAfter + assert.Equal(t, timeutil.TimeStamp(expected), newTask.DueDate) }) }) }