Add session handling for saved filters
This commit is contained in:
parent
0dd519c9e9
commit
5b76312004
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue