mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-07 04:00:17 -06:00
[server][core] WIP: UpdateResourceModified
This commit is contained in:
@@ -130,7 +130,7 @@ func setupImportCommand() *cobra.Command {
|
||||
}
|
||||
return err
|
||||
}
|
||||
return dbh.UpdateResourceModified(ctx, destParent.ID())
|
||||
return f.updateResourceModified(destParent.ID())
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
})
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
@@ -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 {
|
||||
|
||||
9
server/internal/core/fs/update.go
Normal file
9
server/internal/core/fs/update.go
Normal 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
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user