diff --git a/server/internal/command/fs/import.go b/server/internal/command/fs/import.go index 4d302c3f..01b258b3 100644 --- a/server/internal/command/fs/import.go +++ b/server/internal/command/fs/import.go @@ -130,7 +130,7 @@ func setupImportCommand() *cobra.Command { } return err } - return dbh.UpdateResourceModified(ctx, destParent.ID()) + return f.updateResourceModified(destParent.ID()) }) if err == nil { diff --git a/server/internal/core/db/fs.sql.go b/server/internal/core/db/fs.sql.go index 435e6422..9c03e4bf 100644 --- a/server/internal/core/db/fs.sql.go +++ b/server/internal/core/db/fs.sql.go @@ -46,120 +46,4 @@ func (q *Queries) UpdateResourceContents(ctx context.Context, arg UpdateResource arg.ID, ) return err -} - -const updateResourceModified = `-- name: UpdateResourceModified :exec -UPDATE resources -SET - modified = NOW() -WHERE id = $1 -` - -func (q *Queries) UpdateResourceModified(ctx context.Context, id uuid.UUID) error { - _, err := q.db.Exec(ctx, updateResourceModified, id) - return err -} - -const updateResourceName = `-- name: UpdateResourceName :one -UPDATE resources -SET - name = CASE WHEN ($1::text = '') THEN name ELSE $1::text END, - modified = NOW() -WHERE id = $2::uuid -RETURNING id, name, parent, dir, created, modified, deleted, content_length, content_type, content_sha256, permissions, grants -` - -type UpdateResourceNameParams struct { - Name string - ID uuid.UUID -} - -func (q *Queries) UpdateResourceName(ctx context.Context, arg UpdateResourceNameParams) (Resource, error) { - row := q.db.QueryRow(ctx, updateResourceName, arg.Name, arg.ID) - var i Resource - err := row.Scan( - &i.ID, - &i.Name, - &i.Parent, - &i.Dir, - &i.Created, - &i.Modified, - &i.Deleted, - &i.ContentLength, - &i.ContentType, - &i.ContentSha256, - &i.Permissions, - &i.Grants, - ) - return i, err -} - -const updateResourceNameParent = `-- name: UpdateResourceNameParent :one -UPDATE resources -SET - name = CASE WHEN ($1::text = '') THEN name ELSE $1::text END, - parent = $2::uuid, - modified = NOW() -WHERE id = $3::uuid -RETURNING id, name, parent, dir, created, modified, deleted, content_length, content_type, content_sha256, permissions, grants -` - -type UpdateResourceNameParentParams struct { - Name string - Parent uuid.UUID - ID uuid.UUID -} - -func (q *Queries) UpdateResourceNameParent(ctx context.Context, arg UpdateResourceNameParentParams) (Resource, error) { - row := q.db.QueryRow(ctx, updateResourceNameParent, arg.Name, arg.Parent, arg.ID) - var i Resource - err := row.Scan( - &i.ID, - &i.Name, - &i.Parent, - &i.Dir, - &i.Created, - &i.Modified, - &i.Deleted, - &i.ContentLength, - &i.ContentType, - &i.ContentSha256, - &i.Permissions, - &i.Grants, - ) - return i, err -} - -const updateResourceParent = `-- name: UpdateResourceParent :one -UPDATE resources -SET - parent = $1::uuid, - modified = NOW() -WHERE id = $2::uuid -RETURNING id, name, parent, dir, created, modified, deleted, content_length, content_type, content_sha256, permissions, grants -` - -type UpdateResourceParentParams struct { - Parent uuid.UUID - ID uuid.UUID -} - -func (q *Queries) UpdateResourceParent(ctx context.Context, arg UpdateResourceParentParams) (Resource, error) { - row := q.db.QueryRow(ctx, updateResourceParent, arg.Parent, arg.ID) - var i Resource - err := row.Scan( - &i.ID, - &i.Name, - &i.Parent, - &i.Dir, - &i.Created, - &i.Modified, - &i.Deleted, - &i.ContentLength, - &i.ContentType, - &i.ContentSha256, - &i.Permissions, - &i.Grants, - ) - return i, err -} +} \ No newline at end of file diff --git a/server/internal/core/db/fs_permissions.sql.go b/server/internal/core/db/fs_permissions.sql.go deleted file mode 100644 index d4ce1898..00000000 --- a/server/internal/core/db/fs_permissions.sql.go +++ /dev/null @@ -1,73 +0,0 @@ -// Code generated by sqlc. DO NOT EDIT. -// versions: -// sqlc v1.26.0 -// source: fs_permissions.sql - -package db - -import ( - "context" - - "github.com/google/uuid" -) - -const grantUserPermissionForResource = `-- name: GrantUserPermissionForResource :exec -UPDATE resources -SET - grants[$1::text] = jsonb_build_object('p', $2::INT, 't', EXTRACT(EPOCH FROM NOW())::INTEGER), - modified = NOW() -WHERE id = $3::uuid -RETURNING permissions -` - -type GrantUserPermissionForResourceParams struct { - Username string - Permission int32 - ResourceID uuid.UUID -} - -func (q *Queries) GrantUserPermissionForResource(ctx context.Context, arg GrantUserPermissionForResourceParams) error { - _, err := q.db.Exec(ctx, grantUserPermissionForResource, arg.Username, arg.Permission, arg.ResourceID) - return err -} - -const recomputePermissions = `-- name: RecomputePermissions :exec -WITH RECURSIVE nodes(id, parent, permissions) AS ( - SELECT r.id, r.parent, phylum_merge_permission_grants(COALESCE(p.permissions, '{}'::JSONB), r.grants) END - FROM resources r - LEFT JOIN resources p - ON r.parent = p.id - WHERE r.id = $1::uuid - UNION ALL - SELECT r.id, r.parent, phylum_merge_permission_grants(n.permissions, r.grants) - FROM resources r JOIN nodes n on r.parent = n.id -) -UPDATE resources - SET permissions = nodes.permissions - FROM nodes - WHERE resources.id = nodes.id -` - -func (q *Queries) RecomputePermissions(ctx context.Context, resourceID uuid.UUID) error { - _, err := q.db.Exec(ctx, recomputePermissions, resourceID) - return err -} - -const revokeUserPermissionForResource = `-- name: RevokeUserPermissionForResource :exec -UPDATE resources -SET - grants = grants - $1::TEXT, - modified = NOW() -WHERE id = $2::uuid -RETURNING permissions -` - -type RevokeUserPermissionForResourceParams struct { - Username string - ResourceID uuid.UUID -} - -func (q *Queries) RevokeUserPermissionForResource(ctx context.Context, arg RevokeUserPermissionForResourceParams) error { - _, err := q.db.Exec(ctx, revokeUserPermissionForResource, arg.Username, arg.ResourceID) - return err -} diff --git a/server/internal/core/fs/copy_move.go b/server/internal/core/fs/copy_move.go index 696b88d2..a483183a 100644 --- a/server/internal/core/fs/copy_move.go +++ b/server/internal/core/fs/copy_move.go @@ -36,6 +36,9 @@ func (r Resource) Move(target string, conflictResolution ResourceBindConflictRes } return Resource{}, false, err } + if r.parentID == destParent.id && r.name == destName { + return r, false, nil + } if !destParent.Dir() { return Resource{}, false, ErrResourceNotCollection } @@ -56,29 +59,44 @@ func (r Resource) Move(target string, conflictResolution ResourceBindConflictRes var deleted = false return res, deleted, r.f.runInTx(func(f filesystem) error { if conflictResolution == ResourceBindConflictResolutionOverwrite || conflictResolution == ResourceBindConflictResolutionDelete { + // TODO: Use f directly instead of Resource if _, err := destParent.DeleteChildRecursive(destName); err == nil { deleted = true } else if !errors.Is(err, ErrResourceNotFound) { return err } } - if result, err := f.db.UpdateResourceNameParent(f.ctx, db.UpdateResourceNameParentParams{ID: r.id, Name: destName, Parent: destParent.ID()}); err != nil { - if strings.Contains(err.Error(), "unique_member_resource_name") { - return ErrResourceNameConflict - } + if err := f.updateResourceNameParent(r.id, destName, destParent.ID()); err != nil { return err } else { if err := f.recomputePermissions(r.id); err != nil { return err } - res = ResourceFromDB(result) - res.f = r.f - res.userPermission = r.userPermission + res = r + res.name = destName + res.parentID = destParent.id return nil } }) } +func (f filesystem) updateResourceNameParent(id uuid.UUID, name string, parent uuid.UUID) error { + const q = `UPDATE resources +SET + name = CASE WHEN ($1::TEXT = '') THEN name ELSE $1::TEXT END, + parent = CASE WHEN ($2 IS NULL) THEN parent ELSE $2::UUID, + modified = NOW() +WHERE id = $1::UUID ` + + if _, err := f.db.Exec(f.ctx, q, id, name, &parent); err != nil { + if strings.Contains(err.Error(), "unique_member_resource_name") { + return ErrResourceNameConflict + } + return err + } + return nil +} + func (r Resource) Copy(target string, id uuid.UUID, recursive bool, conflictResolution ResourceBindConflictResolution) (Resource, bool, error) { // Check source directory permissions if !r.hasPermission(PermissionRead) { @@ -171,7 +189,7 @@ func (r Resource) Copy(target string, id uuid.UUID, recursive bool, conflictReso return err } if created { - return f.db.UpdateResourceModified(f.ctx, destParent.ID()) + return f.updateResourceModified(destParent.ID()) } return nil }) diff --git a/server/internal/core/fs/create.go b/server/internal/core/fs/create.go index 51950109..7389e730 100644 --- a/server/internal/core/fs/create.go +++ b/server/internal/core/fs/create.go @@ -60,7 +60,7 @@ func (r Resource) CreateMemberResource(name string, id uuid.UUID, dir bool, conf if err := f.recomputePermissions(r.id); err != nil { return err } - return f.db.UpdateResourceModified(f.ctx, r.id) + return f.updateResourceModified(r.id) } return nil }) diff --git a/server/internal/core/fs/resource_delete.go b/server/internal/core/fs/resource_delete.go index 97374e16..afb8c1cb 100644 --- a/server/internal/core/fs/resource_delete.go +++ b/server/internal/core/fs/resource_delete.go @@ -4,13 +4,11 @@ import ( "errors" "fmt" "path" - "strings" "time" "github.com/doug-martin/goqu/v9" "github.com/google/uuid" "github.com/jackc/pgx/v5" - "github.com/shroff/phylum/server/internal/core/db" "github.com/sirupsen/logrus" ) @@ -107,14 +105,11 @@ func (r Resource) RestoreDeleted(parentPathOrUUID string, name string, autoRenam err = r.f.runInTx(func(f filesystem) error { if p.id != r.parentID || r.name != name { - if update, err := f.db.UpdateResourceNameParent(f.ctx, db.UpdateResourceNameParentParams{ID: r.ID(), Name: name, Parent: p.id}); err != nil { - if strings.Contains(err.Error(), "unique_member_resource_name") { - return ErrResourceNameConflict - } + if err := f.updateResourceNameParent(r.ID(), name, p.id); err != nil { return err } else { - r.name = update.Name - r.parentID = update.Parent + r.name = name + r.parentID = p.id } } if del, err := f.markNotDeleted(r.id); err != nil { @@ -140,7 +135,7 @@ func (f filesystem) deleteRecursive(id, parent uuid.UUID, softDelete, preserveRo return err } - return f.db.UpdateResourceModified(f.ctx, parent) + return f.updateResourceModified(parent) }) if err == nil && !softDelete { diff --git a/server/internal/core/fs/update.go b/server/internal/core/fs/update.go new file mode 100644 index 00000000..9ff20b1e --- /dev/null +++ b/server/internal/core/fs/update.go @@ -0,0 +1,9 @@ +package fs + +import "github.com/google/uuid" + +func (f filesystem) updateResourceModified(id uuid.UUID) error { + const q = "UPDATE resources SET modified = NOW() WHERE id = $1" + _, err := f.db.Exec(f.ctx, q, id) + return err +} diff --git a/server/sql/queries/fs.sql b/server/sql/queries/fs.sql index a717353e..53196e13 100644 --- a/server/sql/queries/fs.sql +++ b/server/sql/queries/fs.sql @@ -12,35 +12,4 @@ SET content_type = $2, content_sha256 = $3, modified = NOW() -WHERE id = $4; - --- name: UpdateResourceModified :exec -UPDATE resources -SET - modified = NOW() -WHERE id = $1; - --- name: UpdateResourceParent :one -UPDATE resources -SET - parent = @parent::uuid, - modified = NOW() -WHERE id = @id::uuid -RETURNING *; - --- name: UpdateResourceName :one -UPDATE resources -SET - name = CASE WHEN (@name::text = '') THEN name ELSE @name::text END, - modified = NOW() -WHERE id = @id::uuid -RETURNING *; - --- name: UpdateResourceNameParent :one -UPDATE resources -SET - name = CASE WHEN (@name::text = '') THEN name ELSE @name::text END, - parent = @parent::uuid, - modified = NOW() -WHERE id = @id::uuid -RETURNING *; \ No newline at end of file +WHERE id = $4; \ No newline at end of file diff --git a/server/sql/queries/fs_permissions.sql b/server/sql/queries/fs_permissions.sql deleted file mode 100644 index 7d5b6be8..00000000 --- a/server/sql/queries/fs_permissions.sql +++ /dev/null @@ -1,15 +0,0 @@ --- name: GrantUserPermissionForResource :exec -UPDATE resources -SET - grants[@username::text] = jsonb_build_object('p', @permission::INT, 't', EXTRACT(EPOCH FROM NOW())::INTEGER), - modified = NOW() -WHERE id = @resource_id::uuid -RETURNING permissions; - --- name: RevokeUserPermissionForResource :exec -UPDATE resources -SET - grants = grants - @username::TEXT, - modified = NOW() -WHERE id = @resource_id::uuid -RETURNING permissions; \ No newline at end of file