From 3ccc6365a6892f37ee54b0750a34a61e52f6dba1 Mon Sep 17 00:00:00 2001 From: kolaente Date: Mon, 15 Aug 2022 23:25:35 +0200 Subject: [PATCH] fix: prevent moving a list into a pseudo namespace --- docs/content/doc/usage/errors.md | 19 ++++++++++--------- pkg/models/error.go | 30 +++++++++++++++++++++++++++++- pkg/models/list.go | 4 ++++ pkg/models/list_test.go | 19 +++++++++++++++++++ 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/docs/content/doc/usage/errors.md b/docs/content/doc/usage/errors.md index f5325ddd7..521d93ee3 100644 --- a/docs/content/doc/usage/errors.md +++ b/docs/content/doc/usage/errors.md @@ -4,8 +4,8 @@ title: "Errors" draft: false type: "doc" menu: - sidebar: - parent: "usage" +sidebar: +parent: "usage" --- # Errors @@ -52,14 +52,15 @@ This document describes the different errors Vikunja can return. ## List -| ErrorCode | HTTP Status Code | Description | -|-----------|------------------|-------------| -| 3001 | 404 | The list does not exist. | -| 3004 | 403 | The user needs to have read permissions on that list to perform that action. | -| 3005 | 400 | The list title cannot be empty. | -| 3006 | 404 | The list share does not exist. | -| 3007 | 400 | A list with this identifier already exists. | +| ErrorCode | HTTP Status Code | Description | +|-----------|------------------|-------------------------------------------------------------------------------------------------------------------------------| +| 3001 | 404 | The list does not exist. | +| 3004 | 403 | The user needs to have read permissions on that list to perform that action. | +| 3005 | 400 | The list title cannot be empty. | +| 3006 | 404 | The list share does not exist. | +| 3007 | 400 | A list with this identifier already exists. | | 3008 | 412 | The list is archived and can therefore only be accessed read only. This is also true for all tasks associated with this list. | +| 3009 | 412 | The list cannot belong to a dynamically generated namespace like "Favorites". | ## Task diff --git a/pkg/models/error.go b/pkg/models/error.go index 8f97d24c2..eb96d5425 100644 --- a/pkg/models/error.go +++ b/pkg/models/error.go @@ -237,7 +237,7 @@ type ErrListIsArchived struct { ListID int64 } -// IsErrListIsArchived checks if an error is a . +// IsErrListIsArchived checks if an error is a list is archived error. func IsErrListIsArchived(err error) bool { _, ok := err.(ErrListIsArchived) return ok @@ -255,6 +255,34 @@ func (err ErrListIsArchived) HTTPError() web.HTTPError { return web.HTTPError{HTTPCode: http.StatusPreconditionFailed, Code: ErrCodeListIsArchived, Message: "This list is archived. Editing or creating new tasks is not possible."} } +// ErrListCannotBelongToAPseudoNamespace represents an error where a list cannot belong to a pseudo namespace +type ErrListCannotBelongToAPseudoNamespace struct { + ListID int64 + NamespaceID int64 +} + +// IsErrListCannotBelongToAPseudoNamespace checks if an error is a list is archived error. +func IsErrListCannotBelongToAPseudoNamespace(err error) bool { + _, ok := err.(*ErrListCannotBelongToAPseudoNamespace) + return ok +} + +func (err *ErrListCannotBelongToAPseudoNamespace) Error() string { + return fmt.Sprintf("List cannot belong to a pseudo namespace [ListID: %d, NamespaceID: %d]", err.ListID, err.NamespaceID) +} + +// ErrCodeListCannotBelongToAPseudoNamespace holds the unique world-error code of this error +const ErrCodeListCannotBelongToAPseudoNamespace = 3009 + +// HTTPError holds the http error description +func (err *ErrListCannotBelongToAPseudoNamespace) HTTPError() web.HTTPError { + return web.HTTPError{ + HTTPCode: http.StatusPreconditionFailed, + Code: ErrCodeListCannotBelongToAPseudoNamespace, + Message: "This list cannot belong a dynamically generated namespace.", + } +} + // ================ // List task errors // ================ diff --git a/pkg/models/list.go b/pkg/models/list.go index 8857050fa..822943f8d 100644 --- a/pkg/models/list.go +++ b/pkg/models/list.go @@ -543,6 +543,10 @@ func (l *List) CheckIsArchived(s *xorm.Session) (err error) { } func checkListBeforeUpdateOrDelete(s *xorm.Session, list *List) error { + if list.NamespaceID < 0 { + return &ErrListCannotBelongToAPseudoNamespace{ListID: list.ID, NamespaceID: list.NamespaceID} + } + // Check if the namespace exists if list.NamespaceID > 0 { _, err := GetNamespaceByID(s, list.NamespaceID) diff --git a/pkg/models/list_test.go b/pkg/models/list_test.go index 843aad961..4f02b78ee 100644 --- a/pkg/models/list_test.go +++ b/pkg/models/list_test.go @@ -221,6 +221,25 @@ func TestList_CreateOrUpdate(t *testing.T) { assert.False(t, can) // namespace is not writeable by us _ = s.Close() }) + t.Run("pseudo namespace", func(t *testing.T) { + usr := &user.User{ + ID: 6, + Username: "user6", + Email: "user6@example.com", + } + + db.LoadAndAssertFixtures(t) + s := db.NewSession() + list := List{ + ID: 6, + Title: "Test6", + Description: "Lorem Ipsum", + NamespaceID: -1, + } + err := list.Update(s, usr) + assert.Error(t, err) + assert.True(t, IsErrListCannotBelongToAPseudoNamespace(err)) + }) }) }) }