Reorder tasks, lists and kanban buckets (#923)
Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/923 Co-authored-by: konrad <konrad@kola-entertainments.de> Co-committed-by: konrad <konrad@kola-entertainments.de>
This commit is contained in:
parent
dac315db59
commit
6ccb85a0dc
22 changed files with 475 additions and 96 deletions
|
@ -3,6 +3,7 @@
|
||||||
list_id: 1
|
list_id: 1
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
limit: 9999999 # This bucket has a limit we will never exceed in the tests to make sure the logic allows for buckets with limits
|
limit: 9999999 # This bucket has a limit we will never exceed in the tests to make sure the logic allows for buckets with limits
|
||||||
|
position: 2
|
||||||
created: 2020-04-18 21:13:52
|
created: 2020-04-18 21:13:52
|
||||||
updated: 2020-04-18 21:13:52
|
updated: 2020-04-18 21:13:52
|
||||||
- id: 2
|
- id: 2
|
||||||
|
@ -10,6 +11,7 @@
|
||||||
list_id: 1
|
list_id: 1
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
limit: 3
|
limit: 3
|
||||||
|
position: 1
|
||||||
created: 2020-04-18 21:13:52
|
created: 2020-04-18 21:13:52
|
||||||
updated: 2020-04-18 21:13:52
|
updated: 2020-04-18 21:13:52
|
||||||
- id: 3
|
- id: 3
|
||||||
|
@ -17,6 +19,7 @@
|
||||||
list_id: 1
|
list_id: 1
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
is_done_bucket: 1
|
is_done_bucket: 1
|
||||||
|
position: 3
|
||||||
created: 2020-04-18 21:13:52
|
created: 2020-04-18 21:13:52
|
||||||
updated: 2020-04-18 21:13:52
|
updated: 2020-04-18 21:13:52
|
||||||
- id: 4
|
- id: 4
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
identifier: test1
|
identifier: test1
|
||||||
owner_id: 1
|
owner_id: 1
|
||||||
namespace_id: 1
|
namespace_id: 1
|
||||||
|
position: 3
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -14,6 +15,7 @@
|
||||||
identifier: test2
|
identifier: test2
|
||||||
owner_id: 3
|
owner_id: 3
|
||||||
namespace_id: 1
|
namespace_id: 1
|
||||||
|
position: 2
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -23,6 +25,7 @@
|
||||||
identifier: test3
|
identifier: test3
|
||||||
owner_id: 3
|
owner_id: 3
|
||||||
namespace_id: 2
|
namespace_id: 2
|
||||||
|
position: 1
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -32,6 +35,7 @@
|
||||||
identifier: test4
|
identifier: test4
|
||||||
owner_id: 3
|
owner_id: 3
|
||||||
namespace_id: 3
|
namespace_id: 3
|
||||||
|
position: 4
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -41,6 +45,7 @@
|
||||||
identifier: test5
|
identifier: test5
|
||||||
owner_id: 5
|
owner_id: 5
|
||||||
namespace_id: 5
|
namespace_id: 5
|
||||||
|
position: 5
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -50,6 +55,7 @@
|
||||||
identifier: test6
|
identifier: test6
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 6
|
namespace_id: 6
|
||||||
|
position: 6
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -59,6 +65,7 @@
|
||||||
identifier: test7
|
identifier: test7
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 6
|
namespace_id: 6
|
||||||
|
position: 7
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -68,6 +75,7 @@
|
||||||
identifier: test8
|
identifier: test8
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 6
|
namespace_id: 6
|
||||||
|
position: 8
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -77,6 +85,7 @@
|
||||||
identifier: test9
|
identifier: test9
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 6
|
namespace_id: 6
|
||||||
|
position: 9
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -86,6 +95,7 @@
|
||||||
identifier: test10
|
identifier: test10
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 6
|
namespace_id: 6
|
||||||
|
position: 10
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -95,6 +105,7 @@
|
||||||
identifier: test11
|
identifier: test11
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 6
|
namespace_id: 6
|
||||||
|
position: 11
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -104,6 +115,7 @@
|
||||||
identifier: test12
|
identifier: test12
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 7
|
namespace_id: 7
|
||||||
|
position: 12
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -113,6 +125,7 @@
|
||||||
identifier: test13
|
identifier: test13
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 8
|
namespace_id: 8
|
||||||
|
position: 13
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -122,6 +135,7 @@
|
||||||
identifier: test14
|
identifier: test14
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 9
|
namespace_id: 9
|
||||||
|
position: 14
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -131,6 +145,7 @@
|
||||||
identifier: test15
|
identifier: test15
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 10
|
namespace_id: 10
|
||||||
|
position: 15
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -140,6 +155,7 @@
|
||||||
identifier: test16
|
identifier: test16
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 11
|
namespace_id: 11
|
||||||
|
position: 16
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -149,6 +165,7 @@
|
||||||
identifier: test17
|
identifier: test17
|
||||||
owner_id: 6
|
owner_id: 6
|
||||||
namespace_id: 12
|
namespace_id: 12
|
||||||
|
position: 17
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
# This list is owned by user 7, and several other users have access to it via different methods.
|
# This list is owned by user 7, and several other users have access to it via different methods.
|
||||||
|
@ -160,6 +177,7 @@
|
||||||
identifier: test18
|
identifier: test18
|
||||||
owner_id: 7
|
owner_id: 7
|
||||||
namespace_id: 13
|
namespace_id: 13
|
||||||
|
position: 18
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -169,6 +187,7 @@
|
||||||
identifier: test19
|
identifier: test19
|
||||||
owner_id: 7
|
owner_id: 7
|
||||||
namespace_id: 14
|
namespace_id: 14
|
||||||
|
position: 19
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
# User 1 does not have access to this list
|
# User 1 does not have access to this list
|
||||||
|
@ -179,6 +198,7 @@
|
||||||
identifier: test20
|
identifier: test20
|
||||||
owner_id: 13
|
owner_id: 13
|
||||||
namespace_id: 15
|
namespace_id: 15
|
||||||
|
position: 20
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -188,6 +208,7 @@
|
||||||
identifier: test21
|
identifier: test21
|
||||||
owner_id: 1
|
owner_id: 1
|
||||||
namespace_id: 16
|
namespace_id: 16
|
||||||
|
position: 21
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -198,6 +219,7 @@
|
||||||
owner_id: 1
|
owner_id: 1
|
||||||
namespace_id: 1
|
namespace_id: 1
|
||||||
is_archived: 1
|
is_archived: 1
|
||||||
|
position: 22
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
-
|
-
|
||||||
|
@ -207,5 +229,6 @@
|
||||||
identifier: test23
|
identifier: test23
|
||||||
owner_id: 12
|
owner_id: 12
|
||||||
namespace_id: 17
|
namespace_id: 17
|
||||||
|
position: 23
|
||||||
updated: 2018-12-02 15:13:12
|
updated: 2018-12-02 15:13:12
|
||||||
created: 2018-12-01 15:13:12
|
created: 2018-12-01 15:13:12
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
created: 2018-12-01 01:12:04
|
created: 2018-12-01 01:12:04
|
||||||
updated: 2018-12-01 01:12:04
|
updated: 2018-12-01 01:12:04
|
||||||
bucket_id: 1
|
bucket_id: 1
|
||||||
|
position: 2
|
||||||
- id: 2
|
- id: 2
|
||||||
title: 'task #2 done'
|
title: 'task #2 done'
|
||||||
done: true
|
done: true
|
||||||
|
@ -17,6 +18,7 @@
|
||||||
created: 2018-12-01 01:12:04
|
created: 2018-12-01 01:12:04
|
||||||
updated: 2018-12-01 01:12:04
|
updated: 2018-12-01 01:12:04
|
||||||
bucket_id: 1
|
bucket_id: 1
|
||||||
|
position: 4
|
||||||
- id: 3
|
- id: 3
|
||||||
title: 'task #3 high prio'
|
title: 'task #3 high prio'
|
||||||
done: false
|
done: false
|
||||||
|
|
|
@ -113,49 +113,49 @@ func TestTaskCollection(t *testing.T) {
|
||||||
t.Run("by priority", func(t *testing.T) {
|
t.Run("by priority", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}}, urlParams)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}}, urlParams)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
||||||
})
|
})
|
||||||
t.Run("by priority desc", func(t *testing.T) {
|
t.Run("by priority desc", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"desc"}}, urlParams)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"desc"}}, urlParams)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `[{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1`)
|
assert.Contains(t, rec.Body.String(), `[{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1`)
|
||||||
})
|
})
|
||||||
t.Run("by priority asc", func(t *testing.T) {
|
t.Run("by priority asc", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"asc"}}, urlParams)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"asc"}}, urlParams)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
||||||
})
|
})
|
||||||
// should equal duedate asc
|
// should equal duedate asc
|
||||||
t.Run("by due_date", func(t *testing.T) {
|
t.Run("by due_date", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}}, urlParams)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}}, urlParams)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
||||||
})
|
})
|
||||||
t.Run("by duedate desc", func(t *testing.T) {
|
t.Run("by duedate desc", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"desc"}}, urlParams)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"desc"}}, urlParams)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
|
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
|
||||||
})
|
})
|
||||||
// Due date without unix suffix
|
// Due date without unix suffix
|
||||||
t.Run("by duedate asc without suffix", func(t *testing.T) {
|
t.Run("by duedate asc without suffix", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"asc"}}, urlParams)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"asc"}}, urlParams)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
||||||
})
|
})
|
||||||
t.Run("by due_date without suffix", func(t *testing.T) {
|
t.Run("by due_date without suffix", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}}, urlParams)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}}, urlParams)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
||||||
})
|
})
|
||||||
t.Run("by duedate desc without suffix", func(t *testing.T) {
|
t.Run("by duedate desc without suffix", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"desc"}}, urlParams)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"desc"}}, urlParams)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
|
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
|
||||||
})
|
})
|
||||||
t.Run("by duedate asc", func(t *testing.T) {
|
t.Run("by duedate asc", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"asc"}}, urlParams)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"asc"}}, urlParams)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
||||||
})
|
})
|
||||||
t.Run("invalid sort parameter", func(t *testing.T) {
|
t.Run("invalid sort parameter", func(t *testing.T) {
|
||||||
_, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"loremipsum"}}, urlParams)
|
_, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"loremipsum"}}, urlParams)
|
||||||
|
@ -341,33 +341,33 @@ func TestTaskCollection(t *testing.T) {
|
||||||
t.Run("by priority", func(t *testing.T) {
|
t.Run("by priority", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}}, nil)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}}, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
||||||
})
|
})
|
||||||
t.Run("by priority desc", func(t *testing.T) {
|
t.Run("by priority desc", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"desc"}}, nil)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"desc"}}, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `[{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1`)
|
assert.Contains(t, rec.Body.String(), `[{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1`)
|
||||||
})
|
})
|
||||||
t.Run("by priority asc", func(t *testing.T) {
|
t.Run("by priority asc", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"asc"}}, nil)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"priority"}, "order_by": []string{"asc"}}, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":33,"title":"task #33 with percent done","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":4,"title":"task #4 low prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":1,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":3,"title":"task #3 high prio","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"0001-01-01T00:00:00Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":100,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
||||||
})
|
})
|
||||||
// should equal duedate asc
|
// should equal duedate asc
|
||||||
t.Run("by due_date", func(t *testing.T) {
|
t.Run("by due_date", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}}, nil)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}}, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
||||||
})
|
})
|
||||||
t.Run("by duedate desc", func(t *testing.T) {
|
t.Run("by duedate desc", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"desc"}}, nil)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"desc"}}, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
|
assert.Contains(t, rec.Body.String(), `[{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":6,"title":"task #6 lower due date`)
|
||||||
})
|
})
|
||||||
t.Run("by duedate asc", func(t *testing.T) {
|
t.Run("by duedate asc", func(t *testing.T) {
|
||||||
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"asc"}}, nil)
|
rec, err := testHandler.testReadAllWithUser(url.Values{"sort_by": []string{"due_date"}, "order_by": []string{"asc"}}, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":6,"title":"task #6 lower due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-11-30T22:25:24Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-6","index":6,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":3,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}},{"id":5,"title":"task #5 higher due date","description":"","done":false,"done_at":"0001-01-01T00:00:00Z","due_date":"2018-12-01T03:58:44Z","reminder_dates":null,"list_id":1,"repeat_after":0,"repeat_mode":0,"priority":0,"start_date":"0001-01-01T00:00:00Z","end_date":"0001-01-01T00:00:00Z","assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-5","index":5,"related_tasks":{},"attachments":null,"is_favorite":false,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"kanban_position":0,"created_by":{"id":1,"name":"","username":"user1","created":"2018-12-01T15:13:12Z","updated":"2018-12-02T15:13:12Z"}}]`)
|
||||||
})
|
})
|
||||||
t.Run("invalid parameter", func(t *testing.T) {
|
t.Run("invalid parameter", func(t *testing.T) {
|
||||||
// Invalid parameter should not sort at all
|
// Invalid parameter should not sort at all
|
||||||
|
|
71
pkg/migration/20210725153703.go
Normal file
71
pkg/migration/20210725153703.go
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// 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 (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"src.techknowlogick.com/xormigrate"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tasks20210725153703 struct {
|
||||||
|
ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"listtask"`
|
||||||
|
Position float64 `xorm:"double null" json:"position"`
|
||||||
|
KanbanPosition float64 `xorm:"double null" json:"kanban_position"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tasks20210725153703) TableName() string {
|
||||||
|
return "tasks"
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
migrations = append(migrations, &xormigrate.Migration{
|
||||||
|
ID: "20210725153703",
|
||||||
|
Description: "",
|
||||||
|
Migrate: func(tx *xorm.Engine) error {
|
||||||
|
err := tx.Sync2(tasks20210725153703{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks := []*tasks20210725153703{}
|
||||||
|
err = tx.Where("position is not null").Find(&tasks)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate all old kanban positions to the kanban positions property
|
||||||
|
for _, task := range tasks {
|
||||||
|
task.KanbanPosition = task.Position
|
||||||
|
task.Position = float64(task.ID) * math.Pow(2, 16)
|
||||||
|
_, err = tx.
|
||||||
|
Where("id = ?", task.ID).
|
||||||
|
Cols("kanban_position", "position").
|
||||||
|
Update(task)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Rollback: func(tx *xorm.Engine) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
68
pkg/migration/20210727204942.go
Normal file
68
pkg/migration/20210727204942.go
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
// 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 (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"src.techknowlogick.com/xormigrate"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lists20210727204942 struct {
|
||||||
|
ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"list"`
|
||||||
|
Position float64 `xorm:"double null" json:"position"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lists20210727204942) TableName() string {
|
||||||
|
return "lists"
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
migrations = append(migrations, &xormigrate.Migration{
|
||||||
|
ID: "20210727204942",
|
||||||
|
Description: "Add list position parameter",
|
||||||
|
Migrate: func(tx *xorm.Engine) error {
|
||||||
|
err := tx.Sync2(lists20210727204942{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
lists := []*lists20210727204942{}
|
||||||
|
err = tx.Find(&lists)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, list := range lists {
|
||||||
|
list.Position = float64(list.ID) * math.Pow(2, 16)
|
||||||
|
|
||||||
|
_, err = tx.
|
||||||
|
Where("id = ?", list.ID).
|
||||||
|
Update(list)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Rollback: func(tx *xorm.Engine) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
68
pkg/migration/20210727211037.go
Normal file
68
pkg/migration/20210727211037.go
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
// 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 (
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"src.techknowlogick.com/xormigrate"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type buckets20210727211037 struct {
|
||||||
|
ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"list"`
|
||||||
|
Position float64 `xorm:"double null" json:"position"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (buckets20210727211037) TableName() string {
|
||||||
|
return "buckets"
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
migrations = append(migrations, &xormigrate.Migration{
|
||||||
|
ID: "20210727211037",
|
||||||
|
Description: "Add bucket position property",
|
||||||
|
Migrate: func(tx *xorm.Engine) error {
|
||||||
|
err := tx.Sync2(buckets20210727211037{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
buckets := []*buckets20210727211037{}
|
||||||
|
err = tx.Find(&buckets)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, bucket := range buckets {
|
||||||
|
bucket.Position = float64(bucket.ID) * math.Pow(2, 16)
|
||||||
|
|
||||||
|
_, err = tx.
|
||||||
|
Where("id = ?", bucket.ID).
|
||||||
|
Update(bucket)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Rollback: func(tx *xorm.Engine) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -41,6 +41,9 @@ type Bucket struct {
|
||||||
// If this bucket is the "done bucket". All tasks moved into this bucket will automatically marked as done. All tasks marked as done from elsewhere will be moved into this bucket.
|
// If this bucket is the "done bucket". All tasks moved into this bucket will automatically marked as done. All tasks marked as done from elsewhere will be moved into this bucket.
|
||||||
IsDoneBucket bool `xorm:"BOOL" json:"is_done_bucket"`
|
IsDoneBucket bool `xorm:"BOOL" json:"is_done_bucket"`
|
||||||
|
|
||||||
|
// The position this bucket has when querying all buckets. See the tasks.position property on how to use this.
|
||||||
|
Position float64 `xorm:"double null" json:"position"`
|
||||||
|
|
||||||
// A timestamp when this bucket was created. You cannot change this value.
|
// A timestamp when this bucket was created. You cannot change this value.
|
||||||
Created time.Time `xorm:"created not null" json:"created"`
|
Created time.Time `xorm:"created not null" json:"created"`
|
||||||
// A timestamp when this bucket was last updated. You cannot change this value.
|
// A timestamp when this bucket was last updated. You cannot change this value.
|
||||||
|
@ -134,7 +137,10 @@ func (b *Bucket) ReadAll(s *xorm.Session, auth web.Auth, search string, page int
|
||||||
|
|
||||||
// Get all buckets for this list
|
// Get all buckets for this list
|
||||||
buckets := []*Bucket{}
|
buckets := []*Bucket{}
|
||||||
err = s.Where("list_id = ?", b.ListID).Find(&buckets)
|
err = s.
|
||||||
|
Where("list_id = ?", b.ListID).
|
||||||
|
OrderBy("position").
|
||||||
|
Find(&buckets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -167,7 +173,7 @@ func (b *Bucket) ReadAll(s *xorm.Session, auth web.Auth, search string, page int
|
||||||
opts.sortby = []*sortParam{
|
opts.sortby = []*sortParam{
|
||||||
{
|
{
|
||||||
orderBy: orderAscending,
|
orderBy: orderAscending,
|
||||||
sortBy: taskPropertyPosition,
|
sortBy: taskPropertyKanbanPosition,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
opts.page = page
|
opts.page = page
|
||||||
|
@ -251,6 +257,12 @@ func (b *Bucket) Create(s *xorm.Session, a web.Auth) (err error) {
|
||||||
b.CreatedByID = b.CreatedBy.ID
|
b.CreatedByID = b.CreatedBy.ID
|
||||||
|
|
||||||
_, err = s.Insert(b)
|
_, err = s.Insert(b)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Position = calculateDefaultPosition(b.ID, b.Position)
|
||||||
|
_, err = s.Where("id = ?", b.ID).Update(b)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +301,7 @@ func (b *Bucket) Update(s *xorm.Session, a web.Auth) (err error) {
|
||||||
"title",
|
"title",
|
||||||
"limit",
|
"limit",
|
||||||
"is_done_bucket",
|
"is_done_bucket",
|
||||||
|
"position",
|
||||||
).
|
).
|
||||||
Update(b)
|
Update(b)
|
||||||
return
|
return
|
||||||
|
|
|
@ -49,21 +49,23 @@ func TestBucket_ReadAll(t *testing.T) {
|
||||||
assert.Len(t, buckets, 3)
|
assert.Len(t, buckets, 3)
|
||||||
|
|
||||||
// Assert all tasks are in the right bucket
|
// Assert all tasks are in the right bucket
|
||||||
assert.Len(t, buckets[0].Tasks, 12)
|
assert.Len(t, buckets[0].Tasks, 3)
|
||||||
assert.Len(t, buckets[1].Tasks, 3)
|
assert.Len(t, buckets[1].Tasks, 12)
|
||||||
assert.Len(t, buckets[2].Tasks, 3)
|
assert.Len(t, buckets[2].Tasks, 3)
|
||||||
|
|
||||||
// Assert we have bucket 0, 1, 2, 3 but not 4 (that belongs to a different list)
|
// Assert we have bucket 1, 2, 3 but not 4 (that belongs to a different list) and their position
|
||||||
assert.Equal(t, int64(1), buckets[0].ID)
|
assert.Equal(t, int64(2), buckets[0].ID)
|
||||||
assert.Equal(t, int64(2), buckets[1].ID)
|
assert.Equal(t, int64(1), buckets[1].ID)
|
||||||
assert.Equal(t, int64(3), buckets[2].ID)
|
assert.Equal(t, int64(3), buckets[2].ID)
|
||||||
|
|
||||||
// Kinda assert all tasks are in the right buckets
|
// Kinda assert all tasks are in the right buckets
|
||||||
assert.Equal(t, int64(1), buckets[0].Tasks[0].BucketID)
|
assert.Equal(t, int64(1), buckets[1].Tasks[0].BucketID)
|
||||||
assert.Equal(t, int64(1), buckets[0].Tasks[1].BucketID)
|
assert.Equal(t, int64(1), buckets[1].Tasks[1].BucketID)
|
||||||
assert.Equal(t, int64(2), buckets[1].Tasks[0].BucketID)
|
|
||||||
assert.Equal(t, int64(2), buckets[1].Tasks[1].BucketID)
|
assert.Equal(t, int64(2), buckets[0].Tasks[0].BucketID)
|
||||||
assert.Equal(t, int64(2), buckets[1].Tasks[2].BucketID)
|
assert.Equal(t, int64(2), buckets[0].Tasks[1].BucketID)
|
||||||
|
assert.Equal(t, int64(2), buckets[0].Tasks[2].BucketID)
|
||||||
|
|
||||||
assert.Equal(t, int64(3), buckets[2].Tasks[0].BucketID)
|
assert.Equal(t, int64(3), buckets[2].Tasks[0].BucketID)
|
||||||
assert.Equal(t, int64(3), buckets[2].Tasks[1].BucketID)
|
assert.Equal(t, int64(3), buckets[2].Tasks[1].BucketID)
|
||||||
assert.Equal(t, int64(3), buckets[2].Tasks[2].BucketID)
|
assert.Equal(t, int64(3), buckets[2].Tasks[2].BucketID)
|
||||||
|
@ -87,7 +89,8 @@ func TestBucket_ReadAll(t *testing.T) {
|
||||||
|
|
||||||
buckets := bucketsInterface.([]*Bucket)
|
buckets := bucketsInterface.([]*Bucket)
|
||||||
assert.Len(t, buckets, 3)
|
assert.Len(t, buckets, 3)
|
||||||
assert.Equal(t, int64(2), buckets[0].Tasks[0].ID)
|
assert.Equal(t, int64(2), buckets[1].Tasks[0].ID)
|
||||||
|
assert.Equal(t, int64(33), buckets[1].Tasks[1].ID)
|
||||||
})
|
})
|
||||||
t.Run("accessed by link share", func(t *testing.T) {
|
t.Run("accessed by link share", func(t *testing.T) {
|
||||||
db.LoadAndAssertFixtures(t)
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
|
@ -71,6 +71,9 @@ type List struct {
|
||||||
// Will only returned when retreiving one list.
|
// Will only returned when retreiving one list.
|
||||||
Subscription *Subscription `xorm:"-" json:"subscription,omitempty"`
|
Subscription *Subscription `xorm:"-" json:"subscription,omitempty"`
|
||||||
|
|
||||||
|
// The position this list has when querying all lists. See the tasks.position property on how to use this.
|
||||||
|
Position float64 `xorm:"double null" json:"position"`
|
||||||
|
|
||||||
// A timestamp when this list was created. You cannot change this value.
|
// A timestamp when this list was created. You cannot change this value.
|
||||||
Created time.Time `xorm:"created not null" json:"created"`
|
Created time.Time `xorm:"created not null" json:"created"`
|
||||||
// A timestamp when this list was last updated. You cannot change this value.
|
// A timestamp when this list was last updated. You cannot change this value.
|
||||||
|
@ -284,7 +287,10 @@ func GetListSimpleByID(s *xorm.Session, listID int64) (list *List, err error) {
|
||||||
return nil, ErrListDoesNotExist{ID: listID}
|
return nil, ErrListDoesNotExist{ID: listID}
|
||||||
}
|
}
|
||||||
|
|
||||||
exists, err := s.Where("id = ?", listID).Get(list)
|
exists, err := s.
|
||||||
|
Where("id = ?", listID).
|
||||||
|
OrderBy("position").
|
||||||
|
Get(list)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -361,6 +367,7 @@ func getUserListsStatement(userID int64) *builder.Builder {
|
||||||
builder.Eq{"un.user_id": userID},
|
builder.Eq{"un.user_id": userID},
|
||||||
builder.Eq{"l.owner_id": userID},
|
builder.Eq{"l.owner_id": userID},
|
||||||
)).
|
)).
|
||||||
|
OrderBy("position").
|
||||||
GroupBy("l.id")
|
GroupBy("l.id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,6 +566,12 @@ func CreateOrUpdateList(s *xorm.Session, list *List, auth web.Auth) (err error)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list.Position = calculateDefaultPosition(list.ID, list.Position)
|
||||||
|
_, err = s.Where("id = ?", list.ID).Update(list)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
if list.IsFavorite {
|
if list.IsFavorite {
|
||||||
if err := addToFavorites(s, list.ID, auth, FavoriteKindList); err != nil {
|
if err := addToFavorites(s, list.ID, auth, FavoriteKindList); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -572,6 +585,7 @@ func CreateOrUpdateList(s *xorm.Session, list *List, auth web.Auth) (err error)
|
||||||
"identifier",
|
"identifier",
|
||||||
"hex_color",
|
"hex_color",
|
||||||
"background_file_id",
|
"background_file_id",
|
||||||
|
"position",
|
||||||
}
|
}
|
||||||
if list.Description != "" {
|
if list.Description != "" {
|
||||||
colsToUpdate = append(colsToUpdate, "description")
|
colsToUpdate = append(colsToUpdate, "description")
|
||||||
|
|
|
@ -200,8 +200,11 @@ func TestList_ReadAll(t *testing.T) {
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, reflect.TypeOf(lists3).Kind(), reflect.Slice)
|
assert.Equal(t, reflect.TypeOf(lists3).Kind(), reflect.Slice)
|
||||||
ls := reflect.ValueOf(lists3)
|
ls := lists3.([]*List)
|
||||||
assert.Equal(t, 16, ls.Len())
|
assert.Equal(t, 16, len(ls))
|
||||||
|
assert.Equal(t, int64(3), ls[0].ID) // List 3 has a position of 1 and should be sorted first
|
||||||
|
assert.Equal(t, int64(1), ls[1].ID)
|
||||||
|
assert.Equal(t, int64(4), ls[2].ID)
|
||||||
_ = s.Close()
|
_ = s.Close()
|
||||||
})
|
})
|
||||||
t.Run("lists for nonexistant user", func(t *testing.T) {
|
t.Run("lists for nonexistant user", func(t *testing.T) {
|
||||||
|
|
|
@ -315,6 +315,7 @@ func getNamespaceSubscriptions(s *xorm.Session, namespaceIDs []int64, userID int
|
||||||
func getListsForNamespaces(s *xorm.Session, namespaceIDs []int64, archived bool) ([]*List, error) {
|
func getListsForNamespaces(s *xorm.Session, namespaceIDs []int64, archived bool) ([]*List, error) {
|
||||||
lists := []*List{}
|
lists := []*List{}
|
||||||
listQuery := s.
|
listQuery := s.
|
||||||
|
OrderBy("position").
|
||||||
In("namespace_id", namespaceIDs)
|
In("namespace_id", namespaceIDs)
|
||||||
|
|
||||||
if !archived {
|
if !archived {
|
||||||
|
|
|
@ -73,11 +73,11 @@ func validateTaskField(fieldName string) error {
|
||||||
taskPropertyCreated,
|
taskPropertyCreated,
|
||||||
taskPropertyUpdated,
|
taskPropertyUpdated,
|
||||||
taskPropertyPosition,
|
taskPropertyPosition,
|
||||||
|
taskPropertyKanbanPosition,
|
||||||
taskPropertyBucketID:
|
taskPropertyBucketID:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ErrInvalidTaskField{TaskField: fieldName}
|
return ErrInvalidTaskField{TaskField: fieldName}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTaskFilterOptsFromCollection(tf *TaskCollection) (opts *taskOptions, err error) {
|
func getTaskFilterOptsFromCollection(tf *TaskCollection) (opts *taskOptions, err error) {
|
||||||
|
|
|
@ -26,25 +26,26 @@ type (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
taskPropertyID string = "id"
|
taskPropertyID string = "id"
|
||||||
taskPropertyTitle string = "title"
|
taskPropertyTitle string = "title"
|
||||||
taskPropertyDescription string = "description"
|
taskPropertyDescription string = "description"
|
||||||
taskPropertyDone string = "done"
|
taskPropertyDone string = "done"
|
||||||
taskPropertyDoneAt string = "done_at"
|
taskPropertyDoneAt string = "done_at"
|
||||||
taskPropertyDueDate string = "due_date"
|
taskPropertyDueDate string = "due_date"
|
||||||
taskPropertyCreatedByID string = "created_by_id"
|
taskPropertyCreatedByID string = "created_by_id"
|
||||||
taskPropertyListID string = "list_id"
|
taskPropertyListID string = "list_id"
|
||||||
taskPropertyRepeatAfter string = "repeat_after"
|
taskPropertyRepeatAfter string = "repeat_after"
|
||||||
taskPropertyPriority string = "priority"
|
taskPropertyPriority string = "priority"
|
||||||
taskPropertyStartDate string = "start_date"
|
taskPropertyStartDate string = "start_date"
|
||||||
taskPropertyEndDate string = "end_date"
|
taskPropertyEndDate string = "end_date"
|
||||||
taskPropertyHexColor string = "hex_color"
|
taskPropertyHexColor string = "hex_color"
|
||||||
taskPropertyPercentDone string = "percent_done"
|
taskPropertyPercentDone string = "percent_done"
|
||||||
taskPropertyUID string = "uid"
|
taskPropertyUID string = "uid"
|
||||||
taskPropertyCreated string = "created"
|
taskPropertyCreated string = "created"
|
||||||
taskPropertyUpdated string = "updated"
|
taskPropertyUpdated string = "updated"
|
||||||
taskPropertyPosition string = "position"
|
taskPropertyPosition string = "position"
|
||||||
taskPropertyBucketID string = "bucket_id"
|
taskPropertyKanbanPosition string = "kanban_position"
|
||||||
|
taskPropertyBucketID string = "bucket_id"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -90,6 +90,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
BucketID: 1,
|
BucketID: 1,
|
||||||
IsFavorite: true,
|
IsFavorite: true,
|
||||||
|
Position: 2,
|
||||||
Labels: []*Label{
|
Labels: []*Label{
|
||||||
label4,
|
label4,
|
||||||
},
|
},
|
||||||
|
@ -160,6 +161,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user1,
|
CreatedBy: user1,
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
BucketID: 1,
|
BucketID: 1,
|
||||||
|
Position: 4,
|
||||||
Labels: []*Label{
|
Labels: []*Label{
|
||||||
label4,
|
label4,
|
||||||
},
|
},
|
||||||
|
@ -517,6 +519,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
Created: time.Unix(1543626724, 0).In(loc),
|
Created: time.Unix(1543626724, 0).In(loc),
|
||||||
Updated: time.Unix(1543626724, 0).In(loc),
|
Updated: time.Unix(1543626724, 0).In(loc),
|
||||||
BucketID: 1,
|
BucketID: 1,
|
||||||
|
Position: 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1033,6 +1036,51 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "order by position",
|
||||||
|
fields: fields{
|
||||||
|
SortBy: []string{"position", "id"},
|
||||||
|
OrderBy: []string{"asc", "asc"},
|
||||||
|
},
|
||||||
|
args: args{
|
||||||
|
a: &user.User{ID: 1},
|
||||||
|
},
|
||||||
|
want: []*Task{
|
||||||
|
// the other ones don't have a position set
|
||||||
|
task3,
|
||||||
|
task4,
|
||||||
|
task5,
|
||||||
|
task6,
|
||||||
|
task7,
|
||||||
|
task8,
|
||||||
|
task9,
|
||||||
|
task10,
|
||||||
|
task11,
|
||||||
|
task12,
|
||||||
|
task15,
|
||||||
|
task16,
|
||||||
|
task17,
|
||||||
|
task18,
|
||||||
|
task19,
|
||||||
|
task20,
|
||||||
|
task21,
|
||||||
|
task22,
|
||||||
|
task23,
|
||||||
|
task24,
|
||||||
|
task25,
|
||||||
|
task26,
|
||||||
|
task27,
|
||||||
|
task28,
|
||||||
|
task29,
|
||||||
|
task30,
|
||||||
|
task31,
|
||||||
|
task32,
|
||||||
|
task33,
|
||||||
|
// The only tasks with a position set
|
||||||
|
task1,
|
||||||
|
task2,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|
|
@ -118,6 +118,8 @@ type Task struct {
|
||||||
// A 64-Bit float leaves plenty of room to initially give tasks a position with 2^16 difference to the previous task
|
// A 64-Bit float leaves plenty of room to initially give tasks a position with 2^16 difference to the previous task
|
||||||
// which also leaves a lot of room for rearranging and sorting later.
|
// which also leaves a lot of room for rearranging and sorting later.
|
||||||
Position float64 `xorm:"double null" json:"position"`
|
Position float64 `xorm:"double null" json:"position"`
|
||||||
|
// The position of tasks in the kanban board. See the docs for the `position` property on how to use this.
|
||||||
|
KanbanPosition float64 `xorm:"double null" json:"kanban_position"`
|
||||||
|
|
||||||
// The user who initially created the task.
|
// The user who initially created the task.
|
||||||
CreatedBy *user.User `xorm:"-" json:"created_by" valid:"-"`
|
CreatedBy *user.User `xorm:"-" json:"created_by" valid:"-"`
|
||||||
|
@ -836,6 +838,14 @@ func setTaskBucket(s *xorm.Session, task *Task, originalTask *Task, doCheckBucke
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func calculateDefaultPosition(entityID int64, position float64) float64 {
|
||||||
|
if position == 0 {
|
||||||
|
return float64(entityID) * math.Pow(2, 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
return position
|
||||||
|
}
|
||||||
|
|
||||||
// Create is the implementation to create a list task
|
// Create is the implementation to create a list task
|
||||||
// @Summary Create a task
|
// @Summary Create a task
|
||||||
// @Description Inserts a task into a list.
|
// @Description Inserts a task into a list.
|
||||||
|
@ -895,9 +905,8 @@ func createTask(s *xorm.Session, t *Task, a web.Auth, updateAssignees bool) (err
|
||||||
|
|
||||||
t.Index = latestTask.Index + 1
|
t.Index = latestTask.Index + 1
|
||||||
// If no position was supplied, set a default one
|
// If no position was supplied, set a default one
|
||||||
if t.Position == 0 {
|
t.Position = calculateDefaultPosition(latestTask.ID+1, t.Position)
|
||||||
t.Position = float64(latestTask.ID+1) * math.Pow(2, 16)
|
t.KanbanPosition = calculateDefaultPosition(latestTask.ID+1, t.KanbanPosition)
|
||||||
}
|
|
||||||
if _, err = s.Insert(t); err != nil {
|
if _, err = s.Insert(t); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1001,6 +1010,7 @@ func (t *Task) Update(s *xorm.Session, a web.Auth) (err error) {
|
||||||
"bucket_id",
|
"bucket_id",
|
||||||
"position",
|
"position",
|
||||||
"repeat_mode",
|
"repeat_mode",
|
||||||
|
"kanban_position",
|
||||||
}
|
}
|
||||||
|
|
||||||
// When a repeating task is marked as done, we update all deadlines and reminders and set it as undone
|
// When a repeating task is marked as done, we update all deadlines and reminders and set it as undone
|
||||||
|
@ -1107,6 +1117,9 @@ func (t *Task) Update(s *xorm.Session, a web.Auth) (err error) {
|
||||||
if t.Position == 0 {
|
if t.Position == 0 {
|
||||||
ot.Position = 0
|
ot.Position = 0
|
||||||
}
|
}
|
||||||
|
if t.KanbanPosition == 0 {
|
||||||
|
ot.KanbanPosition = 0
|
||||||
|
}
|
||||||
// Repeat from current date
|
// Repeat from current date
|
||||||
if t.RepeatMode == TaskRepeatModeDefault {
|
if t.RepeatMode == TaskRepeatModeDefault {
|
||||||
ot.RepeatMode = TaskRepeatModeDefault
|
ot.RepeatMode = TaskRepeatModeDefault
|
||||||
|
|
|
@ -192,12 +192,12 @@ func TestTask_Update(t *testing.T) {
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
|
|
||||||
task := &Task{
|
task := &Task{
|
||||||
ID: 4,
|
ID: 4,
|
||||||
Title: "test10000",
|
Title: "test10000",
|
||||||
Description: "Lorem Ipsum Dolor",
|
Description: "Lorem Ipsum Dolor",
|
||||||
Position: 10,
|
KanbanPosition: 10,
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
BucketID: 2, // Bucket 2 already has 3 tasks and a limit of 3
|
BucketID: 2, // Bucket 2 already has 3 tasks and a limit of 3
|
||||||
}
|
}
|
||||||
err := task.Update(s, u)
|
err := task.Update(s, u)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
|
@ -196,10 +196,10 @@ func convertTrelloDataToVikunja(trelloData []*trello.Board) (fullVikunjaHierachi
|
||||||
|
|
||||||
// The usual stuff: Title, description, position, bucket id
|
// The usual stuff: Title, description, position, bucket id
|
||||||
task := &models.Task{
|
task := &models.Task{
|
||||||
Title: card.Name,
|
Title: card.Name,
|
||||||
Description: card.Desc,
|
Description: card.Desc,
|
||||||
Position: card.Pos,
|
KanbanPosition: card.Pos,
|
||||||
BucketID: bucketID,
|
BucketID: bucketID,
|
||||||
}
|
}
|
||||||
|
|
||||||
if card.Due != nil {
|
if card.Due != nil {
|
||||||
|
|
|
@ -209,11 +209,11 @@ func TestConvertTrelloToVikunja(t *testing.T) {
|
||||||
},
|
},
|
||||||
Tasks: []*models.Task{
|
Tasks: []*models.Task{
|
||||||
{
|
{
|
||||||
Title: "Test Card 1",
|
Title: "Test Card 1",
|
||||||
Description: "Card Description",
|
Description: "Card Description",
|
||||||
BucketID: 1,
|
BucketID: 1,
|
||||||
Position: 123,
|
KanbanPosition: 123,
|
||||||
DueDate: time1,
|
DueDate: time1,
|
||||||
Labels: []*models.Label{
|
Labels: []*models.Label{
|
||||||
{
|
{
|
||||||
Title: "Label 1",
|
Title: "Label 1",
|
||||||
|
@ -248,18 +248,18 @@ func TestConvertTrelloToVikunja(t *testing.T) {
|
||||||
|
|
||||||
* [ ] Pending Task
|
* [ ] Pending Task
|
||||||
* [ ] Another Pending Task`,
|
* [ ] Another Pending Task`,
|
||||||
BucketID: 1,
|
BucketID: 1,
|
||||||
Position: 124,
|
KanbanPosition: 124,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Test Card 3",
|
Title: "Test Card 3",
|
||||||
BucketID: 1,
|
BucketID: 1,
|
||||||
Position: 126,
|
KanbanPosition: 126,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Test Card 4",
|
Title: "Test Card 4",
|
||||||
BucketID: 1,
|
BucketID: 1,
|
||||||
Position: 127,
|
KanbanPosition: 127,
|
||||||
Labels: []*models.Label{
|
Labels: []*models.Label{
|
||||||
{
|
{
|
||||||
Title: "Label 2",
|
Title: "Label 2",
|
||||||
|
@ -268,9 +268,9 @@ func TestConvertTrelloToVikunja(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Test Card 5",
|
Title: "Test Card 5",
|
||||||
BucketID: 2,
|
BucketID: 2,
|
||||||
Position: 111,
|
KanbanPosition: 111,
|
||||||
Labels: []*models.Label{
|
Labels: []*models.Label{
|
||||||
{
|
{
|
||||||
Title: "Label 3",
|
Title: "Label 3",
|
||||||
|
@ -279,20 +279,20 @@ func TestConvertTrelloToVikunja(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Test Card 6",
|
Title: "Test Card 6",
|
||||||
BucketID: 2,
|
BucketID: 2,
|
||||||
Position: 222,
|
KanbanPosition: 222,
|
||||||
DueDate: time1,
|
DueDate: time1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Test Card 7",
|
Title: "Test Card 7",
|
||||||
BucketID: 2,
|
BucketID: 2,
|
||||||
Position: 333,
|
KanbanPosition: 333,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Title: "Test Card 8",
|
Title: "Test Card 8",
|
||||||
BucketID: 2,
|
BucketID: 2,
|
||||||
Position: 444,
|
KanbanPosition: 444,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -306,9 +306,9 @@ func TestConvertTrelloToVikunja(t *testing.T) {
|
||||||
},
|
},
|
||||||
Tasks: []*models.Task{
|
Tasks: []*models.Task{
|
||||||
{
|
{
|
||||||
Title: "Test Card 634",
|
Title: "Test Card 634",
|
||||||
BucketID: 3,
|
BucketID: 3,
|
||||||
Position: 123,
|
KanbanPosition: 123,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -323,9 +323,9 @@ func TestConvertTrelloToVikunja(t *testing.T) {
|
||||||
},
|
},
|
||||||
Tasks: []*models.Task{
|
Tasks: []*models.Task{
|
||||||
{
|
{
|
||||||
Title: "Test Card 63423",
|
Title: "Test Card 63423",
|
||||||
BucketID: 4,
|
BucketID: 4,
|
||||||
Position: 123,
|
KanbanPosition: 123,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -7218,6 +7218,10 @@ var doc = `{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"position": {
|
||||||
|
"description": "The position this bucket has when querying all buckets. See the tasks.position property on how to use this.",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
"sort_by": {
|
"sort_by": {
|
||||||
"description": "The query parameter to sort by. This is for ex. done, priority, etc.",
|
"description": "The query parameter to sort by. This is for ex. done, priority, etc.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -7325,6 +7329,10 @@ var doc = `{
|
||||||
"description": "True if a task is a favorite task. Favorite tasks show up in a separate \"Important\" list. This value depends on the user making the call to the api.",
|
"description": "True if a task is a favorite task. Favorite tasks show up in a separate \"Important\" list. This value depends on the user making the call to the api.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"kanban_position": {
|
||||||
|
"description": "The position of tasks in the kanban board. See the docs for the ` + "`" + `position` + "`" + ` property on how to use this.",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"description": "An array of labels which are associated with this task.",
|
"description": "An array of labels which are associated with this task.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -7573,6 +7581,10 @@ var doc = `{
|
||||||
"description": "The user who created this list.",
|
"description": "The user who created this list.",
|
||||||
"$ref": "#/definitions/user.User"
|
"$ref": "#/definitions/user.User"
|
||||||
},
|
},
|
||||||
|
"position": {
|
||||||
|
"description": "The position this list has when querying all lists. See the tasks.position property on how to use this.",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"description": "The subscription status for the user reading this list. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one list.",
|
"description": "The subscription status for the user reading this list. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one list.",
|
||||||
"$ref": "#/definitions/models.Subscription"
|
"$ref": "#/definitions/models.Subscription"
|
||||||
|
@ -7901,6 +7913,10 @@ var doc = `{
|
||||||
"description": "True if a task is a favorite task. Favorite tasks show up in a separate \"Important\" list. This value depends on the user making the call to the api.",
|
"description": "True if a task is a favorite task. Favorite tasks show up in a separate \"Important\" list. This value depends on the user making the call to the api.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"kanban_position": {
|
||||||
|
"description": "The position of tasks in the kanban board. See the docs for the ` + "`" + `position` + "`" + ` property on how to use this.",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"description": "An array of labels which are associated with this task.",
|
"description": "An array of labels which are associated with this task.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
|
|
@ -7201,6 +7201,10 @@
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"position": {
|
||||||
|
"description": "The position this bucket has when querying all buckets. See the tasks.position property on how to use this.",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
"sort_by": {
|
"sort_by": {
|
||||||
"description": "The query parameter to sort by. This is for ex. done, priority, etc.",
|
"description": "The query parameter to sort by. This is for ex. done, priority, etc.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -7308,6 +7312,10 @@
|
||||||
"description": "True if a task is a favorite task. Favorite tasks show up in a separate \"Important\" list. This value depends on the user making the call to the api.",
|
"description": "True if a task is a favorite task. Favorite tasks show up in a separate \"Important\" list. This value depends on the user making the call to the api.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"kanban_position": {
|
||||||
|
"description": "The position of tasks in the kanban board. See the docs for the `position` property on how to use this.",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"description": "An array of labels which are associated with this task.",
|
"description": "An array of labels which are associated with this task.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
@ -7556,6 +7564,10 @@
|
||||||
"description": "The user who created this list.",
|
"description": "The user who created this list.",
|
||||||
"$ref": "#/definitions/user.User"
|
"$ref": "#/definitions/user.User"
|
||||||
},
|
},
|
||||||
|
"position": {
|
||||||
|
"description": "The position this list has when querying all lists. See the tasks.position property on how to use this.",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
"subscription": {
|
"subscription": {
|
||||||
"description": "The subscription status for the user reading this list. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one list.",
|
"description": "The subscription status for the user reading this list. You can only read this property, use the subscription endpoints to modify it.\nWill only returned when retreiving one list.",
|
||||||
"$ref": "#/definitions/models.Subscription"
|
"$ref": "#/definitions/models.Subscription"
|
||||||
|
@ -7884,6 +7896,10 @@
|
||||||
"description": "True if a task is a favorite task. Favorite tasks show up in a separate \"Important\" list. This value depends on the user making the call to the api.",
|
"description": "True if a task is a favorite task. Favorite tasks show up in a separate \"Important\" list. This value depends on the user making the call to the api.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
"kanban_position": {
|
||||||
|
"description": "The position of tasks in the kanban board. See the docs for the `position` property on how to use this.",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"description": "An array of labels which are associated with this task.",
|
"description": "An array of labels which are associated with this task.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
|
|
@ -102,6 +102,10 @@ definitions:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
type: array
|
type: array
|
||||||
|
position:
|
||||||
|
description: The position this bucket has when querying all buckets. See the
|
||||||
|
tasks.position property on how to use this.
|
||||||
|
type: number
|
||||||
sort_by:
|
sort_by:
|
||||||
description: The query parameter to sort by. This is for ex. done, priority,
|
description: The query parameter to sort by. This is for ex. done, priority,
|
||||||
etc.
|
etc.
|
||||||
|
@ -186,6 +190,10 @@ definitions:
|
||||||
a separate "Important" list. This value depends on the user making the call
|
a separate "Important" list. This value depends on the user making the call
|
||||||
to the api.
|
to the api.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
kanban_position:
|
||||||
|
description: The position of tasks in the kanban board. See the docs for the
|
||||||
|
`position` property on how to use this.
|
||||||
|
type: number
|
||||||
labels:
|
labels:
|
||||||
description: An array of labels which are associated with this task.
|
description: An array of labels which are associated with this task.
|
||||||
items:
|
items:
|
||||||
|
@ -403,6 +411,10 @@ definitions:
|
||||||
owner:
|
owner:
|
||||||
$ref: '#/definitions/user.User'
|
$ref: '#/definitions/user.User'
|
||||||
description: The user who created this list.
|
description: The user who created this list.
|
||||||
|
position:
|
||||||
|
description: The position this list has when querying all lists. See the tasks.position
|
||||||
|
property on how to use this.
|
||||||
|
type: number
|
||||||
subscription:
|
subscription:
|
||||||
$ref: '#/definitions/models.Subscription'
|
$ref: '#/definitions/models.Subscription'
|
||||||
description: |-
|
description: |-
|
||||||
|
@ -669,6 +681,10 @@ definitions:
|
||||||
a separate "Important" list. This value depends on the user making the call
|
a separate "Important" list. This value depends on the user making the call
|
||||||
to the api.
|
to the api.
|
||||||
type: boolean
|
type: boolean
|
||||||
|
kanban_position:
|
||||||
|
description: The position of tasks in the kanban board. See the docs for the
|
||||||
|
`position` property on how to use this.
|
||||||
|
type: number
|
||||||
labels:
|
labels:
|
||||||
description: An array of labels which are associated with this task.
|
description: An array of labels which are associated with this task.
|
||||||
items:
|
items:
|
||||||
|
|
Loading…
Reference in a new issue