1
0

Favorite lists (#654)

Add tests

Remove the favorites pseudo namespace if there are no lists or tasks favorited

Regenerate swagger docs

Fix favorite lists not being updated because of nonexisting users (the favorite list does not have one)

Make the pseudo favorites list always favorited

Add favorited lists to the favorites pseudo namespace

Add favorite field to list

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: https://kolaente.dev/vikunja/api/pulls/654
This commit is contained in:
konrad
2020-09-06 14:20:16 +00:00
parent e5559137dd
commit 6bdddd462a
9 changed files with 124 additions and 14 deletions

View File

@ -57,6 +57,9 @@ type List struct {
// Holds extra information about the background set since some background providers require attribution or similar. If not null, the background can be accessed at /lists/{listID}/background
BackgroundInformation interface{} `xorm:"-" json:"background_information"`
// True if a list is a favorite. Favorite lists show up in a separate namespace.
IsFavorite bool `xorm:"default false" json:"is_favorite"`
// A timestamp when this list was created. You cannot change this value.
Created time.Time `xorm:"created not null" json:"created"`
// A timestamp when this list was last updated. You cannot change this value.
@ -80,6 +83,7 @@ var FavoritesPseudoList = List{
Title: "Favorites",
Description: "This list has all tasks marked as favorites.",
NamespaceID: FavoritesPseudoNamespace.ID,
IsFavorite: true,
Created: time.Now(),
Updated: time.Now(),
}
@ -464,7 +468,7 @@ func GenerateListIdentifier(l *List, sess *xorm.Engine) (err error) {
func CreateOrUpdateList(list *List) (err error) {
// Check if the namespace exists
if list.NamespaceID != 0 {
if list.NamespaceID != 0 && list.NamespaceID != FavoritesPseudoNamespace.ID {
_, err = GetNamespaceByID(list.NamespaceID)
if err != nil {
return err
@ -503,6 +507,7 @@ func CreateOrUpdateList(list *List) (err error) {
"is_archived",
"identifier",
"hex_color",
"is_favorite",
}
if list.Description != "" {
colsToUpdate = append(colsToUpdate, "description")

View File

@ -292,19 +292,6 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
all = append(all[:1], all[2:]...)
}
// Check if we have any favorites and remove the favorites namespace from the list if not
favoriteCount, err := x.
Join("INNER", "list", "tasks.list_id = list.id").
Join("INNER", "namespaces", "list.namespace_id = namespaces.id").
Where(builder.And(builder.Eq{"is_favorite": true}, builder.In("namespaces.id", namespaceids))).
Count(&Task{})
if err != nil {
return nil, 0, 0, err
}
if favoriteCount == 0 {
all = append(all[:0], all[1:]...)
}
// More details for the lists
err = AddListDetails(lists)
if err != nil {
@ -323,9 +310,38 @@ func (n *Namespace) ReadAll(a web.Auth, search string, page int, perPage int) (r
}
for _, list := range lists {
if list.IsFavorite {
nMap[pseudoFavoriteNamespace.ID].Lists = append(nMap[pseudoFavoriteNamespace.ID].Lists, list)
}
nMap[list.NamespaceID].Lists = append(nMap[list.NamespaceID].Lists, list)
}
// Check if we have any favorites or favorited lists and remove the favorites namespace from the list if not
var favoriteCount int64
favoriteCount, err = x.
Join("INNER", "list", "tasks.list_id = list.id").
Join("INNER", "namespaces", "list.namespace_id = namespaces.id").
Where(builder.And(builder.Eq{"tasks.is_favorite": true}, builder.In("namespaces.id", namespaceids))).
Count(&Task{})
if err != nil {
return nil, 0, 0, err
}
// If we don't have any favorites in the favorites pseudo list, remove that pseudo list from the namespace
if favoriteCount == 0 {
for in, l := range nMap[pseudoFavoriteNamespace.ID].Lists {
if l.ID == FavoritesPseudoList.ID {
nMap[pseudoFavoriteNamespace.ID].Lists = append(nMap[pseudoFavoriteNamespace.ID].Lists[:in], nMap[pseudoFavoriteNamespace.ID].Lists[in+1:]...)
break
}
}
}
// If we don't have any favorites in the namespace, remove it
if len(nMap[pseudoFavoriteNamespace.ID].Lists) == 0 {
all = append(all[:0], all[1:]...)
}
numberOfTotalItems, err = x.
Table("namespaces").
Join("LEFT", "team_namespaces", "namespaces.id = team_namespaces.namespace_id").

View File

@ -136,6 +136,8 @@ func TestNamespace_Delete(t *testing.T) {
func TestNamespace_ReadAll(t *testing.T) {
user1 := &user.User{ID: 1}
user11 := &user.User{ID: 11}
user12 := &user.User{ID: 12}
t.Run("normal", func(t *testing.T) {
n := &Namespace{}
@ -166,4 +168,21 @@ func TestNamespace_ReadAll(t *testing.T) {
assert.Equal(t, int64(-2), namespaces[0].ID) // The first one should be the one with favorites
assert.Equal(t, int64(-1), namespaces[1].ID) // The second one should be the one with the shared namespaces
})
t.Run("no favorites", func(t *testing.T) {
n := &Namespace{}
nn, _, _, err := n.ReadAll(user11, "", 1, -1)
namespaces := nn.([]*NamespaceWithLists)
assert.NoError(t, err)
// Assert the first namespace is not the favorites namespace
assert.NotEqual(t, FavoritesPseudoNamespace.ID, namespaces[0].ID)
})
t.Run("no favorite tasks but namespace", func(t *testing.T) {
n := &Namespace{}
nn, _, _, err := n.ReadAll(user12, "", 1, -1)
namespaces := nn.([]*NamespaceWithLists)
assert.NoError(t, err)
// Assert the first namespace is the favorites namespace and contains lists
assert.Equal(t, FavoritesPseudoNamespace.ID, namespaces[0].ID)
assert.NotEqual(t, 0, namespaces[0].Lists)
})
}