-- -- For use with https://github.com/supabase/supabase/tree/master/examples/slack-clone/nextjs-slack-clone -- -- Custom types create type public.app_permission as enum ('events.see.hidden'); create type public.app_role as enum ('sa', 'gm'); -- USERS create table public.users ( id uuid references auth.users not null primary key, -- UUID from auth.users username text ); comment on table public.users is 'Profile data for each user.'; comment on column public.users.id is 'References the internal Supabase Auth user.'; -- USER ROLES create table public.user_roles ( id bigint generated by default as identity primary key, user_id uuid references public.users on delete cascade not null, role app_role not null, unique (user_id, role) ); comment on table public.user_roles is 'Application roles for each user.'; -- ROLE PERMISSIONS create table public.role_permissions ( id bigint generated by default as identity primary key, role app_role not null, permission app_permission not null, unique (role, permission) ); comment on table public.role_permissions is 'Application permissions for each role.'; -- authorize with role-based access control (RBAC) create function public.authorize( requested_permission app_permission ) returns boolean as $$ declare bind_permissions int; begin select count(*) from public.role_permissions where role_permissions.permission = authorize.requested_permission and role_permissions.role = (auth.jwt() ->> 'user_role')::public.app_role into bind_permissions; return bind_permissions > 0; end; $$ language plpgsql security definer set search_path = public; -- Secure the tables alter table public.users enable row level security; alter table public.user_roles enable row level security; alter table public.role_permissions enable row level security; create policy "Allow logged-in read access" on public.users for select using ( auth.role() = 'authenticated' ); create policy "Allow individual insert access" on public.users for insert with check ( auth.uid() = id ); create policy "Allow individual update access" on public.users for update using ( auth.uid() = id ); create policy "Allow individual read access" on public.user_roles for select using ( auth.uid() = user_id ); -- Send "previous data" on change alter table public.users replica identity full; -- inserts a row into public.users and assigns roles create function public.handle_new_user() returns trigger as $$ declare is_admin boolean; begin insert into public.users (id, username) values (new.id, new.email); return new; end; $$ language plpgsql security definer set search_path = auth, public; -- trigger the function every time a user is created create trigger on_auth_user_created after insert on auth.users for each row execute procedure public.handle_new_user(); /** * HELPER FUNCTIONS * Create test user helper method. */ create or replace function public.create_user( email text ) returns uuid security definer set search_path = auth as $$ declare user_id uuid; begin user_id := extensions.uuid_generate_v4(); insert into auth.users (id, email) values (user_id, email) returning id into user_id; return user_id; end; $$ language plpgsql;