1
0

Add task filter for lists and namespaces (#748)

Add more tests for getting namespaces

Fix namespaces not found

Fix namespaces not found

Make like the default

Update docs & fix docs

Enable searching namespaces by their ids

Enable searching lists by their ids

Enable searching labels by their ids

Enable searching by user ids

Update docs

Add namespace filter

Add task filter for lists

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: https://kolaente.dev/vikunja/api/pulls/748
Co-Authored-By: konrad <konrad@kola-entertainments.de>
Co-Committed-By: konrad <konrad@kola-entertainments.de>
This commit is contained in:
konrad
2020-12-21 23:13:15 +00:00
parent 111efd5fae
commit 2d4e2e452c
12 changed files with 288 additions and 51 deletions

View File

@ -18,8 +18,12 @@ package models
import (
"sort"
"strconv"
"strings"
"time"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/metrics"
"code.vikunja.io/api/pkg/user"
"code.vikunja.io/web"
@ -51,6 +55,9 @@ type Namespace struct {
// A timestamp when this namespace was last updated. You cannot change this value.
Updated time.Time `xorm:"updated not null" json:"updated"`
// If set to true, will only return the namespaces, not their lists.
NamespacesOnly bool `xorm:"-" json:"-" query:"namespaces_only"`
web.CRUDable `xorm:"-" json:"-"`
web.Rights `xorm:"-" json:"-"`
}
@ -171,6 +178,19 @@ type NamespaceWithLists struct {
Lists []*List `xorm:"-" json:"lists"`
}
func makeNamespaceSliceFromMap(namespaces map[int64]*NamespaceWithLists, userMap map[int64]*user.User) []*NamespaceWithLists {
all := make([]*NamespaceWithLists, 0, len(namespaces))
for _, n := range namespaces {
n.Owner = userMap[n.OwnerID]
all = append(all, n)
}
sort.Slice(all, func(i, j int) bool {
return all[i].ID < all[j].ID
})
return all
}
// ReadAll gets all namespaces a user has access to
// @Summary Get all namespaces a user has access to
// @Description Returns all namespaces a user has access to.
@ -181,10 +201,12 @@ type NamespaceWithLists struct {
// @Param per_page query int false "The maximum number of items per page. Note this parameter is limited by the configured maximum of items per page."
// @Param s query string false "Search namespaces by name."
// @Param is_archived query bool false "If true, also returns all archived namespaces."
// @Param namespaces_only query bool false "If true, also returns only namespaces without their lists."
// @Security JWTKeyAuth
// @Success 200 {array} models.NamespaceWithLists "The Namespaces."
// @Failure 500 {object} models.Message "Internal error"
// @Router /namespaces [get]
//nolint:gocyclo
func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (result interface{}, resultCount int, numberOfTotalItems int64, err error) {
if _, is := a.(*LinkSharing); is {
return nil, 0, 0, ErrGenericForbidden{}
@ -210,6 +232,22 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
)
}
var filterCond builder.Cond = &builder.Like{"namespaces.title", "%" + search + "%"}
vals := strings.Split(search, ",")
ids := []int64{}
for _, val := range vals {
v, err := strconv.ParseInt(val, 10, 64)
if err != nil {
log.Debugf("Namespace search string part '%s' is not a number: %s", val, err)
continue
}
ids = append(ids, v)
}
if len(ids) > 0 {
filterCond = builder.In("namespaces.id", ids)
}
limit, start := getLimitFromPageIndex(page, perPage)
query := x.Select("namespaces.*").
Table("namespaces").
@ -220,7 +258,7 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
Or("namespaces.owner_id = ?", doer.ID).
Or("users_namespace.user_id = ?", doer.ID).
GroupBy("namespaces.id").
Where("namespaces.title LIKE ?", "%"+search+"%").
Where(filterCond).
Where(isArchivedCond)
if limit > 0 {
query = query.Limit(limit, start)
@ -230,6 +268,22 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
return nil, 0, 0, err
}
numberOfTotalItems, err = x.
Table("namespaces").
Join("LEFT", "team_namespaces", "namespaces.id = team_namespaces.namespace_id").
Join("LEFT", "team_members", "team_members.team_id = team_namespaces.team_id").
Join("LEFT", "users_namespace", "users_namespace.namespace_id = namespaces.id").
Where("team_members.user_id = ?", doer.ID).
Or("namespaces.owner_id = ?", doer.ID).
Or("users_namespace.user_id = ?", doer.ID).
And("namespaces.is_archived = false").
GroupBy("namespaces.id").
Where(filterCond).
Count(&NamespaceWithLists{})
if err != nil {
return nil, 0, 0, err
}
// Make a list of namespace ids
var namespaceids []int64
var userIDs []int64
@ -245,6 +299,11 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
return nil, 0, 0, err
}
if n.NamespacesOnly {
all := makeNamespaceSliceFromMap(namespaces, userMap)
return all, len(all), numberOfTotalItems, nil
}
// Get all lists
lists := []*List{}
listQuery := x.
@ -258,22 +317,6 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
return nil, 0, 0, err
}
numberOfTotalItems, err = x.
Table("namespaces").
Join("LEFT", "team_namespaces", "namespaces.id = team_namespaces.namespace_id").
Join("LEFT", "team_members", "team_members.team_id = team_namespaces.team_id").
Join("LEFT", "users_namespace", "users_namespace.namespace_id = namespaces.id").
Where("team_members.user_id = ?", doer.ID).
Or("namespaces.owner_id = ?", doer.ID).
Or("users_namespace.user_id = ?", doer.ID).
And("namespaces.is_archived = false").
GroupBy("namespaces.id").
Where("namespaces.title LIKE ?", "%"+search+"%").
Count(&NamespaceWithLists{})
if err != nil {
return nil, 0, 0, err
}
///////////////
// Shared Lists
@ -397,15 +440,7 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
//////////////////////
// Put it all together (and sort it)
all := make([]*NamespaceWithLists, 0, len(namespaces))
for _, n := range namespaces {
n.Owner = userMap[n.OwnerID]
all = append(all, n)
}
sort.Slice(all, func(i, j int) bool {
return all[i].ID < all[j].ID
})
all := makeNamespaceSliceFromMap(namespaces, userMap)
return all, len(all), numberOfTotalItems, nil
}