initial commit: rocket.new export of broadcastbeat
This commit is contained in:
144
supabase/migrations/20260321200000_notifications.sql
Normal file
144
supabase/migrations/20260321200000_notifications.sql
Normal file
@@ -0,0 +1,144 @@
|
||||
-- Notifications Migration for BroadcastBeat
|
||||
-- Tracks thread replies, mentions, upvotes, and follow activity
|
||||
|
||||
-- ============================================================
|
||||
-- 1. NOTIFICATIONS TABLE
|
||||
-- ============================================================
|
||||
CREATE TABLE IF NOT EXISTS public.notifications (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
user_id UUID NOT NULL REFERENCES public.user_profiles(id) ON DELETE CASCADE,
|
||||
type TEXT NOT NULL CHECK (type IN ('thread_reply', 'mention', 'upvote', 'follow')),
|
||||
title TEXT NOT NULL,
|
||||
body TEXT,
|
||||
link TEXT,
|
||||
actor_id UUID REFERENCES public.user_profiles(id) ON DELETE SET NULL,
|
||||
actor_name TEXT,
|
||||
is_read BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON public.notifications(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_notifications_user_unread ON public.notifications(user_id, is_read) WHERE is_read = false;
|
||||
CREATE INDEX IF NOT EXISTS idx_notifications_created_at ON public.notifications(created_at DESC);
|
||||
|
||||
-- ============================================================
|
||||
-- 2. RLS POLICIES
|
||||
-- ============================================================
|
||||
ALTER TABLE public.notifications ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DROP POLICY IF EXISTS "Users can view own notifications" ON public.notifications;
|
||||
CREATE POLICY "Users can view own notifications"
|
||||
ON public.notifications FOR SELECT
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
DROP POLICY IF EXISTS "Users can update own notifications" ON public.notifications;
|
||||
CREATE POLICY "Users can update own notifications"
|
||||
ON public.notifications FOR UPDATE
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
DROP POLICY IF EXISTS "Users can delete own notifications" ON public.notifications;
|
||||
CREATE POLICY "Users can delete own notifications"
|
||||
ON public.notifications FOR DELETE
|
||||
USING (auth.uid() = user_id);
|
||||
|
||||
DROP POLICY IF EXISTS "Service role can insert notifications" ON public.notifications;
|
||||
CREATE POLICY "Service role can insert notifications"
|
||||
ON public.notifications FOR INSERT
|
||||
WITH CHECK (true);
|
||||
|
||||
-- ============================================================
|
||||
-- 3. AUTO-NOTIFY ON FORUM REPLY
|
||||
-- ============================================================
|
||||
CREATE OR REPLACE FUNCTION public.notify_thread_reply()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
v_thread_author UUID;
|
||||
v_thread_title TEXT;
|
||||
v_thread_id UUID;
|
||||
BEGIN
|
||||
SELECT author_id, title, id INTO v_thread_author, v_thread_title, v_thread_id
|
||||
FROM public.forum_threads
|
||||
WHERE id = NEW.thread_id;
|
||||
|
||||
-- Notify thread author (if not replying to own thread and not AI)
|
||||
IF v_thread_author IS NOT NULL
|
||||
AND v_thread_author <> NEW.author_id
|
||||
AND NEW.is_ai_response = false THEN
|
||||
INSERT INTO public.notifications (user_id, type, title, body, link, actor_id, actor_name)
|
||||
VALUES (
|
||||
v_thread_author,
|
||||
'thread_reply',
|
||||
'New reply to your thread',
|
||||
v_thread_title,
|
||||
'/forum/thread/' || v_thread_id::TEXT,
|
||||
NEW.author_id,
|
||||
NEW.author_name
|
||||
);
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_notify_thread_reply ON public.forum_replies;
|
||||
CREATE TRIGGER trg_notify_thread_reply
|
||||
AFTER INSERT ON public.forum_replies
|
||||
FOR EACH ROW EXECUTE FUNCTION public.notify_thread_reply();
|
||||
|
||||
-- ============================================================
|
||||
-- 4. AUTO-NOTIFY ON UPVOTE
|
||||
-- ============================================================
|
||||
CREATE OR REPLACE FUNCTION public.notify_upvote()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
v_target_author UUID;
|
||||
v_target_title TEXT;
|
||||
v_link TEXT;
|
||||
v_voter_name TEXT;
|
||||
BEGIN
|
||||
-- Only notify on upvotes (vote_value = 1)
|
||||
IF NEW.vote_value <> 1 THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
SELECT username INTO v_voter_name FROM public.user_profiles WHERE id = NEW.user_id;
|
||||
|
||||
IF NEW.target_type = 'thread' THEN
|
||||
SELECT author_id, title INTO v_target_author, v_target_title
|
||||
FROM public.forum_threads WHERE id = NEW.target_id;
|
||||
v_link := '/forum/thread/' || NEW.target_id::TEXT;
|
||||
ELSE
|
||||
SELECT fr.author_id, ft.title INTO v_target_author, v_target_title
|
||||
FROM public.forum_replies fr
|
||||
JOIN public.forum_threads ft ON ft.id = fr.thread_id
|
||||
WHERE fr.id = NEW.target_id;
|
||||
v_link := '/forum/thread/' || (
|
||||
SELECT thread_id FROM public.forum_replies WHERE id = NEW.target_id
|
||||
)::TEXT;
|
||||
END IF;
|
||||
|
||||
IF v_target_author IS NOT NULL AND v_target_author <> NEW.user_id THEN
|
||||
INSERT INTO public.notifications (user_id, type, title, body, link, actor_id, actor_name)
|
||||
VALUES (
|
||||
v_target_author,
|
||||
'upvote',
|
||||
'Someone upvoted your ' || NEW.target_type,
|
||||
v_target_title,
|
||||
v_link,
|
||||
NEW.user_id,
|
||||
COALESCE(v_voter_name, 'A member')
|
||||
);
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_notify_upvote ON public.forum_votes;
|
||||
CREATE TRIGGER trg_notify_upvote
|
||||
AFTER INSERT ON public.forum_votes
|
||||
FOR EACH ROW EXECUTE FUNCTION public.notify_upvote();
|
||||
Reference in New Issue
Block a user