From 24ce940885b464039a8fc7ec8fb45348498ac863 Mon Sep 17 00:00:00 2001 From: konrad Date: Sat, 25 May 2019 07:33:57 +0000 Subject: [PATCH] Put reminders in an extra table (#75) --- Featurecreep.md | 2 +- go.sum | 1 + pkg/integrations/task_test.go | 12 +- pkg/migration/20190524205441.go | 70 +++ pkg/models/fixtures/task_reminders.yml | 8 + pkg/models/fixtures/tasks.yml | 1 - pkg/models/list_task_readall.go | 38 +- pkg/models/list_task_readall_test.go | 808 +++---------------------- pkg/models/list_tasks.go | 30 +- pkg/models/list_tasks_create_update.go | 91 ++- pkg/models/models.go | 1 + 11 files changed, 320 insertions(+), 742 deletions(-) create mode 100644 pkg/migration/20190524205441.go create mode 100644 pkg/models/fixtures/task_reminders.yml diff --git a/Featurecreep.md b/Featurecreep.md index 95e952e125..f0f161064c 100644 --- a/Featurecreep.md +++ b/Featurecreep.md @@ -214,7 +214,7 @@ Sorry for some of them being in German, I'll tranlate them at some point. * [x] Things like list/task order should use queries and not url params * [x] Fix lint errors * [x] Add settings for max open/idle connections and max connection lifetime -* [ ] Reminders should use an extra table so we can make reverse lookups aka "give me all tasks with reminders in this period" which we'll need for things like email reminders notifications +* [x] Reminders should use an extra table so we can make reverse lookups aka "give me all tasks with reminders in this period" which we'll need for things like email reminders notifications * [ ] Teams and users should also have uuids (for users these can be the username) * [ ] When giving a team or user access to a list/namespace, they should be reffered to by uuid, not numeric id * [ ] Adding users to a team should also use uuid diff --git a/go.sum b/go.sum index 5449a8bc85..a6d3e0d934 100644 --- a/go.sum +++ b/go.sum @@ -27,6 +27,7 @@ github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMe github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cweill/gotests v1.5.3 h1:k3t4wW/x/YNixWZJhUIn+mivmK5iV1tJVOwVYkx0UcU= github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U= github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/pkg/integrations/task_test.go b/pkg/integrations/task_test.go index 087a5814fb..d9da983dce 100644 --- a/pkg/integrations/task_test.go +++ b/pkg/integrations/task_test.go @@ -80,33 +80,33 @@ func TestListTask(t *testing.T) { t.Run("by priority", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"priority"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1`) + assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1`) }) t.Run("by priority desc", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"prioritydesc"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1`) + assert.Contains(t, rec.Body.String(), `[{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1`) }) t.Run("by priority asc", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"priorityasc"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","created":0,"updated":0}},{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","created":0,"updated":0}}]`) + assert.Contains(t, rec.Body.String(), `{"id":31,"text":"task #31 with color","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"f0f0f0","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":4,"text":"task #4 low prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":1,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":3,"text":"task #3 high prio","description":"","done":false,"doneAt":0,"dueDate":0,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":100,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}}]`) }) // should equal duedate desc t.Run("by duedate", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"dueadate"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`) + assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`) }) t.Run("by duedate desc", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"dueadatedesc"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`) + assert.Contains(t, rec.Body.String(), `[{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":6,"text":"task #6 lower due date"`) }) t.Run("by duedate asc", func(t *testing.T) { rec, err := testHandler.testReadAll(url.Values{"sort": []string{"duedateasc"}}, nil) assert.NoError(t, err) - assert.Contains(t, rec.Body.String(), `{"id":6,"text":"task #6 lower due date","description":"","done":false,"doneAt":0,"dueDate":1543616724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","created":0,"updated":0}},{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":0,"username":"","created":0,"updated":0}}]`) + assert.Contains(t, rec.Body.String(), `{"id":6,"text":"task #6 lower due date","description":"","done":false,"doneAt":0,"dueDate":1543616724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}},{"id":5,"text":"task #5 higher due date","description":"","done":false,"doneAt":0,"dueDate":1543636724,"reminderDates":null,"listID":1,"repeatAfter":0,"parentTaskID":0,"priority":0,"startDate":0,"endDate":0,"assignees":null,"labels":null,"hexColor":"","subtasks":null,"created":1543626724,"updated":1543626724,"createdBy":{"id":1,"username":"user1","created":0,"updated":0}}]`) }) t.Run("invalid parameter", func(t *testing.T) { // Invalid parameter should not sort at all diff --git a/pkg/migration/20190524205441.go b/pkg/migration/20190524205441.go new file mode 100644 index 0000000000..a201ac6705 --- /dev/null +++ b/pkg/migration/20190524205441.go @@ -0,0 +1,70 @@ +// Vikunja is a todo-list application to facilitate your life. +// Copyright 2019 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 General Public License 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package migration + +import ( + "github.com/go-xorm/xorm" + "src.techknowlogick.com/xormigrate" +) + +type taskReminder20190524205441 struct { + ID int64 `xorm:"int(11) autoincr not null unique pk"` + TaskID int64 `xorm:"int(11) not null INDEX"` + ReminderUnix int64 `xorm:"int(11) not null INDEX"` + Created int64 `xorm:"created not null"` +} + +// TableName returns a pretty table name +func (taskReminder20190524205441) TableName() string { + return "task_reminders" +} + +func init() { + migrations = append(migrations, &xormigrate.Migration{ + ID: "20190524205441", + Description: "Add extra table for reminders", + Migrate: func(tx *xorm.Engine) error { + err := tx.Sync2(taskReminder20190524205441{}) + if err != nil { + return err + } + + // get all current reminders and put them into the new table + var allTasks []*listTask20190511202210 + err = tx.Find(&allTasks) + if err != nil { + return err + } + + reminders := []*taskReminder20190524205441{} + for _, t := range allTasks { + for _, reminder := range t.RemindersUnix { + reminders = append(reminders, &taskReminder20190524205441{TaskID: t.ID, ReminderUnix: reminder}) + } + } + _, err = tx.Insert(reminders) + if err != nil { + return err + } + + return dropTableColum(tx, "tasks", "reminders_unix") + }, + Rollback: func(tx *xorm.Engine) error { + return tx.DropTables(taskReminder20190524205441{}) + }, + }) +} diff --git a/pkg/models/fixtures/task_reminders.yml b/pkg/models/fixtures/task_reminders.yml new file mode 100644 index 0000000000..46e308022c --- /dev/null +++ b/pkg/models/fixtures/task_reminders.yml @@ -0,0 +1,8 @@ +- id: 1 + task_id: 27 + reminder_unix: 1543626724 + created: 1543626724 +- id: 2 + task_id: 27 + reminder_unix: 1543626824 + created: 1543626724 diff --git a/pkg/models/fixtures/tasks.yml b/pkg/models/fixtures/tasks.yml index 11941be482..a57c79f785 100644 --- a/pkg/models/fixtures/tasks.yml +++ b/pkg/models/fixtures/tasks.yml @@ -167,7 +167,6 @@ - id: 27 text: 'task #27 with reminders' created_by_id: 1 - reminders_unix: '[1543626724,1543626824]' list_id: 1 created: 1543626724 updated: 1543626724 diff --git a/pkg/models/list_task_readall.go b/pkg/models/list_task_readall.go index 290e924b6d..e9d2538dbd 100644 --- a/pkg/models/list_task_readall.go +++ b/pkg/models/list_task_readall.go @@ -8,6 +8,7 @@ package models import ( "code.vikunja.io/web" + "sort" "time" ) @@ -66,7 +67,7 @@ func (t *ListTask) ReadAll(search string, a web.Auth, page int) (interface{}, er } //GetTasksByUser returns all tasks for a user -func GetTasksByUser(search string, u *User, page int, sortby SortBy, startDate time.Time, endDate time.Time) (tasks []*ListTask, err error) { +func GetTasksByUser(search string, u *User, page int, sortby SortBy, startDate time.Time, endDate time.Time) ([]*ListTask, error) { // Get all lists lists, err := getRawListsForUser("", u, page) if err != nil { @@ -91,6 +92,8 @@ func GetTasksByUser(search string, u *User, page int, sortby SortBy, startDate t orderby = "due_date_unix asc" } + taskMap := make(map[int64]*ListTask) + // Then return all tasks for that lists if startDate.Unix() != 0 || endDate.Unix() != 0 { @@ -111,7 +114,7 @@ func GetTasksByUser(search string, u *User, page int, sortby SortBy, startDate t "(end_date_unix BETWEEN ? and ?))", startDateUnix, endDateUnix, startDateUnix, endDateUnix, startDateUnix, endDateUnix). And("(parent_task_id = 0 OR parent_task_id IS NULL)"). OrderBy(orderby). - Find(&tasks); err != nil { + Find(&taskMap); err != nil { return nil, err } } else { @@ -119,10 +122,39 @@ func GetTasksByUser(search string, u *User, page int, sortby SortBy, startDate t Where("text LIKE ?", "%"+search+"%"). And("(parent_task_id = 0 OR parent_task_id IS NULL)"). OrderBy(orderby). - Find(&tasks); err != nil { + Find(&taskMap); err != nil { return nil, err } } + tasks, err := addMoreInfoToTasks(taskMap) + if err != nil { + return nil, err + } + // Because the list is sorted by id which we don't want (since we're dealing with maps) + // we have to manually sort the tasks again here. + sortTasks(tasks, sortby) + return tasks, err } + +func sortTasks(tasks []*ListTask, by SortBy) { + switch by { + case SortTasksByPriorityDesc: + sort.Slice(tasks, func(i, j int) bool { + return tasks[i].Priority > tasks[j].Priority + }) + case SortTasksByPriorityAsc: + sort.Slice(tasks, func(i, j int) bool { + return tasks[i].Priority < tasks[j].Priority + }) + case SortTasksByDueDateDesc: + sort.Slice(tasks, func(i, j int) bool { + return tasks[i].DueDateUnix > tasks[j].DueDateUnix + }) + case SortTasksByDueDateAsc: + sort.Slice(tasks, func(i, j int) bool { + return tasks[i].DueDateUnix < tasks[j].DueDateUnix + }) + } +} diff --git a/pkg/models/list_task_readall_test.go b/pkg/models/list_task_readall_test.go index 5f6e1f102d..80901acf41 100644 --- a/pkg/models/list_task_readall_test.go +++ b/pkg/models/list_task_readall_test.go @@ -16,21 +16,51 @@ import ( ) func sortTasksForTesting(by SortBy) (tasks []*ListTask) { + user1 := User{ + ID: 1, + Username: "user1", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + IsActive: true, + } + user2 := User{ + ID: 2, + Username: "user2", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + } + user6 := User{ + ID: 6, + Username: "user6", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + IsActive: true, + } + tasks = []*ListTask{ { ID: 1, Text: "task #1", Description: "Lorem Ipsum", CreatedByID: 1, + CreatedBy: user1, ListID: 1, - Created: 1543626724, - Updated: 1543626724, + Labels: []*Label{ + { + ID: 4, + Title: "Label #4 - visible via other task", + CreatedByID: 2, + CreatedBy: &user2, + Updated: 0, + Created: 0, + }, + }, + Created: 1543626724, + Updated: 1543626724, }, { ID: 2, Text: "task #2 done", Done: true, CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -39,6 +69,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 3, Text: "task #3 high prio", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -48,6 +79,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 4, Text: "task #4 low prio", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -57,6 +89,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 5, Text: "task #5 higher due date", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -66,6 +99,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 6, Text: "task #6 lower due date", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -75,6 +109,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 7, Text: "task #7 with start date", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -84,6 +119,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 8, Text: "task #8 with end date", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -93,6 +129,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 9, Text: "task #9 with start and end date", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -103,6 +140,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 10, Text: "task #10 basic", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -111,6 +149,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 11, Text: "task #11 basic", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -119,6 +158,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 12, Text: "task #12 basic", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -127,6 +167,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 15, Text: "task #15", CreatedByID: 6, + CreatedBy: user6, ListID: 6, Created: 1543626724, Updated: 1543626724, @@ -135,6 +176,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 16, Text: "task #16", CreatedByID: 6, + CreatedBy: user6, ListID: 7, Created: 1543626724, Updated: 1543626724, @@ -143,6 +185,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 17, Text: "task #17", CreatedByID: 6, + CreatedBy: user6, ListID: 8, Created: 1543626724, Updated: 1543626724, @@ -151,6 +194,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 18, Text: "task #18", CreatedByID: 6, + CreatedBy: user6, ListID: 9, Created: 1543626724, Updated: 1543626724, @@ -159,6 +203,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 19, Text: "task #19", CreatedByID: 6, + CreatedBy: user6, ListID: 10, Created: 1543626724, Updated: 1543626724, @@ -167,6 +212,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 20, Text: "task #20", CreatedByID: 6, + CreatedBy: user6, ListID: 11, Created: 1543626724, Updated: 1543626724, @@ -175,6 +221,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 21, Text: "task #21", CreatedByID: 6, + CreatedBy: user6, ListID: 12, Created: 1543626724, Updated: 1543626724, @@ -183,6 +230,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 22, Text: "task #22", CreatedByID: 6, + CreatedBy: user6, ListID: 13, Created: 1543626724, Updated: 1543626724, @@ -191,6 +239,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 23, Text: "task #23", CreatedByID: 6, + CreatedBy: user6, ListID: 14, Created: 1543626724, Updated: 1543626724, @@ -199,6 +248,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 24, Text: "task #24", CreatedByID: 6, + CreatedBy: user6, ListID: 15, Created: 1543626724, Updated: 1543626724, @@ -207,6 +257,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 25, Text: "task #25", CreatedByID: 6, + CreatedBy: user6, ListID: 16, Created: 1543626724, Updated: 1543626724, @@ -215,6 +266,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 26, Text: "task #26", CreatedByID: 6, + CreatedBy: user6, ListID: 17, Created: 1543626724, Updated: 1543626724, @@ -223,6 +275,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 27, Text: "task #27 with reminders", CreatedByID: 1, + CreatedBy: user1, RemindersUnix: []int64{1543626724, 1543626824}, ListID: 1, Created: 1543626724, @@ -232,6 +285,7 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 28, Text: "task #28 with repeat after", CreatedByID: 1, + CreatedBy: user1, ListID: 1, RepeatAfter: 3600, Created: 1543626724, @@ -241,15 +295,21 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { ID: 30, Text: "task #30 with assignees", CreatedByID: 1, + CreatedBy: user1, ListID: 1, - Created: 1543626724, - Updated: 1543626724, + Assignees: []*User{ + &user1, + &user2, + }, + Created: 1543626724, + Updated: 1543626724, }, { ID: 31, Text: "task #31 with color", HexColor: "f0f0f0", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -269,10 +329,6 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { sort.Slice(tasks, func(i, j int) bool { return tasks[i].DueDateUnix > tasks[j].DueDateUnix }) - // Swap since sqlite seems to sort differently - tmp := tasks[5] - tasks[5] = tasks[3] - tasks[3] = tmp case SortTasksByDueDateAsc: sort.Slice(tasks, func(i, j int) bool { return tasks[i].DueDateUnix < tasks[j].DueDateUnix @@ -284,6 +340,15 @@ func sortTasksForTesting(by SortBy) (tasks []*ListTask) { func TestListTask_ReadAll(t *testing.T) { assert.NoError(t, LoadFixtures()) + + // Dummy users + user1 := User{ + ID: 1, + Username: "user1", + Password: "$2a$14$dcadBoMBL9jQoOcZK8Fju.cy0Ptx2oZECkKLnaa8ekRoTFe1w7To.", + IsActive: true, + } + type fields struct { ID int64 Text string @@ -352,244 +417,7 @@ func TestListTask_ReadAll(t *testing.T) { a: &User{ID: 1}, page: 0, }, - want: []*ListTask{ - { - ID: 1, - Text: "task #1", - Description: "Lorem Ipsum", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 2, - Text: "task #2 done", - Done: true, - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 5, - Text: "task #5 higher due date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - DueDateUnix: 1543636724, - }, - { - ID: 6, - Text: "task #6 lower due date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - DueDateUnix: 1543616724, - }, - { - ID: 7, - Text: "task #7 with start date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - StartDateUnix: 1544600000, - }, - { - ID: 8, - Text: "task #8 with end date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - EndDateUnix: 1544700000, - }, - { - ID: 9, - Text: "task #9 with start and end date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - StartDateUnix: 1544600000, - EndDateUnix: 1544700000, - }, - { - ID: 10, - Text: "task #10 basic", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 11, - Text: "task #11 basic", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 12, - Text: "task #12 basic", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, { - ID: 15, - Text: "task #15", - CreatedByID: 6, - ListID: 6, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 16, - Text: "task #16", - CreatedByID: 6, - ListID: 7, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 17, - Text: "task #17", - CreatedByID: 6, - ListID: 8, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 18, - Text: "task #18", - CreatedByID: 6, - ListID: 9, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 19, - Text: "task #19", - CreatedByID: 6, - ListID: 10, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 20, - Text: "task #20", - CreatedByID: 6, - ListID: 11, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 21, - Text: "task #21", - CreatedByID: 6, - ListID: 12, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 22, - Text: "task #22", - CreatedByID: 6, - ListID: 13, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 23, - Text: "task #23", - CreatedByID: 6, - ListID: 14, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 24, - Text: "task #24", - CreatedByID: 6, - ListID: 15, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 25, - Text: "task #25", - CreatedByID: 6, - ListID: 16, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 26, - Text: "task #26", - CreatedByID: 6, - ListID: 17, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 27, - Text: "task #27 with reminders", - CreatedByID: 1, - RemindersUnix: []int64{1543626724, 1543626824}, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 28, - Text: "task #28 with repeat after", - CreatedByID: 1, - ListID: 1, - RepeatAfter: 3600, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 30, - Text: "task #30 with assignees", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 31, - Text: "task #31 with color", - HexColor: "f0f0f0", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 4, - Text: "task #4 low prio", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - Priority: 1, - }, - { - ID: 3, - Text: "task #3 high prio", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - Priority: 100, - }, - }, + want: sortTasksForTesting(SortTasksByPriorityAsc), wantErr: false, }, { @@ -615,245 +443,7 @@ func TestListTask_ReadAll(t *testing.T) { a: &User{ID: 1}, page: 0, }, - want: []*ListTask{ - { - ID: 5, - Text: "task #5 higher due date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - DueDateUnix: 1543636724, - }, - { - ID: 6, - Text: "task #6 lower due date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - DueDateUnix: 1543616724, - }, - { - ID: 1, - Text: "task #1", - Description: "Lorem Ipsum", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 2, - Text: "task #2 done", - Done: true, - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 3, - Text: "task #3 high prio", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - Priority: 100, - }, - { - ID: 4, - Text: "task #4 low prio", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - Priority: 1, - }, - { - ID: 7, - Text: "task #7 with start date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - StartDateUnix: 1544600000, - }, - { - ID: 8, - Text: "task #8 with end date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - EndDateUnix: 1544700000, - }, - { - ID: 9, - Text: "task #9 with start and end date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - StartDateUnix: 1544600000, - EndDateUnix: 1544700000, - }, - { - ID: 10, - Text: "task #10 basic", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 11, - Text: "task #11 basic", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 12, - Text: "task #12 basic", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 15, - Text: "task #15", - CreatedByID: 6, - ListID: 6, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 16, - Text: "task #16", - CreatedByID: 6, - ListID: 7, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 17, - Text: "task #17", - CreatedByID: 6, - ListID: 8, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 18, - Text: "task #18", - CreatedByID: 6, - ListID: 9, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 19, - Text: "task #19", - CreatedByID: 6, - ListID: 10, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 20, - Text: "task #20", - CreatedByID: 6, - ListID: 11, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 21, - Text: "task #21", - CreatedByID: 6, - ListID: 12, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 22, - Text: "task #22", - CreatedByID: 6, - ListID: 13, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 23, - Text: "task #23", - CreatedByID: 6, - ListID: 14, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 24, - Text: "task #24", - CreatedByID: 6, - ListID: 15, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 25, - Text: "task #25", - CreatedByID: 6, - ListID: 16, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 26, - Text: "task #26", - CreatedByID: 6, - ListID: 17, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 27, - Text: "task #27 with reminders", - CreatedByID: 1, - RemindersUnix: []int64{1543626724, 1543626824}, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 28, - Text: "task #28 with repeat after", - CreatedByID: 1, - ListID: 1, - RepeatAfter: 3600, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 30, - Text: "task #30 with assignees", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 31, - Text: "task #31 with color", - HexColor: "f0f0f0", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - }, + want: sortTasksForTesting(SortTasksByDueDateDesc), wantErr: false, }, { @@ -866,245 +456,7 @@ func TestListTask_ReadAll(t *testing.T) { a: &User{ID: 1}, page: 0, }, - want: []*ListTask{ - { - ID: 1, - Text: "task #1", - Description: "Lorem Ipsum", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 2, - Text: "task #2 done", - Done: true, - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 3, - Text: "task #3 high prio", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - Priority: 100, - }, - { - ID: 4, - Text: "task #4 low prio", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - Priority: 1, - }, - { - ID: 7, - Text: "task #7 with start date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - StartDateUnix: 1544600000, - }, - { - ID: 8, - Text: "task #8 with end date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - EndDateUnix: 1544700000, - }, - { - ID: 9, - Text: "task #9 with start and end date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - StartDateUnix: 1544600000, - EndDateUnix: 1544700000, - }, - { - ID: 10, - Text: "task #10 basic", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 11, - Text: "task #11 basic", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 12, - Text: "task #12 basic", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 15, - Text: "task #15", - CreatedByID: 6, - ListID: 6, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 16, - Text: "task #16", - CreatedByID: 6, - ListID: 7, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 17, - Text: "task #17", - CreatedByID: 6, - ListID: 8, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 18, - Text: "task #18", - CreatedByID: 6, - ListID: 9, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 19, - Text: "task #19", - CreatedByID: 6, - ListID: 10, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 20, - Text: "task #20", - CreatedByID: 6, - ListID: 11, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 21, - Text: "task #21", - CreatedByID: 6, - ListID: 12, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 22, - Text: "task #22", - CreatedByID: 6, - ListID: 13, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 23, - Text: "task #23", - CreatedByID: 6, - ListID: 14, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 24, - Text: "task #24", - CreatedByID: 6, - ListID: 15, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 25, - Text: "task #25", - CreatedByID: 6, - ListID: 16, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 26, - Text: "task #26", - CreatedByID: 6, - ListID: 17, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 27, - Text: "task #27 with reminders", - CreatedByID: 1, - RemindersUnix: []int64{1543626724, 1543626824}, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 28, - Text: "task #28 with repeat after", - CreatedByID: 1, - ListID: 1, - RepeatAfter: 3600, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 30, - Text: "task #30 with assignees", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 31, - Text: "task #31 with color", - HexColor: "f0f0f0", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - }, - { - ID: 6, - Text: "task #6 lower due date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - DueDateUnix: 1543616724, - }, - { - ID: 5, - Text: "task #5 higher due date", - CreatedByID: 1, - ListID: 1, - Created: 1543626724, - Updated: 1543626724, - DueDateUnix: 1543636724, - }, - }, + want: sortTasksForTesting(SortTasksByDueDateAsc), wantErr: false, }, { @@ -1137,6 +489,7 @@ func TestListTask_ReadAll(t *testing.T) { ID: 7, Text: "task #7 with start date", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -1146,6 +499,7 @@ func TestListTask_ReadAll(t *testing.T) { ID: 9, Text: "task #9 with start and end date", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -1171,6 +525,7 @@ func TestListTask_ReadAll(t *testing.T) { ID: 8, Text: "task #8 with end date", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -1180,6 +535,7 @@ func TestListTask_ReadAll(t *testing.T) { ID: 9, Text: "task #9 with start and end date", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -1204,6 +560,7 @@ func TestListTask_ReadAll(t *testing.T) { ID: 8, Text: "task #8 with end date", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -1213,6 +570,7 @@ func TestListTask_ReadAll(t *testing.T) { ID: 9, Text: "task #9 with start and end date", CreatedByID: 1, + CreatedBy: user1, ListID: 1, Created: 1543626724, Updated: 1543626724, @@ -1253,7 +611,7 @@ func TestListTask_ReadAll(t *testing.T) { return } if diff, equal := messagediff.PrettyDiff(got, tt.want); !equal { - t.Errorf("Test %s, LabelTask.ReadAll() = %v, want %v, diff: %v", tt.name, got, tt.want, diff) + t.Errorf("Test %s, LabelTask.ReadAll() = %v, want %v, \ndiff: %v", tt.name, got, tt.want, diff) } }) } diff --git a/pkg/models/list_tasks.go b/pkg/models/list_tasks.go index 7282572ca6..85bc6c1d54 100644 --- a/pkg/models/list_tasks.go +++ b/pkg/models/list_tasks.go @@ -36,7 +36,7 @@ type ListTask struct { // A unix timestamp when the task is due. DueDateUnix int64 `xorm:"int(11) INDEX null" json:"dueDate"` // An array of unix timestamps when the user wants to be reminded of the task. - RemindersUnix []int64 `xorm:"JSON TEXT null" json:"reminderDates"` + RemindersUnix []int64 `xorm:"-" json:"reminderDates"` CreatedByID int64 `xorm:"int(11) not null" json:"-"` // ID of the user who put that task on the list // The list this task belongs to. ListID int64 `xorm:"int(11) INDEX not null" json:"listID" param:"list"` @@ -84,6 +84,19 @@ func (ListTask) TableName() string { return "tasks" } +// TaskReminder holds a reminder on a task +type TaskReminder struct { + ID int64 `xorm:"int(11) autoincr not null unique pk"` + TaskID int64 `xorm:"int(11) not null INDEX"` + ReminderUnix int64 `xorm:"int(11) not null INDEX"` + Created int64 `xorm:"created not null"` +} + +// TableName returns a pretty table name +func (TaskReminder) TableName() string { + return "task_reminders" +} + // GetTasksByListID gets all todotasks for a list func GetTasksByListID(listID int64) (tasks []*ListTask, err error) { // make a map so we can put in a lot of other stuff more easily @@ -236,12 +249,27 @@ func addMoreInfoToTasks(taskMap map[int64]*ListTask) (tasks []*ListTask, err err return } + // Get all reminders and put them in a map to have it easier later + reminders := []*TaskReminder{} + err = x.Table("task_reminders").In("task_id", taskIDs).Find(&reminders) + if err != nil { + return + } + + taskRemindersUnix := make(map[int64][]int64) + for _, r := range reminders { + taskRemindersUnix[r.TaskID] = append(taskRemindersUnix[r.TaskID], r.ReminderUnix) + } + // Add all user objects to the appropriate tasks for _, task := range taskMap { // Make created by user objects taskMap[task.ID].CreatedBy = *users[task.CreatedByID] + // Add the reminders + taskMap[task.ID].RemindersUnix = taskRemindersUnix[task.ID] + // Reorder all subtasks if task.ParentTaskID != 0 { taskMap[task.ParentTaskID].Subtasks = append(taskMap[task.ParentTaskID].Subtasks, task) diff --git a/pkg/models/list_tasks_create_update.go b/pkg/models/list_tasks_create_update.go index a2997406fb..07914c096e 100644 --- a/pkg/models/list_tasks_create_update.go +++ b/pkg/models/list_tasks_create_update.go @@ -78,6 +78,11 @@ func (t *ListTask) Create(a web.Auth) (err error) { return err } + // Update the reminders + if err := t.updateReminders(t.RemindersUnix); err != nil { + return err + } + metrics.UpdateCount(1, metrics.TaskCountKey) err = updateListLastUpdated(&List{ID: t.ListID}) @@ -118,6 +123,11 @@ func (t *ListTask) Update() (err error) { return err } + // Update the reminders + if err := ot.updateReminders(t.RemindersUnix); err != nil { + return err + } + // Update the labels // // Maybe FIXME: @@ -162,10 +172,6 @@ func (t *ListTask) Update() (err error) { if t.DueDateUnix == 0 { ot.DueDateUnix = 0 } - // Reminders - if len(t.RemindersUnix) == 0 { - ot.RemindersUnix = nil - } // Repeat after if t.RepeatAfter == 0 { ot.RepeatAfter = 0 @@ -192,7 +198,6 @@ func (t *ListTask) Update() (err error) { "description", "done", "due_date_unix", - "reminders_unix", "repeat_after", "parent_task_id", "priority", @@ -232,3 +237,79 @@ func updateDone(oldTask *ListTask, newTask *ListTask) { oldTask.DoneAtUnix = 0 } } + +// Creates or deletes all necessary remindes without unneded db operations. +// The parameter is a slice with unix dates which holds the new reminders. +func (t *ListTask) updateReminders(reminders []int64) (err error) { + + // If we're removing everything, delete all reminders right away + if len(reminders) == 0 && len(t.RemindersUnix) > 0 { + _, err = x.Where("task_id = ?", t.ID). + Delete(TaskReminder{}) + t.RemindersUnix = nil + return err + } + + // If we didn't change anything (from 0 to zero) don't do anything. + if len(reminders) == 0 && len(t.RemindersUnix) == 0 { + return nil + } + + // Make a hashmap of the new reminders for easier comparison + newReminders := make(map[int64]*TaskReminder, len(reminders)) + for _, newReminder := range reminders { + newReminders[newReminder] = &TaskReminder{ReminderUnix: newReminder} + } + + // Get old reminders to delete + var found bool + var remindersToDelete []int64 + oldReminders := make(map[int64]*TaskReminder, len(t.RemindersUnix)) + for _, oldReminder := range t.RemindersUnix { + found = false + // If a new reminder is already in the list with old reminders + if newReminders[oldReminder] != nil { + found = true + } + + // Put all reminders which are only on the old list to the trash + if !found { + remindersToDelete = append(remindersToDelete, oldReminder) + } + + oldReminders[oldReminder] = &TaskReminder{ReminderUnix: oldReminder} + } + + // Delete all reminders not passed + if len(remindersToDelete) > 0 { + _, err = x.In("reminder_unix", remindersToDelete). + And("task_id = ?", t.ID). + Delete(ListTaskAssginee{}) + if err != nil { + return err + } + } + + // Loop through our users and add them + for _, r := range reminders { + // Check if the reminder already exists and only inserts it if not + if oldReminders[r] != nil { + // continue outer loop + continue + } + + // Add the new reminder + _, err = x.Insert(TaskReminder{TaskID: t.ID, ReminderUnix: r}) + if err != nil { + return err + } + } + + t.RemindersUnix = reminders + if len(reminders) == 0 { + t.RemindersUnix = nil + } + + err = updateListLastUpdated(&List{ID: t.ListID}) + return +} diff --git a/pkg/models/models.go b/pkg/models/models.go index 6543f3cd38..6bb9267d48 100644 --- a/pkg/models/models.go +++ b/pkg/models/models.go @@ -47,6 +47,7 @@ func GetTables() []interface{} { &ListTaskAssginee{}, &Label{}, &LabelTask{}, + &TaskReminder{}, } }