fix(filter): correctly filter for buckets
This commit is contained in:
parent
ef1cc9720c
commit
eebfee73d3
@ -1045,7 +1045,7 @@ func IsErrInvalidFilterExpression(err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (err ErrInvalidFilterExpression) Error() string {
|
func (err ErrInvalidFilterExpression) Error() string {
|
||||||
return fmt.Sprintf("Task filter expression is invalid [ExpressionError: %v]", err.ExpressionError)
|
return fmt.Sprintf("Task filter expression '%s' is invalid [ExpressionError: %v]", err.Expression, err.ExpressionError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrCodeInvalidFilterExpression holds the unique world-error code of this error
|
// ErrCodeInvalidFilterExpression holds the unique world-error code of this error
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.vikunja.io/api/pkg/log"
|
"code.vikunja.io/api/pkg/log"
|
||||||
@ -175,26 +177,35 @@ func (b *Bucket) ReadAll(s *xorm.Session, auth web.Auth, search string, page int
|
|||||||
opts.search = search
|
opts.search = search
|
||||||
opts.filterConcat = filterConcatAnd
|
opts.filterConcat = filterConcatAnd
|
||||||
|
|
||||||
var bucketFilterIndex int
|
for _, filter := range opts.filters {
|
||||||
for i, filter := range opts.filters {
|
|
||||||
if filter.field == taskPropertyBucketID {
|
if filter.field == taskPropertyBucketID {
|
||||||
bucketFilterIndex = i
|
|
||||||
|
// Limiting the map to the one filter we're looking for is the easiest way to ensure we only
|
||||||
|
// get tasks in this bucket
|
||||||
|
bucketID := filter.value.(int64)
|
||||||
|
bucket := bucketMap[bucketID]
|
||||||
|
|
||||||
|
bucketMap = make(map[int64]*Bucket, 1)
|
||||||
|
bucketMap[bucketID] = bucket
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if bucketFilterIndex == 0 {
|
originalFilter := opts.filter
|
||||||
opts.filters = append(opts.filters, &taskFilter{
|
|
||||||
field: taskPropertyBucketID,
|
|
||||||
value: 0,
|
|
||||||
comparator: taskFilterComparatorEquals,
|
|
||||||
})
|
|
||||||
bucketFilterIndex = len(opts.filters) - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
for id, bucket := range bucketMap {
|
for id, bucket := range bucketMap {
|
||||||
|
|
||||||
opts.filters[bucketFilterIndex].value = id
|
if !strings.Contains(originalFilter, "bucket_id") {
|
||||||
|
var filterString string
|
||||||
|
if originalFilter == "" {
|
||||||
|
filterString = "bucket_id = " + strconv.FormatInt(id, 10)
|
||||||
|
} else {
|
||||||
|
filterString = "(" + originalFilter + ") && bucket_id = " + strconv.FormatInt(id, 10)
|
||||||
|
}
|
||||||
|
opts.filters, err = getTaskFiltersFromFilterString(filterString)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ts, _, total, err := getRawTasksForProjects(s, []*Project{{ID: bucket.ProjectID}}, auth, opts)
|
ts, _, total, err := getRawTasksForProjects(s, []*Project{{ID: bucket.ProjectID}}, auth, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -92,6 +92,30 @@ func TestBucket_ReadAll(t *testing.T) {
|
|||||||
assert.Equal(t, int64(2), buckets[0].Tasks[0].ID)
|
assert.Equal(t, int64(2), buckets[0].Tasks[0].ID)
|
||||||
assert.Equal(t, int64(33), buckets[0].Tasks[1].ID)
|
assert.Equal(t, int64(33), buckets[0].Tasks[1].ID)
|
||||||
})
|
})
|
||||||
|
t.Run("filtered by bucket", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
s := db.NewSession()
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
testuser := &user.User{ID: 1}
|
||||||
|
b := &Bucket{
|
||||||
|
ProjectID: 1,
|
||||||
|
TaskCollection: TaskCollection{
|
||||||
|
Filter: "title ~ 'task' && bucket_id = 2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
bucketsInterface, _, _, err := b.ReadAll(s, testuser, "", -1, 0)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
buckets := bucketsInterface.([]*Bucket)
|
||||||
|
assert.Len(t, buckets, 3)
|
||||||
|
assert.Len(t, buckets[0].Tasks, 0)
|
||||||
|
assert.Len(t, buckets[1].Tasks, 3)
|
||||||
|
assert.Len(t, buckets[2].Tasks, 0)
|
||||||
|
assert.Equal(t, int64(3), buckets[1].Tasks[0].ID)
|
||||||
|
assert.Equal(t, int64(4), buckets[1].Tasks[1].ID)
|
||||||
|
assert.Equal(t, int64(5), buckets[1].Tasks[2].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)
|
||||||
s := db.NewSession()
|
s := db.NewSession()
|
||||||
|
@ -105,7 +105,7 @@ func getTaskFilterOptsFromCollection(tf *TaskCollection) (opts *taskSearchOption
|
|||||||
filter: tf.Filter,
|
filter: tf.Filter,
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.filters, err = getTaskFiltersByCollections(tf)
|
opts.filters, err = getTaskFiltersFromFilterString(tf.Filter)
|
||||||
return opts, err
|
return opts, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,29 +144,29 @@ func parseFilterFromExpression(f fexpr.ExprGroup) (filter *taskFilter, err error
|
|||||||
return filter, nil
|
return filter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTaskFiltersByCollections(c *TaskCollection) (filters []*taskFilter, err error) {
|
func getTaskFiltersFromFilterString(filter string) (filters []*taskFilter, err error) {
|
||||||
|
|
||||||
if c.Filter == "" {
|
if filter == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Filter = strings.ReplaceAll(c.Filter, " in ", " ?= ")
|
filter = strings.ReplaceAll(filter, " in ", " ?= ")
|
||||||
|
|
||||||
parsedFilter, err := fexpr.Parse(c.Filter)
|
parsedFilter, err := fexpr.Parse(filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &ErrInvalidFilterExpression{
|
return nil, &ErrInvalidFilterExpression{
|
||||||
Expression: c.Filter,
|
Expression: filter,
|
||||||
ExpressionError: err,
|
ExpressionError: err,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filters = make([]*taskFilter, 0, len(parsedFilter))
|
filters = make([]*taskFilter, 0, len(parsedFilter))
|
||||||
for _, f := range parsedFilter {
|
for _, f := range parsedFilter {
|
||||||
filter, err := parseFilterFromExpression(f)
|
parsedFilter, err := parseFilterFromExpression(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
filters = append(filters, filter)
|
filters = append(filters, parsedFilter)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
Loading…
x
Reference in New Issue
Block a user