mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 01:40:01 +00:00
fd7107290a
Restrict marking a bill paid to admins only, per requirement. - BillDetailPage: gate Mark Paid / Mark Unpaid on useAuth().isAdmin (was only hidden in board view). - BillApprovalsPage: gate Print Checks (which sets bills to paid) on isAdmin. - Migration: BEFORE INSERT/UPDATE trigger enforce_admin_marks_bill_paid() rejects the transition into 'paid' for authenticated non-admins. Service-role / system contexts (auth.uid() null: buildium-sync, accounting triggers, autopay) remain allowed. Verified: admin allowed, non-admin blocked (23514). Note: the approver column showing "None" in production is a stale-deploy issue — the DB column was renamed vendor_name->approver_name (Jun 4) but prod still ran code querying vendor_name. Deploying current main resolves it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
35 lines
1.3 KiB
PL/PgSQL
35 lines
1.3 KiB
PL/PgSQL
-- Restrict the "paid" transition on bills to administrators only.
|
|
--
|
|
-- Background: bills RLS lets admin, manager, association_management, and
|
|
-- accounting staff update bills, so any of them could mark a bill paid. Per
|
|
-- requirement, only admins may do that. This trigger enforces it at the data
|
|
-- layer regardless of how the write arrives (UI, API, direct SQL).
|
|
--
|
|
-- System/automation contexts (buildium-sync, accounting triggers, autopay)
|
|
-- run with the service role, where auth.uid() is NULL — those remain allowed
|
|
-- so imports and back-syncs continue to work.
|
|
|
|
create or replace function public.enforce_admin_marks_bill_paid()
|
|
returns trigger
|
|
language plpgsql
|
|
security definer
|
|
set search_path to 'public'
|
|
as $$
|
|
begin
|
|
if NEW.status = 'paid'
|
|
and (TG_OP = 'INSERT' or OLD.status is distinct from 'paid') then
|
|
if auth.uid() is not null
|
|
and not public.has_role(auth.uid(), 'admin'::app_role) then
|
|
raise exception 'Only administrators can mark a bill as paid'
|
|
using errcode = 'check_violation';
|
|
end if;
|
|
end if;
|
|
return NEW;
|
|
end;
|
|
$$;
|
|
|
|
drop trigger if exists trg_bills_admin_paid_guard on public.bills;
|
|
create trigger trg_bills_admin_paid_guard
|
|
before insert or update on public.bills
|
|
for each row execute function public.enforce_admin_marks_bill_paid();
|