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 {
|
||||
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
|
||||
|
@ -17,6 +17,8 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"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.filterConcat = filterConcatAnd
|
||||
|
||||
var bucketFilterIndex int
|
||||
for i, filter := range opts.filters {
|
||||
for _, filter := range opts.filters {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
if bucketFilterIndex == 0 {
|
||||
opts.filters = append(opts.filters, &taskFilter{
|
||||
field: taskPropertyBucketID,
|
||||
value: 0,
|
||||
comparator: taskFilterComparatorEquals,
|
||||
})
|
||||
bucketFilterIndex = len(opts.filters) - 1
|
||||
}
|
||||
|
||||
originalFilter := opts.filter
|
||||
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)
|
||||
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(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) {
|
||||
db.LoadAndAssertFixtures(t)
|
||||
s := db.NewSession()
|
||||
|
@ -105,7 +105,7 @@ func getTaskFilterOptsFromCollection(tf *TaskCollection) (opts *taskSearchOption
|
||||
filter: tf.Filter,
|
||||
}
|
||||
|
||||
opts.filters, err = getTaskFiltersByCollections(tf)
|
||||
opts.filters, err = getTaskFiltersFromFilterString(tf.Filter)
|
||||
return opts, err
|
||||
}
|
||||
|
||||
|
@ -144,29 +144,29 @@ func parseFilterFromExpression(f fexpr.ExprGroup) (filter *taskFilter, err error
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
return nil, &ErrInvalidFilterExpression{
|
||||
Expression: c.Filter,
|
||||
Expression: filter,
|
||||
ExpressionError: err,
|
||||
}
|
||||
}
|
||||
|
||||
filters = make([]*taskFilter, 0, len(parsedFilter))
|
||||
for _, f := range parsedFilter {
|
||||
filter, err := parseFilterFromExpression(f)
|
||||
parsedFilter, err := parseFilterFromExpression(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filters = append(filters, filter)
|
||||
filters = append(filters, parsedFilter)
|
||||
}
|
||||
|
||||
return
|
||||
|
Loading…
x
Reference in New Issue
Block a user