Files
root-org/supabase/migrations/056_definitive_rls_fix.sql
2026-02-09 11:36:39 +02:00

867 lines
31 KiB
PL/PgSQL

-- ============================================================
-- Migration 056: Definitive RLS fix
--
-- Root cause: (select auth.uid()) inside a policy that queries
-- org_members triggers PostgreSQL 42P17 infinite recursion,
-- because org_members' own SELECT policy also queries org_members.
--
-- Fix (per Supabase docs tip #4 & #5):
-- 1. Create SECURITY DEFINER helper functions that bypass RLS
-- 2. Use those in all policies — no self-referencing, no recursion
-- 3. Wrap function calls in (select ...) for InitPlan caching
-- ============================================================
-- ============================================================
-- STEP 1: Create helper functions (SECURITY DEFINER = bypass RLS)
-- ============================================================
-- Returns all org_ids the current user belongs to
CREATE OR REPLACE FUNCTION public.get_user_org_ids()
RETURNS SETOF uuid
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = ''
AS $$
SELECT org_members.org_id FROM public.org_members WHERE user_id = auth.uid();
$$;
-- Returns the user's role in a specific org (or NULL if not a member)
CREATE OR REPLACE FUNCTION public.get_user_org_role(org_id uuid)
RETURNS text
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = ''
AS $$
SELECT role FROM public.org_members
WHERE org_members.org_id = get_user_org_role.org_id AND user_id = auth.uid()
LIMIT 1;
$$;
-- is_org_member already exists from migration 039, just ensure it's correct
CREATE OR REPLACE FUNCTION public.is_org_member(org_id uuid)
RETURNS boolean
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = ''
AS $$
SELECT EXISTS (
SELECT 1 FROM public.org_members
WHERE org_members.org_id = is_org_member.org_id
AND user_id = auth.uid()
);
$$;
-- Returns true if user has editor+ role in the given org
CREATE OR REPLACE FUNCTION public.is_org_editor(org_id uuid)
RETURNS boolean
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = ''
AS $$
SELECT EXISTS (
SELECT 1 FROM public.org_members
WHERE org_members.org_id = is_org_editor.org_id
AND user_id = auth.uid()
AND role IN ('owner', 'admin', 'editor')
);
$$;
-- Returns true if user has admin+ role in the given org
CREATE OR REPLACE FUNCTION public.is_org_admin(org_id uuid)
RETURNS boolean
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = ''
AS $$
SELECT EXISTS (
SELECT 1 FROM public.org_members
WHERE org_members.org_id = is_org_admin.org_id
AND user_id = auth.uid()
AND role IN ('owner', 'admin')
);
$$;
-- ============================================================
-- STEP 2: Drop ALL existing policies on all public tables
-- ============================================================
DO $$
DECLARE
r record;
BEGIN
FOR r IN
SELECT schemaname, tablename, policyname
FROM pg_policies
WHERE schemaname = 'public'
LOOP
EXECUTE format('DROP POLICY IF EXISTS %I ON %I.%I',
r.policyname, r.schemaname, r.tablename);
END LOOP;
END;
$$;
-- ============================================================
-- STEP 3: Recreate ALL policies using helper functions
-- ============================================================
-- ── profiles ──
CREATE POLICY "Profiles are viewable by everyone" ON public.profiles
FOR SELECT TO authenticated USING (true);
CREATE POLICY "Users can update own profile" ON public.profiles
FOR UPDATE TO authenticated USING ((select auth.uid()) = id);
-- ── organizations ──
CREATE POLICY "Anyone can create organizations" ON public.organizations
FOR INSERT TO authenticated WITH CHECK (true);
CREATE POLICY "Members can view their organizations" ON public.organizations
FOR SELECT TO authenticated
USING (
(select public.is_platform_admin())
OR (select public.is_org_member(id))
);
CREATE POLICY "Admins can update organizations" ON public.organizations
FOR UPDATE TO authenticated
USING (
(select public.is_platform_admin())
OR (select public.is_org_admin(id))
)
WITH CHECK (
(select public.is_platform_admin())
OR (select public.is_org_admin(id))
);
CREATE POLICY "Owners can delete organizations" ON public.organizations
FOR DELETE TO authenticated
USING (
(select public.is_platform_admin())
OR EXISTS (
SELECT 1 FROM public.org_members
WHERE org_id = organizations.id AND user_id = auth.uid() AND role = 'owner'
)
);
-- ── org_members ──
-- KEY FIX: use get_user_org_ids() to avoid self-referencing recursion
CREATE POLICY "Members can view org members" ON public.org_members
FOR SELECT TO authenticated
USING (org_id IN (select public.get_user_org_ids()));
CREATE POLICY "Allow member inserts" ON public.org_members
FOR INSERT TO authenticated
WITH CHECK (
(select public.is_org_admin(org_id))
OR org_members.user_id = (select auth.uid())
);
CREATE POLICY "Admins can update members" ON public.org_members
FOR UPDATE TO authenticated
USING ((select public.is_org_admin(org_id)))
WITH CHECK ((select public.is_org_admin(org_id)));
CREATE POLICY "Admins can delete members" ON public.org_members
FOR DELETE TO authenticated
USING ((select public.is_org_admin(org_id)));
-- ── org_roles ──
CREATE POLICY "Org members can view roles" ON public.org_roles
FOR SELECT TO authenticated
USING ((select public.is_org_member(org_id)));
CREATE POLICY "Admins can manage roles" ON public.org_roles
FOR ALL TO authenticated
USING ((select public.is_org_admin(org_id)));
-- ── org_invites ──
CREATE POLICY "Anyone can view invite by token" ON public.org_invites
FOR SELECT TO anon, authenticated USING (true);
CREATE POLICY "Admins can manage invites" ON public.org_invites
FOR ALL TO authenticated
USING ((select public.is_org_admin(org_id)));
-- ── documents ──
CREATE POLICY "Members can manage documents" ON public.documents
FOR ALL TO authenticated
USING ((select public.is_org_member(org_id)))
WITH CHECK ((select public.is_org_member(org_id)));
-- ── document_locks ──
CREATE POLICY "Org members can view document locks" ON public.document_locks
FOR SELECT TO authenticated
USING (EXISTS (
SELECT 1 FROM public.documents d
WHERE d.id = document_locks.document_id
AND (select public.is_org_member(d.org_id))
));
CREATE POLICY "Users can insert their own locks" ON public.document_locks
FOR INSERT TO authenticated WITH CHECK (user_id = (select auth.uid()));
CREATE POLICY "Users can update their own locks" ON public.document_locks
FOR UPDATE TO authenticated USING (user_id = (select auth.uid()));
CREATE POLICY "Users can delete locks" ON public.document_locks
FOR DELETE TO authenticated
USING (user_id = (select auth.uid()) OR last_heartbeat < (now() - interval '2 minutes'));
-- ── kanban_boards ──
CREATE POLICY "Members can manage boards" ON public.kanban_boards
FOR ALL TO authenticated
USING ((select public.is_org_member(org_id)))
WITH CHECK ((select public.is_org_member(org_id)));
-- ── kanban_columns ──
CREATE POLICY "Members can manage columns" ON public.kanban_columns
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.kanban_boards b
WHERE b.id = kanban_columns.board_id
AND (select public.is_org_member(b.org_id))
));
-- ── kanban_cards ──
CREATE POLICY "Members can manage cards" ON public.kanban_cards
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.kanban_columns c
JOIN public.kanban_boards b ON c.board_id = b.id
WHERE c.id = kanban_cards.column_id
AND (select public.is_org_member(b.org_id))
));
-- ── card_assignees ──
CREATE POLICY "Card assignees inherit card access" ON public.card_assignees
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.kanban_cards kc
JOIN public.kanban_columns kcol ON kcol.id = kc.column_id
JOIN public.kanban_boards kb ON kb.id = kcol.board_id
WHERE kc.id = card_assignees.card_id
AND (select public.is_org_member(kb.org_id))
));
-- ── checklist_items ──
CREATE POLICY "Members can manage checklist items" ON public.checklist_items
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.kanban_cards c
JOIN public.kanban_columns col ON c.column_id = col.id
JOIN public.kanban_boards b ON col.board_id = b.id
WHERE c.id = checklist_items.card_id
AND (select public.is_org_member(b.org_id))
));
-- ── kanban_checklist_items ──
CREATE POLICY "Checklist items inherit card access" ON public.kanban_checklist_items
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.kanban_cards c
JOIN public.kanban_columns col ON c.column_id = col.id
JOIN public.kanban_boards b ON col.board_id = b.id
WHERE c.id = kanban_checklist_items.card_id
AND (select public.is_org_member(b.org_id))
));
-- ── kanban_comments ──
CREATE POLICY "Comments inherit card access" ON public.kanban_comments
FOR SELECT TO authenticated
USING (EXISTS (
SELECT 1 FROM public.kanban_cards c
JOIN public.kanban_columns col ON c.column_id = col.id
JOIN public.kanban_boards b ON col.board_id = b.id
WHERE c.id = kanban_comments.card_id
AND (select public.is_org_member(b.org_id))
));
CREATE POLICY "Users can insert own comments" ON public.kanban_comments
FOR INSERT TO authenticated
WITH CHECK (
user_id = (select auth.uid())
AND EXISTS (
SELECT 1 FROM public.kanban_cards c
JOIN public.kanban_columns col ON c.column_id = col.id
JOIN public.kanban_boards b ON col.board_id = b.id
WHERE c.id = kanban_comments.card_id
AND (select public.is_org_member(b.org_id))
)
);
CREATE POLICY "Users can update own comments" ON public.kanban_comments
FOR UPDATE TO authenticated USING (user_id = (select auth.uid()));
CREATE POLICY "Users can delete own comments" ON public.kanban_comments
FOR DELETE TO authenticated USING (user_id = (select auth.uid()));
-- ── kanban_labels ──
CREATE POLICY "Labels accessible to org members" ON public.kanban_labels
FOR ALL TO authenticated
USING ((select public.is_org_member(org_id)));
-- ── card_labels ──
CREATE POLICY "Card labels inherit card access" ON public.card_labels
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.kanban_cards c
JOIN public.kanban_columns col ON c.column_id = col.id
JOIN public.kanban_boards b ON col.board_id = b.id
WHERE c.id = card_labels.card_id
AND (select public.is_org_member(b.org_id))
));
-- ── tags ──
CREATE POLICY "Users can view tags in their orgs" ON public.tags
FOR SELECT TO authenticated
USING (org_id IN (select public.get_user_org_ids()));
CREATE POLICY "Admins can manage tags" ON public.tags
FOR ALL TO authenticated
USING ((select public.is_org_admin(org_id)));
-- ── card_tags ──
CREATE POLICY "Members can manage card tags" ON public.card_tags
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.tags t
WHERE t.id = card_tags.tag_id
AND (select public.is_org_member(t.org_id))
));
-- ── teams ──
CREATE POLICY "Users can view teams in their orgs" ON public.teams
FOR SELECT TO authenticated
USING (org_id IN (select public.get_user_org_ids()));
CREATE POLICY "Admins can manage teams" ON public.teams
FOR ALL TO authenticated
USING ((select public.is_org_admin(org_id)));
-- ── team_members ──
CREATE POLICY "Users can view team members" ON public.team_members
FOR SELECT TO authenticated
USING (EXISTS (
SELECT 1 FROM public.teams t
WHERE t.id = team_members.team_id
AND (select public.is_org_member(t.org_id))
));
CREATE POLICY "Admins can manage team members" ON public.team_members
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.teams t
WHERE t.id = team_members.team_id
AND (select public.is_org_admin(t.org_id))
));
-- ── calendar_events ──
CREATE POLICY "Members can manage calendar events" ON public.calendar_events
FOR ALL TO authenticated
USING ((select public.is_org_member(org_id)))
WITH CHECK ((select public.is_org_member(org_id)));
-- ── event_attendees ──
CREATE POLICY "Members can manage event attendees" ON public.event_attendees
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.events e
WHERE e.id = event_attendees.event_id
AND (select public.is_org_member(e.org_id))
));
-- ── org_google_calendars ──
CREATE POLICY "Members can view org calendar" ON public.org_google_calendars
FOR SELECT TO authenticated
USING ((select public.is_org_member(org_id)));
CREATE POLICY "Admins can manage org calendar" ON public.org_google_calendars
FOR ALL TO authenticated
USING ((select public.is_org_admin(org_id)));
-- ── activity_log ──
CREATE POLICY "Users can view org activity" ON public.activity_log
FOR SELECT TO authenticated
USING ((select public.is_org_member(org_id)));
CREATE POLICY "Users can insert own activity" ON public.activity_log
FOR INSERT TO authenticated WITH CHECK (user_id = (select auth.uid()));
-- ── user_preferences ──
CREATE POLICY "Users can manage own preferences" ON public.user_preferences
FOR ALL TO authenticated USING (user_id = (select auth.uid()));
-- ── matrix_credentials ──
CREATE POLICY "Users can read own matrix credentials" ON public.matrix_credentials
FOR SELECT TO authenticated USING ((select auth.uid()) = user_id);
CREATE POLICY "Users can insert own matrix credentials" ON public.matrix_credentials
FOR INSERT TO authenticated WITH CHECK ((select auth.uid()) = user_id);
CREATE POLICY "Users can update own matrix credentials" ON public.matrix_credentials
FOR UPDATE TO authenticated USING ((select auth.uid()) = user_id);
CREATE POLICY "Users can delete own matrix credentials" ON public.matrix_credentials
FOR DELETE TO authenticated USING ((select auth.uid()) = user_id);
-- ── events ──
CREATE POLICY "Members can manage events" ON public.events
FOR ALL TO authenticated
USING ((select public.is_org_member(org_id)))
WITH CHECK ((select public.is_org_member(org_id)));
-- ── event_members ──
CREATE POLICY "Members can manage event members" ON public.event_members
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.events e
WHERE e.id = event_members.event_id
AND (select public.is_org_member(e.org_id))
))
WITH CHECK (EXISTS (
SELECT 1 FROM public.events e
WHERE e.id = event_members.event_id
AND (select public.is_org_member(e.org_id))
));
-- ── event_roles ──
CREATE POLICY "Members can manage event roles" ON public.event_roles
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.events e
WHERE e.id = event_roles.event_id
AND (select public.is_org_member(e.org_id))
));
-- ── event_departments ──
CREATE POLICY "Members can manage event departments" ON public.event_departments
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.events e
WHERE e.id = event_departments.event_id
AND (select public.is_org_member(e.org_id))
))
WITH CHECK (EXISTS (
SELECT 1 FROM public.events e
WHERE e.id = event_departments.event_id
AND (select public.is_org_member(e.org_id))
));
-- ── event_member_departments ──
CREATE POLICY "Members can manage member departments" ON public.event_member_departments
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_members em
JOIN public.events e ON em.event_id = e.id
WHERE em.id = event_member_departments.event_member_id
AND (select public.is_org_member(e.org_id))
));
-- ── event_task_columns ──
CREATE POLICY "Members can manage event task columns" ON public.event_task_columns
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.events e
WHERE e.id = event_task_columns.event_id
AND (select public.is_org_member(e.org_id))
));
-- ── event_tasks ──
CREATE POLICY "Members can manage event tasks" ON public.event_tasks
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.events e
WHERE e.id = event_tasks.event_id
AND (select public.is_org_member(e.org_id))
));
-- ── department_dashboards ──
CREATE POLICY "Members can manage department dashboards" ON public.department_dashboards
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = department_dashboards.department_id
AND (select public.is_org_member(e.org_id))
));
-- ── dashboard_panels ──
CREATE POLICY "Members can manage dashboard panels" ON public.dashboard_panels
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.department_dashboards dd
JOIN public.event_departments ed ON dd.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE dd.id = dashboard_panels.dashboard_id
AND (select public.is_org_member(e.org_id))
));
-- ── department_checklists ──
CREATE POLICY "Members can manage department checklists" ON public.department_checklists
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = department_checklists.department_id
AND (select public.is_org_member(e.org_id))
));
-- ── department_checklist_items ──
CREATE POLICY "Members can manage dept checklist items" ON public.department_checklist_items
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.department_checklists dc
JOIN public.event_departments ed ON dc.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE dc.id = department_checklist_items.checklist_id
AND (select public.is_org_member(e.org_id))
));
-- ── department_notes ──
CREATE POLICY "Members can manage department notes" ON public.department_notes
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = department_notes.department_id
AND (select public.is_org_member(e.org_id))
));
-- ── schedule_stages ──
CREATE POLICY "schedule_stages_select" ON public.schedule_stages
FOR SELECT TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = schedule_stages.department_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "schedule_stages_insert" ON public.schedule_stages
FOR INSERT TO authenticated
WITH CHECK (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = schedule_stages.department_id
AND (select public.is_org_editor(e.org_id))
));
CREATE POLICY "schedule_stages_update" ON public.schedule_stages
FOR UPDATE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = schedule_stages.department_id
AND (select public.is_org_editor(e.org_id))
));
CREATE POLICY "schedule_stages_delete" ON public.schedule_stages
FOR DELETE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = schedule_stages.department_id
AND (select public.is_org_editor(e.org_id))
));
-- ── schedule_blocks ──
CREATE POLICY "schedule_blocks_select" ON public.schedule_blocks
FOR SELECT TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = schedule_blocks.department_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "schedule_blocks_insert" ON public.schedule_blocks
FOR INSERT TO authenticated
WITH CHECK (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = schedule_blocks.department_id
AND (select public.is_org_editor(e.org_id))
));
CREATE POLICY "schedule_blocks_update" ON public.schedule_blocks
FOR UPDATE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = schedule_blocks.department_id
AND (select public.is_org_editor(e.org_id))
));
CREATE POLICY "schedule_blocks_delete" ON public.schedule_blocks
FOR DELETE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = schedule_blocks.department_id
AND (select public.is_org_editor(e.org_id))
));
-- ── department_contacts ──
CREATE POLICY "department_contacts_select" ON public.department_contacts
FOR SELECT TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = department_contacts.department_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "department_contacts_insert" ON public.department_contacts
FOR INSERT TO authenticated
WITH CHECK (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = department_contacts.department_id
AND (select public.is_org_editor(e.org_id))
));
CREATE POLICY "department_contacts_update" ON public.department_contacts
FOR UPDATE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = department_contacts.department_id
AND (select public.is_org_editor(e.org_id))
));
CREATE POLICY "department_contacts_delete" ON public.department_contacts
FOR DELETE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = department_contacts.department_id
AND (select public.is_org_editor(e.org_id))
));
-- ── budget_categories ──
CREATE POLICY "Members can manage budget categories" ON public.budget_categories
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = budget_categories.department_id
AND (select public.is_org_member(e.org_id))
));
-- ── budget_items ──
CREATE POLICY "Members can manage budget items" ON public.budget_items
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = budget_items.department_id
AND (select public.is_org_member(e.org_id))
));
-- ── sponsor_tiers ──
CREATE POLICY "Members can manage sponsor tiers" ON public.sponsor_tiers
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = sponsor_tiers.department_id
AND (select public.is_org_member(e.org_id))
));
-- ── sponsors ──
CREATE POLICY "Members can manage sponsors" ON public.sponsors
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = sponsors.department_id
AND (select public.is_org_member(e.org_id))
));
-- ── sponsor_deliverables ──
CREATE POLICY "Members can manage sponsor deliverables" ON public.sponsor_deliverables
FOR ALL TO authenticated
USING (EXISTS (
SELECT 1 FROM public.sponsors s
JOIN public.event_departments ed ON s.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE s.id = sponsor_deliverables.sponsor_id
AND (select public.is_org_member(e.org_id))
));
-- ── sponsor_allocations ──
CREATE POLICY "sponsor_allocations_select" ON public.sponsor_allocations
FOR SELECT TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = sponsor_allocations.department_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "sponsor_allocations_insert" ON public.sponsor_allocations
FOR INSERT TO authenticated
WITH CHECK (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = sponsor_allocations.department_id
AND (select public.is_org_editor(e.org_id))
));
CREATE POLICY "sponsor_allocations_update" ON public.sponsor_allocations
FOR UPDATE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = sponsor_allocations.department_id
AND (select public.is_org_editor(e.org_id))
));
CREATE POLICY "sponsor_allocations_delete" ON public.sponsor_allocations
FOR DELETE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = sponsor_allocations.department_id
AND (select public.is_org_editor(e.org_id))
));
-- ── org_contacts ──
CREATE POLICY "org_contacts_select" ON public.org_contacts
FOR SELECT TO authenticated
USING ((select public.is_org_member(org_id)));
CREATE POLICY "org_contacts_insert" ON public.org_contacts
FOR INSERT TO authenticated
WITH CHECK ((select public.is_org_editor(org_id)));
CREATE POLICY "org_contacts_update" ON public.org_contacts
FOR UPDATE TO authenticated
USING ((select public.is_org_editor(org_id)));
CREATE POLICY "org_contacts_delete" ON public.org_contacts
FOR DELETE TO authenticated
USING ((select public.is_org_editor(org_id)));
-- ── department_pinned_contacts ──
CREATE POLICY "dept_pinned_contacts_select" ON public.department_pinned_contacts
FOR SELECT TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = department_pinned_contacts.department_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "dept_pinned_contacts_insert" ON public.department_pinned_contacts
FOR INSERT TO authenticated
WITH CHECK (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = department_pinned_contacts.department_id
AND (select public.is_org_editor(e.org_id))
));
CREATE POLICY "dept_pinned_contacts_delete" ON public.department_pinned_contacts
FOR DELETE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON e.id = ed.event_id
WHERE ed.id = department_pinned_contacts.department_id
AND (select public.is_org_editor(e.org_id))
));
-- ── map_layers ──
CREATE POLICY "Org members can view map layers" ON public.map_layers
FOR SELECT TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = map_layers.department_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "Editors can insert map layers" ON public.map_layers
FOR INSERT TO authenticated
WITH CHECK (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = map_layers.department_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "Editors can update map layers" ON public.map_layers
FOR UPDATE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = map_layers.department_id
AND (select public.is_org_member(e.org_id))
))
WITH CHECK (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = map_layers.department_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "Editors can delete map layers" ON public.map_layers
FOR DELETE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.event_departments ed
JOIN public.events e ON ed.event_id = e.id
WHERE ed.id = map_layers.department_id
AND (select public.is_org_member(e.org_id))
));
-- ── map_pins ──
CREATE POLICY "Org members can view map pins" ON public.map_pins
FOR SELECT TO authenticated
USING (EXISTS (
SELECT 1 FROM public.map_layers ml
JOIN public.event_departments ed ON ml.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE ml.id = map_pins.layer_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "Editors can insert map pins" ON public.map_pins
FOR INSERT TO authenticated
WITH CHECK (EXISTS (
SELECT 1 FROM public.map_layers ml
JOIN public.event_departments ed ON ml.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE ml.id = map_pins.layer_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "Editors can update map pins" ON public.map_pins
FOR UPDATE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.map_layers ml
JOIN public.event_departments ed ON ml.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE ml.id = map_pins.layer_id
AND (select public.is_org_member(e.org_id))
))
WITH CHECK (EXISTS (
SELECT 1 FROM public.map_layers ml
JOIN public.event_departments ed ON ml.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE ml.id = map_pins.layer_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "Editors can delete map pins" ON public.map_pins
FOR DELETE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.map_layers ml
JOIN public.event_departments ed ON ml.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE ml.id = map_pins.layer_id
AND (select public.is_org_member(e.org_id))
));
-- ── map_shapes ──
CREATE POLICY "Org members can view map shapes" ON public.map_shapes
FOR SELECT TO authenticated
USING (EXISTS (
SELECT 1 FROM public.map_layers ml
JOIN public.event_departments ed ON ml.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE ml.id = map_shapes.layer_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "Editors can insert map shapes" ON public.map_shapes
FOR INSERT TO authenticated
WITH CHECK (EXISTS (
SELECT 1 FROM public.map_layers ml
JOIN public.event_departments ed ON ml.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE ml.id = map_shapes.layer_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "Editors can update map shapes" ON public.map_shapes
FOR UPDATE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.map_layers ml
JOIN public.event_departments ed ON ml.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE ml.id = map_shapes.layer_id
AND (select public.is_org_member(e.org_id))
))
WITH CHECK (EXISTS (
SELECT 1 FROM public.map_layers ml
JOIN public.event_departments ed ON ml.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE ml.id = map_shapes.layer_id
AND (select public.is_org_member(e.org_id))
));
CREATE POLICY "Editors can delete map shapes" ON public.map_shapes
FOR DELETE TO authenticated
USING (EXISTS (
SELECT 1 FROM public.map_layers ml
JOIN public.event_departments ed ON ml.department_id = ed.id
JOIN public.events e ON ed.event_id = e.id
WHERE ml.id = map_shapes.layer_id
AND (select public.is_org_member(e.org_id))
));