Enable a list to be moved across namespaces (#1096)
Co-authored-by: Simon Hilchenbach <simon@hilchenba.ch> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/1096 Reviewed-by: konrad <k@knt.li> Co-authored-by: shilch <simon@hilchenba.ch> Co-committed-by: shilch <simon@hilchenba.ch>
This commit is contained in:
parent
da318e3db1
commit
f7a06e4644
7 changed files with 89 additions and 4 deletions
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"go.testEnvVars": {
|
||||||
|
"VIKUNJA_SERVICE_ROOTPATH": "${workspaceRoot}"
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,9 +11,9 @@ menu:
|
||||||
# Mage
|
# Mage
|
||||||
|
|
||||||
Vikunja uses [Mage](https://magefile.org/) to script common development tasks and even releasing.
|
Vikunja uses [Mage](https://magefile.org/) to script common development tasks and even releasing.
|
||||||
Mage is a pure go solution which allows for greater flexibility and things like better paralelization.
|
Mage is a pure go solution which allows for greater flexibility and things like better parallelization.
|
||||||
|
|
||||||
This document explains what taks are available and what they do.
|
This document explains what tasks are available and what they do.
|
||||||
|
|
||||||
{{< table_of_contents >}}
|
{{< table_of_contents >}}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
// You should have received a copy of the GNU Affero General Public Licensee
|
// You should have received a copy of the GNU Affero General Public Licensee
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//go:build mage
|
||||||
// +build mage
|
// +build mage
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
@ -349,7 +350,7 @@ func (Test) Unit() {
|
||||||
mg.Deps(initVars)
|
mg.Deps(initVars)
|
||||||
setApiPackages()
|
setApiPackages()
|
||||||
// We run everything sequentially and not in parallel to prevent issues with real test databases
|
// We run everything sequentially and not in parallel to prevent issues with real test databases
|
||||||
args := append([]string{"test", Goflags[0], "-p", "1", "-timeout", "20m"}, ApiPackages...)
|
args := append([]string{"test", Goflags[0], "-p", "1", "-coverprofile", "cover.out", "-timeout", "20m"}, ApiPackages...)
|
||||||
runAndStreamOutput("go", args...)
|
runAndStreamOutput("go", args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -630,6 +630,7 @@ func UpdateList(s *xorm.Session, list *List, auth web.Auth, updateListBackground
|
||||||
"is_archived",
|
"is_archived",
|
||||||
"identifier",
|
"identifier",
|
||||||
"hex_color",
|
"hex_color",
|
||||||
|
"namespace_id",
|
||||||
"position",
|
"position",
|
||||||
}
|
}
|
||||||
if list.Description != "" {
|
if list.Description != "" {
|
||||||
|
|
|
@ -116,6 +116,25 @@ func (l *List) CanUpdate(s *xorm.Session, a web.Auth) (canUpdate bool, err error
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the list
|
||||||
|
ol, err := GetListSimpleByID(s, l.ID)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we're moving the list into a different namespace.
|
||||||
|
// If that is the case, we need to verify permissions to do so.
|
||||||
|
if l.NamespaceID != 0 && l.NamespaceID != ol.NamespaceID {
|
||||||
|
newNamespace := &Namespace{ID: l.NamespaceID}
|
||||||
|
can, err := newNamespace.CanWrite(s, a)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !can {
|
||||||
|
return false, ErrGenericForbidden{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fid := getSavedFilterIDFromListID(l.ID)
|
fid := getSavedFilterIDFromListID(l.ID)
|
||||||
if fid > 0 {
|
if fid > 0 {
|
||||||
sf, err := getSavedFilterSimpleByID(s, fid)
|
sf, err := getSavedFilterSimpleByID(s, fid)
|
||||||
|
|
|
@ -163,6 +163,65 @@ func TestList_CreateOrUpdate(t *testing.T) {
|
||||||
assert.True(t, IsErrListIdentifierIsNotUnique(err))
|
assert.True(t, IsErrListIdentifierIsNotUnique(err))
|
||||||
_ = s.Close()
|
_ = s.Close()
|
||||||
})
|
})
|
||||||
|
t.Run("change namespace", func(t *testing.T) {
|
||||||
|
t.Run("own", 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: 7, // from 6
|
||||||
|
}
|
||||||
|
can, err := list.CanUpdate(s, usr)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, can)
|
||||||
|
err = list.Update(s, usr)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = s.Commit()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
db.AssertExists(t, "lists", map[string]interface{}{
|
||||||
|
"id": list.ID,
|
||||||
|
"title": list.Title,
|
||||||
|
"description": list.Description,
|
||||||
|
"namespace_id": list.NamespaceID,
|
||||||
|
}, false)
|
||||||
|
})
|
||||||
|
// FIXME: The check for whether the namespace is archived is missing in namespace.CanWrite
|
||||||
|
// t.Run("archived own", func(t *testing.T) {
|
||||||
|
// db.LoadAndAssertFixtures(t)
|
||||||
|
// s := db.NewSession()
|
||||||
|
// list := List{
|
||||||
|
// ID: 1,
|
||||||
|
// Title: "Test1",
|
||||||
|
// Description: "Lorem Ipsum",
|
||||||
|
// NamespaceID: 16, // from 1
|
||||||
|
// }
|
||||||
|
// can, err := list.CanUpdate(s, usr)
|
||||||
|
// assert.NoError(t, err)
|
||||||
|
// assert.False(t, can) // namespace is archived and thus not writeable
|
||||||
|
// _ = s.Close()
|
||||||
|
// })
|
||||||
|
t.Run("others", func(t *testing.T) {
|
||||||
|
db.LoadAndAssertFixtures(t)
|
||||||
|
s := db.NewSession()
|
||||||
|
list := List{
|
||||||
|
ID: 1,
|
||||||
|
Title: "Test1",
|
||||||
|
Description: "Lorem Ipsum",
|
||||||
|
NamespaceID: 2, // from 1
|
||||||
|
}
|
||||||
|
can, _ := list.CanUpdate(s, usr)
|
||||||
|
assert.False(t, can) // namespace is not writeable by us
|
||||||
|
_ = s.Close()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9215,5 +9215,5 @@ func (s *s) ReadDoc() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
swag.Register(swag.Name, &s{})
|
swag.Register("swagger", &s{})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue