Skip to content

Commit

Permalink
#84 - Updating policies and functions to allow creating user scoped t…
Browse files Browse the repository at this point in the history
…ags; Adding RPCs and migrations
  • Loading branch information
dleadbetter committed Nov 15, 2024
1 parent 0261b1d commit 9899466
Show file tree
Hide file tree
Showing 14 changed files with 529 additions and 3 deletions.
18 changes: 18 additions & 0 deletions SQL Scripts/functions/archive_tag_definition_rpc.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
CREATE
OR REPLACE FUNCTION archive_tag_definition_rpc(_tag_definition_id uuid)
RETURNS BOOLEAN AS $body$
BEGIN
-- Check project policy that tag definition can be updated by this user
IF NOT (check_action_policy_user_from_tag_definition(auth.uid(), _tag_definition_id))
THEN
RETURN FALSE;
END IF;

-- Archive the tag definition
UPDATE public.tag_definitions td
SET is_archived = TRUE
WHERE td.id = _tag_definition_id;

RETURN TRUE;
END
$body$ LANGUAGE plpgsql SECURITY DEFINER;
15 changes: 15 additions & 0 deletions SQL Scripts/functions/archive_tags_for_target.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
CREATE OR REPLACE FUNCTION archive_tags_for_target(_target_type tag_target_types, _target_id uuid)
RETURNS bool
AS
$body$
BEGIN
UPDATE public.tags t
SET is_archived = TRUE
FROM public.tag_definitions td
WHERE td.id = t.tag_definition_id
AND td.target_type = _target_type
AND t.target_id = _target_id;

RETURN TRUE;
END
$body$ LANGUAGE plpgsql SECURITY DEFINER;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CREATE OR REPLACE FUNCTION check_action_policy_user_from_tag_definition(user_id uuid, tag_definition_id uuid)
RETURNS bool
AS $body$
DECLARE
_scope VARCHAR;
_scope_id UUID;
BEGIN
SELECT scope, scope_id INTO _scope, _scope_id FROM public.tag_definitions WHERE id = tag_definition_id;

RETURN _scope = 'user' AND _scope_id = user_id;
END ;
$body$ LANGUAGE plpgsql SECURITY DEFINER;
4 changes: 2 additions & 2 deletions SQL Scripts/functions/check_archive_project.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
CREATE
OR REPLACE FUNCTION public.check_archive_project()
CREATE OR REPLACE FUNCTION public.check_archive_project()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
Expand All @@ -11,6 +10,7 @@ BEGIN
UPDATE public.invites AS i SET is_archived = TRUE WHERE i.project_id = OLD.id;
UPDATE public.layers AS l SET is_archived = TRUE WHERE l.project_id = OLD.id;
UPDATE public.project_groups AS p SET is_archived = TRUE WHERE p.project_id = OLD.id;
SELECT public.archive_tags_for_target('project', OLD.id);
END IF;
RETURN NEW;
END;
Expand Down
53 changes: 53 additions & 0 deletions SQL Scripts/functions/create_tags_for_tag_definitions_rpc.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
CREATE
OR REPLACE FUNCTION create_tags_for_tag_definitions_rpc(
_tag_definition_ids uuid[],
_scope tag_scope_types,
_scope_id uuid,
_target_type tag_target_types,
_target_id uuid
) RETURNS BOOLEAN AS $body$
DECLARE
_new_tag_definition_ids uuid[];
_tag_definition_id uuid;
BEGIN
-- Check authorization
IF NOT (_scope = 'user' AND _scope_id = auth.uid())
THEN
RETURN FALSE;
END IF;

-- Delete any tags that are no longer in the list of tag_definition_ids
UPDATE public.tags t
SET is_archived = TRUE
FROM public.tag_definitions td
WHERE td.id = t.tag_definition_id
AND td.scope = _scope
AND td.scope_id = _scope_id
AND td.target_type = _target_type
AND t.target_id = _target_id
AND NOT ( t.tag_definition_id = ANY( _tag_definition_ids ));

-- Create new tags
_new_tag_definition_ids := ARRAY(
SELECT id
FROM public.tag_definitions td
WHERE td.is_archived = FALSE
AND td.scope = _scope
AND td.scope_id = _scope_id
AND td.target_type = _target_type
AND td.id = ANY( _tag_definition_ids )
AND NOT EXISTS (SELECT 1
FROM public.tags t
WHERE t.tag_definition_id = td.id
AND t.target_id = _target_id
AND t.is_archived = FALSE)
);

FOREACH _tag_definition_id IN ARRAY _new_tag_definition_ids
LOOP
INSERT INTO public.tags (tag_definition_id, target_id) VALUES (_tag_definition_id, _target_id);
END LOOP;

RETURN TRUE;
END
$body$ LANGUAGE plpgsql SECURITY DEFINER;
38 changes: 38 additions & 0 deletions SQL Scripts/functions/create_tags_for_targets_rpc.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
CREATE
OR REPLACE FUNCTION create_tags_for_targets_rpc(
_tag_definition_id uuid,
_target_ids uuid[]
) RETURNS BOOLEAN AS $body$
DECLARE
_scope tag_scope_types;
_scope_id uuid;
BEGIN
SELECT td.scope, td.scope_id INTO _scope, _scope_id
FROM public.tag_definitions td
WHERE td.id = _tag_definition_id;

