81 lines
4.7 KiB
PL/PgSQL
81 lines
4.7 KiB
PL/PgSQL
alter table public.bug_reports drop constraint bug_reports_state_check;
|
|
alter table public.bug_reports add constraint bug_reports_state_check check(state in ('draft','pending','open','done'));
|
|
alter table public.bug_reports
|
|
add column closed_at timestamptz,
|
|
add column delete_after timestamptz,
|
|
add column linear_done_synced boolean not null default false,
|
|
add column cleanup_run_id text,
|
|
add column cleanup_lease_until timestamptz,
|
|
add column cleanup_error text,
|
|
add column purge_started_at timestamptz,
|
|
add column status_checked_at timestamptz;
|
|
create index bug_reports_cleanup on public.bug_reports(delete_after) where state='done';
|
|
|
|
create function public.set_bug_report_done(p_report uuid,p_done boolean,p_closed_at timestamptz default null)
|
|
returns boolean language plpgsql security invoker set search_path='' as $$
|
|
declare report public.bug_reports; finished timestamptz;
|
|
begin
|
|
select * into report from public.bug_reports where id=p_report and state<>'draft' for update;
|
|
if not found or report.purge_started_at is not null then return false; end if;
|
|
if p_done then
|
|
finished=coalesce(report.closed_at,least(coalesce(p_closed_at,clock_timestamp()),clock_timestamp()));
|
|
update public.bug_reports set state='done',closed_at=finished,delete_after=finished+interval '3 days',updated_at=clock_timestamp()
|
|
where id=p_report;
|
|
elsif report.state='done' then
|
|
update public.bug_reports set state='open',closed_at=null,delete_after=null,linear_done_synced=false,
|
|
cleanup_run_id=null,cleanup_lease_until=null,cleanup_error=null,updated_at=clock_timestamp() where id=p_report;
|
|
end if;
|
|
return true;
|
|
end; $$;
|
|
|
|
create function public.claim_bug_cleanup(p_report uuid,p_worker text)
|
|
returns setof public.bug_reports language sql security invoker set search_path='' as $$
|
|
update public.bug_reports set cleanup_run_id=p_worker,cleanup_lease_until=clock_timestamp()+interval '3 minutes'
|
|
where id=p_report and state='done' and closed_at is not null
|
|
and (cleanup_run_id is null or cleanup_run_id like 'starting:%')
|
|
and (cleanup_lease_until is null or cleanup_lease_until<clock_timestamp()) returning *;
|
|
$$;
|
|
create function public.begin_bug_purge(p_report uuid,p_closed_at timestamptz)
|
|
returns boolean language plpgsql security invoker set search_path='' as $$
|
|
begin
|
|
update public.bug_reports set purge_started_at=coalesce(purge_started_at,clock_timestamp())
|
|
where id=p_report and state='done' and closed_at=p_closed_at and delete_after<=clock_timestamp() and linear_done_synced;
|
|
return found;
|
|
end; $$;
|
|
create function public.finish_bug_purge(p_report uuid,p_closed_at timestamptz)
|
|
returns boolean language plpgsql security invoker set search_path='' as $$
|
|
begin
|
|
delete from public.bug_reports where id=p_report and state='done' and closed_at=p_closed_at
|
|
and delete_after<=clock_timestamp() and purge_started_at is not null;
|
|
return found;
|
|
end; $$;
|
|
|
|
-- A closed conversation cannot gain new messages while deletion is in progress.
|
|
create function public.guard_done_bug_message() returns trigger
|
|
language plpgsql security invoker set search_path='' as $$
|
|
begin
|
|
perform 1 from public.bug_reports where id=new.report_id and purge_started_at is null
|
|
and (new.kind<>'user' or state<>'done') for share;
|
|
if not found then raise exception 'This bug report is Done'; end if;
|
|
return new;
|
|
end; $$;
|
|
create trigger guard_done_bug_message before insert on public.bug_report_messages
|
|
for each row execute function public.guard_done_bug_message();
|
|
revoke all on function public.set_bug_report_done(uuid,boolean,timestamptz),public.claim_bug_cleanup(uuid,text),
|
|
public.begin_bug_purge(uuid,timestamptz),public.finish_bug_purge(uuid,timestamptz),public.guard_done_bug_message()
|
|
from public,anon,authenticated;
|
|
grant execute on function public.set_bug_report_done(uuid,boolean,timestamptz),public.claim_bug_cleanup(uuid,text),
|
|
public.begin_bug_purge(uuid,timestamptz),public.finish_bug_purge(uuid,timestamptz),public.guard_done_bug_message() to service_role;
|
|
|
|
create function public.receive_bug_close(p_report uuid,p_external uuid) returns boolean
|
|
language plpgsql security invoker set search_path='' as $$
|
|
begin
|
|
perform 1 from public.bug_reports where id=p_report and state<>'draft' and purge_started_at is null for update;
|
|
if not found or exists(select 1 from public.bug_report_messages where external_id=p_external) then return false; end if;
|
|
insert into public.bug_report_messages(report_id,kind,body,author_name,delivered,external_id)
|
|
values(p_report,'system','Report closed.','Support',true,p_external);
|
|
return public.set_bug_report_done(p_report,true,null);
|
|
end; $$;
|
|
revoke all on function public.receive_bug_close(uuid,uuid) from public,anon,authenticated;
|
|
grant execute on function public.receive_bug_close(uuid,uuid) to service_role;
|