V1
This commit is contained in:
@@ -68,11 +68,18 @@ Deno.serve(async (req) => {
|
||||
const byId = new Map((profiles ?? []).map((pr: any) => [pr.id, pr]))
|
||||
const users = list.users.map((u) => {
|
||||
const pr: any = byId.get(u.id) ?? {}
|
||||
const roles =
|
||||
Array.isArray(pr.roles) && pr.roles.length
|
||||
? pr.roles
|
||||
: pr.role
|
||||
? [pr.role]
|
||||
: []
|
||||
return {
|
||||
id: u.id,
|
||||
email: u.email ?? '',
|
||||
full_name: pr.full_name ?? '',
|
||||
role: pr.role ?? 'other',
|
||||
roles,
|
||||
is_admin: pr.is_admin ?? false,
|
||||
created_at: pr.created_at ?? u.created_at
|
||||
}
|
||||
@@ -81,17 +88,21 @@ Deno.serve(async (req) => {
|
||||
}
|
||||
|
||||
case 'create': {
|
||||
const { email, password, full_name, role, is_admin } = p
|
||||
const { email, password, full_name, role, roles, is_admin } = p
|
||||
if (!email || !password) return json({ error: 'Email et mot de passe requis.' }, 400)
|
||||
if (String(password).length < 6)
|
||||
return json({ error: 'Le mot de passe doit faire au moins 6 caractères.' }, 400)
|
||||
|
||||
// Liste de pôles (rôles) ; le premier fait office de rôle principal.
|
||||
const roleList: string[] = Array.isArray(roles) && roles.length ? roles : role ? [role] : []
|
||||
const primary = roleList[0] ?? 'other'
|
||||
|
||||
// Crée le compte (email déjà confirmé : connexion immédiate possible).
|
||||
const { data: created, error } = await admin.auth.admin.createUser({
|
||||
email,
|
||||
password,
|
||||
email_confirm: true,
|
||||
user_metadata: { full_name: full_name || email.split('@')[0], role: role || 'other' }
|
||||
user_metadata: { full_name: full_name || email.split('@')[0], role: primary }
|
||||
})
|
||||
if (error) return json({ error: error.message }, 400)
|
||||
|
||||
@@ -100,7 +111,8 @@ Deno.serve(async (req) => {
|
||||
.from('profiles')
|
||||
.update({
|
||||
full_name: full_name || email.split('@')[0],
|
||||
role: role || 'other',
|
||||
role: primary,
|
||||
roles: roleList.length ? roleList : [primary],
|
||||
is_admin: !!is_admin
|
||||
})
|
||||
.eq('id', created.user.id)
|
||||
@@ -119,15 +131,23 @@ Deno.serve(async (req) => {
|
||||
}
|
||||
|
||||
case 'update': {
|
||||
const { id, full_name, role, is_admin } = p
|
||||
const { id, full_name, role, roles, is_admin } = p
|
||||
if (!id) return json({ error: 'Identifiant manquant.' }, 400)
|
||||
if (id === user.id && is_admin === false)
|
||||
return json({ error: 'Tu ne peux pas retirer ton propre statut admin.' }, 400)
|
||||
|
||||
const patch: Record<string, unknown> = {}
|
||||
if (full_name !== undefined) patch.full_name = full_name
|
||||
if (role !== undefined) patch.role = role
|
||||
if (is_admin !== undefined) patch.is_admin = !!is_admin
|
||||
// Gestion des pôles : roles = liste complète, role = principal (roles[0]).
|
||||
if (Array.isArray(roles)) {
|
||||
const primary = roles[0] ?? 'other'
|
||||
patch.roles = roles.length ? roles : [primary]
|
||||
patch.role = primary
|
||||
} else if (role !== undefined) {
|
||||
patch.role = role
|
||||
patch.roles = [role]
|
||||
}
|
||||
if (Object.keys(patch).length === 0) return json({ error: 'Rien à modifier.' }, 400)
|
||||
|
||||
const { error } = await admin.from('profiles').update(patch).eq('id', id)
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
-- =====================================================================
|
||||
-- GameDev Tracker — Migration v2
|
||||
-- À exécuter UNE FOIS dans : Supabase > SQL Editor > New query
|
||||
-- (pour une base déjà créée avec schema.sql v1)
|
||||
--
|
||||
-- Contenu :
|
||||
-- • Suppression des JALONS (milestones)
|
||||
-- • Notion de PÔLE sur les tâches et les bugs
|
||||
-- • Plusieurs personnes assignables sur une tâche (assignee_ids)
|
||||
-- • Système de NOTIFICATIONS (assignation à un pôle)
|
||||
-- =====================================================================
|
||||
|
||||
-- ---------- Pôle sur tâches & bugs (réutilise l'enum member_role) -----
|
||||
alter table public.tasks add column if not exists pole member_role;
|
||||
alter table public.bugs add column if not exists pole member_role;
|
||||
|
||||
-- ---------- Plusieurs assignés par tâche -----------------------------
|
||||
alter table public.tasks
|
||||
add column if not exists assignee_ids uuid[] not null default '{}';
|
||||
|
||||
-- Reprend l'assigné unique existant dans le nouveau tableau.
|
||||
update public.tasks
|
||||
set assignee_ids = array[assignee_id]
|
||||
where assignee_id is not null
|
||||
and (assignee_ids is null or assignee_ids = '{}');
|
||||
|
||||
alter table public.tasks drop column if exists assignee_id;
|
||||
|
||||
-- ---------- Suppression des jalons -----------------------------------
|
||||
alter table public.tasks drop column if exists milestone_id;
|
||||
drop table if exists public.milestones cascade;
|
||||
drop type if exists milestone_status;
|
||||
|
||||
-- ---------- Notifications --------------------------------------------
|
||||
create table if not exists public.notifications (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
user_id uuid not null references public.profiles(id) on delete cascade,
|
||||
project_id uuid references public.projects(id) on delete cascade,
|
||||
kind text not null, -- 'task' | 'bug'
|
||||
title text not null, -- ex : « Nouvelle tâche »
|
||||
body text, -- titre de la tâche / du bug
|
||||
entity_id uuid, -- id de la tâche / du bug
|
||||
pole member_role, -- pôle destinataire
|
||||
read boolean not null default false,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create index if not exists idx_notifications_user on public.notifications(user_id);
|
||||
|
||||
alter table public.notifications enable row level security;
|
||||
|
||||
-- Chacun lit/modifie SES notifications ; l'insertion est ouverte à tout
|
||||
-- membre connecté (afin de notifier les autres membres d'un pôle).
|
||||
drop policy if exists notifications_select on public.notifications;
|
||||
drop policy if exists notifications_insert on public.notifications;
|
||||
drop policy if exists notifications_update on public.notifications;
|
||||
drop policy if exists notifications_delete on public.notifications;
|
||||
|
||||
create policy notifications_select on public.notifications
|
||||
for select to authenticated using (user_id = auth.uid());
|
||||
create policy notifications_insert on public.notifications
|
||||
for insert to authenticated with check (true);
|
||||
create policy notifications_update on public.notifications
|
||||
for update to authenticated using (user_id = auth.uid()) with check (user_id = auth.uid());
|
||||
create policy notifications_delete on public.notifications
|
||||
for delete to authenticated using (user_id = auth.uid());
|
||||
|
||||
do $$ begin
|
||||
alter publication supabase_realtime add table public.notifications;
|
||||
exception when duplicate_object then null; end $$;
|
||||
@@ -0,0 +1,25 @@
|
||||
-- =====================================================================
|
||||
-- GameDev Tracker — Migration v3
|
||||
-- À exécuter UNE FOIS dans : Supabase > SQL Editor > New query
|
||||
-- (après migration_v2.sql)
|
||||
--
|
||||
-- Contenu :
|
||||
-- • Temps « libre » dans la feuille de temps (réunion, etc.) :
|
||||
-- une entrée peut ne pas être liée à une tâche du Kanban.
|
||||
-- =====================================================================
|
||||
|
||||
-- La tâche devient optionnelle ; un libellé libre la remplace si absente.
|
||||
alter table public.time_logs alter column task_id drop not null;
|
||||
alter table public.time_logs add column if not exists label text;
|
||||
|
||||
-- Rattachement direct au projet (pour retrouver aussi les entrées sans tâche).
|
||||
alter table public.time_logs
|
||||
add column if not exists project_id uuid references public.projects(id) on delete cascade;
|
||||
|
||||
-- Backfill : les entrées existantes héritent du projet de leur tâche.
|
||||
update public.time_logs tl
|
||||
set project_id = t.project_id
|
||||
from public.tasks t
|
||||
where tl.task_id = t.id and tl.project_id is null;
|
||||
|
||||
create index if not exists idx_time_logs_project on public.time_logs(project_id);
|
||||
@@ -0,0 +1,18 @@
|
||||
-- =====================================================================
|
||||
-- GameDev Tracker — Migration v4
|
||||
-- À exécuter UNE FOIS dans : Supabase > SQL Editor > New query
|
||||
-- (après migration_v3.sql)
|
||||
--
|
||||
-- Contenu :
|
||||
-- • Un membre peut appartenir à PLUSIEURS pôles (rôles).
|
||||
-- profiles.role reste le rôle « principal » ; profiles.roles
|
||||
-- contient l'ensemble des pôles.
|
||||
-- =====================================================================
|
||||
|
||||
alter table public.profiles
|
||||
add column if not exists roles member_role[] not null default '{}';
|
||||
|
||||
-- Backfill : les profils existants héritent de leur rôle unique actuel.
|
||||
update public.profiles
|
||||
set roles = array[role]
|
||||
where roles = '{}';
|
||||
+82
-28
@@ -17,10 +17,6 @@ do $$ begin
|
||||
create type priority_level as enum ('low','medium','high','urgent');
|
||||
exception when duplicate_object then null; end $$;
|
||||
|
||||
do $$ begin
|
||||
create type milestone_status as enum ('planned','in_progress','done');
|
||||
exception when duplicate_object then null; end $$;
|
||||
|
||||
do $$ begin
|
||||
create type bug_severity as enum ('low','medium','high','critical');
|
||||
exception when duplicate_object then null; end $$;
|
||||
@@ -33,8 +29,11 @@ exception when duplicate_object then null; end $$;
|
||||
create table if not exists public.profiles (
|
||||
id uuid primary key references auth.users(id) on delete cascade,
|
||||
full_name text not null default 'Membre',
|
||||
role member_role not null default 'other',
|
||||
role member_role not null default 'other', -- rôle principal (= roles[0])
|
||||
roles member_role[] not null default '{}', -- tous les pôles du membre
|
||||
avatar_color text not null default '#7c5cff',
|
||||
avatar_url text, -- photo de profil (optionnelle)
|
||||
onboarded boolean not null default false, -- a terminé l'accueil
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
@@ -47,18 +46,9 @@ create table if not exists public.projects (
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
-- ---------- Jalons (milestones) --------------------------------------
|
||||
create table if not exists public.milestones (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
project_id uuid not null references public.projects(id) on delete cascade,
|
||||
title text not null,
|
||||
description text,
|
||||
due_date date,
|
||||
status milestone_status not null default 'planned',
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
-- ---------- Tâches ---------------------------------------------------
|
||||
-- Un « pôle » (= member_role) reçoit la tâche ; une ou plusieurs
|
||||
-- personnes de ce pôle peuvent y être assignées (assignee_ids).
|
||||
create table if not exists public.tasks (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
project_id uuid not null references public.projects(id) on delete cascade,
|
||||
@@ -66,8 +56,8 @@ create table if not exists public.tasks (
|
||||
description text,
|
||||
status task_status not null default 'todo',
|
||||
priority priority_level not null default 'medium',
|
||||
assignee_id uuid references public.profiles(id) on delete set null,
|
||||
milestone_id uuid references public.milestones(id) on delete set null,
|
||||
pole member_role,
|
||||
assignee_ids uuid[] not null default '{}',
|
||||
due_date date,
|
||||
position double precision not null default 0,
|
||||
created_by uuid references public.profiles(id) on delete set null,
|
||||
@@ -84,6 +74,7 @@ create table if not exists public.bugs (
|
||||
severity bug_severity not null default 'medium',
|
||||
status bug_status not null default 'open',
|
||||
priority priority_level not null default 'medium',
|
||||
pole member_role,
|
||||
assignee_id uuid references public.profiles(id) on delete set null,
|
||||
reporter_id uuid references public.profiles(id) on delete set null,
|
||||
created_at timestamptz not null default now(),
|
||||
@@ -92,7 +83,6 @@ create table if not exists public.bugs (
|
||||
|
||||
create index if not exists idx_tasks_project on public.tasks(project_id);
|
||||
create index if not exists idx_bugs_project on public.bugs(project_id);
|
||||
create index if not exists idx_milestones_project on public.milestones(project_id);
|
||||
|
||||
-- ---------- Maj automatique de updated_at ----------------------------
|
||||
create or replace function public.touch_updated_at()
|
||||
@@ -110,12 +100,15 @@ create trigger trg_bugs_touch before update on public.bugs
|
||||
-- ---------- Création auto du profil à l'inscription ------------------
|
||||
create or replace function public.handle_new_user()
|
||||
returns trigger language plpgsql security definer set search_path = public as $$
|
||||
declare r member_role;
|
||||
begin
|
||||
insert into public.profiles (id, full_name, role)
|
||||
r := coalesce((new.raw_user_meta_data->>'role')::member_role, 'other');
|
||||
insert into public.profiles (id, full_name, role, roles)
|
||||
values (
|
||||
new.id,
|
||||
coalesce(new.raw_user_meta_data->>'full_name', split_part(new.email,'@',1)),
|
||||
coalesce((new.raw_user_meta_data->>'role')::member_role, 'other')
|
||||
r,
|
||||
array[r]
|
||||
)
|
||||
on conflict (id) do nothing;
|
||||
return new;
|
||||
@@ -130,14 +123,13 @@ create trigger on_auth_user_created
|
||||
-- Équipe privée et de confiance : tout membre connecté a accès complet.
|
||||
alter table public.profiles enable row level security;
|
||||
alter table public.projects enable row level security;
|
||||
alter table public.milestones enable row level security;
|
||||
alter table public.tasks enable row level security;
|
||||
alter table public.bugs enable row level security;
|
||||
|
||||
do $$
|
||||
declare t text;
|
||||
begin
|
||||
foreach t in array array['profiles','projects','milestones','tasks','bugs'] loop
|
||||
foreach t in array array['profiles','projects','tasks','bugs'] loop
|
||||
execute format('drop policy if exists %I_all on public.%I', t, t);
|
||||
execute format(
|
||||
'create policy %I_all on public.%I for all to authenticated using (true) with check (true)',
|
||||
@@ -152,9 +144,6 @@ exception when duplicate_object then null; end $$;
|
||||
do $$ begin
|
||||
alter publication supabase_realtime add table public.bugs;
|
||||
exception when duplicate_object then null; end $$;
|
||||
do $$ begin
|
||||
alter publication supabase_realtime add table public.milestones;
|
||||
exception when duplicate_object then null; end $$;
|
||||
do $$ begin
|
||||
alter publication supabase_realtime add table public.profiles;
|
||||
exception when duplicate_object then null; end $$;
|
||||
@@ -223,10 +212,13 @@ create trigger trg_profiles_guard_admin before update on public.profiles
|
||||
alter table public.tasks
|
||||
add column if not exists tags text[] not null default '{}';
|
||||
|
||||
-- ---------- Journal du temps passé (par tâche, par membre) -----------
|
||||
-- ---------- Journal du temps passé (par tâche OU activité libre) -----
|
||||
-- task_id null + label => temps « libre » (réunion, etc.).
|
||||
create table if not exists public.time_logs (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
task_id uuid not null references public.tasks(id) on delete cascade,
|
||||
project_id uuid references public.projects(id) on delete cascade,
|
||||
task_id uuid references public.tasks(id) on delete cascade,
|
||||
label text,
|
||||
user_id uuid references public.profiles(id) on delete set null,
|
||||
minutes integer not null check (minutes > 0),
|
||||
note text,
|
||||
@@ -235,6 +227,7 @@ create table if not exists public.time_logs (
|
||||
);
|
||||
|
||||
create index if not exists idx_time_logs_task on public.time_logs(task_id);
|
||||
create index if not exists idx_time_logs_project on public.time_logs(project_id);
|
||||
create index if not exists idx_time_logs_user on public.time_logs(user_id);
|
||||
|
||||
alter table public.time_logs enable row level security;
|
||||
@@ -245,3 +238,64 @@ create policy time_logs_all on public.time_logs
|
||||
do $$ begin
|
||||
alter publication supabase_realtime add table public.time_logs;
|
||||
exception when duplicate_object then null; end $$;
|
||||
|
||||
-- =====================================================================
|
||||
-- NOTIFICATIONS (assignation d'une tâche / d'un bug à un pôle)
|
||||
-- =====================================================================
|
||||
create table if not exists public.notifications (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
user_id uuid not null references public.profiles(id) on delete cascade,
|
||||
project_id uuid references public.projects(id) on delete cascade,
|
||||
kind text not null, -- 'task' | 'bug'
|
||||
title text not null, -- ex : « Nouvelle tâche »
|
||||
body text, -- titre de la tâche / du bug
|
||||
entity_id uuid, -- id de la tâche / du bug
|
||||
pole member_role, -- pôle destinataire
|
||||
read boolean not null default false,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
create index if not exists idx_notifications_user on public.notifications(user_id);
|
||||
|
||||
alter table public.notifications enable row level security;
|
||||
|
||||
-- Chacun lit/modifie SES notifications ; l'insertion est ouverte à tout
|
||||
-- membre connecté (afin de notifier les autres membres d'un pôle).
|
||||
drop policy if exists notifications_select on public.notifications;
|
||||
drop policy if exists notifications_insert on public.notifications;
|
||||
drop policy if exists notifications_update on public.notifications;
|
||||
drop policy if exists notifications_delete on public.notifications;
|
||||
|
||||
create policy notifications_select on public.notifications
|
||||
for select to authenticated using (user_id = auth.uid());
|
||||
create policy notifications_insert on public.notifications
|
||||
for insert to authenticated with check (true);
|
||||
create policy notifications_update on public.notifications
|
||||
for update to authenticated using (user_id = auth.uid()) with check (user_id = auth.uid());
|
||||
create policy notifications_delete on public.notifications
|
||||
for delete to authenticated using (user_id = auth.uid());
|
||||
|
||||
do $$ begin
|
||||
alter publication supabase_realtime add table public.notifications;
|
||||
exception when duplicate_object then null; end $$;
|
||||
|
||||
-- =====================================================================
|
||||
-- STOCKAGE : photos de profil (bucket "avatars")
|
||||
-- =====================================================================
|
||||
insert into storage.buckets (id, name, public)
|
||||
values ('avatars', 'avatars', true)
|
||||
on conflict (id) do nothing;
|
||||
|
||||
drop policy if exists avatars_read on storage.objects;
|
||||
drop policy if exists avatars_insert on storage.objects;
|
||||
drop policy if exists avatars_update on storage.objects;
|
||||
drop policy if exists avatars_delete on storage.objects;
|
||||
|
||||
create policy avatars_read on storage.objects
|
||||
for select using (bucket_id = 'avatars');
|
||||
create policy avatars_insert on storage.objects
|
||||
for insert to authenticated with check (bucket_id = 'avatars');
|
||||
create policy avatars_update on storage.objects
|
||||
for update to authenticated using (bucket_id = 'avatars');
|
||||
create policy avatars_delete on storage.objects
|
||||
for delete to authenticated using (bucket_id = 'avatars');
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
-- =====================================================================
|
||||
-- GameDev Tracker — Mise à jour complète (v2 + v3 + v4)
|
||||
-- À coller dans : Supabase > SQL Editor > New query > Run
|
||||
-- Sans danger si une partie a déjà été appliquée (tout est idempotent).
|
||||
-- =====================================================================
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- v2 — Pôles, assignation multiple, notifications, suppression jalons
|
||||
-- ---------------------------------------------------------------------
|
||||
alter table public.tasks add column if not exists pole member_role;
|
||||
alter table public.bugs add column if not exists pole member_role;
|
||||
|
||||
alter table public.tasks
|
||||
add column if not exists assignee_ids uuid[] not null default '{}';
|
||||
|
||||
-- Reprend l'assigné unique existant dans le tableau (si la colonne existe encore).
|
||||
do $$ begin
|
||||
if exists (select 1 from information_schema.columns
|
||||
where table_schema='public' and table_name='tasks' and column_name='assignee_id') then
|
||||
update public.tasks
|
||||
set assignee_ids = array[assignee_id]
|
||||
where assignee_id is not null and (assignee_ids is null or assignee_ids = '{}');
|
||||
alter table public.tasks drop column assignee_id;
|
||||
end if;
|
||||
end $$;
|
||||
|
||||
alter table public.tasks drop column if exists milestone_id;
|
||||
drop table if exists public.milestones cascade;
|
||||
drop type if exists milestone_status;
|
||||
|
||||
create table if not exists public.notifications (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
user_id uuid not null references public.profiles(id) on delete cascade,
|
||||
project_id uuid references public.projects(id) on delete cascade,
|
||||
kind text not null,
|
||||
title text not null,
|
||||
body text,
|
||||
entity_id uuid,
|
||||
pole member_role,
|
||||
read boolean not null default false,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
create index if not exists idx_notifications_user on public.notifications(user_id);
|
||||
alter table public.notifications enable row level security;
|
||||
|
||||
drop policy if exists notifications_select on public.notifications;
|
||||
drop policy if exists notifications_insert on public.notifications;
|
||||
drop policy if exists notifications_update on public.notifications;
|
||||
drop policy if exists notifications_delete on public.notifications;
|
||||
create policy notifications_select on public.notifications
|
||||
for select to authenticated using (user_id = auth.uid());
|
||||
create policy notifications_insert on public.notifications
|
||||
for insert to authenticated with check (true);
|
||||
create policy notifications_update on public.notifications
|
||||
for update to authenticated using (user_id = auth.uid()) with check (user_id = auth.uid());
|
||||
create policy notifications_delete on public.notifications
|
||||
for delete to authenticated using (user_id = auth.uid());
|
||||
|
||||
do $$ begin
|
||||
alter publication supabase_realtime add table public.notifications;
|
||||
exception when duplicate_object then null; end $$;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- v3 — Feuille de temps : entrées libres (réunion, etc.)
|
||||
-- ---------------------------------------------------------------------
|
||||
-- Crée la table si elle n'a jamais existé (ancienne base sans suivi du temps).
|
||||
create table if not exists public.time_logs (
|
||||
id uuid primary key default gen_random_uuid(),
|
||||
project_id uuid references public.projects(id) on delete cascade,
|
||||
task_id uuid references public.tasks(id) on delete cascade,
|
||||
label text,
|
||||
user_id uuid references public.profiles(id) on delete set null,
|
||||
minutes integer not null check (minutes > 0),
|
||||
note text,
|
||||
logged_at date not null default current_date,
|
||||
created_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
-- Si la table existait déjà (ancienne version), on l'aligne sur le nouveau format.
|
||||
alter table public.time_logs alter column task_id drop not null;
|
||||
alter table public.time_logs add column if not exists label text;
|
||||
alter table public.time_logs
|
||||
add column if not exists project_id uuid references public.projects(id) on delete cascade;
|
||||
|
||||
update public.time_logs tl
|
||||
set project_id = t.project_id
|
||||
from public.tasks t
|
||||
where tl.task_id = t.id and tl.project_id is null;
|
||||
|
||||
create index if not exists idx_time_logs_task on public.time_logs(task_id);
|
||||
create index if not exists idx_time_logs_project on public.time_logs(project_id);
|
||||
create index if not exists idx_time_logs_user on public.time_logs(user_id);
|
||||
|
||||
alter table public.time_logs enable row level security;
|
||||
drop policy if exists time_logs_all on public.time_logs;
|
||||
create policy time_logs_all on public.time_logs
|
||||
for all to authenticated using (true) with check (true);
|
||||
|
||||
do $$ begin
|
||||
alter publication supabase_realtime add table public.time_logs;
|
||||
exception when duplicate_object then null; end $$;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- v4 — Plusieurs pôles (rôles) par membre
|
||||
-- ---------------------------------------------------------------------
|
||||
alter table public.profiles
|
||||
add column if not exists roles member_role[] not null default '{}';
|
||||
|
||||
update public.profiles
|
||||
set roles = array[role]
|
||||
where roles = '{}';
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- v5 — Accueil (onboarding) des nouveaux membres
|
||||
-- ---------------------------------------------------------------------
|
||||
alter table public.profiles
|
||||
add column if not exists onboarded boolean not null default false;
|
||||
|
||||
-- Les membres déjà présents ne sont pas ré-embarqués : on les marque « fait ».
|
||||
update public.profiles set onboarded = true where onboarded = false;
|
||||
|
||||
-- ---------------------------------------------------------------------
|
||||
-- v6 — Photo de profil (avatar image) : colonne + bucket de stockage
|
||||
-- ---------------------------------------------------------------------
|
||||
alter table public.profiles add column if not exists avatar_url text;
|
||||
|
||||
-- Bucket public "avatars" pour héberger les photos de profil.
|
||||
insert into storage.buckets (id, name, public)
|
||||
values ('avatars', 'avatars', true)
|
||||
on conflict (id) do nothing;
|
||||
|
||||
-- Lecture publique ; écriture réservée aux membres connectés.
|
||||
drop policy if exists avatars_read on storage.objects;
|
||||
drop policy if exists avatars_insert on storage.objects;
|
||||
drop policy if exists avatars_update on storage.objects;
|
||||
drop policy if exists avatars_delete on storage.objects;
|
||||
|
||||
create policy avatars_read on storage.objects
|
||||
for select using (bucket_id = 'avatars');
|
||||
create policy avatars_insert on storage.objects
|
||||
for insert to authenticated with check (bucket_id = 'avatars');
|
||||
create policy avatars_update on storage.objects
|
||||
for update to authenticated using (bucket_id = 'avatars');
|
||||
create policy avatars_delete on storage.objects
|
||||
for delete to authenticated using (bucket_id = 'avatars');
|
||||
Reference in New Issue
Block a user