#1416: Step 3a Add new fields to TaskReminder
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
cernst 2023-03-07 17:54:21 +01:00
parent 4a41a8a6ca
commit e0487516a3
13 changed files with 265 additions and 124 deletions

View File

@ -6,6 +6,8 @@
task_id: 27
reminder: 2018-12-01 01:13:44
created: 2018-12-01 01:12:04
relative_to: 'start_date'
relative_period: -3600
- id: 3
task_id: 2
reminder: 2018-12-01 01:13:44

View File

@ -244,7 +244,7 @@
created: 2018-12-01 01:12:04
updated: 2018-12-01 01:12:04
- id: 27
title: 'task #27 with reminders'
title: 'task #27 with reminders and start_date'
done: false
created_by_id: 1
list_id: 1
@ -252,6 +252,7 @@
bucket_id: 1
created: 2018-12-01 01:12:04
updated: 2018-12-01 01:12:04
start_date: 2018-11-30 22:25:24
- id: 28
title: 'task #28 with repeat after'
done: false

View File

@ -42,14 +42,14 @@ func TestTaskCollection(t *testing.T) {
assert.NoError(t, err)
// Not using assert.Equal to avoid having the tests break every time we add new fixtures
assert.Contains(t, rec.Body.String(), `task #1`)
assert.Contains(t, rec.Body.String(), `task #2`)
assert.Contains(t, rec.Body.String(), `task #3`)
assert.Contains(t, rec.Body.String(), `task #4`)
assert.Contains(t, rec.Body.String(), `task #5`)
assert.Contains(t, rec.Body.String(), `task #6`)
assert.Contains(t, rec.Body.String(), `task #7`)
assert.Contains(t, rec.Body.String(), `task #8`)
assert.Contains(t, rec.Body.String(), `task #9`)
assert.Contains(t, rec.Body.String(), `task #2 `)
assert.Contains(t, rec.Body.String(), `task #3 `)
assert.Contains(t, rec.Body.String(), `task #4 `)
assert.Contains(t, rec.Body.String(), `task #5 `)
assert.Contains(t, rec.Body.String(), `task #6 `)
assert.Contains(t, rec.Body.String(), `task #7 `)
assert.Contains(t, rec.Body.String(), `task #8 `)
assert.Contains(t, rec.Body.String(), `task #9 `)
assert.Contains(t, rec.Body.String(), `task #10`)
assert.Contains(t, rec.Body.String(), `task #11`)
assert.Contains(t, rec.Body.String(), `task #12`)
@ -75,14 +75,14 @@ func TestTaskCollection(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"s": []string{"task #6"}}, urlParams)
assert.NoError(t, err)
assert.NotContains(t, rec.Body.String(), `task #1`)
assert.NotContains(t, rec.Body.String(), `task #2`)
assert.NotContains(t, rec.Body.String(), `task #3`)
assert.NotContains(t, rec.Body.String(), `task #4`)
assert.NotContains(t, rec.Body.String(), `task #5`)
assert.Contains(t, rec.Body.String(), `task #6`)
assert.NotContains(t, rec.Body.String(), `task #7`)
assert.NotContains(t, rec.Body.String(), `task #8`)
assert.NotContains(t, rec.Body.String(), `task #9`)
assert.NotContains(t, rec.Body.String(), `task #2 `)
assert.NotContains(t, rec.Body.String(), `task #3 `)
assert.NotContains(t, rec.Body.String(), `task #4 `)
assert.NotContains(t, rec.Body.String(), `task #5 `)
assert.Contains(t, rec.Body.String(), `task #6 `)
assert.NotContains(t, rec.Body.String(), `task #7 `)
assert.NotContains(t, rec.Body.String(), `task #8 `)
assert.NotContains(t, rec.Body.String(), `task #9 `)
assert.NotContains(t, rec.Body.String(), `task #10`)
assert.NotContains(t, rec.Body.String(), `task #11`)
assert.NotContains(t, rec.Body.String(), `task #12`)
@ -93,14 +93,14 @@ func TestTaskCollection(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"s": []string{"tASk #6"}}, urlParams)
assert.NoError(t, err)
assert.NotContains(t, rec.Body.String(), `task #1`)
assert.NotContains(t, rec.Body.String(), `task #2`)
assert.NotContains(t, rec.Body.String(), `task #3`)
assert.NotContains(t, rec.Body.String(), `task #4`)
assert.NotContains(t, rec.Body.String(), `task #5`)
assert.Contains(t, rec.Body.String(), `task #6`)
assert.NotContains(t, rec.Body.String(), `task #7`)
assert.NotContains(t, rec.Body.String(), `task #8`)
assert.NotContains(t, rec.Body.String(), `task #9`)
assert.NotContains(t, rec.Body.String(), `task #2 `)
assert.NotContains(t, rec.Body.String(), `task #3 `)
assert.NotContains(t, rec.Body.String(), `task #4 `)
assert.NotContains(t, rec.Body.String(), `task #5 `)
assert.Contains(t, rec.Body.String(), `task #6 `)
assert.NotContains(t, rec.Body.String(), `task #7 `)
assert.NotContains(t, rec.Body.String(), `task #8 `)
assert.NotContains(t, rec.Body.String(), `task #9 `)
assert.NotContains(t, rec.Body.String(), `task #10`)
assert.NotContains(t, rec.Body.String(), `task #11`)
assert.NotContains(t, rec.Body.String(), `task #12`)
@ -190,14 +190,14 @@ func TestTaskCollection(t *testing.T) {
)
assert.NoError(t, err)
assert.NotContains(t, rec.Body.String(), `task #1`)
assert.NotContains(t, rec.Body.String(), `task #2`)
assert.NotContains(t, rec.Body.String(), `task #3`)
assert.NotContains(t, rec.Body.String(), `task #4`)
assert.Contains(t, rec.Body.String(), `task #5`)
assert.Contains(t, rec.Body.String(), `task #6`)
assert.Contains(t, rec.Body.String(), `task #7`)
assert.Contains(t, rec.Body.String(), `task #8`)
assert.Contains(t, rec.Body.String(), `task #9`)
assert.NotContains(t, rec.Body.String(), `task #2 `)
assert.NotContains(t, rec.Body.String(), `task #3 `)
assert.NotContains(t, rec.Body.String(), `task #4 `)
assert.Contains(t, rec.Body.String(), `task #5 `)
assert.Contains(t, rec.Body.String(), `task #6 `)
assert.Contains(t, rec.Body.String(), `task #7 `)
assert.Contains(t, rec.Body.String(), `task #8 `)
assert.Contains(t, rec.Body.String(), `task #9 `)
assert.NotContains(t, rec.Body.String(), `task #10`)
assert.NotContains(t, rec.Body.String(), `task #11`)
assert.NotContains(t, rec.Body.String(), `task #12`)
@ -215,14 +215,14 @@ func TestTaskCollection(t *testing.T) {
)
assert.NoError(t, err)
assert.NotContains(t, rec.Body.String(), `task #1`)
assert.NotContains(t, rec.Body.String(), `task #2`)
assert.NotContains(t, rec.Body.String(), `task #3`)
assert.NotContains(t, rec.Body.String(), `task #4`)
assert.NotContains(t, rec.Body.String(), `task #5`)
assert.NotContains(t, rec.Body.String(), `task #6`)
assert.Contains(t, rec.Body.String(), `task #7`)
assert.NotContains(t, rec.Body.String(), `task #8`)
assert.Contains(t, rec.Body.String(), `task #9`)
assert.NotContains(t, rec.Body.String(), `task #2 `)
assert.NotContains(t, rec.Body.String(), `task #3 `)
assert.NotContains(t, rec.Body.String(), `task #4 `)
assert.NotContains(t, rec.Body.String(), `task #5 `)
assert.NotContains(t, rec.Body.String(), `task #6 `)
assert.Contains(t, rec.Body.String(), `task #7 `)
assert.NotContains(t, rec.Body.String(), `task #8 `)
assert.Contains(t, rec.Body.String(), `task #9 `)
assert.NotContains(t, rec.Body.String(), `task #10`)
assert.NotContains(t, rec.Body.String(), `task #11`)
assert.NotContains(t, rec.Body.String(), `task #12`)
@ -255,14 +255,14 @@ func TestTaskCollection(t *testing.T) {
)
assert.NoError(t, err)
assert.NotContains(t, rec.Body.String(), `task #1`)
assert.NotContains(t, rec.Body.String(), `task #2`)
assert.NotContains(t, rec.Body.String(), `task #3`)
assert.NotContains(t, rec.Body.String(), `task #4`)
assert.Contains(t, rec.Body.String(), `task #5`)
assert.Contains(t, rec.Body.String(), `task #6`)
assert.Contains(t, rec.Body.String(), `task #7`)
assert.NotContains(t, rec.Body.String(), `task #8`)
assert.Contains(t, rec.Body.String(), `task #9`)
assert.NotContains(t, rec.Body.String(), `task #2 `)
assert.NotContains(t, rec.Body.String(), `task #3 `)
assert.NotContains(t, rec.Body.String(), `task #4 `)
assert.Contains(t, rec.Body.String(), `task #5 `)
assert.Contains(t, rec.Body.String(), `task #6 `)
assert.Contains(t, rec.Body.String(), `task #7 `)
assert.NotContains(t, rec.Body.String(), `task #8 `)
assert.Contains(t, rec.Body.String(), `task #9 `)
assert.NotContains(t, rec.Body.String(), `task #10`)
assert.NotContains(t, rec.Body.String(), `task #11`)
assert.NotContains(t, rec.Body.String(), `task #12`)
@ -291,14 +291,14 @@ func TestTaskCollection(t *testing.T) {
)
assert.NoError(t, err)
assert.NotContains(t, rec.Body.String(), `task #1`)
assert.NotContains(t, rec.Body.String(), `task #2`)
assert.NotContains(t, rec.Body.String(), `task #3`)
assert.NotContains(t, rec.Body.String(), `task #4`)
assert.Contains(t, rec.Body.String(), `task #5`)
assert.Contains(t, rec.Body.String(), `task #6`)
assert.Contains(t, rec.Body.String(), `task #7`)
assert.Contains(t, rec.Body.String(), `task #8`)
assert.Contains(t, rec.Body.String(), `task #9`)
assert.NotContains(t, rec.Body.String(), `task #2 `)
assert.NotContains(t, rec.Body.String(), `task #3 `)
assert.NotContains(t, rec.Body.String(), `task #4 `)
assert.Contains(t, rec.Body.String(), `task #5 `)
assert.Contains(t, rec.Body.String(), `task #6 `)
assert.Contains(t, rec.Body.String(), `task #7 `)
assert.Contains(t, rec.Body.String(), `task #8 `)
assert.Contains(t, rec.Body.String(), `task #9 `)
assert.NotContains(t, rec.Body.String(), `task #10`)
assert.NotContains(t, rec.Body.String(), `task #11`)
assert.NotContains(t, rec.Body.String(), `task #12`)
@ -314,14 +314,14 @@ func TestTaskCollection(t *testing.T) {
assert.NoError(t, err)
// Not using assert.Equal to avoid having the tests break every time we add new fixtures
assert.Contains(t, rec.Body.String(), `task #1`)
assert.Contains(t, rec.Body.String(), `task #2`)
assert.Contains(t, rec.Body.String(), `task #3`)
assert.Contains(t, rec.Body.String(), `task #4`)
assert.Contains(t, rec.Body.String(), `task #5`)
assert.Contains(t, rec.Body.String(), `task #6`)
assert.Contains(t, rec.Body.String(), `task #7`)
assert.Contains(t, rec.Body.String(), `task #8`)
assert.Contains(t, rec.Body.String(), `task #9`)
assert.Contains(t, rec.Body.String(), `task #2 `)
assert.Contains(t, rec.Body.String(), `task #3 `)
assert.Contains(t, rec.Body.String(), `task #4 `)
assert.Contains(t, rec.Body.String(), `task #5 `)
assert.Contains(t, rec.Body.String(), `task #6 `)
assert.Contains(t, rec.Body.String(), `task #7 `)
assert.Contains(t, rec.Body.String(), `task #8 `)
assert.Contains(t, rec.Body.String(), `task #9 `)
assert.Contains(t, rec.Body.String(), `task #10`)
assert.Contains(t, rec.Body.String(), `task #11`)
assert.Contains(t, rec.Body.String(), `task #12`)
@ -347,14 +347,14 @@ func TestTaskCollection(t *testing.T) {
rec, err := testHandler.testReadAllWithUser(url.Values{"s": []string{"task #6"}}, nil)
assert.NoError(t, err)
assert.NotContains(t, rec.Body.String(), `task #1`)
assert.NotContains(t, rec.Body.String(), `task #2`)
assert.NotContains(t, rec.Body.String(), `task #3`)
assert.NotContains(t, rec.Body.String(), `task #4`)
assert.NotContains(t, rec.Body.String(), `task #5`)
assert.Contains(t, rec.Body.String(), `task #6`)
assert.NotContains(t, rec.Body.String(), `task #7`)
assert.NotContains(t, rec.Body.String(), `task #8`)
assert.NotContains(t, rec.Body.String(), `task #9`)
assert.NotContains(t, rec.Body.String(), `task #2 `)
assert.NotContains(t, rec.Body.String(), `task #3 `)
assert.NotContains(t, rec.Body.String(), `task #4 `)
assert.NotContains(t, rec.Body.String(), `task #5 `)
assert.Contains(t, rec.Body.String(), `task #6 `)
assert.NotContains(t, rec.Body.String(), `task #7 `)
assert.NotContains(t, rec.Body.String(), `task #8 `)
assert.NotContains(t, rec.Body.String(), `task #9 `)
assert.NotContains(t, rec.Body.String(), `task #10`)
assert.NotContains(t, rec.Body.String(), `task #11`)
assert.NotContains(t, rec.Body.String(), `task #12`)
@ -417,14 +417,14 @@ func TestTaskCollection(t *testing.T) {
)
assert.NoError(t, err)
assert.NotContains(t, rec.Body.String(), `task #1`)
assert.NotContains(t, rec.Body.String(), `task #2`)
assert.NotContains(t, rec.Body.String(), `task #3`)
assert.NotContains(t, rec.Body.String(), `task #4`)
assert.Contains(t, rec.Body.String(), `task #5`)
assert.Contains(t, rec.Body.String(), `task #6`)
assert.Contains(t, rec.Body.String(), `task #7`)
assert.Contains(t, rec.Body.String(), `task #8`)
assert.Contains(t, rec.Body.String(), `task #9`)
assert.NotContains(t, rec.Body.String(), `task #2 `)
assert.NotContains(t, rec.Body.String(), `task #3 `)
assert.NotContains(t, rec.Body.String(), `task #4 `)
assert.Contains(t, rec.Body.String(), `task #5 `)
assert.Contains(t, rec.Body.String(), `task #6 `)
assert.Contains(t, rec.Body.String(), `task #7 `)
assert.Contains(t, rec.Body.String(), `task #8 `)
assert.Contains(t, rec.Body.String(), `task #9 `)
assert.NotContains(t, rec.Body.String(), `task #10`)
assert.NotContains(t, rec.Body.String(), `task #11`)
assert.NotContains(t, rec.Body.String(), `task #12`)
@ -442,14 +442,14 @@ func TestTaskCollection(t *testing.T) {
)
assert.NoError(t, err)
assert.NotContains(t, rec.Body.String(), `task #1`)
assert.NotContains(t, rec.Body.String(), `task #2`)
assert.NotContains(t, rec.Body.String(), `task #3`)
assert.NotContains(t, rec.Body.String(), `task #4`)
assert.NotContains(t, rec.Body.String(), `task #5`)
assert.NotContains(t, rec.Body.String(), `task #6`)
assert.Contains(t, rec.Body.String(), `task #7`)
assert.NotContains(t, rec.Body.String(), `task #8`)
assert.Contains(t, rec.Body.String(), `task #9`)
assert.NotContains(t, rec.Body.String(), `task #2 `)
assert.NotContains(t, rec.Body.String(), `task #3 `)
assert.NotContains(t, rec.Body.String(), `task #4 `)
assert.NotContains(t, rec.Body.String(), `task #5 `)
assert.NotContains(t, rec.Body.String(), `task #6 `)
assert.Contains(t, rec.Body.String(), `task #7 `)
assert.NotContains(t, rec.Body.String(), `task #8 `)
assert.Contains(t, rec.Body.String(), `task #9 `)
assert.NotContains(t, rec.Body.String(), `task #10`)
assert.NotContains(t, rec.Body.String(), `task #11`)
assert.NotContains(t, rec.Body.String(), `task #12`)

View File

@ -117,24 +117,24 @@ func TestTask(t *testing.T) {
assert.NotContains(t, rec.Body.String(), `"reminder_dates":[1543626724,1543626824]`)
})
t.Run("Reminders", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"listtask": "1"}, `{"reminders": [{"Reminder": "2020-02-10T10:00:00Z"},{"Reminder": "2020-02-11T10:00:00Z"}]}`)
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"listtask": "1"}, `{"reminders": [{"reminder": "2020-02-10T10:00:00Z"},{"reminder": "2020-02-11T10:00:00Z"}]}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"reminders":[`)
assert.Contains(t, rec.Body.String(), `{"Reminder":"2020-02-10T10:00:00Z"}`)
assert.Contains(t, rec.Body.String(), `{"Reminder":"2020-02-11T10:00:00Z"}`)
assert.Contains(t, rec.Body.String(), `{"reminder":"2020-02-10T10:00:00Z"`)
assert.Contains(t, rec.Body.String(), `{"reminder":"2020-02-11T10:00:00Z"`)
assert.NotContains(t, rec.Body.String(), `"reminders":null`)
})
t.Run("Reminders unset to empty array", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"listtask": "27"}, `{"reminders": []}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"reminders":null`)
assert.NotContains(t, rec.Body.String(), `{"Reminder":"2020-02-10T10:00:00Z"}`)
assert.NotContains(t, rec.Body.String(), `{"Reminder":"2020-02-10T10:00:00Z"`)
})
t.Run("Reminders unset to null", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"listtask": "27"}, `{"reminders": null}`)
assert.NoError(t, err)
assert.Contains(t, rec.Body.String(), `"reminder_dates":null`)
assert.NotContains(t, rec.Body.String(), `{"Reminder":"2020-02-10T10:00:00Z"}`)
assert.NotContains(t, rec.Body.String(), `{"Reminder":"2020-02-10T10:00:00Z"`)
})
t.Run("Repeat after", func(t *testing.T) {
rec, err := testHandler.testUpdateWithUser(nil, map[string]string{"listtask": "1"}, `{"repeat_after":3600}`)

View File

@ -0,0 +1,44 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public Licensee as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public Licensee for more details.
//
// You should have received a copy of the GNU Affero General Public Licensee
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package migration
import (
"src.techknowlogick.com/xormigrate"
"xorm.io/xorm"
)
type taskReminders20230307171848 struct {
RelativePeriod int64 `xorm:"bigint null" json:"relative_period"`
RelativeTo string `xorm:"varchar(50) null" json:"relative_to,omitempty"`
}
func (taskReminders20230307171848) TableName() string {
return "task_reminders"
}
func init() {
migrations = append(migrations, &xormigrate.Migration{
ID: "20230307171848",
Description: "Add relative period to task reminders",
Migrate: func(tx *xorm.Engine) error {
return tx.Sync2(taskReminders20230307171848{})
},
Rollback: func(tx *xorm.Engine) error {
return nil
},
})
}

View File

@ -480,7 +480,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
}
task27 := &Task{
ID: 27,
Title: "task #27 with reminders",
Title: "task #27 with reminders and start_date",
Identifier: "test1-12",
Index: 12,
CreatedByID: 1,
@ -497,12 +497,15 @@ func TestTaskCollection_ReadAll(t *testing.T) {
Created: time.Unix(1543626724, 0).In(loc),
},
{
ID: 2,
TaskID: 27,
Reminder: time.Unix(1543626824, 0).In(loc),
Created: time.Unix(1543626724, 0).In(loc),
ID: 2,
TaskID: 27,
Reminder: time.Unix(1543626824, 0).In(loc),
Created: time.Unix(1543626724, 0).In(loc),
RelativePeriod: -3600,
RelativeTo: "start_date",
},
},
StartDate: time.Unix(1543616724, 0).In(loc),
ListID: 1,
BucketID: 1,
RelatedTasks: map[RelationKind][]*Task{},
@ -1268,7 +1271,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
return
}
t.Errorf("Test %s, Task.ReadAll() = %v, want %v, \ndiff: %v", tt.name, got, tt.want, diff)
t.Errorf("Test %s, Task.ReadAll() = %v, \nwant %v, \ndiff: %v", tt.name, got, tt.want, diff)
}
})
}

