-- Transactional fixtures; uses existing accounts on a configured project. begin; do $$ declare owner uuid; member uuid; fixture uuid; comment uuid; report uuid; table_name text; client_role text; permission text; totals record; begin if not exists(select 1 from auth.users) then insert into auth.users(id) select gen_random_uuid() from generate_series(1, 2); end if; select id into owner from auth.users order by id limit 1; select id into member from auth.users where id <> owner order by id limit 1; if member is null then raise exception 'Two fixture accounts are required'; end if; insert into public.profiles(id) values(owner),(member) on conflict(id) do nothing; insert into public.datasets(owner_id,name,source,bounds,state) values(owner,'Community regression','plugin','{"minX":0,"minZ":0,"maxX":64,"maxZ":64}','published') returning id into fixture; select * into totals from public.map_reaction_summary(fixture); if totals.likes <> 0 or totals.dislikes <> 0 then raise exception 'Empty totals are incorrect'; end if; insert into public.map_reactions(dataset_id,user_id,value) values(fixture,owner,1),(fixture,member,-1); begin insert into public.map_reactions(dataset_id,user_id,value) values(fixture,owner,-1); raise exception 'Duplicate reaction accepted'; exception when unique_violation then null; end; begin update public.map_reactions set value=0 where dataset_id=fixture and user_id=owner; raise exception 'Invalid reaction accepted'; exception when check_violation then null; end; select * into totals from public.map_reaction_summary(fixture); if totals.likes <> 1 or totals.dislikes <> 1 then raise exception 'Mixed totals are incorrect'; end if; update public.map_reactions set value=1 where dataset_id=fixture and user_id=member; select * into totals from public.map_reaction_summary(fixture); if totals.likes <> 2 or totals.dislikes <> 0 then raise exception 'Changed reaction counted incorrectly'; end if; delete from public.map_reactions where dataset_id=fixture and user_id=member; select * into totals from public.map_reaction_summary(fixture); if totals.likes <> 1 then raise exception 'Reaction withdrawal counted incorrectly'; end if; insert into public.map_comments(dataset_id,author_id,body) values(fixture,member,'A useful map.') returning id into comment; begin insert into public.map_comments(dataset_id,author_id,body) values(fixture,member,' '); raise exception 'Blank comment accepted'; exception when check_violation then null; end; begin update public.map_comments set body=repeat('x',2001) where id=comment; raise exception 'Oversized comment accepted'; exception when check_violation then null; end; begin update public.map_comments set body=' padded ' where id=comment; raise exception 'Untrimmed comment accepted'; exception when check_violation then null; end; update public.map_comments set removed_at=now(),removed_by=owner where id=comment; if not exists(select 1 from public.map_comments where id=comment and body='A useful map.' and removed_at is not null and removed_by=owner) then raise exception 'Comment removal lost its audit record'; end if; insert into public.community_reports(reporter_id,target,comment_id,category,reason) values(owner,'comment',comment,'spam','Repeated unrelated messages.') returning id into report; begin insert into public.community_reports(reporter_id,target,comment_id,category,reason) values(owner,'comment',comment,'advertising','Repeated advertising messages.'); raise exception 'Duplicate open comment report accepted'; exception when unique_violation then null; end; update public.community_reports set state='dismissed',reviewer_id=member,reviewed_at=now(),review_reason='Reviewed the context.' where id=report; insert into public.community_reports(reporter_id,target,comment_id,category,reason) values(owner,'comment',comment,'advertising','New advertising in this comment.'); insert into public.community_reports(reporter_id,target,account_id,category,reason) values(owner,'account',member,'advertising','Profile contains repeated advertising.'); begin insert into public.community_reports(reporter_id,target,account_id,category,reason) values(owner,'account',member,'spam','Repeated unsolicited messages.'); raise exception 'Duplicate open account report accepted'; exception when unique_violation then null; end; begin insert into public.community_reports(reporter_id,target,account_id,category,reason) values(owner,'comment',member,'other','A mismatched report target.'); raise exception 'Mismatched report target accepted'; exception when check_violation then null; end; begin insert into public.community_reports(reporter_id,target,account_id,category,reason) values(member,'account',owner,'unknown','An invalid report category.'); raise exception 'Invalid category accepted'; exception when check_violation then null; end; begin insert into public.community_reports(reporter_id,target,account_id,category,reason) values(member,'account',owner,'other','short'); raise exception 'Short report accepted'; exception when check_violation then null; end; begin update public.community_reports set reason=repeat('x',2001) where id=report; raise exception 'Oversized report accepted'; exception when check_violation then null; end; begin update public.community_reports set review_reason=repeat('x',2001) where id=report; raise exception 'Oversized review accepted'; exception when check_violation then null; end; begin update public.community_reports set state='unknown' where id=report; raise exception 'Invalid report state accepted'; exception when check_violation then null; end; foreach table_name in array array['map_reactions','map_comments','community_reports'] loop if not (select relrowsecurity from pg_class where oid=('public.'||table_name)::regclass) then raise exception 'RLS disabled for %', table_name; end if; foreach client_role in array array['anon','authenticated'] loop foreach permission in array array['SELECT','INSERT','UPDATE','DELETE'] loop if has_table_privilege(client_role,'public.'||table_name,permission) then raise exception 'Client permission exposed: % % %',client_role,table_name,permission; end if; end loop; end loop; if not has_table_privilege('service_role','public.'||table_name,'SELECT,INSERT,UPDATE,DELETE') then raise exception 'Service role missing permissions on %',table_name; end if; end loop; if has_function_privilege('anon','public.map_reaction_summary(uuid)','EXECUTE') or has_function_privilege('authenticated','public.map_reaction_summary(uuid)','EXECUTE') or not has_function_privilege('service_role','public.map_reaction_summary(uuid)','EXECUTE') then raise exception 'Reaction RPC grants incorrect'; end if; if (select prosecdef from pg_proc where oid='public.map_reaction_summary(uuid)'::regprocedure) then raise exception 'Reaction RPC must use caller privileges'; end if; delete from public.datasets where id=fixture; if exists(select 1 from public.map_comments where id=comment) or exists(select 1 from public.map_reactions where dataset_id=fixture) or exists(select 1 from public.community_reports where comment_id=comment) then raise exception 'Map deletion left community content behind'; end if; end; $$; rollback;