mirror of
https://github.com/supabase/supabase.git
synced 2026-07-05 02:24:20 +08:00
chore: adds full schema as file to slack clone example
This commit is contained in:
162
examples/nextjs-slack-clone/full-schema.sql
Normal file
162
examples/nextjs-slack-clone/full-schema.sql
Normal file
@@ -0,0 +1,162 @@
|
||||
--
|
||||
-- For use with https://github.com/supabase/supabase/tree/master/examples/nextjs-slack-clone
|
||||
--
|
||||
|
||||
-- Custom types
|
||||
create type public.app_permission as enum ('channels.delete', 'messages.delete');
|
||||
create type public.app_role as enum ('admin', 'moderator');
|
||||
create type public.user_status as enum ('ONLINE', 'OFFLINE');
|
||||
|
||||
-- USERS
|
||||
create table public.users (
|
||||
id uuid not null primary key, -- UUID from auth.users
|
||||
username text,
|
||||
status user_status default 'OFFLINE'::public.user_status
|
||||
);
|
||||
comment on table public.users is 'Profile data for each user.';
|
||||
comment on column public.users.id is 'References the internal Supabase Auth user.';
|
||||
|
||||
-- CHANNELS
|
||||
create table public.channels (
|
||||
id bigint generated by default as identity primary key,
|
||||
inserted_at timestamp with time zone default timezone('utc'::text, now()) not null,
|
||||
slug text not null unique,
|
||||
created_by uuid references public.users not null
|
||||
);
|
||||
comment on table public.channels is 'Topics and groups.';
|
||||
|
||||
-- MESSAGES
|
||||
create table public.messages (
|
||||
id bigint generated by default as identity primary key,
|
||||
inserted_at timestamp with time zone default timezone('utc'::text, now()) not null,
|
||||
message text,
|
||||
user_id uuid references public.users not null,
|
||||
channel_id bigint references public.channels on delete cascade not null
|
||||
);
|
||||
comment on table public.messages is 'Individual messages sent by each user.';
|
||||
|
||||
-- USER ROLES
|
||||
create table public.user_roles (
|
||||
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 (
|
||||
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,
|
||||
user_id uuid
|
||||
)
|
||||
returns boolean as $$
|
||||
declare
|
||||
bind_permissions int;
|
||||
begin
|
||||
select count(*)
|
||||
from public.role_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;
|
||||
$$ language plpgsql security definer;
|
||||
|
||||
-- Secure the tables
|
||||
alter table public.users enable row level security;
|
||||
alter table public.channels enable row level security;
|
||||
alter table public.messages 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 logged-in read access" on public.channels for select using ( auth.role() = 'authenticated' );
|
||||
create policy "Allow individual insert access" on public.channels for insert with check ( auth.uid() = created_by );
|
||||
create policy "Allow individual delete access" on public.channels for delete using ( auth.uid() = created_by );
|
||||
create policy "Allow authorized delete access" on public.channels for delete using ( authorize('channels.delete', auth.uid()) );
|
||||
create policy "Allow logged-in read access" on public.messages for select using ( auth.role() = 'authenticated' );
|
||||
create policy "Allow individual insert access" on public.messages for insert with check ( auth.uid() = user_id );
|
||||
create policy "Allow individual update access" on public.messages for update using ( auth.uid() = user_id );
|
||||
create policy "Allow individual delete access" on public.messages for delete using ( auth.uid() = user_id );
|
||||
create policy "Allow authorized delete access" on public.messages for delete using ( authorize('messages.delete', auth.uid()) );
|
||||
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;
|
||||
alter table public.channels replica identity full;
|
||||
alter table public.messages 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);
|
||||
|
||||
select count(*) = 1 from auth.users into is_admin;
|
||||
|
||||
if position('+supaadmin@' in new.email) > 0 then
|
||||
insert into public.user_roles (user_id, role) values (new.id, 'admin');
|
||||
elsif position('+supamod@' in new.email) > 0 then
|
||||
insert into public.user_roles (user_id, role) values (new.id, 'moderator');
|
||||
end if;
|
||||
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql security definer;
|
||||
|
||||
-- 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();
|
||||
|
||||
/**
|
||||
* REALTIME SUBSCRIPTIONS
|
||||
* Only allow realtime listening on public tables.
|
||||
*/
|
||||
|
||||
begin;
|
||||
-- remove the realtime publication
|
||||
drop publication if exists supabase_realtime;
|
||||
|
||||
-- re-create the publication but don't enable it for any tables
|
||||
create publication supabase_realtime;
|
||||
commit;
|
||||
|
||||
-- add tables to the publication
|
||||
alter publication supabase_realtime add table public.channels;
|
||||
alter publication supabase_realtime add table public.messages;
|
||||
alter publication supabase_realtime add table public.users;
|
||||
|
||||
-- DUMMY DATA
|
||||
insert into public.users (id, username)
|
||||
values
|
||||
('8d0fd2b3-9ca7-4d9e-a95f-9e13dded323e', 'supabot');
|
||||
|
||||
insert into public.channels (slug, created_by)
|
||||
values
|
||||
('public', '8d0fd2b3-9ca7-4d9e-a95f-9e13dded323e'),
|
||||
('random', '8d0fd2b3-9ca7-4d9e-a95f-9e13dded323e');
|
||||
|
||||
insert into public.messages (message, channel_id, user_id)
|
||||
values
|
||||
('Hello World 👋', 1, '8d0fd2b3-9ca7-4d9e-a95f-9e13dded323e'),
|
||||
('Perfection is attained, not when there is nothing more to add, but when there is nothing left to take away.', 2, '8d0fd2b3-9ca7-4d9e-a95f-9e13dded323e');
|
||||
|
||||
insert into public.role_permissions (role, permission)
|
||||
values
|
||||
('admin', 'channels.delete'),
|
||||
('admin', 'messages.delete'),
|
||||
('moderator', 'messages.delete');
|
||||
|
||||
Reference in New Issue
Block a user