View File

@ -33,13 +33,27 @@ import (
"code.vikunja.io/api/pkg/user"
)
// ReminderRelation represents the task attribute which the period based reminder relates to
type ReminderRelation string
// All valid ReminderRelations
const (
DueDate ReminderRelation = `due_date`
StartDate ReminderRelation = `start_date`
EndDate ReminderRelation = `end_date`
)
// TaskReminder holds a reminder on a task
type TaskReminder struct {
ID int64 `xorm:"bigint autoincr not null unique pk" json:"-"`
TaskID int64 `xorm:"bigint not null INDEX" json:"-"`
// The absolute time when the user wants to be reminded of the task.
Reminder time.Time `xorm:"DATETIME not null INDEX 'reminder'"`
Reminder time.Time `xorm:"DATETIME not null INDEX 'reminder'" json:"reminder"`
Created time.Time `xorm:"created not null" json:"-"`
// A period in seconds relative to another date argument. Negative values mean the reminder triggers before the date, positive after.
RelativePeriod int64 `xorm:"bigint null" json:"relative_period"`
// The name of the date field to which the relative period refers to.
RelativeTo ReminderRelation `xorm:"varchar(50) null" json:"relative_to"`
}
// TableName returns a pretty table name

View File

@ -973,14 +973,12 @@ func createTask(s *xorm.Session, t *Task, a web.Auth, updateAssignees bool) (err
}
}
// Update the reminders
//
// Deprecated: the if clause can be removed if ReminderDates will be removed
// Deprecated: the if clause can be removed when ReminderDates will be removed
if t.ReminderDates != nil {
if err := t.updateRemindersFromReminderDates(t.ReminderDates); err != nil {
return err
}
t.updateRemindersFromReminderDates(t.ReminderDates)
}
// Update the reminders
if err := t.updateReminders(s, t.Reminders); err != nil {
return err
}
@ -1068,12 +1066,11 @@ func (t *Task) Update(s *xorm.Session, a web.Auth) (err error) {
return err
}
// Deprecated: This statement can be removed if ReminderDates will be removed
// Deprecated: This statement can be removed when ReminderDates will be removed
if t.ReminderDates != nil {
if err := t.updateRemindersFromReminderDates(t.ReminderDates); err != nil {
return err
}
t.updateRemindersFromReminderDates(t.ReminderDates)
}
// Update the reminders
if err := ot.updateReminders(s, t.Reminders); err != nil {
return err
@ -1505,18 +1502,24 @@ func updateDone(oldTask *Task, newTask *Task) {
}
// Deprecated: will be removed when ReminderDates are removed from Task.
// For now the method just creates Taskeminder Objects from the ReminderDates
func (t *Task) updateRemindersFromReminderDates(reminders []time.Time) (err error) {
// For now the method just creates Taskeminder objects from the ReminderDates
func (t *Task) updateRemindersFromReminderDates(reminderDates []time.Time) {
// if the client still sends old reminder_dates, then these will overwrite the absolute triggers
// of the Reminders, sent by the client. We assume that clients still sending old reminder_dates do not
// understand the new reminders.
for _, reminder := range reminders {
t.Reminders = append(t.Reminders, &TaskReminder{TaskID: t.ID, Reminder: reminder})
// remove absolute triggers in Reminders
updatedReminders := make([]*TaskReminder, 0)
for _, reminder := range t.Reminders {
if reminder.RelativeTo != "" {
updatedReminders = append(updatedReminders, reminder)
}
}
t.ReminderDates = reminders
if len(reminders) == 0 {
t.ReminderDates = nil
// append absolute triggers from ReminderDates
for _, reminderDate := range reminderDates {
updatedReminders = append(updatedReminders, &TaskReminder{TaskID: t.ID, Reminder: reminderDate})
}
return
t.Reminders = updatedReminders
}
// Removes all old reminders and adds the new ones. This is a lot easier and less buggy than

View File

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

View File

@ -101,7 +101,8 @@ func TestConvertTicktickTasksToVikunja(t *testing.T) {
{Title: "label1"},
{Title: "label2"},
})
//assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[0].ReminderDates, tickTickTasks[0].) // TODO
assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[0].Reminders[0].RelativeTo, models.ReminderRelation("due_date"))
assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[0].Reminders[0].RelativePeriod, int64(-24*3600))
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 +128,8 @@ func TestConvertTicktickTasksToVikunja(t *testing.T) {
{Title: "label2"},
{Title: "other label"},
})
//assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[0].ReminderDates, tickTickTasks[0].) // TODO
assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[2].Reminders[0].RelativeTo, models.ReminderRelation("due_date"))
assert.Equal(t, vikunjaTasks[0].Lists[0].Tasks[2].Reminders[0].RelativePeriod, int64(-24*3600))
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