-- Check authorization
IF NOT (public.check_action_policy_user_from_tag_definition(auth.uid(), _tag_definition_id))
THEN
RETURN FALSE;
END IF;

-- Delete any tags that are no longer in the list of tag_definition_ids
UPDATE public.tags t
SET is_archived = TRUE
WHERE t.tag_definition_id = _tag_definition_id
AND NOT ( t.target_id = ANY( _target_ids ));

-- Create new tags
INSERT INTO public.tags (tag_definition_id, target_id)
SELECT _tag_definition_id, id
FROM UNNEST( _target_ids ) AS id
WHERE NOT EXISTS ( SELECT 1
FROM public.tags t
WHERE t.tag_definition_id = _tag_definition_id
AND t.target_id = id
AND t.is_archived = FALSE );

RETURN TRUE;
END
$body$ LANGUAGE plpgsql SECURITY DEFINER;
20 changes: 20 additions & 0 deletions SQL Scripts/policies/tag_definitions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ SELECT
SCOPE = 'system'
AND public.check_action_policy_organization (auth.uid (), 'tag_definitions', 'SELECT')
)
OR (
SCOPE = 'user'
AND created_by = auth.uid()
)
)
);

Expand All @@ -50,6 +54,10 @@ WITH
)
)
)
OR (
SCOPE = 'user'
AND created_by = auth.uid()
)
)
);

Expand All @@ -74,6 +82,10 @@ UPDATE TO authenticated USING (
)
)
)
OR (
SCOPE = 'user'
AND created_by = auth.uid()
)
)
)
WITH
Expand All @@ -95,6 +107,10 @@ WITH
)
)
)
OR (
SCOPE = 'user'
AND created_by = auth.uid()
)
)
);

Expand All @@ -118,5 +134,9 @@ CREATE POLICY "Users with correct policies can DELETE on tag_definitions" ON pub
)
)
)
OR (
SCOPE = 'user'
AND created_by = auth.uid()
)
)
);
5 changes: 5 additions & 0 deletions SQL Scripts/policies/tags.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ SELECT
AND (
public.check_action_policy_organization (auth.uid (), 'tags', 'SELECT')
OR public.check_action_policy_project_from_tag_definition (auth.uid (), 'tags', 'SELECT', tag_definition_id)
OR public.check_action_policy_user_from_tag_definition(auth.uid(), tag_definition_id)
)
);

Expand All @@ -19,6 +20,7 @@ WITH
AND (
public.check_action_policy_organization (auth.uid (), 'tags', 'INSERT')
OR public.check_action_policy_project_from_tag_definition (auth.uid (), 'tags', 'INSERT', tag_definition_id)
OR public.check_action_policy_user_from_tag_definition(auth.uid(), tag_definition_id)
)
);

Expand All @@ -30,6 +32,7 @@ UPDATE TO authenticated USING (
AND (
public.check_action_policy_organization (auth.uid (), 'tags', 'UPDATE')
OR public.check_action_policy_project_from_tag_definition (auth.uid (), 'tags', 'UPDATE', tag_definition_id)
OR public.check_action_policy_user_from_tag_definition(auth.uid(), tag_definition_id)
)
)
WITH
Expand All @@ -38,6 +41,7 @@ WITH
AND (
public.check_action_policy_organization (auth.uid (), 'tags', 'UPDATE')
OR public.check_action_policy_project_from_tag_definition (auth.uid (), 'tags', 'UPDATE', tag_definition_id)
OR public.check_action_policy_user_from_tag_definition(auth.uid(), tag_definition_id)
)
);

Expand All @@ -48,5 +52,6 @@ CREATE POLICY "Users with correct policies can DELETE on tags" ON public.tags FO
AND (
public.check_action_policy_organization (auth.uid (), 'tags', 'DELETE')
OR public.check_action_policy_project_from_tag_definition (auth.uid (), 'tags', 'DELETE', tag_definition_id)
OR public.check_action_policy_user_from_tag_definition(auth.uid(), tag_definition_id)
)
);
8 changes: 7 additions & 1 deletion SQL Scripts/tables/tag_definitions.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-- tag_definitions table --
CREATE TYPE tag_scope_types AS ENUM ('system', 'organization', 'project');
CREATE TYPE tag_scope_types AS ENUM ('system', 'organization', 'project', 'user');

CREATE TYPE tag_target_types AS ENUM ('project', 'group', 'document', 'context', 'layer', 'profile');

Expand Down Expand Up @@ -31,3 +31,9 @@ ALTER TABLE public.tag_definitions
-- Changes 10/24/24
ALTER TABLE public.tag_definitions
ADD COLUMN metadata json NOT NULL DEFAULT '{}';

-- Changes 11/8/24
ALTER TYPE tag_scope_types ADD VALUE IF NOT EXISTS 'user' AFTER 'project';

ALTER TABLE public.tag_definitions
ALTER COLUMN scope TYPE tag_scope_types USING (scope::tag_scope_types);
Loading

0 comments on commit 9899466

Please sign in to comment.