[server][core] WIP: UpdateResourceModified

This commit is contained in:
Abhishek Shroff
2025-03-30 13:14:12 +05:30
parent e9f4fc3f0b
commit 5ef615c009
9 changed files with 43 additions and 256 deletions

View File

@@ -130,7 +130,7 @@ func setupImportCommand() *cobra.Command {
}
return err
}
return dbh.UpdateResourceModified(ctx, destParent.ID())
return f.updateResourceModified(destParent.ID())
})
if err == nil {

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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
})

View File

@@ -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
})

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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 *;
WHERE id = $4;

View File

@@ -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;