Add task filters for kanban
Signed-off-by: kolaente <k@knt.li>
This commit is contained in:
parent
2d4e2e452c
commit
fa68e89c04
5 changed files with 262 additions and 39 deletions
|
@ -48,6 +48,9 @@ type Bucket struct {
|
||||||
CreatedBy *user.User `xorm:"-" json:"created_by" valid:"-"`
|
CreatedBy *user.User `xorm:"-" json:"created_by" valid:"-"`
|
||||||
CreatedByID int64 `xorm:"bigint not null" json:"-"`
|
CreatedByID int64 `xorm:"bigint not null" json:"-"`
|
||||||
|
|
||||||
|
// Including the task collection type so we can use task filters on kanban
|
||||||
|
TaskCollection `xorm:"-" json:"-"`
|
||||||
|
|
||||||
web.Rights `xorm:"-" json:"-"`
|
web.Rights `xorm:"-" json:"-"`
|
||||||
web.CRUDable `xorm:"-" json:"-"`
|
web.CRUDable `xorm:"-" json:"-"`
|
||||||
}
|
}
|
||||||
|
@ -86,6 +89,11 @@ func getDefaultBucket(s *xorm.Session, listID int64) (bucket *Bucket, err error)
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Security JWTKeyAuth
|
// @Security JWTKeyAuth
|
||||||
// @Param id path int true "List Id"
|
// @Param id path int true "List Id"
|
||||||
|
// @Param filter_by query string false "The name of the field to filter by. Allowed values are all task properties. Task properties which are their own object require passing in the id of that entity. Accepts an array for multiple filters which will be chanied together, all supplied filter must match."
|
||||||
|
// @Param filter_value query string false "The value to filter for."
|
||||||
|
// @Param filter_comparator query string false "The comparator to use for a filter. Available values are `equals`, `greater`, `greater_equals`, `less`, `less_equals`, `like` and `in`. `in` expects comma-separated values in `filter_value`. Defaults to `equals`"
|
||||||
|
// @Param filter_concat query string false "The concatinator to use for filters. Available values are `and` or `or`. Defaults to `or`."
|
||||||
|
// @Param filter_include_nulls query string false "If set to true the result will include filtered fields whose value is set to `null`. Available values are `true` or `false`. Defaults to `false`."
|
||||||
// @Success 200 {array} models.Bucket "The buckets with their tasks"
|
// @Success 200 {array} models.Bucket "The buckets with their tasks"
|
||||||
// @Failure 500 {object} models.Message "Internal server error"
|
// @Failure 500 {object} models.Message "Internal server error"
|
||||||
// @Router /lists/{id}/buckets [get]
|
// @Router /lists/{id}/buckets [get]
|
||||||
|
@ -121,19 +129,16 @@ func (b *Bucket) ReadAll(auth web.Auth, search string, page int, perPage int) (r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all tasks for this list
|
// Get all tasks for this list
|
||||||
opts := &taskOptions{
|
b.TaskCollection.ListID = b.ListID
|
||||||
sortby: []*sortParam{
|
b.TaskCollection.OrderBy = []string{string(orderAscending)}
|
||||||
{
|
b.TaskCollection.SortBy = []string{taskPropertyPosition}
|
||||||
sortBy: taskPropertyPosition,
|
ts, _, _, err := b.TaskCollection.ReadAll(auth, "", -1, 0)
|
||||||
orderBy: orderAscending,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
tasks, _, _, err := getTasksForLists([]*List{{ID: b.ListID}}, auth, opts)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks := ts.([]*Task)
|
||||||
|
|
||||||
// Put all tasks in their buckets
|
// Put all tasks in their buckets
|
||||||
// All tasks which are not associated to any bucket will have bucket id 0 which is the nil value for int64
|
// All tasks which are not associated to any bucket will have bucket id 0 which is the nil value for int64
|
||||||
// Since we created a bucked with that id at the beginning, all tasks should be in there.
|
// Since we created a bucked with that id at the beginning, all tasks should be in there.
|
||||||
|
|
|
@ -25,43 +25,64 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBucket_ReadAll(t *testing.T) {
|
func TestBucket_ReadAll(t *testing.T) {
|
||||||
db.LoadAndAssertFixtures(t)
|
t.Run("normal", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
testuser := &user.User{ID: 1}
|
testuser := &user.User{ID: 1}
|
||||||
b := &Bucket{ListID: 1}
|
b := &Bucket{ListID: 1}
|
||||||
bucketsInterface, _, _, err := b.ReadAll(testuser, "", 0, 0)
|
bucketsInterface, _, _, err := b.ReadAll(testuser, "", 0, 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
buckets, is := bucketsInterface.([]*Bucket)
|
buckets, is := bucketsInterface.([]*Bucket)
|
||||||
assert.True(t, is)
|
assert.True(t, is)
|
||||||
|
|
||||||
// Assert that we have a user for each bucket
|
// Assert that we have a user for each bucket
|
||||||
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 our three test buckets
|
// Assert our three test buckets
|
||||||
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, 12)
|
||||||
assert.Len(t, buckets[1].Tasks, 3)
|
assert.Len(t, buckets[1].Tasks, 3)
|
||||||
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 0, 1, 2, 3 but not 4 (that belongs to a different list)
|
||||||
assert.Equal(t, int64(1), buckets[0].ID)
|
assert.Equal(t, int64(1), buckets[0].ID)
|
||||||
assert.Equal(t, int64(2), buckets[1].ID)
|
assert.Equal(t, int64(2), 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[0].Tasks[0].BucketID)
|
||||||
assert.Equal(t, int64(1), buckets[0].Tasks[1].BucketID)
|
assert.Equal(t, int64(1), buckets[0].Tasks[1].BucketID)
|
||||||
assert.Equal(t, int64(2), buckets[1].Tasks[0].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[1].Tasks[1].BucketID)
|
||||||
assert.Equal(t, int64(2), buckets[1].Tasks[2].BucketID)
|
assert.Equal(t, int64(2), buckets[1].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)
|
||||||
|
})
|
||||||
|
t.Run("filtered", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
|
||||||
|
testuser := &user.User{ID: 1}
|
||||||
|
b := &Bucket{
|
||||||
|
ListID: 1,
|
||||||
|
TaskCollection: TaskCollection{
|
||||||
|
FilterBy: []string{"title"},
|
||||||
|
FilterComparator: []string{"like"},
|
||||||
|
FilterValue: []string{"done"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
bucketsInterface, _, _, err := b.ReadAll(testuser, "", 0, 0)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
buckets := bucketsInterface.([]*Bucket)
|
||||||
|
assert.Len(t, buckets, 3)
|
||||||
|
assert.Equal(t, int64(2), buckets[0].Tasks[0].ID)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBucket_Delete(t *testing.T) {
|
func TestBucket_Delete(t *testing.T) {
|
||||||
|
|
|
@ -1222,6 +1222,36 @@ var doc = `{
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the field to filter by. Allowed values are all task properties. Task properties which are their own object require passing in the id of that entity. Accepts an array for multiple filters which will be chanied together, all supplied filter must match.",
|
||||||
|
"name": "filter_by",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "The value to filter for.",
|
||||||
|
"name": "filter_value",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "The comparator to use for a filter. Available values are ` + "`" + `equals` + "`" + `, ` + "`" + `greater` + "`" + `, ` + "`" + `greater_equals` + "`" + `, ` + "`" + `less` + "`" + `, ` + "`" + `less_equals` + "`" + `, ` + "`" + `like` + "`" + ` and ` + "`" + `in` + "`" + `. ` + "`" + `in` + "`" + ` expects comma-separated values in ` + "`" + `filter_value` + "`" + `. Defaults to ` + "`" + `equals` + "`" + `",
|
||||||
|
"name": "filter_comparator",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "The concatinator to use for filters. Available values are ` + "`" + `and` + "`" + ` or ` + "`" + `or` + "`" + `. Defaults to ` + "`" + `or` + "`" + `.",
|
||||||
|
"name": "filter_concat",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "If set to true the result will include filtered fields whose value is set to ` + "`" + `null` + "`" + `. Available values are ` + "`" + `true` + "`" + ` or ` + "`" + `false` + "`" + `. Defaults to ` + "`" + `false` + "`" + `.",
|
||||||
|
"name": "filter_include_nulls",
|
||||||
|
"in": "query"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
|
@ -6808,6 +6838,35 @@ var doc = `{
|
||||||
"description": "The user who initially created the bucket.",
|
"description": "The user who initially created the bucket.",
|
||||||
"$ref": "#/definitions/user.User"
|
"$ref": "#/definitions/user.User"
|
||||||
},
|
},
|
||||||
|
"filter_by": {
|
||||||
|
"description": "The field name of the field to filter by",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filter_comparator": {
|
||||||
|
"description": "The comparator for field and value",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filter_concat": {
|
||||||
|
"description": "The way all filter conditions are concatenated together, can be either \"and\" or \"or\".,",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"filter_include_nulls": {
|
||||||
|
"description": "If set to true, the result will also include null values",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"filter_value": {
|
||||||
|
"description": "The value of the field name to filter by",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"description": "The unique, numeric id of this bucket.",
|
"description": "The unique, numeric id of this bucket.",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
@ -6820,6 +6879,20 @@ var doc = `{
|
||||||
"description": "The list this bucket belongs to.",
|
"description": "The list this bucket belongs to.",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"order_by": {
|
||||||
|
"description": "The query parameter to order the items by. This can be either asc or desc, with asc being the default.",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sort_by": {
|
||||||
|
"description": "The query parameter to sort by. This is for ex. done, priority, etc.",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"description": "All tasks which belong to this bucket.",
|
"description": "All tasks which belong to this bucket.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
|
|
@ -1205,6 +1205,36 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "The name of the field to filter by. Allowed values are all task properties. Task properties which are their own object require passing in the id of that entity. Accepts an array for multiple filters which will be chanied together, all supplied filter must match.",
|
||||||
|
"name": "filter_by",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "The value to filter for.",
|
||||||
|
"name": "filter_value",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "The comparator to use for a filter. Available values are `equals`, `greater`, `greater_equals`, `less`, `less_equals`, `like` and `in`. `in` expects comma-separated values in `filter_value`. Defaults to `equals`",
|
||||||
|
"name": "filter_comparator",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "The concatinator to use for filters. Available values are `and` or `or`. Defaults to `or`.",
|
||||||
|
"name": "filter_concat",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "If set to true the result will include filtered fields whose value is set to `null`. Available values are `true` or `false`. Defaults to `false`.",
|
||||||
|
"name": "filter_include_nulls",
|
||||||
|
"in": "query"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
|
@ -6791,6 +6821,35 @@
|
||||||
"description": "The user who initially created the bucket.",
|
"description": "The user who initially created the bucket.",
|
||||||
"$ref": "#/definitions/user.User"
|
"$ref": "#/definitions/user.User"
|
||||||
},
|
},
|
||||||
|
"filter_by": {
|
||||||
|
"description": "The field name of the field to filter by",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filter_comparator": {
|
||||||
|
"description": "The comparator for field and value",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filter_concat": {
|
||||||
|
"description": "The way all filter conditions are concatenated together, can be either \"and\" or \"or\".,",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"filter_include_nulls": {
|
||||||
|
"description": "If set to true, the result will also include null values",
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"filter_value": {
|
||||||
|
"description": "The value of the field name to filter by",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"description": "The unique, numeric id of this bucket.",
|
"description": "The unique, numeric id of this bucket.",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
|
@ -6803,6 +6862,20 @@
|
||||||
"description": "The list this bucket belongs to.",
|
"description": "The list this bucket belongs to.",
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"order_by": {
|
||||||
|
"description": "The query parameter to order the items by. This can be either asc or desc, with asc being the default.",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sort_by": {
|
||||||
|
"description": "The query parameter to sort by. This is for ex. done, priority, etc.",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tasks": {
|
"tasks": {
|
||||||
"description": "All tasks which belong to this bucket.",
|
"description": "All tasks which belong to this bucket.",
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
|
|
@ -57,6 +57,27 @@ definitions:
|
||||||
created_by:
|
created_by:
|
||||||
$ref: '#/definitions/user.User'
|
$ref: '#/definitions/user.User'
|
||||||
description: The user who initially created the bucket.
|
description: The user who initially created the bucket.
|
||||||
|
filter_by:
|
||||||
|
description: The field name of the field to filter by
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
filter_comparator:
|
||||||
|
description: The comparator for field and value
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
filter_concat:
|
||||||
|
description: The way all filter conditions are concatenated together, can be either "and" or "or".,
|
||||||
|
type: string
|
||||||
|
filter_include_nulls:
|
||||||
|
description: If set to true, the result will also include null values
|
||||||
|
type: boolean
|
||||||
|
filter_value:
|
||||||
|
description: The value of the field name to filter by
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
id:
|
id:
|
||||||
description: The unique, numeric id of this bucket.
|
description: The unique, numeric id of this bucket.
|
||||||
type: integer
|
type: integer
|
||||||
|
@ -66,6 +87,16 @@ definitions:
|
||||||
list_id:
|
list_id:
|
||||||
description: The list this bucket belongs to.
|
description: The list this bucket belongs to.
|
||||||
type: integer
|
type: integer
|
||||||
|
order_by:
|
||||||
|
description: The query parameter to order the items by. This can be either asc or desc, with asc being the default.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
sort_by:
|
||||||
|
description: The query parameter to sort by. This is for ex. done, priority, etc.
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
tasks:
|
tasks:
|
||||||
description: All tasks which belong to this bucket.
|
description: All tasks which belong to this bucket.
|
||||||
items:
|
items:
|
||||||
|
@ -1849,6 +1880,26 @@ paths:
|
||||||
name: id
|
name: id
|
||||||
required: true
|
required: true
|
||||||
type: integer
|
type: integer
|
||||||
|
- description: The name of the field to filter by. Allowed values are all task properties. Task properties which are their own object require passing in the id of that entity. Accepts an array for multiple filters which will be chanied together, all supplied filter must match.
|
||||||
|
in: query
|
||||||
|
name: filter_by
|
||||||
|
type: string
|
||||||
|
- description: The value to filter for.
|
||||||
|
in: query
|
||||||
|
name: filter_value
|
||||||
|
type: string
|
||||||
|
- description: The comparator to use for a filter. Available values are `equals`, `greater`, `greater_equals`, `less`, `less_equals`, `like` and `in`. `in` expects comma-separated values in `filter_value`. Defaults to `equals`
|
||||||
|
in: query
|
||||||
|
name: filter_comparator
|
||||||
|
type: string
|
||||||
|
- description: The concatinator to use for filters. Available values are `and` or `or`. Defaults to `or`.
|
||||||
|
in: query
|
||||||
|
name: filter_concat
|
||||||
|
type: string
|
||||||
|
- description: If set to true the result will include filtered fields whose value is set to `null`. Available values are `true` or `false`. Defaults to `false`.
|
||||||
|
in: query
|
||||||
|
name: filter_include_nulls
|
||||||
|
type: string
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
|
|
Loading…
Reference in a new issue