From ada63198a1e6fbe468f6d9174bf6e423c1c122f8 Mon Sep 17 00:00:00 2001 From: Abhishek Shroff Date: Sat, 3 Aug 2024 08:07:49 +0530 Subject: [PATCH] WIP: Permissions --- server/internal/app/resources.go | 24 +++++++++++ server/internal/command/command.go | 4 +- .../migrations/data/006_permissions.sql | 10 +++++ server/internal/sql/models.go | 6 +++ server/internal/sql/permissions.sql.go | 42 +++++++++++++++++++ server/sql/queries/permissions.sql | 10 +++++ server/sql/queries/resources.sql | 2 +- 7 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 server/internal/app/resources.go create mode 100644 server/internal/migrations/data/006_permissions.sql create mode 100644 server/internal/sql/permissions.sql.go create mode 100644 server/sql/queries/permissions.sql diff --git a/server/internal/app/resources.go b/server/internal/app/resources.go new file mode 100644 index 00000000..a4f5ffda --- /dev/null +++ b/server/internal/app/resources.go @@ -0,0 +1,24 @@ +package app + +import ( + "context" + "errors" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5" + "github.com/shroff/phylum/server/internal/sql" +) + +var ErrResourceNotFound = errors.New("resource not found") + +func (a *App) LocateResource(id uuid.UUID, username string) (uuid.UUID, int, error) { + result, err := a.Db.Queries().PermissionsForResource(context.Background(), sql.PermissionsForResourceParams{ResourceID: id, Username: username}) + if err == pgx.ErrNoRows { + err = ErrResourceNotFound + } + if err != nil { + return uuid.UUID{}, 0, err + } + + return result.ID, int(result.Permission.Int32), nil +} diff --git a/server/internal/command/command.go b/server/internal/command/command.go index eae4b2cd..892cad0d 100644 --- a/server/internal/command/command.go +++ b/server/internal/command/command.go @@ -56,7 +56,9 @@ func SetupCommand() { defer func() { logrus.Info("Shutting Down App") - app.Default.Cleanup() + if app.Default != nil { + app.Default.Cleanup() + } }() rootCmd.AddCommand([]*cobra.Command{ diff --git a/server/internal/migrations/data/006_permissions.sql b/server/internal/migrations/data/006_permissions.sql new file mode 100644 index 00000000..1670e3a2 --- /dev/null +++ b/server/internal/migrations/data/006_permissions.sql @@ -0,0 +1,10 @@ +CREATE TABLE permissions( + resource_id uuid NOT NULL, + username TEXT NOT NULL, + permission INT NOT NULL, + PRIMARY KEY(resource_id, username) +); + +---- create above / drop below ---- + +DROP TABLE permissions; \ No newline at end of file diff --git a/server/internal/sql/models.go b/server/internal/sql/models.go index 178dcacd..27266e9c 100644 --- a/server/internal/sql/models.go +++ b/server/internal/sql/models.go @@ -16,6 +16,12 @@ type AccessToken struct { Username string } +type Permission struct { + ResourceID uuid.UUID + Username string + Permission int32 +} + type Resource struct { ID uuid.UUID Parent *uuid.UUID diff --git a/server/internal/sql/permissions.sql.go b/server/internal/sql/permissions.sql.go new file mode 100644 index 00000000..a94ea754 --- /dev/null +++ b/server/internal/sql/permissions.sql.go @@ -0,0 +1,42 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.26.0 +// source: permissions.sql + +package sql + +import ( + "context" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" +) + +const permissionsForResource = `-- name: PermissionsForResource :one +WITH RECURSIVE nodes(id, parent, permission) AS ( + SELECT r.id, r.parent, p.permission + FROM resources r LEFT JOIN permissions p on r.id = p.resource_id WHERE r.id = $1::uuid AND p.username = $2::text + UNION ALL + SELECT r.id, r.parent, CASE WHEN (n.permission IS NULL OR p.permission > n.permission) THEN p.permission ELSE n.permission END + FROM resources r JOIN nodes n ON r.id = n.parent LEFT JOIN permissions p ON r.id = p.resource_id AND p.username = $2::text +) +SELECT id, parent, permission FROM nodes WHERE parent IS NULL +` + +type PermissionsForResourceParams struct { + ResourceID uuid.UUID + Username string +} + +type PermissionsForResourceRow struct { + ID uuid.UUID + Parent *uuid.UUID + Permission pgtype.Int4 +} + +func (q *Queries) PermissionsForResource(ctx context.Context, arg PermissionsForResourceParams) (PermissionsForResourceRow, error) { + row := q.db.QueryRow(ctx, permissionsForResource, arg.ResourceID, arg.Username) + var i PermissionsForResourceRow + err := row.Scan(&i.ID, &i.Parent, &i.Permission) + return i, err +} diff --git a/server/sql/queries/permissions.sql b/server/sql/queries/permissions.sql new file mode 100644 index 00000000..2b89c0b4 --- /dev/null +++ b/server/sql/queries/permissions.sql @@ -0,0 +1,10 @@ + +-- name: PermissionsForResource :one +WITH RECURSIVE nodes(id, parent, permission) AS ( + SELECT r.id, r.parent, p.permission + FROM resources r LEFT JOIN permissions p on r.id = p.resource_id WHERE r.id = @resource_id::uuid AND p.username = @username::text + UNION ALL + SELECT r.id, r.parent, CASE WHEN (n.permission IS NULL OR p.permission > n.permission) THEN p.permission ELSE n.permission END + FROM resources r JOIN nodes n ON r.id = n.parent LEFT JOIN permissions p ON r.id = p.resource_id AND p.username = @username::text +) +SELECT * FROM nodes WHERE parent IS NULL; \ No newline at end of file diff --git a/server/sql/queries/resources.sql b/server/sql/queries/resources.sql index 9157e3f3..f7fb50c8 100644 --- a/server/sql/queries/resources.sql +++ b/server/sql/queries/resources.sql @@ -80,4 +80,4 @@ WITH RECURSIVE nodes(id, parent) AS ( ) DELETE FROM resources WHERE id in (SELECT id FROM nodes) -RETURNING id, dir; \ No newline at end of file +RETURNING id, dir;