-- 1. Allow association participants (which includes ARC members who are owners/board members) to see votes CREATE POLICY "Participants can view entity votes" ON public.entity_votes FOR SELECT USING (public.can_comment_on_entity(auth.uid(), entity_type, entity_id)); -- 2. Helper to determine if an ARC application is locked CREATE OR REPLACE FUNCTION public.is_arc_application_locked(_application_id uuid) RETURNS boolean LANGUAGE sql STABLE SECURITY DEFINER SET search_path = public AS $$ SELECT EXISTS ( SELECT 1 FROM public.arc_applications WHERE id = _application_id AND lower(coalesce(status,'')) IN ('approved','denied') ); $$; -- 3. Block writes to entity_votes/entity_comments tied to a locked ARC application CREATE OR REPLACE FUNCTION public.prevent_writes_on_locked_arc() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path = public AS $$ DECLARE v_entity_type text; v_entity_id uuid; BEGIN v_entity_type := COALESCE(NEW.entity_type, OLD.entity_type); v_entity_id := COALESCE(NEW.entity_id, OLD.entity_id); IF v_entity_type = 'arc_application' AND public.is_arc_application_locked(v_entity_id) THEN RAISE EXCEPTION 'This ARC application has been finalized (approved or denied) and is locked from further changes.' USING ERRCODE = 'check_violation'; END IF; RETURN COALESCE(NEW, OLD); END; $$; DROP TRIGGER IF EXISTS trg_lock_entity_votes_arc ON public.entity_votes; CREATE TRIGGER trg_lock_entity_votes_arc BEFORE INSERT OR UPDATE OR DELETE ON public.entity_votes FOR EACH ROW EXECUTE FUNCTION public.prevent_writes_on_locked_arc(); DROP TRIGGER IF EXISTS trg_lock_entity_comments_arc ON public.entity_comments; CREATE TRIGGER trg_lock_entity_comments_arc BEFORE INSERT OR UPDATE OR DELETE ON public.entity_comments FOR EACH ROW EXECUTE FUNCTION public.prevent_writes_on_locked_arc(); -- 4. Block updates to a finalized ARC application (except a deliberate status reset by an admin) CREATE OR REPLACE FUNCTION public.prevent_updates_on_finalized_arc() RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path = public AS $$ BEGIN IF lower(COALESCE(OLD.status,'')) IN ('approved','denied') THEN -- Allow admins to reopen by changing status away from approved/denied; otherwise block. IF NEW.status IS DISTINCT FROM OLD.status AND lower(COALESCE(NEW.status,'')) NOT IN ('approved','denied') AND public.has_role(auth.uid(), 'admin'::public.app_role) THEN RETURN NEW; END IF; RAISE EXCEPTION 'This ARC application has been finalized (approved or denied) and is locked from further changes.' USING ERRCODE = 'check_violation'; END IF; RETURN NEW; END; $$; DROP TRIGGER IF EXISTS trg_lock_arc_application_updates ON public.arc_applications; CREATE TRIGGER trg_lock_arc_application_updates BEFORE UPDATE ON public.arc_applications FOR EACH ROW EXECUTE FUNCTION public.prevent_updates_on_finalized_arc();