mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 09:50:01 +00:00
183fe0a93c
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
86 lines
3.1 KiB
PL/PgSQL
86 lines
3.1 KiB
PL/PgSQL
|
|
CREATE TABLE public.board_vote_email_tokens (
|
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
board_vote_id uuid NOT NULL REFERENCES public.board_votes(id) ON DELETE CASCADE,
|
|
board_member_id uuid NOT NULL REFERENCES public.board_members(id) ON DELETE CASCADE,
|
|
token uuid NOT NULL UNIQUE DEFAULT gen_random_uuid(),
|
|
email text NOT NULL,
|
|
member_name text,
|
|
sent_at timestamp with time zone,
|
|
voted_at timestamp with time zone,
|
|
vote_option text,
|
|
created_at timestamp with time zone NOT NULL DEFAULT now(),
|
|
UNIQUE (board_vote_id, board_member_id)
|
|
);
|
|
|
|
CREATE INDEX idx_bvet_token ON public.board_vote_email_tokens(token);
|
|
CREATE INDEX idx_bvet_vote ON public.board_vote_email_tokens(board_vote_id);
|
|
|
|
ALTER TABLE public.board_vote_email_tokens ENABLE ROW LEVEL SECURITY;
|
|
|
|
CREATE POLICY "Staff manage board vote tokens"
|
|
ON public.board_vote_email_tokens
|
|
FOR ALL TO authenticated
|
|
USING (public.has_role(auth.uid(),'admin'::public.app_role) OR public.has_role(auth.uid(),'manager'::public.app_role))
|
|
WITH CHECK (public.has_role(auth.uid(),'admin'::public.app_role) OR public.has_role(auth.uid(),'manager'::public.app_role));
|
|
|
|
CREATE OR REPLACE FUNCTION public.lookup_board_vote_by_token(p_token uuid)
|
|
RETURNS TABLE(
|
|
token_id uuid,
|
|
board_vote_id uuid,
|
|
vote_title text,
|
|
vote_description text,
|
|
vote_options text[],
|
|
vote_status text,
|
|
association_name text,
|
|
member_name text,
|
|
email text,
|
|
voted_at timestamp with time zone,
|
|
vote_option text
|
|
)
|
|
LANGUAGE sql STABLE SECURITY DEFINER SET search_path = public
|
|
AS $$
|
|
SELECT t.id, bv.id, bv.title, bv.description, bv.vote_options, bv.status,
|
|
a.name, t.member_name, t.email, t.voted_at, t.vote_option
|
|
FROM public.board_vote_email_tokens t
|
|
JOIN public.board_votes bv ON bv.id = t.board_vote_id
|
|
LEFT JOIN public.associations a ON a.id = bv.association_id
|
|
WHERE t.token = p_token
|
|
LIMIT 1;
|
|
$$;
|
|
|
|
CREATE OR REPLACE FUNCTION public.record_board_vote_by_token(p_token uuid, p_option text)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public
|
|
AS $$
|
|
DECLARE
|
|
v_token RECORD;
|
|
v_vote RECORD;
|
|
BEGIN
|
|
SELECT * INTO v_token FROM public.board_vote_email_tokens WHERE token = p_token;
|
|
IF v_token IS NULL THEN
|
|
RETURN jsonb_build_object('ok', false, 'error', 'Invalid token');
|
|
END IF;
|
|
IF v_token.voted_at IS NOT NULL THEN
|
|
RETURN jsonb_build_object('ok', false, 'error', 'Vote already recorded', 'already_voted', true);
|
|
END IF;
|
|
|
|
SELECT * INTO v_vote FROM public.board_votes WHERE id = v_token.board_vote_id;
|
|
IF v_vote.status <> 'open' THEN
|
|
RETURN jsonb_build_object('ok', false, 'error', 'Voting is closed for this item');
|
|
END IF;
|
|
IF NOT (p_option = ANY(v_vote.vote_options)) THEN
|
|
RETURN jsonb_build_object('ok', false, 'error', 'Invalid vote option');
|
|
END IF;
|
|
|
|
UPDATE public.board_vote_email_tokens
|
|
SET voted_at = now(), vote_option = p_option
|
|
WHERE id = v_token.id;
|
|
|
|
RETURN jsonb_build_object('ok', true);
|
|
END;
|
|
$$;
|
|
|
|
GRANT EXECUTE ON FUNCTION public.lookup_board_vote_by_token(uuid) TO anon, authenticated;
|
|
GRANT EXECUTE ON FUNCTION public.record_board_vote_by_token(uuid, text) TO anon, authenticated;
|