Shuffle/supabase/migrations/20261102100100_profiles.sql
cschlaefke 317634dac5
Some checks are pending
CI / flutter (push) Waiting to run
CI / supabase (push) Waiting to run
CI / supabase-tests (push) Waiting to run
chore: initial project kit
2026-11-02 12:14:09 +01:00

81 lines
2.9 KiB
PL/PgSQL

-- R1 Konto und Profil: profiles, Anlage beim Registrieren.
create table public.profiles (
id uuid primary key references auth.users (id) on delete cascade,
display_name text not null check (char_length(display_name) between 1 and 30),
bio text check (char_length(bio) <= 300),
city text check (char_length(city) <= 100),
city_visible boolean not null default true,
avatar_path text,
locale text not null default 'de' check (locale in ('de', 'en')),
terms_accepted_at timestamptz not null,
age_confirmed_at timestamptz not null,
deleted_at timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create trigger set_updated_at before update on public.profiles
for each row execute function public.set_updated_at();
-- Profil automatisch anlegen. Die Registrierung scheitert ohne Altersbestätigung (ab 16)
-- und ohne Zustimmung zu den Nutzungsbedingungen. Die App sendet beide als user_metadata.
create or replace function public.handle_new_user()
returns trigger
language plpgsql
security definer
set search_path = ''
as $$
declare
meta jsonb := coalesce(new.raw_user_meta_data, '{}'::jsonb);
name text;
begin
if coalesce(meta ->> 'age_confirmed', '') <> 'true' then
raise exception 'age_confirmation_required';
end if;
if coalesce(meta ->> 'terms_accepted', '') <> 'true' then
raise exception 'terms_acceptance_required';
end if;
name := left(btrim(coalesce(
nullif(btrim(meta ->> 'display_name'), ''),
nullif(split_part(new.email, '@', 1), ''),
'Spieler'
)), 30);
insert into public.profiles (id, display_name, locale, terms_accepted_at, age_confirmed_at)
values (
new.id,
name,
case when meta ->> 'locale' in ('de', 'en') then meta ->> 'locale' else 'de' end,
now(),
now()
);
return new;
end;
$$;
revoke all on function public.handle_new_user() from public, anon, authenticated;
create trigger on_auth_user_created
after insert on auth.users
for each row execute function public.handle_new_user();
-- Zugriff: Jeder sieht nur das eigene Profil. Fremde Profile gibt es nur über die View
-- public_profiles (siehe Migration plays), und dort nur für Mitspieler.
alter table public.profiles enable row level security;
revoke all on public.profiles from anon, authenticated;
grant select on public.profiles to authenticated;
-- Nur diese Spalten darf der Nutzer ändern; Bestätigungen und Löschmarke nie.
grant update (display_name, bio, city, city_visible, avatar_path, locale)
on public.profiles to authenticated;
create policy profiles_select_own on public.profiles
for select to authenticated
using (id = (select auth.uid()));
create policy profiles_update_own on public.profiles
for update to authenticated
using (id = (select auth.uid()))
with check (id = (select auth.uid()));