Add session handling for saved filters

This commit is contained in:
kolaente 2020-12-22 21:26:19 +01:00
parent 0dd519c9e9
commit 5b76312004
Signed by: konrad
GPG Key ID: F40E70337AB24C9B
4 changed files with 113 additions and 51 deletions

View File

@ -408,7 +408,7 @@ func (n *Namespace) ReadAll(s *xorm.Session, a web.Auth, search string, page int
/////////////////
// Saved Filters
savedFilters, err := getSavedFiltersForUser(a)
savedFilters, err := getSavedFiltersForUser(s, a)
if err != nil {
return nil, 0, 0, err
}

View File

@ -49,14 +49,14 @@ type SavedFilter struct {
}
// TableName returns a better table name for saved filters
func (s *SavedFilter) TableName() string {
func (sf *SavedFilter) TableName() string {
return "saved_filters"
}
func (s *SavedFilter) getTaskCollection() *TaskCollection {
func (sf *SavedFilter) getTaskCollection() *TaskCollection {
// We're resetting the listID to return tasks from all lists
s.Filters.ListID = 0
return s.Filters
sf.Filters.ListID = 0
return sf.Filters
}
// Returns the saved filter ID from a list ID. Will not check if the filter actually exists.
@ -80,13 +80,13 @@ func getListIDFromSavedFilterID(filterID int64) (listID int64) {
return
}
func getSavedFiltersForUser(auth web.Auth) (filters []*SavedFilter, err error) {
func getSavedFiltersForUser(s *xorm.Session, auth web.Auth) (filters []*SavedFilter, err error) {
// Link shares can't view or modify saved filters, therefore we can error out right away
if _, is := auth.(*LinkSharing); is {
return nil, ErrSavedFilterNotAvailableForLinkShare{LinkShareID: auth.GetID()}
}
err = x.Where("owner_id = ?", auth.GetID()).Find(&filters)
err = s.Where("owner_id = ?", auth.GetID()).Find(&filters)
return
}
@ -101,9 +101,9 @@ func getSavedFiltersForUser(auth web.Auth) (filters []*SavedFilter, err error) {
// @Failure 403 {object} web.HTTPError "The user does not have access to that saved filter."
// @Failure 500 {object} models.Message "Internal error"
// @Router /filters [put]
func (s *SavedFilter) Create(auth web.Auth) error {
s.OwnerID = auth.GetID()
_, err := x.Insert(s)
func (sf *SavedFilter) Create(s *xorm.Session, auth web.Auth) error {
sf.OwnerID = auth.GetID()
_, err := s.Insert(sf)
return err
}
@ -133,10 +133,10 @@ func getSavedFilterSimpleByID(s *xorm.Session, id int64) (sf *SavedFilter, err e
// @Failure 403 {object} web.HTTPError "The user does not have access to that saved filter."
// @Failure 500 {object} models.Message "Internal error"
// @Router /filters/{id} [get]
func (s *SavedFilter) ReadOne() error {
func (sf *SavedFilter) ReadOne(s *xorm.Session) error {
// s already contains almost the full saved filter from the rights check, we only need to add the user
u, err := user.GetUserByID(s.OwnerID)
s.Owner = u
u, err := user.GetUserByID(sf.OwnerID)
sf.Owner = u
return err
}
@ -153,15 +153,15 @@ func (s *SavedFilter) ReadOne() error {
// @Failure 404 {object} web.HTTPError "The saved filter does not exist."
// @Failure 500 {object} models.Message "Internal error"
// @Router /filters/{id} [post]
func (s *SavedFilter) Update() error {
_, err := x.
Where("id = ?", s.ID).
func (sf *SavedFilter) Update(s *xorm.Session) error {
_, err := s.
Where("id = ?", sf.ID).
Cols(
"title",
"description",
"filters",
).
Update(s)
Update(sf)
return err
}
@ -178,7 +178,9 @@ func (s *SavedFilter) Update() error {
// @Failure 404 {object} web.HTTPError "The saved filter does not exist."
// @Failure 500 {object} models.Message "Internal error"
// @Router /filters/{id} [delete]
func (s *SavedFilter) Delete() error {
_, err := x.Where("id = ?", s.ID).Delete(s)
func (sf *SavedFilter) Delete(s *xorm.Session) error {
_, err := s.
Where("id = ?", sf.ID).
Delete(sf)
return err
}

View File

@ -16,28 +16,31 @@
package models
import "code.vikunja.io/web"
import (
"code.vikunja.io/web"
"xorm.io/xorm"
)
// CanRead checks if a user has the right to read a saved filter
func (s *SavedFilter) CanRead(auth web.Auth) (bool, int, error) {
can, err := s.canDoFilter(auth)
func (sf *SavedFilter) CanRead(s *xorm.Session, auth web.Auth) (bool, int, error) {
can, err := sf.canDoFilter(s, auth)
return can, int(RightAdmin), err
}
// CanDelete checks if a user has the right to delete a saved filter
func (s *SavedFilter) CanDelete(auth web.Auth) (bool, error) {
return s.canDoFilter(auth)
func (sf *SavedFilter) CanDelete(s *xorm.Session, auth web.Auth) (bool, error) {
return sf.canDoFilter(s, auth)
}
// CanUpdate checks if a user has the right to update a saved filter
func (s *SavedFilter) CanUpdate(auth web.Auth) (bool, error) {
func (sf *SavedFilter) CanUpdate(s *xorm.Session, auth web.Auth) (bool, error) {
// A normal check would replace the passed struct which in our case would override the values we want to update.
sf := &SavedFilter{ID: s.ID}
return sf.canDoFilter(auth)
sff := &SavedFilter{ID: sf.ID}
return sff.canDoFilter(s, auth)
}
// CanCreate checks if a user has the right to update a saved filter
func (s *SavedFilter) CanCreate(auth web.Auth) (bool, error) {
func (sf *SavedFilter) CanCreate(s *xorm.Session, auth web.Auth) (bool, error) {
if _, is := auth.(*LinkSharing); is {
return false, nil
}
@ -46,23 +49,23 @@ func (s *SavedFilter) CanCreate(auth web.Auth) (bool, error) {
}
// Helper function to check saved filter rights sind they all have the same logic
func (s *SavedFilter) canDoFilter(auth web.Auth) (can bool, err error) {
func (sf *SavedFilter) canDoFilter(s *xorm.Session, auth web.Auth) (can bool, err error) {
// Link shares can't view or modify saved filters, therefore we can error out right away
if _, is := auth.(*LinkSharing); is {
return false, ErrSavedFilterNotAvailableForLinkShare{LinkShareID: auth.GetID(), SavedFilterID: s.ID}
return false, ErrSavedFilterNotAvailableForLinkShare{LinkShareID: auth.GetID(), SavedFilterID: sf.ID}
}
sf, err := getSavedFilterSimpleByID(s.ID)
sff, err := getSavedFilterSimpleByID(s, sf.ID)
if err != nil {
return false, err
}
// Only owners are allowed to do something with a saved filter
if sf.OwnerID != auth.GetID() {
if sff.OwnerID != auth.GetID() {
return false, nil
}
*s = *sf
*sf = *sff
return true, nil
}

View File

@ -45,6 +45,9 @@ func TestSavedFilter_getFilterIDFromListID(t *testing.T) {
func TestSavedFilter_Create(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
Title: "test",
Description: "Lorem Ipsum dolor sit amet",
@ -52,9 +55,11 @@ func TestSavedFilter_Create(t *testing.T) {
}
u := &user.User{ID: 1}
err := sf.Create(u)
err := sf.Create(s, u)
assert.NoError(t, err)
assert.Equal(t, u.ID, sf.OwnerID)
err = s.Commit()
assert.NoError(t, err)
vals := map[string]interface{}{
"title": "'test'",
"description": "'Lorem Ipsum dolor sit amet'",
@ -72,26 +77,34 @@ func TestSavedFilter_Create(t *testing.T) {
func TestSavedFilter_ReadOne(t *testing.T) {
user1 := &user.User{ID: 1}
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
}
// canRead pre-populates the struct
_, _, err := sf.CanRead(user1)
_, _, err := sf.CanRead(s, user1)
assert.NoError(t, err)
err = sf.ReadOne()
err = sf.ReadOne(s)
assert.NoError(t, err)
assert.NotNil(t, sf.Owner)
}
func TestSavedFilter_Update(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
Title: "NewTitle",
Description: "", // Explicitly reset the description
Filters: &TaskCollection{},
}
err := sf.Update()
err := sf.Update(s)
assert.NoError(t, err)
err = s.Commit()
assert.NoError(t, err)
db.AssertExists(t, "saved_filters", map[string]interface{}{
"id": 1,
@ -102,10 +115,15 @@ func TestSavedFilter_Update(t *testing.T) {
func TestSavedFilter_Delete(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
}
err := sf.Delete()
err := sf.Delete(s)
assert.NoError(t, err)
err = s.Commit()
assert.NoError(t, err)
db.AssertMissing(t, "saved_filters", map[string]interface{}{
"id": 1,
@ -120,50 +138,65 @@ func TestSavedFilter_Rights(t *testing.T) {
t.Run("create", func(t *testing.T) {
// Should always be true
db.LoadAndAssertFixtures(t)
can, err := (&SavedFilter{}).CanCreate(user1)
s := x.NewSession()
defer s.Close()
can, err := (&SavedFilter{}).CanCreate(s, user1)
assert.NoError(t, err)
assert.True(t, can)
})
t.Run("read", func(t *testing.T) {
t.Run("owner", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
Title: "Lorem",
}
can, max, err := sf.CanRead(user1)
can, max, err := sf.CanRead(s, user1)
assert.NoError(t, err)
assert.Equal(t, int(RightAdmin), max)
assert.True(t, can)
})
t.Run("not owner", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
Title: "Lorem",
}
can, _, err := sf.CanRead(user2)
can, _, err := sf.CanRead(s, user2)
assert.NoError(t, err)
assert.False(t, can)
})
t.Run("nonexisting", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 9999,
Title: "Lorem",
}
can, _, err := sf.CanRead(user1)
can, _, err := sf.CanRead(s, user1)
assert.Error(t, err)
assert.True(t, IsErrSavedFilterDoesNotExist(err))
assert.False(t, can)
})
t.Run("link share", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
Title: "Lorem",
}
can, _, err := sf.CanRead(ls)
can, _, err := sf.CanRead(s, ls)
assert.Error(t, err)
assert.True(t, IsErrSavedFilterNotAvailableForLinkShare(err))
assert.False(t, can)
@ -172,42 +205,54 @@ func TestSavedFilter_Rights(t *testing.T) {
t.Run("update", func(t *testing.T) {
t.Run("owner", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
Title: "Lorem",
}
can, err := sf.CanUpdate(user1)
can, err := sf.CanUpdate(s, user1)
assert.NoError(t, err)
assert.True(t, can)
})
t.Run("not owner", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
Title: "Lorem",
}
can, err := sf.CanUpdate(user2)
can, err := sf.CanUpdate(s, user2)
assert.NoError(t, err)
assert.False(t, can)
})
t.Run("nonexisting", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 9999,
Title: "Lorem",
}
can, err := sf.CanUpdate(user1)
can, err := sf.CanUpdate(s, user1)
assert.Error(t, err)
assert.True(t, IsErrSavedFilterDoesNotExist(err))
assert.False(t, can)
})
t.Run("link share", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
Title: "Lorem",
}
can, err := sf.CanUpdate(ls)
can, err := sf.CanUpdate(s, ls)
assert.Error(t, err)
assert.True(t, IsErrSavedFilterNotAvailableForLinkShare(err))
assert.False(t, can)
@ -216,40 +261,52 @@ func TestSavedFilter_Rights(t *testing.T) {
t.Run("delete", func(t *testing.T) {
t.Run("owner", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
}
can, err := sf.CanDelete(user1)
can, err := sf.CanDelete(s, user1)
assert.NoError(t, err)
assert.True(t, can)
})
t.Run("not owner", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
}
can, err := sf.CanDelete(user2)
can, err := sf.CanDelete(s, user2)
assert.NoError(t, err)
assert.False(t, can)
})
t.Run("nonexisting", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 9999,
Title: "Lorem",
}
can, err := sf.CanDelete(user1)
can, err := sf.CanDelete(s, user1)
assert.Error(t, err)
assert.True(t, IsErrSavedFilterDoesNotExist(err))
assert.False(t, can)
})
t.Run("link share", func(t *testing.T) {
db.LoadAndAssertFixtures(t)
s := x.NewSession()
defer s.Close()
sf := &SavedFilter{
ID: 1,
Title: "Lorem",
}
can, err := sf.CanDelete(ls)
can, err := sf.CanDelete(s, ls)
assert.Error(t, err)
assert.True(t, IsErrSavedFilterNotAvailableForLinkShare(err))
assert.False(t, can)