Skip to content
This repository has been archived by the owner on Aug 17, 2022. It is now read-only.

Commit

Permalink
Merge pull request #4 from technologiestiftung/staging
Browse files Browse the repository at this point in the history
  • Loading branch information
ff6347 authored Apr 5, 2022
2 parents e8a9a23 + f7ade6a commit 3bfcd6a
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 4 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# 1.0.0-rc.1 (2022-04-05)


### Features

* **profiles:** adds user profiles and permission model ([66c4f31](https://github.com/technologiestiftung/qtrees-backend/commit/66c4f31be8abbdaa7904219e5c3d31cccdccd6bd))
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
},
"name": "@technologiestiftung/qtrees-backend",
"description": "Backend / API of Qtrees",
"version": "0.1.0",
"version": "1.0.0-rc.1",
"scripts": {
"test": "jest"
},
Expand Down
2 changes: 1 addition & 1 deletion sql/create-users-and-permissions.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-- setup is detived from https://github.com/supabase/supabase/blob/a45a8114c1e38af87de4b1af820c97a883777364/examples/nextjs-slack-clone/readme.md
-- setup is derived from https://github.com/supabase/supabase/blob/a45a8114c1e38af87de4b1af820c97a883777364/examples/nextjs-slack-clone/readme.md
-- access scope types
create type public.app_permission as enum ('tree.update');
-- for example ALTER TYPE public.app_permission ADD VALUE 'tree.delete' AFTER 'redtree.update';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
-- This script was generated by the Schema Diff utility in pgAdmin 4
-- For the circular dependencies, the order in which Schema Diff writes the objects is not very sophisticated
-- and may require manual changes to the script to ensure changes are applied in the correct order.
-- Please report an issue for any failure with the reproduction steps.
-- Type: app_permission
-- DROP TYPE IF EXISTS public.app_permission;
CREATE TYPE public.app_permission AS ENUM ('tree.update');
ALTER TYPE public.app_permission OWNER TO postgres;
-- Type: app_role
-- DROP TYPE IF EXISTS public.app_role;
CREATE TYPE public.app_role AS ENUM ('admin', 'editor', 'viewer');
ALTER TYPE public.app_role OWNER TO postgres;
--
--
--
-- user profiles
CREATE TABLE IF NOT EXISTS public.profiles (
id uuid NOT NULL,
updated_at timestamp with time zone,
username text COLLATE pg_catalog."default",
CONSTRAINT profiles_pkey PRIMARY KEY (id),
CONSTRAINT profiles_username_key UNIQUE (username),
CONSTRAINT profiles_id_fkey FOREIGN KEY (id) REFERENCES auth.users (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT username_length CHECK (char_length(username) >= 3),
CONSTRAINT special_char CHECK (username ~* '^[a-za-z0-9_-]*$'::text)
) TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.profiles OWNER to postgres;
ALTER TABLE IF EXISTS public.profiles ENABLE ROW LEVEL SECURITY;
GRANT ALL ON TABLE public.profiles TO anon;
GRANT ALL ON TABLE public.profiles TO authenticated;
GRANT ALL ON TABLE public.profiles TO postgres;
GRANT ALL ON TABLE public.profiles TO service_role;
CREATE UNIQUE INDEX IF NOT EXISTS user_name_case_insensitive ON public.profiles USING btree (
lower(username) COLLATE pg_catalog."default" ASC NULLS LAST
) TABLESPACE pg_default;
--
--
--
-- user roles
CREATE TABLE IF NOT EXISTS public.user_roles (
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY (
INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1
),
user_id uuid NOT NULL,
role app_role NOT NULL,
CONSTRAINT user_roles_pkey PRIMARY KEY (id),
CONSTRAINT user_roles_user_id_role_key UNIQUE (user_id, role),
CONSTRAINT user_roles_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.profiles (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE
) TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.user_roles OWNER to postgres;
ALTER TABLE IF EXISTS public.user_roles ENABLE ROW LEVEL SECURITY;
GRANT ALL ON TABLE public.user_roles TO anon;
GRANT ALL ON TABLE public.user_roles TO authenticated;
GRANT ALL ON TABLE public.user_roles TO postgres;
GRANT ALL ON TABLE public.user_roles TO service_role;
COMMENT ON TABLE public.user_roles IS 'Application roles for each user';
--
--
--
--
--
-- role permissions
CREATE TABLE IF NOT EXISTS public.role_permissions (
id bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY (
INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 9223372036854775807 CACHE 1
),
role app_role NOT NULL,
permission app_permission NOT NULL,
CONSTRAINT role_permissions_pkey PRIMARY KEY (id),
CONSTRAINT role_permissions_role_permission_key UNIQUE (role, permission)
) TABLESPACE pg_default;
ALTER TABLE IF EXISTS public.role_permissions OWNER to postgres;
ALTER TABLE IF EXISTS public.role_permissions ENABLE ROW LEVEL SECURITY;
GRANT ALL ON TABLE public.role_permissions TO anon;
GRANT ALL ON TABLE public.role_permissions TO authenticated;
GRANT ALL ON TABLE public.role_permissions TO postgres;
GRANT ALL ON TABLE public.role_permissions TO service_role;
COMMENT ON TABLE public.role_permissions IS 'Application permissions for each role';
--
--
--
--
-- functions
CREATE OR REPLACE FUNCTION public.authorizate(
requested_permission app_permission,
user_id uuid
) RETURNS boolean LANGUAGE 'plpgsql' COST 100 VOLATILE SECURITY DEFINER PARALLEL UNSAFE AS $BODY$
declare bind_permissions int;
begin
select count(*)
from public.permissions
inner join public.user_roles on role_permissions.role = user_roles.role
where role_permissions.permission = authorize.requested_permission
and user_roles.user_id = authorize.user_id into bind_permissions;
return bind_permissions > 0;
end;
$BODY$;
ALTER FUNCTION public.authorizate(app_permission, uuid) OWNER TO postgres;
GRANT EXECUTE ON FUNCTION public.authorizate(app_permission, uuid) TO PUBLIC;
GRANT EXECUTE ON FUNCTION public.authorizate(app_permission, uuid) TO anon;
GRANT EXECUTE ON FUNCTION public.authorizate(app_permission, uuid) TO authenticated;
GRANT EXECUTE ON FUNCTION public.authorizate(app_permission, uuid) TO postgres;
GRANT EXECUTE ON FUNCTION public.authorizate(app_permission, uuid) TO service_role;
--
--
--
CREATE OR REPLACE FUNCTION public.handle_new_user() RETURNS trigger LANGUAGE 'plpgsql' COST 100 VOLATILE NOT LEAKPROOF SECURITY DEFINER AS $BODY$
declare is_admin boolean;
begin
insert into public.users (id, username)
values (new.id, new.email);
select count(*) = 1
from auth.users into is_admin;
insert into public.user_roles (user_id, role)
values (new.id, 'viewer');
return new;
end;
$BODY$;
ALTER FUNCTION public.handle_new_user() OWNER TO postgres;
GRANT EXECUTE ON FUNCTION public.handle_new_user() TO authenticated;
GRANT EXECUTE ON FUNCTION public.handle_new_user() TO postgres;
GRANT EXECUTE ON FUNCTION public.handle_new_user() TO PUBLIC;
GRANT EXECUTE ON FUNCTION public.handle_new_user() TO anon;
GRANT EXECUTE ON FUNCTION public.handle_new_user() TO service_role;
--
--
-- policies
-- user role
CREATE POLICY "Allow individual read access" ON public.user_roles AS PERMISSIVE FOR
SELECT TO public USING ((auth.uid() = user_id));
-- user profiles
CREATE POLICY "public profiles are viewable by everyone." ON public.profiles AS PERMISSIVE FOR
SELECT TO public USING (true);
CREATE POLICY "users can insert their own profile." ON public.profiles AS PERMISSIVE FOR
INSERT TO public WITH CHECK ((auth.uid() = id));
CREATE POLICY "users can update own profile." ON public.profiles AS PERMISSIVE FOR
UPDATE TO public USING ((auth.uid() = id));

0 comments on commit 3bfcd6a

Please sign in to comment.