#1416: Add relative Reminders #1427

Merged
konrad merged 21 commits from ce72/api:1416_reminders into main 2023-03-27 20:07:08 +00:00
10 changed files with 59 additions and 59 deletions
Showing only changes of commit 3dedc040db - Show all commits

View File

@ -95,19 +95,19 @@ func TestTask(t *testing.T) {
assert.Contains(t, rec.Body.String(), `"due_date":"0001-01-01T00:00:00Z"`)
assert.NotContains(t, rec.Body.String(), `"due_date":"2020-02-10T10:00:00Z"`)
})
t.Run("Reminders", func(t *testing.T) {
t.Run("ReminderDates", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"listtask": "1"}, `{"reminder_dates": ["2020-02-10T10:00:00Z","2020-02-11T10:00:00Z"]}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"reminder_dates":["2020-02-10T10:00:00Z","2020-02-11T10:00:00Z"]`)
assert.NotContains(t, rec.Body.String(), `"reminder_dates": null`)
})
t.Run("Reminders unset to empty array", func(t *testing.T) {
t.Run("ReminderDates unset to empty array", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"listtask": "27"}, `{"reminder_dates": []}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"reminder_dates":null`)
assert.NotContains(t, rec.Body.String(), `"reminder_dates":[1543626724,1543626824]`)
})
t.Run("Reminders unset to null", func(t *testing.T) {
t.Run("ReminderDates unset to null", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"listtask": "27"}, `{"reminder_dates": null}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"reminder_dates":null`)

View File

@ -169,7 +169,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
label4,
},
RelatedTasks: map[RelationKind][]*Task{},
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Unix(1543626824, 0).In(loc),
},
Created: time.Unix(1543626724, 0).In(loc),
@ -477,7 +477,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
Index: 12,
CreatedByID: 1,
CreatedBy: user1,
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Unix(1543626724, 0).In(loc),
time.Unix(1543626824, 0).In(loc),
},
@ -906,9 +906,9 @@ func TestTaskCollection_ReadAll(t *testing.T) {
wantErr: false,
},
{
name: "filtered reminders",
name: "filtered reminder dates",
fields: fields{
FilterBy: []string{"reminders", "reminders"},
FilterBy: []string{"ReminderDates", "ReminderDates"},
FilterValue: []string{"2018-10-01T00:00:00+00:00", "2018-12-10T00:00:00+00:00"},
FilterComparator: []string{"greater", "less"},
},

View File

@ -62,7 +62,7 @@ type Task struct {
// The time when the task is due.
DueDate time.Time `xorm:"DATETIME INDEX null 'due_date'" json:"due_date"`
// An array of datetimes when the user wants to be reminded of the task.
Reminders []time.Time `xorm:"-" json:"reminder_dates"`
ReminderDates []time.Time `xorm:"-" json:"reminder_dates"`
// The list this task belongs to.
ListID int64 `xorm:"bigint INDEX not null" json:"list_id" param:"list"`
// An amount in seconds this task repeats itself. If this is set, when marking the task as done, it will mark itself as "undone" and then increase all remindes and the due date by its amount.
@ -334,7 +334,7 @@ func getRawTasksForLists(s *xorm.Session, lists []*List, a web.Auth, opts *taskO
var filters = make([]builder.Cond, 0, len(opts.filters))
// To still find tasks with nil values, we exclude 0s when comparing with >/< values.
for _, f := range opts.filters {
if f.field == "reminders" {
if f.field == "ReminderDates" {
ce72 marked this conversation as resolved Outdated

This is the value which consumers of the api will pass in for filtering. For consistency, this should be called

This is the value which consumers of the api will pass in for filtering. For consistency, this should be called

We'll also need a similar check to filter for the new reminders.

We'll also need a similar check to filter for the new reminders.
Outdated
Review

This is the value which consumers of the api will pass in for filtering. For consistency, this should be called

Yes, this has to be fixed. I still need to figure out how to apply the filter on an attribute in an Substructure.

> This is the value which consumers of the api will pass in for filtering. For consistency, this should be called Yes, this has to be fixed. I still need to figure out how to apply the filter on an attribute in an Substructure.
Outdated
Review

We'll also need a similar check to filter for the new reminders.

I think in the end we need only one to filter by reminder trigger dates. And this filter has still to be migrated from Task.ReminderDates to the new Task.Reminders.

> We'll also need a similar check to filter for the new reminders. I think in the end we need only one to filter by reminder trigger dates. And this filter has still to be migrated from Task.ReminderDates to the new Task.Reminders.

I think in the end we need only one to filter by reminder trigger dates.

That's true.

> I think in the end we need only one to filter by reminder trigger dates. That's true.
Outdated
Review

This has now been fixed. Filter queries for "reminders" will be applied to task_reminders.reminder column.

This has now been fixed. Filter queries for "reminders" will be applied to task_reminders.reminder column.
f.field = "reminder" // This is the name in the db
filter, err := getFilterCond(f, opts.filterIncludeNulls)
if err != nil {
@ -773,7 +773,7 @@ func addMoreInfoToTasks(s *xorm.Session, taskMap map[int64]*Task, a web.Auth) (e
task.CreatedBy = users[task.CreatedByID]
// Add the reminders
task.Reminders = taskReminders[task.ID]
task.ReminderDates = taskReminders[task.ID]
// Prepare the subtasks
task.RelatedTasks = make(RelatedTaskMap)
@ -965,7 +965,7 @@ func createTask(s *xorm.Session, t *Task, a web.Auth, updateAssignees bool) (err
}
// Update the reminders
if err := t.updateReminders(s, t.Reminders); err != nil {
if err := t.updateReminders(s, t.ReminderDates); err != nil {
return err
}
@ -1023,9 +1023,9 @@ func (t *Task) Update(s *xorm.Session, a web.Auth) (err error) {
return
}
ot.Reminders = make([]time.Time, len(reminders))
ot.ReminderDates = make([]time.Time, len(reminders))
for i, r := range reminders {
ot.Reminders[i] = r.Reminder
ot.ReminderDates[i] = r.Reminder
}
targetBucket, err := setTaskBucket(s, t, &ot, t.BucketID != 0 && t.BucketID != ot.BucketID)
@ -1049,7 +1049,7 @@ func (t *Task) Update(s *xorm.Session, a web.Auth) (err error) {
}
// Update the reminders
if err := ot.updateReminders(s, t.Reminders); err != nil {
if err := ot.updateReminders(s, t.ReminderDates); err != nil {
return err
}
@ -1326,14 +1326,14 @@ func setTaskDatesDefault(oldTask, newTask *Task) {
}
}
newTask.Reminders = oldTask.Reminders
newTask.ReminderDates = oldTask.ReminderDates
// When repeating from the current date, all reminders should keep their difference to each other.
// To make this easier, we sort them first because we can then rely on the fact the first is the smallest
if len(oldTask.Reminders) > 0 {
for in, r := range oldTask.Reminders {
newTask.Reminders[in] = r.Add(repeatDuration)
for !newTask.Reminders[in].After(now) {
newTask.Reminders[in] = newTask.Reminders[in].Add(repeatDuration)
if len(oldTask.ReminderDates) > 0 {
for in, r := range oldTask.ReminderDates {
newTask.ReminderDates[in] = r.Add(repeatDuration)
for !newTask.ReminderDates[in].After(now) {
newTask.ReminderDates[in] = newTask.ReminderDates[in].Add(repeatDuration)
}
}
}
@ -1361,10 +1361,10 @@ func setTaskDatesMonthRepeat(oldTask, newTask *Task) {
newTask.DueDate = addOneMonthToDate(oldTask.DueDate)
}
newTask.Reminders = oldTask.Reminders
if len(oldTask.Reminders) > 0 {
for in, r := range oldTask.Reminders {
newTask.Reminders[in] = addOneMonthToDate(r)
newTask.ReminderDates = oldTask.ReminderDates
if len(oldTask.ReminderDates) > 0 {
for in, r := range oldTask.ReminderDates {
newTask.ReminderDates[in] = addOneMonthToDate(r)
}
}
@ -1400,17 +1400,17 @@ func setTaskDatesFromCurrentDateRepeat(oldTask, newTask *Task) {
newTask.DueDate = now.Add(repeatDuration)
}
newTask.Reminders = oldTask.Reminders
newTask.ReminderDates = oldTask.ReminderDates
// When repeating from the current date, all reminders should keep their difference to each other.
// To make this easier, we sort them first because we can then rely on the fact the first is the smallest
if len(oldTask.Reminders) > 0 {
sort.Slice(oldTask.Reminders, func(i, j int) bool {
return oldTask.Reminders[i].Unix() < oldTask.Reminders[j].Unix()
if len(oldTask.ReminderDates) > 0 {
sort.Slice(oldTask.ReminderDates, func(i, j int) bool {
return oldTask.ReminderDates[i].Unix() < oldTask.ReminderDates[j].Unix()
})
first := oldTask.Reminders[0]
for in, r := range oldTask.Reminders {
first := oldTask.ReminderDates[0]
for in, r := range oldTask.ReminderDates {
diff := r.Sub(first)
newTask.Reminders[in] = now.Add(repeatDuration + diff)
newTask.ReminderDates[in] = now.Add(repeatDuration + diff)
}
}
@ -1505,9 +1505,9 @@ func (t *Task) updateReminders(s *xorm.Session, reminders []time.Time) (err erro
}
}
t.Reminders = reminders
t.ReminderDates = reminders
if len(reminders) == 0 {
t.Reminders = nil
t.ReminderDates = nil
}
err = updateListLastUpdated(s, &List{ID: t.ListID})

View File

@ -376,7 +376,7 @@ func TestTask_Update(t *testing.T) {
task := &Task{
ID: 1,
Title: "test",
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Unix(1674745156, 0),
time.Unix(1674745156, 223),
},
@ -487,7 +487,7 @@ func TestUpdateDone(t *testing.T) {
oldTask := &Task{
Done: false,
RepeatAfter: 8600,
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Unix(1550000000, 0),
time.Unix(1555000000, 0),
},
@ -506,9 +506,9 @@ func TestUpdateDone(t *testing.T) {
expected2 = expected2.Add(time.Duration(oldTask.RepeatAfter) * time.Second)
}
assert.Len(t, newTask.Reminders, 2)
assert.Equal(t, expected1, newTask.Reminders[0])
assert.Equal(t, expected2, newTask.Reminders[1])
assert.Len(t, newTask.ReminderDates, 2)
assert.Equal(t, expected1, newTask.ReminderDates[0])
assert.Equal(t, expected2, newTask.ReminderDates[1])
assert.False(t, newTask.Done)
})
t.Run("update start date", func(t *testing.T) {
@ -585,7 +585,7 @@ func TestUpdateDone(t *testing.T) {
Done: false,
RepeatAfter: 8600,
RepeatMode: TaskRepeatModeFromCurrentDate,
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Unix(1550000000, 0),
time.Unix(1555000000, 0),
},
@ -595,12 +595,12 @@ func TestUpdateDone(t *testing.T) {
}
updateDone(oldTask, newTask)
diff := oldTask.Reminders[1].Sub(oldTask.Reminders[0])
diff := oldTask.ReminderDates[1].Sub(oldTask.ReminderDates[0])
assert.Len(t, newTask.Reminders, 2)
assert.Len(t, newTask.ReminderDates, 2)
// Only comparing unix timestamps because time.Time use nanoseconds which can't ever possibly have the same value
assert.Equal(t, time.Now().Add(time.Duration(oldTask.RepeatAfter)*time.Second).Unix(), newTask.Reminders[0].Unix())
assert.Equal(t, time.Now().Add(diff+time.Duration(oldTask.RepeatAfter)*time.Second).Unix(), newTask.Reminders[1].Unix())
assert.Equal(t, time.Now().Add(time.Duration(oldTask.RepeatAfter)*time.Second).Unix(), newTask.ReminderDates[0].Unix())
assert.Equal(t, time.Now().Add(diff+time.Duration(oldTask.RepeatAfter)*time.Second).Unix(), newTask.ReminderDates[1].Unix())
assert.False(t, newTask.Done)
})
t.Run("start date", func(t *testing.T) {
@ -678,7 +678,7 @@ func TestUpdateDone(t *testing.T) {
oldTask := &Task{
Done: false,
RepeatMode: TaskRepeatModeMonth,
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Unix(1550000000, 0),
time.Unix(1555000000, 0),
},
@ -686,13 +686,13 @@ func TestUpdateDone(t *testing.T) {
newTask := &Task{
Done: true,
}
oldReminders := make([]time.Time, len(oldTask.Reminders))
copy(oldReminders, oldTask.Reminders)
oldReminders := make([]time.Time, len(oldTask.ReminderDates))
copy(oldReminders, oldTask.ReminderDates)
updateDone(oldTask, newTask)
assert.Len(t, newTask.Reminders, len(oldReminders))
for i, r := range newTask.Reminders {
assert.Len(t, newTask.ReminderDates, len(oldReminders))
for i, r := range newTask.ReminderDates {
assert.True(t, r.After(oldReminders[i]))
assert.NotEqual(t, oldReminders[i].Month(), r.Month())
}

View File

@ -329,7 +329,7 @@ func convertMicrosoftTodoData(todoData []*list) (vikunjsStructure []*models.Name
return nil, err
}
task.Reminders = []time.Time{reminder}
task.ReminderDates = []time.Time{reminder}
}
// Due Date

View File

@ -141,7 +141,7 @@ func TestConverting(t *testing.T) {
{
Task: models.Task{
Title: "Task 5",
Reminders: []time.Time{
ReminderDates: []time.Time{
testtimeTime,
},
},

View File

@ -147,7 +147,7 @@ func convertTickTickToVikunja(tasks []*tickTickTask) (result []*models.Namespace
}
if !t.DueDate.IsZero() && t.Reminder > 0 {
task.Task.Reminders = []time.Time{
task.Task.ReminderDates = []time.Time{
t.DueDate.Add(t.Reminder * -1),
}
}

View File

@ -101,7 +101,7 @@ func TestConvertTicktickTasksToVikunja(t *testing.T) {
{Title: "label1"},
{Title: "label2"},
})
//assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[0].Reminders, tickTickTasks[0].) // TODO
//assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[0].ReminderDates, tickTickTasks[0].) // TODO
assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[0].Position, tickTickTasks[0].Order)
assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[0].Done, false)
@ -127,7 +127,7 @@ func TestConvertTicktickTasksToVikunja(t *testing.T) {
{Title: "label2"},
{Title: "other label"},
})
//assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[0].Reminders, tickTickTasks[0].) // TODO
//assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[0].ReminderDates, tickTickTasks[0].) // TODO
assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[2].Position, tickTickTasks[2].Order)
assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[2].Done, false)

View File

@ -471,7 +471,7 @@ func convertTodoistToVikunja(sync *sync, doneItems map[string]*doneItem) (fullVi
return nil, err
}
tasks[r.ItemID].Reminders = append(tasks[r.ItemID].Reminders, date.In(config.GetTimeZone()))
tasks[r.ItemID].ReminderDates = append(tasks[r.ItemID].ReminderDates, date.In(config.GetTimeZone()))
}
return []*models.NamespaceWithListsAndTasks{

View File

@ -388,7 +388,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
Description: "Lorem Ipsum dolor sit amet",
Done: false,
Created: time1,
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Date(2020, time.June, 15, 23, 59, 0, 0, time.UTC).In(config.GetTimeZone()),
time.Date(2020, time.June, 16, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone()),
},
@ -407,7 +407,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
Title: "Task400000002",
Done: false,
Created: time1,
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Date(2020, time.July, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone()),
},
},
@ -421,7 +421,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
Created: time1,
DoneAt: time3,
Labels: vikunjaLabels,
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone()),
},
},
@ -441,7 +441,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
DueDate: dueTime,
Created: time1,
DoneAt: time3,
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone()),
},
},
@ -531,7 +531,7 @@ func TestConvertTodoistToVikunja(t *testing.T) {
Title: "Task400000009",
Done: false,
Created: time1,
Reminders: []time.Time{
ReminderDates: []time.Time{
time.Date(2020, time.June, 15, 7, 0, 0, 0, time.UTC).In(config.GetTimeZone()),
},
},