Add real buckets for tasks which don't have one (#446)
Add docs for error code Add moving new tasks into the default bucket when none was provided Add moving tasks in default bucket when deleting one Fix tests again Add test for removing a bucket Fix tests Prevent removing the last bucket Remove the empty pseudo bucket Add migration to create a new bucket for each list (and put all tasks in it Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/446
This commit is contained in:
parent
2b1fc441e6
commit
231dc3913f
12 changed files with 364 additions and 58 deletions
|
@ -128,3 +128,4 @@ This document describes the different errors Vikunja can return.
|
||||||
|-----------|------------------|-------------|
|
|-----------|------------------|-------------|
|
||||||
| 10001 | 404 | The bucket does not exist. |
|
| 10001 | 404 | The bucket does not exist. |
|
||||||
| 10002 | 400 | The bucket does not belong to that list. |
|
| 10002 | 400 | The bucket does not belong to that list. |
|
||||||
|
| 10003 | 412 | You cannot remove the last bucket on a list. |
|
||||||
|
|
|
@ -101,3 +101,107 @@
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
created: 1587244432
|
created: 1587244432
|
||||||
updated: 1587244432
|
updated: 1587244432
|
||||||
|
- id: 18
|
||||||
|
title: testbucket18
|
||||||
|
list_id: 5
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 19
|
||||||
|
title: testbucket19
|
||||||
|
list_id: 21
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 20
|
||||||
|
title: testbucket20
|
||||||
|
list_id: 22
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 21
|
||||||
|
title: testbucket21
|
||||||
|
list_id: 3
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
# Duplicate buckets to make deletion of one of them possible
|
||||||
|
- id: 22
|
||||||
|
title: testbucket22
|
||||||
|
list_id: 6
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 23
|
||||||
|
title: testbucket23
|
||||||
|
list_id: 7
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 24
|
||||||
|
title: testbucket24
|
||||||
|
list_id: 8
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 25
|
||||||
|
title: testbucket25
|
||||||
|
list_id: 9
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 26
|
||||||
|
title: testbucket26
|
||||||
|
list_id: 10
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 27
|
||||||
|
title: testbucket27
|
||||||
|
list_id: 11
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 28
|
||||||
|
title: testbucket28
|
||||||
|
list_id: 12
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 29
|
||||||
|
title: testbucket29
|
||||||
|
list_id: 13
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 30
|
||||||
|
title: testbucket30
|
||||||
|
list_id: 14
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 31
|
||||||
|
title: testbucket31
|
||||||
|
list_id: 15
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 32
|
||||||
|
title: testbucket32
|
||||||
|
list_id: 16
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
- id: 33
|
||||||
|
title: testbucket33
|
||||||
|
list_id: 17
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
# This bucket is the last one in its list
|
||||||
|
- id: 34
|
||||||
|
title: testbucket34
|
||||||
|
list_id: 18
|
||||||
|
created_by_id: 1
|
||||||
|
created: 1587244432
|
||||||
|
updated: 1587244432
|
||||||
|
|
|
@ -87,12 +87,14 @@
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
start_date_unix: 1544600000
|
start_date_unix: 1544600000
|
||||||
end_date_unix: 1544700000
|
end_date_unix: 1544700000
|
||||||
|
bucket_id: 1
|
||||||
- id: 10
|
- id: 10
|
||||||
text: 'task #10 basic'
|
text: 'task #10 basic'
|
||||||
done: false
|
done: false
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
list_id: 1
|
list_id: 1
|
||||||
index: 10
|
index: 10
|
||||||
|
bucket_id: 1
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 11
|
- id: 11
|
||||||
|
@ -101,6 +103,7 @@
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
list_id: 1
|
list_id: 1
|
||||||
index: 11
|
index: 11
|
||||||
|
bucket_id: 1
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 12
|
- id: 12
|
||||||
|
@ -109,6 +112,7 @@
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
list_id: 1
|
list_id: 1
|
||||||
index: 12
|
index: 12
|
||||||
|
bucket_id: 1
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 13
|
- id: 13
|
||||||
|
@ -117,6 +121,7 @@
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
list_id: 2
|
list_id: 2
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 4
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 14
|
- id: 14
|
||||||
|
@ -125,6 +130,7 @@
|
||||||
created_by_id: 5
|
created_by_id: 5
|
||||||
list_id: 5
|
list_id: 5
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 18
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 15
|
- id: 15
|
||||||
|
@ -133,6 +139,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 6
|
list_id: 6
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 6
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 16
|
- id: 16
|
||||||
|
@ -141,6 +148,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 7
|
list_id: 7
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 7
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 17
|
- id: 17
|
||||||
|
@ -149,6 +157,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 8
|
list_id: 8
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 8
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 18
|
- id: 18
|
||||||
|
@ -157,6 +166,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 9
|
list_id: 9
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 9
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 19
|
- id: 19
|
||||||
|
@ -165,6 +175,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 10
|
list_id: 10
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 10
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 20
|
- id: 20
|
||||||
|
@ -173,6 +184,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 11
|
list_id: 11
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 11
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 21
|
- id: 21
|
||||||
|
@ -181,6 +193,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 12
|
list_id: 12
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 12
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 22
|
- id: 22
|
||||||
|
@ -189,6 +202,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 13
|
list_id: 13
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 13
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 23
|
- id: 23
|
||||||
|
@ -197,6 +211,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 14
|
list_id: 14
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 14
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 24
|
- id: 24
|
||||||
|
@ -205,6 +220,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 15
|
list_id: 15
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 15
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 25
|
- id: 25
|
||||||
|
@ -213,6 +229,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 16
|
list_id: 16
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 16
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 26
|
- id: 26
|
||||||
|
@ -221,6 +238,7 @@
|
||||||
created_by_id: 6
|
created_by_id: 6
|
||||||
list_id: 17
|
list_id: 17
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 17
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 27
|
- id: 27
|
||||||
|
@ -229,6 +247,7 @@
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
list_id: 1
|
list_id: 1
|
||||||
index: 12
|
index: 12
|
||||||
|
bucket_id: 1
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 28
|
- id: 28
|
||||||
|
@ -238,6 +257,7 @@
|
||||||
repeat_after: 3600
|
repeat_after: 3600
|
||||||
list_id: 1
|
list_id: 1
|
||||||
index: 13
|
index: 13
|
||||||
|
bucket_id: 1
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 29
|
- id: 29
|
||||||
|
@ -246,6 +266,7 @@
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
list_id: 1
|
list_id: 1
|
||||||
index: 14
|
index: 14
|
||||||
|
bucket_id: 1
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 30
|
- id: 30
|
||||||
|
@ -254,6 +275,7 @@
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
list_id: 1
|
list_id: 1
|
||||||
index: 15
|
index: 15
|
||||||
|
bucket_id: 1
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 31
|
- id: 31
|
||||||
|
@ -263,6 +285,7 @@
|
||||||
list_id: 1
|
list_id: 1
|
||||||
index: 16
|
index: 16
|
||||||
hex_color: f0f0f0
|
hex_color: f0f0f0
|
||||||
|
bucket_id: 1
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 32
|
- id: 32
|
||||||
|
@ -271,6 +294,7 @@
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
list_id: 3
|
list_id: 3
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 21
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 33
|
- id: 33
|
||||||
|
@ -280,6 +304,7 @@
|
||||||
list_id: 1
|
list_id: 1
|
||||||
index: 17
|
index: 17
|
||||||
percent_done: 0.5
|
percent_done: 0.5
|
||||||
|
bucket_id: 1
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
# This task is forbidden for user1
|
# This task is forbidden for user1
|
||||||
|
@ -289,6 +314,7 @@
|
||||||
created_by_id: 13
|
created_by_id: 13
|
||||||
list_id: 20
|
list_id: 20
|
||||||
index: 20
|
index: 20
|
||||||
|
bucket_id: 5
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 35
|
- id: 35
|
||||||
|
@ -297,6 +323,7 @@
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
list_id: 21
|
list_id: 21
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 19
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
- id: 36
|
- id: 36
|
||||||
|
@ -305,6 +332,7 @@
|
||||||
created_by_id: 1
|
created_by_id: 1
|
||||||
list_id: 22
|
list_id: 22
|
||||||
index: 1
|
index: 1
|
||||||
|
bucket_id: 20
|
||||||
created: 1543626724
|
created: 1543626724
|
||||||
updated: 1543626724
|
updated: 1543626724
|
||||||
|
|
||||||
|
|
|
@ -133,7 +133,7 @@ func TestBucket(t *testing.T) {
|
||||||
})
|
})
|
||||||
t.Run("Delete", func(t *testing.T) {
|
t.Run("Delete", func(t *testing.T) {
|
||||||
t.Run("Normal", func(t *testing.T) {
|
t.Run("Normal", func(t *testing.T) {
|
||||||
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "1"})
|
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "1", "bucket": "1"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
||||||
})
|
})
|
||||||
|
@ -145,70 +145,70 @@ func TestBucket(t *testing.T) {
|
||||||
t.Run("Rights check", func(t *testing.T) {
|
t.Run("Rights check", func(t *testing.T) {
|
||||||
t.Run("Forbidden", func(t *testing.T) {
|
t.Run("Forbidden", func(t *testing.T) {
|
||||||
// Owned by user13
|
// Owned by user13
|
||||||
_, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "5"})
|
_, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "20", "bucket": "5"})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
|
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
|
||||||
})
|
})
|
||||||
t.Run("Shared Via Team readonly", func(t *testing.T) {
|
t.Run("Shared Via Team readonly", func(t *testing.T) {
|
||||||
_, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "6"})
|
_, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "6", "bucket": "6"})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
|
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
|
||||||
})
|
})
|
||||||
t.Run("Shared Via Team write", func(t *testing.T) {
|
t.Run("Shared Via Team write", func(t *testing.T) {
|
||||||
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "7"})
|
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "7", "bucket": "7"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
||||||
})
|
})
|
||||||
t.Run("Shared Via Team admin", func(t *testing.T) {
|
t.Run("Shared Via Team admin", func(t *testing.T) {
|
||||||
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "8"})
|
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "8", "bucket": "8"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Shared Via User readonly", func(t *testing.T) {
|
t.Run("Shared Via User readonly", func(t *testing.T) {
|
||||||
_, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "9"})
|
_, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "9", "bucket": "9"})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
|
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
|
||||||
})
|
})
|
||||||
t.Run("Shared Via User write", func(t *testing.T) {
|
t.Run("Shared Via User write", func(t *testing.T) {
|
||||||
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "10"})
|
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "10", "bucket": "10"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
||||||
})
|
})
|
||||||
t.Run("Shared Via User admin", func(t *testing.T) {
|
t.Run("Shared Via User admin", func(t *testing.T) {
|
||||||
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "11"})
|
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "11", "bucket": "11"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Shared Via NamespaceTeam readonly", func(t *testing.T) {
|
t.Run("Shared Via NamespaceTeam readonly", func(t *testing.T) {
|
||||||
_, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "12"})
|
_, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "12", "bucket": "12"})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
|
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
|
||||||
})
|
})
|
||||||
t.Run("Shared Via NamespaceTeam write", func(t *testing.T) {
|
t.Run("Shared Via NamespaceTeam write", func(t *testing.T) {
|
||||||
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "13"})
|
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "13", "bucket": "13"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
||||||
})
|
})
|
||||||
t.Run("Shared Via NamespaceTeam admin", func(t *testing.T) {
|
t.Run("Shared Via NamespaceTeam admin", func(t *testing.T) {
|
||||||
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "14"})
|
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "14", "bucket": "14"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Shared Via NamespaceUser readonly", func(t *testing.T) {
|
t.Run("Shared Via NamespaceUser readonly", func(t *testing.T) {
|
||||||
_, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "15"})
|
_, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "15", "bucket": "15"})
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
|
assert.Contains(t, err.(*echo.HTTPError).Message, `Forbidden`)
|
||||||
})
|
})
|
||||||
t.Run("Shared Via NamespaceUser write", func(t *testing.T) {
|
t.Run("Shared Via NamespaceUser write", func(t *testing.T) {
|
||||||
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "16"})
|
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "16", "bucket": "16"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
||||||
})
|
})
|
||||||
t.Run("Shared Via NamespaceUser admin", func(t *testing.T) {
|
t.Run("Shared Via NamespaceUser admin", func(t *testing.T) {
|
||||||
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"bucket": "17"})
|
rec, err := testHandler.testDeleteWithUser(nil, map[string]string{"list": "17", "bucket": "17"})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
assert.Contains(t, rec.Body.String(), `"message":"Successfully deleted."`)
|
||||||
})
|
})
|
||||||
|
|
|
@ -95,7 +95,7 @@ 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,"text":"task #33 with percent done","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":0,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":4,"text":"task #4 low prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":1,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":3,"text":"task #3 high prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":100,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":33,"text":"task #33 with percent done","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":0,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":4,"text":"task #4 low prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":1,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":3,"text":"task #3 high prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":100,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}}]`)
|
||||||
})
|
})
|
||||||
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)
|
||||||
|
@ -105,7 +105,7 @@ func TestTaskCollection(t *testing.T) {
|
||||||
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,"text":"task #33 with percent done","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":0,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":4,"text":"task #4 low prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":1,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":3,"text":"task #3 high prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":100,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":33,"text":"task #33 with percent done","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":0,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":4,"text":"task #4 low prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":1,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":3,"text":"task #3 high prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":100,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}}]`)
|
||||||
})
|
})
|
||||||
// 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) {
|
||||||
|
@ -270,7 +270,7 @@ 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,"text":"task #33 with percent done","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":0,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":4,"text":"task #4 low prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":1,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":3,"text":"task #3 high prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":100,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":33,"text":"task #33 with percent done","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":0,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":4,"text":"task #4 low prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":1,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":3,"text":"task #3 high prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":100,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}}]`)
|
||||||
})
|
})
|
||||||
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)
|
||||||
|
@ -280,7 +280,7 @@ func TestTaskCollection(t *testing.T) {
|
||||||
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,"text":"task #33 with percent done","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":0,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":0,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":4,"text":"task #4 low prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":1,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":3,"text":"task #3 high prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":100,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}}]`)
|
assert.Contains(t, rec.Body.String(), `{"id":33,"text":"task #33 with percent done","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":0,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0.5,"identifier":"test1-17","index":17,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":1,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":4,"text":"task #4 low prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":1,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-4","index":4,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}},{"id":3,"text":"task #3 high prio","description":"","done":false,"done_at":null,"due_date":null,"reminder_dates":null,"list_id":1,"repeat_after":0,"priority":100,"start_date":null,"end_date":null,"assignees":null,"labels":null,"hex_color":"","percent_done":0,"identifier":"test1-3","index":3,"related_tasks":{},"attachments":null,"created":"2018-12-01T01:12:04Z","updated":"2018-12-01T01:12:04Z","bucket_id":2,"position":0,"created_by":{"id":1,"username":"user1","created":null,"updated":null}}]`)
|
||||||
})
|
})
|
||||||
// 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) {
|
||||||
|
|
75
pkg/migration/20200425182634.go
Normal file
75
pkg/migration/20200425182634.go
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
// Vikunja is a to-do list application to facilitate your life.
|
||||||
|
// Copyright 2018-2020 Vikunja and contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package migration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.vikunja.io/api/pkg/models"
|
||||||
|
"src.techknowlogick.com/xormigrate"
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
migrations = append(migrations, &xormigrate.Migration{
|
||||||
|
ID: "20200425182634",
|
||||||
|
Description: "Create one bucket for each list",
|
||||||
|
Migrate: func(tx *xorm.Engine) (err error) {
|
||||||
|
lists := []*models.List{}
|
||||||
|
err = tx.Find(&lists)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks := []*models.Task{}
|
||||||
|
err = tx.Find(&tasks)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// This map contains all buckets with their list ids as key
|
||||||
|
buckets := make(map[int64]*models.Bucket, len(lists))
|
||||||
|
for _, l := range lists {
|
||||||
|
buckets[l.ID] = &models.Bucket{
|
||||||
|
ListID: l.ID,
|
||||||
|
Title: "New Bucket",
|
||||||
|
// The bucket creator is just the same as the list's one
|
||||||
|
CreatedByID: l.OwnerID,
|
||||||
|
}
|
||||||
|
_, err = tx.Insert(buckets[l.ID])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range tasks {
|
||||||
|
if t.ListID != l.ID {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
t.BucketID = buckets[l.ID].ID
|
||||||
|
_, err = tx.Where("id = ?", t.ID).Update(t)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
},
|
||||||
|
Rollback: func(tx *xorm.Engine) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -1251,3 +1251,31 @@ func (err ErrBucketDoesNotBelongToList) HTTPError() web.HTTPError {
|
||||||
Message: "This bucket does not belong to that list.",
|
Message: "This bucket does not belong to that list.",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrCannotRemoveLastBucket represents an error where a kanban bucket is the last on a list and thus cannot be removed.
|
||||||
|
type ErrCannotRemoveLastBucket struct {
|
||||||
|
BucketID int64
|
||||||
|
ListID int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsErrCannotRemoveLastBucket checks if an error is ErrCannotRemoveLastBucket.
|
||||||
|
func IsErrCannotRemoveLastBucket(err error) bool {
|
||||||
|
_, ok := err.(ErrCannotRemoveLastBucket)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrCannotRemoveLastBucket) Error() string {
|
||||||
|
return fmt.Sprintf("Cannot remove last bucket of list [BucketID: %d, ListID: %d]", err.BucketID, err.ListID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCodeCannotRemoveLastBucket holds the unique world-error code of this error
|
||||||
|
const ErrCodeCannotRemoveLastBucket = 10003
|
||||||
|
|
||||||
|
// HTTPError holds the http error description
|
||||||
|
func (err ErrCannotRemoveLastBucket) HTTPError() web.HTTPError {
|
||||||
|
return web.HTTPError{
|
||||||
|
HTTPCode: http.StatusPreconditionFailed,
|
||||||
|
Code: ErrCodeCannotRemoveLastBucket,
|
||||||
|
Message: "You cannot remove the last bucket on this list.",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ import (
|
||||||
"code.vikunja.io/api/pkg/timeutil"
|
"code.vikunja.io/api/pkg/timeutil"
|
||||||
"code.vikunja.io/api/pkg/user"
|
"code.vikunja.io/api/pkg/user"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bucket represents a kanban bucket
|
// Bucket represents a kanban bucket
|
||||||
|
@ -64,6 +63,15 @@ func getBucketByID(id int64) (b *Bucket, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDefaultBucket(listID int64) (bucket *Bucket, err error) {
|
||||||
|
bucket = &Bucket{}
|
||||||
|
_, err = x.
|
||||||
|
Where("list_id = ?", listID).
|
||||||
|
OrderBy("id asc").
|
||||||
|
Get(bucket)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// ReadAll returns all buckets with their tasks for a certain list
|
// ReadAll returns all buckets with their tasks for a certain list
|
||||||
// @Summary Get all kanban buckets of a list
|
// @Summary Get all kanban buckets of a list
|
||||||
// @Description Returns all kanban buckets with belong to a list including their tasks.
|
// @Description Returns all kanban buckets with belong to a list including their tasks.
|
||||||
|
@ -81,23 +89,7 @@ func (b *Bucket) ReadAll(auth web.Auth, search string, page int, perPage int) (r
|
||||||
// I'll probably just don't do it and instead make individual tasks archivable.
|
// I'll probably just don't do it and instead make individual tasks archivable.
|
||||||
|
|
||||||
// Get all buckets for this list
|
// Get all buckets for this list
|
||||||
buckets := []*Bucket{
|
buckets := []*Bucket{}
|
||||||
{
|
|
||||||
// This is the default bucket for all tasks which are not associated to a bucket.
|
|
||||||
ID: 0,
|
|
||||||
Title: "Not associated to a bucket",
|
|
||||||
ListID: b.ListID,
|
|
||||||
Created: timeutil.FromTime(time.Now()),
|
|
||||||
Updated: timeutil.FromTime(time.Now()),
|
|
||||||
CreatedByID: auth.GetID(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
buckets[0].CreatedBy, err = user.GetFromAuth(auth)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = x.Where("list_id = ?", b.ListID).Find(&buckets)
|
err = x.Where("list_id = ?", b.ListID).Find(&buckets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
@ -189,7 +181,7 @@ func (b *Bucket) Update() (err error) {
|
||||||
|
|
||||||
// Delete removes a bucket, but no tasks
|
// Delete removes a bucket, but no tasks
|
||||||
// @Summary Deletes an existing bucket
|
// @Summary Deletes an existing bucket
|
||||||
// @Description Deletes an existing kanban bucket and dissociates all of its task. It does not delete any tasks.
|
// @Description Deletes an existing kanban bucket and dissociates all of its task. It does not delete any tasks. You cannot delete the last bucket on a list.
|
||||||
// @tags task
|
// @tags task
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
|
@ -201,8 +193,26 @@ func (b *Bucket) Update() (err error) {
|
||||||
// @Failure 500 {object} models.Message "Internal error"
|
// @Failure 500 {object} models.Message "Internal error"
|
||||||
// @Router /lists/{listID}/buckets/{bucketID} [delete]
|
// @Router /lists/{listID}/buckets/{bucketID} [delete]
|
||||||
func (b *Bucket) Delete() (err error) {
|
func (b *Bucket) Delete() (err error) {
|
||||||
|
// Prevent removing the last bucket
|
||||||
|
total, err := x.Where("list_id = ?", b.ListID).Count(&Bucket{})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if total <= 1 {
|
||||||
|
return ErrCannotRemoveLastBucket{
|
||||||
|
BucketID: b.ID,
|
||||||
|
ListID: b.ListID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the default bucket
|
||||||
|
defaultBucket, err := getDefaultBucket(b.ListID)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Remove all associations of tasks to that bucket
|
// Remove all associations of tasks to that bucket
|
||||||
_, err = x.Where("bucket_id = ?", b.ID).Cols("bucket_id").Update(&Task{BucketID: 0})
|
_, err = x.Where("bucket_id = ?", b.ID).Cols("bucket_id").Update(&Task{BucketID: defaultBucket.ID})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,30 +38,55 @@ func TestBucket_ReadAll(t *testing.T) {
|
||||||
assert.Equal(t, testuser.ID, buckets[0].CreatedBy.ID)
|
assert.Equal(t, testuser.ID, buckets[0].CreatedBy.ID)
|
||||||
assert.Equal(t, testuser.ID, buckets[1].CreatedBy.ID)
|
assert.Equal(t, testuser.ID, buckets[1].CreatedBy.ID)
|
||||||
assert.Equal(t, testuser.ID, buckets[2].CreatedBy.ID)
|
assert.Equal(t, testuser.ID, buckets[2].CreatedBy.ID)
|
||||||
assert.Equal(t, testuser.ID, buckets[3].CreatedBy.ID)
|
|
||||||
|
|
||||||
// Assert our three test buckets + one for all tasks without a bucket
|
// Assert our three test buckets
|
||||||
assert.Len(t, buckets, 4)
|
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, 10)
|
assert.Len(t, buckets[0].Tasks, 12)
|
||||||
assert.Len(t, buckets[1].Tasks, 2)
|
assert.Len(t, buckets[1].Tasks, 3)
|
||||||
assert.Len(t, buckets[2].Tasks, 3)
|
assert.Len(t, buckets[2].Tasks, 3)
|
||||||
assert.Len(t, buckets[3].Tasks, 3)
|
|
||||||
|
|
||||||
// Assert we have bucket 0, 1, 2, 3 but not 4 (that belongs to a different list)
|
// Assert we have bucket 0, 1, 2, 3 but not 4 (that belongs to a different list)
|
||||||
assert.Equal(t, int64(1), buckets[1].ID)
|
assert.Equal(t, int64(1), buckets[0].ID)
|
||||||
assert.Equal(t, int64(2), buckets[2].ID)
|
assert.Equal(t, int64(2), buckets[1].ID)
|
||||||
assert.Equal(t, int64(3), buckets[3].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(0), buckets[0].Tasks[0].BucketID)
|
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[2].Tasks[0].BucketID)
|
assert.Equal(t, int64(2), buckets[1].Tasks[1].BucketID)
|
||||||
assert.Equal(t, int64(2), buckets[2].Tasks[1].BucketID)
|
assert.Equal(t, int64(2), buckets[1].Tasks[2].BucketID)
|
||||||
assert.Equal(t, int64(2), buckets[2].Tasks[2].BucketID)
|
assert.Equal(t, int64(3), buckets[2].Tasks[0].BucketID)
|
||||||
assert.Equal(t, int64(3), buckets[3].Tasks[0].BucketID)
|
assert.Equal(t, int64(3), buckets[2].Tasks[1].BucketID)
|
||||||
assert.Equal(t, int64(3), buckets[3].Tasks[1].BucketID)
|
assert.Equal(t, int64(3), buckets[2].Tasks[2].BucketID)
|
||||||
assert.Equal(t, int64(3), buckets[3].Tasks[2].BucketID)
|
}
|
||||||
|
|
||||||
|
func TestBucket_Delete(t *testing.T) {
|
||||||
|
t.Run("normal", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
b := &Bucket{
|
||||||
|
ID: 2, // The second bucket only has 3 tasks
|
||||||
|
ListID: 1,
|
||||||
|
}
|
||||||
|
err := b.Delete()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// Assert all tasks have been moved to bucket 1 as that one is the first
|
||||||
|
tasks := []*Task{}
|
||||||
|
err = x.Where("bucket_id = ?", 1).Find(&tasks)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, tasks, 15)
|
||||||
|
})
|
||||||
|
t.Run("last bucket in list", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
b := &Bucket{
|
||||||
|
ID: 34,
|
||||||
|
ListID: 18,
|
||||||
|
}
|
||||||
|
err := b.Delete()
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.True(t, IsErrCannotRemoveLastBucket(err))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
Index: 14,
|
Index: 14,
|
||||||
CreatedByID: 1,
|
CreatedByID: 1,
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
|
BucketID: 1,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
},
|
},
|
||||||
|
@ -223,6 +224,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user1,
|
CreatedBy: user1,
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 1,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
StartDate: 1544600000,
|
StartDate: 1544600000,
|
||||||
|
@ -237,6 +239,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user1,
|
CreatedBy: user1,
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 1,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -249,6 +252,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user1,
|
CreatedBy: user1,
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 1,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -261,6 +265,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user1,
|
CreatedBy: user1,
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 1,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -273,6 +278,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 6,
|
ListID: 6,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 6,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -285,6 +291,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 7,
|
ListID: 7,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 7,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -297,6 +304,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 8,
|
ListID: 8,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 8,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -309,6 +317,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 9,
|
ListID: 9,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 9,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -321,6 +330,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 10,
|
ListID: 10,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 10,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -333,6 +343,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 11,
|
ListID: 11,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 11,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -345,6 +356,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 12,
|
ListID: 12,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 12,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -357,6 +369,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 13,
|
ListID: 13,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 13,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -369,6 +382,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 14,
|
ListID: 14,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 14,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -381,6 +395,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 15,
|
ListID: 15,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 15,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -393,6 +408,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 16,
|
ListID: 16,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 16,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -405,6 +421,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user6,
|
CreatedBy: user6,
|
||||||
ListID: 17,
|
ListID: 17,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 17,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -417,6 +434,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user1,
|
CreatedBy: user1,
|
||||||
Reminders: []timeutil.TimeStamp{1543626724, 1543626824},
|
Reminders: []timeutil.TimeStamp{1543626724, 1543626824},
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
|
BucketID: 1,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
|
@ -431,6 +449,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
RepeatAfter: 3600,
|
RepeatAfter: 3600,
|
||||||
|
BucketID: 1,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -457,6 +476,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
BucketID: 1,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -473,6 +493,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
user2,
|
user2,
|
||||||
},
|
},
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 1,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -486,6 +507,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user1,
|
CreatedBy: user1,
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 1,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -498,6 +520,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
CreatedBy: user1,
|
CreatedBy: user1,
|
||||||
ListID: 3,
|
ListID: 3,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 21,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
@ -511,6 +534,7 @@ func TestTaskCollection_ReadAll(t *testing.T) {
|
||||||
ListID: 1,
|
ListID: 1,
|
||||||
PercentDone: 0.5,
|
PercentDone: 0.5,
|
||||||
RelatedTasks: map[RelationKind][]*Task{},
|
RelatedTasks: map[RelationKind][]*Task{},
|
||||||
|
BucketID: 1,
|
||||||
Created: 1543626724,
|
Created: 1543626724,
|
||||||
Updated: 1543626724,
|
Updated: 1543626724,
|
||||||
}
|
}
|
||||||
|
|
|
@ -544,6 +544,15 @@ func (t *Task) Create(a web.Auth) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the default bucket and move the task there
|
||||||
|
if t.BucketID == 0 {
|
||||||
|
defaultBucket, err := getDefaultBucket(t.ListID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.BucketID = defaultBucket.ID
|
||||||
|
}
|
||||||
|
|
||||||
// Get the index for this task
|
// Get the index for this task
|
||||||
latestTask := &Task{}
|
latestTask := &Task{}
|
||||||
_, err = x.Where("list_id = ?", t.ListID).OrderBy("id desc").Get(latestTask)
|
_, err = x.Where("list_id = ?", t.ListID).OrderBy("id desc").Get(latestTask)
|
||||||
|
|
|
@ -47,6 +47,8 @@ func TestTask_Create(t *testing.T) {
|
||||||
// Assert getting a new index
|
// Assert getting a new index
|
||||||
assert.NotEmpty(t, task.Index)
|
assert.NotEmpty(t, task.Index)
|
||||||
assert.Equal(t, int64(18), task.Index)
|
assert.Equal(t, int64(18), task.Index)
|
||||||
|
// Assert moving it into the default bucket
|
||||||
|
assert.Equal(t, int64(1), task.BucketID)
|
||||||
|
|
||||||
})
|
})
|
||||||
t.Run("empty text", func(t *testing.T) {
|
t.Run("empty text", func(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue