diff --git a/server/internal/api/routes/resources.go b/server/internal/api/routes/resources.go index 1bd9dc90..2f2fb7b1 100644 --- a/server/internal/api/routes/resources.go +++ b/server/internal/api/routes/resources.go @@ -17,7 +17,7 @@ const errCodeResourceNotCollection = "resource_not_collection" type resourceResponse struct { ID uuid.UUID `json:"id"` - Parent uuid.UUID `json:"parent"` + Parent *uuid.UUID `json:"parent"` Name string `json:"name"` Dir bool `json:"dir"` Modified time.Time `json:"modified"` diff --git a/server/internal/app/core/filesystem.go b/server/internal/app/core/filesystem.go index 40db8861..37fa4737 100644 --- a/server/internal/app/core/filesystem.go +++ b/server/internal/app/core/filesystem.go @@ -48,7 +48,7 @@ func OpenFileSystem(db *db.DbHandler, ctx context.Context, cs storage.Storage, r id: rootUUID, owner: res.Owner, permission: res.Permission, - parentID: rootUUID, + parentID: nil, name: res.Name, size: 0, collection: true, @@ -203,7 +203,8 @@ func (f filesystem) CreateMemberResource(r Resource, id uuid.UUID, name string, var result db.Resource err := f.db.RunInTx(f.ctx, func(q *db.Queries) error { var err error - if result, err = q.CreateResource(f.ctx, db.CreateResourceParams{ID: id, Owner: f.user, Parent: r.ID(), Name: name, Dir: dir}); err != nil { + parent := r.ID() + if result, err = q.CreateResource(f.ctx, db.CreateResourceParams{ID: id, Owner: f.user, Parent: &parent, Name: name, Dir: dir}); err != nil { return err } return q.UpdateResourceModified(f.ctx, r.ID()) @@ -214,7 +215,7 @@ func (f filesystem) CreateMemberResource(r Resource, id uuid.UUID, name string, return resource{ id: id, owner: r.Owner(), - parentID: r.ID(), + parentID: result.Parent, permission: r.Permission(), name: result.Name, size: 0, @@ -246,22 +247,44 @@ func (f filesystem) DeleteRecursive(r Resource, hardDelete bool) error { } } - emptyUUID := uuid.UUID{} - if r.ParentID() != emptyUUID { - return q.UpdateResourceModified(f.ctx, r.ParentID()) + parent := r.ParentID() + if parent != nil { + return q.UpdateResourceModified(f.ctx, *parent) } return nil }) } func (f filesystem) UpdateName(r Resource, name string) error { + if r.Name() == name { + return nil + } + if r.Permission() < PermissionReadWrite { + return ErrInsufficientPermissions + } return f.db.Queries().UpdateResourceName(f.ctx, db.UpdateResourceNameParams{ID: r.ID(), Name: name}) } func (f filesystem) UpdateParent(r Resource, parent uuid.UUID) error { - emptyUUID := uuid.UUID{} - if r.ParentID() == emptyUUID { - return ErrCannotReparentRootResource + if r.ParentID() == nil { + return ErrInsufficientPermissions + } + if *r.ParentID() == parent { + return nil + } + oldParent, err := f.ResourceByID(*r.ParentID()) + if err != nil { + return err + } + if oldParent.Permission() < PermissionReadWrite { + return ErrInsufficientPermissions + } + newParent, err := f.ResourceByID(parent) + if err != nil { + return err + } + if newParent.Permission() < PermissionReadWrite { + return ErrInsufficientPermissions } return f.db.Queries().UpdateResourceParent(f.ctx, db.UpdateResourceParentParams{ID: r.ID(), Parent: parent}) } diff --git a/server/internal/app/core/resource.go b/server/internal/app/core/resource.go index 557c3018..0f5b4a30 100644 --- a/server/internal/app/core/resource.go +++ b/server/internal/app/core/resource.go @@ -27,7 +27,7 @@ var ( type Resource interface { ID() uuid.UUID Owner() int32 - ParentID() uuid.UUID + ParentID() *uuid.UUID Name() string Size() int64 Permission() int32 @@ -42,7 +42,7 @@ type resource struct { id uuid.UUID owner int32 permission int32 - parentID uuid.UUID + parentID *uuid.UUID name string size int64 collection bool @@ -57,7 +57,7 @@ func (r resource) Owner() int32 { return r.owner } func (r resource) Permission() int32 { return r.permission } -func (r resource) ParentID() uuid.UUID { return r.parentID } +func (r resource) ParentID() *uuid.UUID { return r.parentID } func (r resource) Name() string { return r.name } diff --git a/server/internal/db/migrations/data/002_resources.sql b/server/internal/db/migrations/data/002_resources.sql index 5f9a696b..926410fb 100644 --- a/server/internal/db/migrations/data/002_resources.sql +++ b/server/internal/db/migrations/data/002_resources.sql @@ -1,7 +1,7 @@ CREATE TABLE resources ( id uuid PRIMARY KEY, owner INT NOT NULL REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE, - parent uuid NOT NULL REFERENCES resources(id) ON UPDATE CASCADE ON DELETE CASCADE, + parent uuid REFERENCES resources(id) ON UPDATE CASCADE ON DELETE CASCADE, name TEXT NOT NULL, dir BOOLEAN NOT NULL, created TIMESTAMP NOT NULL, @@ -13,8 +13,8 @@ CREATE TABLE resources ( INSERT INTO resources( SELECT '00000000-0000-0000-0000-000000000000', - id, - '00000000-0000-0000-0000-000000000000', + id, + NULL, 'root', true, NOW(), diff --git a/server/internal/db/models.go b/server/internal/db/models.go index 4da15215..e864dccf 100644 --- a/server/internal/db/models.go +++ b/server/internal/db/models.go @@ -25,7 +25,7 @@ type Permission struct { type Resource struct { ID uuid.UUID Owner int32 - Parent uuid.UUID + Parent *uuid.UUID Name string Dir bool Created pgtype.Timestamp diff --git a/server/internal/db/permissions.sql.go b/server/internal/db/permissions.sql.go index 792f529c..5ff62ea3 100644 --- a/server/internal/db/permissions.sql.go +++ b/server/internal/db/permissions.sql.go @@ -47,7 +47,7 @@ type ReadDirParams struct { type ReadDirRow struct { ID uuid.UUID Owner int32 - Parent uuid.UUID + Parent *uuid.UUID Name string Dir bool Created pgtype.Timestamp @@ -129,7 +129,7 @@ WITH RECURSIVE nodes(resid, id, parent, found, permission) AS ( ON r.id = n.parent LEFT JOIN permissions p ON r.id = p.resource_id AND p.user_id = $4::int - WHERE n.id != '00000000-0000-0000-0000-000000000000'::uuid + WHERE n.parent IS NOT NULL ) SELECT resid AS id, found, r.owner, permission, r.id, r.parent, name, dir, created, modified, deleted, size, etag FROM nodes n JOIN resources r @@ -150,7 +150,7 @@ type ResourceByIDRow struct { Owner int32 Permission int32 ID_2 uuid.UUID - Parent uuid.UUID + Parent *uuid.UUID Name string Dir bool Created pgtype.Timestamp @@ -219,7 +219,7 @@ type ResourceByPathParams struct { type ResourceByPathRow struct { ID uuid.UUID Owner int32 - Parent uuid.UUID + Parent *uuid.UUID Name string Dir bool Created pgtype.Timestamp @@ -269,7 +269,7 @@ SELECT r.name, r.owner, r.modified, LEFT JOIN permissions p ON p.resource_id = r.id AND p.user_id = $1::int - WHERE r.id = '00000000-0000-0000-0000-000000000000'::uuid + WHERE r.parent IS NULL ` type RootResourceRow struct { diff --git a/server/internal/db/resources.sql.go b/server/internal/db/resources.sql.go index e03563bf..e8b79917 100644 --- a/server/internal/db/resources.sql.go +++ b/server/internal/db/resources.sql.go @@ -23,7 +23,7 @@ INSERT INTO resources( type CreateResourceParams struct { ID uuid.UUID Owner int32 - Parent uuid.UUID + Parent *uuid.UUID Name string Dir bool } diff --git a/server/internal/webdav/handler.go b/server/internal/webdav/handler.go index db237322..e46a4d66 100644 --- a/server/internal/webdav/handler.go +++ b/server/internal/webdav/handler.go @@ -145,7 +145,7 @@ func (a adapter) Rename(ctx context.Context, oldName, newName string) error { return fs.ErrNotExist } - if src.ParentID() != parent.ID() { + if *src.ParentID() != parent.ID() { if err = a.fs.UpdateParent(src, parent.ID()); err != nil { return err } diff --git a/server/sql/queries/permissions.sql b/server/sql/queries/permissions.sql index 5f125bb0..12112a16 100644 --- a/server/sql/queries/permissions.sql +++ b/server/sql/queries/permissions.sql @@ -75,7 +75,7 @@ WITH RECURSIVE nodes(resid, id, parent, found, permission) AS ( ON r.id = n.parent LEFT JOIN permissions p ON r.id = p.resource_id AND p.user_id = @user_id::int - WHERE n.id != '00000000-0000-0000-0000-000000000000'::uuid + WHERE n.parent IS NOT NULL ) SELECT resid AS id, found, r.owner, permission, r.id, r.parent, name, dir, created, modified, deleted, size, etag FROM nodes n JOIN resources r @@ -93,7 +93,7 @@ SELECT r.name, r.owner, r.modified, LEFT JOIN permissions p ON p.resource_id = r.id AND p.user_id = @user_id::int - WHERE r.id = '00000000-0000-0000-0000-000000000000'::uuid; + WHERE r.parent IS NULL; -- name: UpdatePermissionsForResource :exec INSERT INTO permissions(resource_id, user_id, permission)