@ -8309,6 +8309,19 @@ const docTemplate = `{
"RelationKindCopiedTo"
]
},
"models.ReminderRelation": {
"type": "string",
"enum": [
"due_date",
"start_date",
"end_date"
],
"x-enum-varnames": [
"DueDate",
"StartDate",
"EndDate"
]
},
"models.Right": {
"type": "integer",
"enum": [
@ -8707,6 +8720,18 @@ const docTemplate = `{
"models.TaskReminder": {
"type": "object",
"properties": {
"relative_period": {
"description": "A period in seconds relative to another date argument. Negative values mean the reminder triggers before the date, positive after.",
"type": "integer"
},
"relative_to": {
"description": "The name of the date field to which the relative period refers to.",
"allOf": [
{
"$ref": "#/definitions/models.ReminderRelation"
}
]
},
"reminder": {
"description": "The absolute time when the user wants to be reminded of the task.",
"type": "string"

View File

@ -8301,6 +8301,19 @@
"RelationKindCopiedTo"
]
},
"models.ReminderRelation": {
"type": "string",
"enum": [
"due_date",
"start_date",
"end_date"
],
"x-enum-varnames": [
"DueDate",
"StartDate",
"EndDate"
]
},
"models.Right": {
"type": "integer",
"enum": [
@ -8699,6 +8712,18 @@
"models.TaskReminder": {
"type": "object",
"properties": {
"relative_period": {
"description": "A period in seconds relative to another date argument. Negative values mean the reminder triggers before the date, positive after.",
"type": "integer"
},
"relative_to": {
"description": "The name of the date field to which the relative period refers to.",
"allOf": [
{
"$ref": "#/definitions/models.ReminderRelation"
}
]
},
"reminder": {
"description": "The absolute time when the user wants to be reminded of the task.",
"type": "string"

View File

@ -602,6 +602,16 @@ definitions:
- RelationKindFollows
- RelationKindCopiedFrom
- RelationKindCopiedTo
models.ReminderRelation:
enum:
- due_date
- start_date
- end_date
type: string
x-enum-varnames:
- DueDate
- StartDate
- EndDate
models.Right:
enum:
- 0
@ -904,6 +914,15 @@ definitions:
type: object
models.TaskReminder:
properties:
relative_period:
description: A period in seconds relative to another date argument. Negative
values mean the reminder triggers before the date, positive after.
type: integer
relative_to:
allOf:
- $ref: '#/definitions/models.ReminderRelation'
description: The name of the date field to which the relative period refers
to.
reminder:
description: The absolute time when the user wants to be reminded of the task.
type: string