145 lines
5.1 KiB
PL/PgSQL
145 lines
5.1 KiB
PL/PgSQL
-- 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();
|