141 lines
4.6 KiB
SQL
141 lines
4.6 KiB
SQL
-- ============================================================
|
|
-- Announcements + Comments tables
|
|
-- ============================================================
|
|
|
|
-- 1. announcements table
|
|
CREATE TABLE IF NOT EXISTS public.announcements (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
author_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
title text NOT NULL,
|
|
body text NOT NULL,
|
|
visible_roles text[] NOT NULL DEFAULT ARRAY['admin','dispatcher','programmer','it_staff']::text[],
|
|
is_template boolean NOT NULL DEFAULT false,
|
|
template_id uuid REFERENCES public.announcements(id) ON DELETE SET NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now(),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE public.announcements ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.announcements REPLICA IDENTITY FULL;
|
|
|
|
-- RLS: SELECT — user can see if their role is in visible_roles OR they are the author
|
|
CREATE POLICY "Announcements: select" ON public.announcements
|
|
FOR SELECT
|
|
USING (
|
|
author_id = auth.uid()
|
|
OR EXISTS (
|
|
SELECT 1 FROM public.profiles p
|
|
WHERE p.id = auth.uid()
|
|
AND p.role::text = ANY(visible_roles)
|
|
)
|
|
);
|
|
|
|
-- RLS: INSERT — admin, dispatcher, programmer, it_staff only
|
|
CREATE POLICY "Announcements: insert" ON public.announcements
|
|
FOR INSERT
|
|
WITH CHECK (
|
|
EXISTS (
|
|
SELECT 1 FROM public.profiles p
|
|
WHERE p.id = auth.uid()
|
|
AND p.role IN ('admin', 'dispatcher', 'programmer', 'it_staff')
|
|
)
|
|
);
|
|
|
|
-- RLS: UPDATE — only the author or admin
|
|
CREATE POLICY "Announcements: update" ON public.announcements
|
|
FOR UPDATE
|
|
USING (
|
|
author_id = auth.uid()
|
|
OR EXISTS (
|
|
SELECT 1 FROM public.profiles p
|
|
WHERE p.id = auth.uid() AND p.role = 'admin'
|
|
)
|
|
);
|
|
|
|
-- RLS: DELETE — only the author or admin
|
|
CREATE POLICY "Announcements: delete" ON public.announcements
|
|
FOR DELETE
|
|
USING (
|
|
author_id = auth.uid()
|
|
OR EXISTS (
|
|
SELECT 1 FROM public.profiles p
|
|
WHERE p.id = auth.uid() AND p.role = 'admin'
|
|
)
|
|
);
|
|
|
|
-- Index for efficient queries
|
|
CREATE INDEX IF NOT EXISTS idx_announcements_created_at ON public.announcements (created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_announcements_visible_roles ON public.announcements USING GIN (visible_roles);
|
|
|
|
-- 2. announcement_comments table
|
|
CREATE TABLE IF NOT EXISTS public.announcement_comments (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
announcement_id uuid NOT NULL REFERENCES public.announcements(id) ON DELETE CASCADE,
|
|
author_id uuid NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
|
|
body text NOT NULL,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
ALTER TABLE public.announcement_comments ENABLE ROW LEVEL SECURITY;
|
|
ALTER TABLE public.announcement_comments REPLICA IDENTITY FULL;
|
|
|
|
-- RLS: SELECT — can read comments if user can see the parent announcement
|
|
CREATE POLICY "Announcement comments: select" ON public.announcement_comments
|
|
FOR SELECT
|
|
USING (
|
|
EXISTS (
|
|
SELECT 1 FROM public.announcements a
|
|
WHERE a.id = announcement_id
|
|
AND (
|
|
a.author_id = auth.uid()
|
|
OR EXISTS (
|
|
SELECT 1 FROM public.profiles p
|
|
WHERE p.id = auth.uid()
|
|
AND p.role::text = ANY(a.visible_roles)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
-- RLS: INSERT — any authenticated user who can see the announcement
|
|
CREATE POLICY "Announcement comments: insert" ON public.announcement_comments
|
|
FOR INSERT
|
|
WITH CHECK (
|
|
author_id = auth.uid()
|
|
AND EXISTS (
|
|
SELECT 1 FROM public.announcements a
|
|
WHERE a.id = announcement_id
|
|
AND (
|
|
a.author_id = auth.uid()
|
|
OR EXISTS (
|
|
SELECT 1 FROM public.profiles p
|
|
WHERE p.id = auth.uid()
|
|
AND p.role::text = ANY(a.visible_roles)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
|
|
-- RLS: DELETE — only the comment author or admin
|
|
CREATE POLICY "Announcement comments: delete" ON public.announcement_comments
|
|
FOR DELETE
|
|
USING (
|
|
author_id = auth.uid()
|
|
OR EXISTS (
|
|
SELECT 1 FROM public.profiles p
|
|
WHERE p.id = auth.uid() AND p.role = 'admin'
|
|
)
|
|
);
|
|
|
|
-- Index for efficient comment lookups
|
|
CREATE INDEX IF NOT EXISTS idx_announcement_comments_announcement_id
|
|
ON public.announcement_comments (announcement_id, created_at);
|
|
|
|
-- 3. Extend notifications table with announcement_id FK
|
|
ALTER TABLE public.notifications
|
|
ADD COLUMN IF NOT EXISTS announcement_id uuid REFERENCES public.announcements(id) ON DELETE CASCADE;
|
|
|
|
-- 4. Enable realtime for both tables
|
|
ALTER PUBLICATION supabase_realtime ADD TABLE public.announcements;
|
|
ALTER PUBLICATION supabase_realtime ADD TABLE public.announcement_comments;
|