* Add v17.6.8 Developer Console UX and race fixes * Add Developer Console numbering delete and grouped error RPCs * Add one-time v17.6.8 release preparation workflow * Prepare Caterium v17.6.8 Developer Console UX * Remove one-time v17.6.8 release workflow --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
237 lines
6.9 KiB
PL/PgSQL
237 lines
6.9 KiB
PL/PgSQL
-- Caterium v17.6.8 Developer Console UX
|
|
-- Persistent company numbers, safe company deletion and grouped production error journal.
|
|
|
|
create sequence if not exists public.sun_workspace_company_number_seq;
|
|
|
|
alter table public.sun_workspaces
|
|
add column if not exists company_number bigint;
|
|
|
|
with numbered as (
|
|
select id,row_number() over(order by created_at,id)::bigint as n
|
|
from public.sun_workspaces
|
|
where company_number is null
|
|
), existing as (
|
|
select coalesce(max(company_number),0)::bigint as max_n from public.sun_workspaces
|
|
)
|
|
update public.sun_workspaces w
|
|
set company_number = numbered.n + existing.max_n
|
|
from numbered,existing
|
|
where w.id=numbered.id and w.company_number is null;
|
|
|
|
select setval(
|
|
'public.sun_workspace_company_number_seq',
|
|
greatest(1,coalesce((select max(company_number) from public.sun_workspaces),0)),
|
|
coalesce((select max(company_number) from public.sun_workspaces),0)>0
|
|
);
|
|
|
|
alter table public.sun_workspaces
|
|
alter column company_number set default nextval('public.sun_workspace_company_number_seq');
|
|
|
|
update public.sun_workspaces
|
|
set company_number=nextval('public.sun_workspace_company_number_seq')
|
|
where company_number is null;
|
|
|
|
alter table public.sun_workspaces
|
|
alter column company_number set not null;
|
|
|
|
create unique index if not exists sun_workspaces_company_number_uq
|
|
on public.sun_workspaces(company_number);
|
|
|
|
create or replace function public.sun_dev_list_companies_v1768()
|
|
returns table(
|
|
workspace_id uuid,
|
|
workspace_name text,
|
|
company_number bigint,
|
|
created_at timestamptz,
|
|
plan_id text,
|
|
plan_name text,
|
|
status text,
|
|
access_mode text,
|
|
trial_ends_at timestamptz,
|
|
current_period_end timestamptz,
|
|
grace_until timestamptz,
|
|
member_count bigint,
|
|
max_members integer,
|
|
owner_email text,
|
|
pending_owner_email text
|
|
)
|
|
language plpgsql
|
|
stable
|
|
security definer
|
|
set search_path='public','auth'
|
|
as $$
|
|
begin
|
|
perform public.sun_require_platform_admin_aal2();
|
|
return query
|
|
select
|
|
w.id,
|
|
w.name,
|
|
w.company_number,
|
|
w.created_at,
|
|
s.plan_id,
|
|
p.name,
|
|
s.status,
|
|
public.sun_subscription_access_mode(w.id),
|
|
s.trial_ends_at,
|
|
s.current_period_end,
|
|
s.grace_until,
|
|
(select count(*) from public.sun_workspace_members m where m.workspace_id=w.id and m.is_active),
|
|
p.max_members,
|
|
(select u.email::text
|
|
from public.sun_workspace_members m
|
|
join auth.users u on u.id=m.user_id
|
|
where m.workspace_id=w.id and m.role='admin' and m.is_active
|
|
order by m.created_at asc
|
|
limit 1),
|
|
(select i.email
|
|
from public.caterium_company_owner_invites i
|
|
where i.workspace_id=w.id and i.used_at is null and i.expires_at>now()
|
|
order by i.created_at desc
|
|
limit 1)
|
|
from public.sun_workspaces w
|
|
left join public.sun_workspace_subscriptions s on s.workspace_id=w.id
|
|
left join public.sun_plans p on p.id=s.plan_id
|
|
order by w.company_number;
|
|
end;
|
|
$$;
|
|
|
|
create or replace function public.sun_dev_delete_company_v1768(
|
|
p_workspace uuid,
|
|
p_confirm_name text
|
|
) returns jsonb
|
|
language plpgsql
|
|
security definer
|
|
set search_path='public','auth'
|
|
as $$
|
|
declare
|
|
v_name text;
|
|
v_number bigint;
|
|
v_members bigint;
|
|
v_orders bigint;
|
|
v_clients bigint;
|
|
v_catalog bigint;
|
|
begin
|
|
perform public.sun_require_platform_admin_aal2();
|
|
|
|
select w.name,w.company_number
|
|
into v_name,v_number
|
|
from public.sun_workspaces w
|
|
where w.id=p_workspace
|
|
for update;
|
|
|
|
if v_name is null then raise exception 'Workspace not found'; end if;
|
|
if trim(coalesce(p_confirm_name,'')) <> v_name then raise exception 'Company name confirmation mismatch'; end if;
|
|
|
|
select count(*) into v_members from public.sun_workspace_members where workspace_id=p_workspace;
|
|
select count(*) into v_orders from public.sun_v17_orders where workspace_id=p_workspace;
|
|
select count(*) into v_clients from public.sun_v17_clients where workspace_id=p_workspace;
|
|
select count(*) into v_catalog from public.sun_v17_catalog_items where workspace_id=p_workspace;
|
|
|
|
perform public.sun_platform_log_event(
|
|
'company.delete',
|
|
p_workspace,
|
|
null,
|
|
jsonb_build_object(
|
|
'company',v_name,
|
|
'company_number',v_number,
|
|
'members',v_members,
|
|
'orders',v_orders,
|
|
'clients',v_clients,
|
|
'catalog_items',v_catalog,
|
|
'auth_accounts_preserved',true
|
|
)
|
|
);
|
|
|
|
delete from public.sun_workspaces where id=p_workspace;
|
|
|
|
return jsonb_build_object(
|
|
'deleted',true,
|
|
'workspace_id',p_workspace,
|
|
'workspace_name',v_name,
|
|
'company_number',v_number,
|
|
'memberships_removed',v_members,
|
|
'auth_accounts_preserved',true
|
|
);
|
|
end;
|
|
$$;
|
|
|
|
create or replace function public.sun_dev_error_groups_v1768(
|
|
p_hours integer default 168,
|
|
p_limit integer default 100
|
|
) returns table(
|
|
workspace_name text,
|
|
app_version text,
|
|
level text,
|
|
message text,
|
|
occurrences bigint,
|
|
first_seen timestamptz,
|
|
last_seen timestamptz,
|
|
sample_stack text,
|
|
source_url text
|
|
)
|
|
language plpgsql
|
|
stable
|
|
security definer
|
|
set search_path='public'
|
|
as $$
|
|
declare
|
|
v_hours integer:=greatest(1,least(coalesce(p_hours,168),720));
|
|
v_limit integer:=greatest(1,least(coalesce(p_limit,100),200));
|
|
begin
|
|
perform public.sun_require_platform_admin_aal2();
|
|
return query
|
|
with scoped as (
|
|
select
|
|
e.*,
|
|
w.name as company_name,
|
|
nullif(e.context->>'url','') as event_url
|
|
from public.sun_v17_error_events e
|
|
left join public.sun_workspaces w on w.id=e.workspace_id
|
|
where e.created_at >= now()-make_interval(hours=>v_hours)
|
|
and coalesce(e.context->>'url','') !~* '^file:'
|
|
), grouped as (
|
|
select
|
|
company_name,
|
|
coalesce(app_version,'') as app_version,
|
|
coalesce(level,'error') as level,
|
|
coalesce(message,'Unknown error') as message,
|
|
count(*)::bigint as occurrences,
|
|
min(created_at) as first_seen,
|
|
max(created_at) as last_seen
|
|
from scoped
|
|
group by company_name,coalesce(app_version,''),coalesce(level,'error'),coalesce(message,'Unknown error')
|
|
)
|
|
select
|
|
g.company_name,
|
|
nullif(g.app_version,''),
|
|
g.level,
|
|
g.message,
|
|
g.occurrences,
|
|
g.first_seen,
|
|
g.last_seen,
|
|
s.stack,
|
|
s.event_url
|
|
from grouped g
|
|
left join lateral (
|
|
select x.stack,x.event_url
|
|
from scoped x
|
|
where x.company_name is not distinct from g.company_name
|
|
and coalesce(x.app_version,'')=g.app_version
|
|
and coalesce(x.level,'error')=g.level
|
|
and coalesce(x.message,'Unknown error')=g.message
|
|
order by x.created_at desc
|
|
limit 1
|
|
) s on true
|
|
order by g.last_seen desc
|
|
limit v_limit;
|
|
end;
|
|
$$;
|
|
|
|
revoke all on function public.sun_dev_list_companies_v1768() from public,anon;
|
|
revoke all on function public.sun_dev_delete_company_v1768(uuid,text) from public,anon;
|
|
revoke all on function public.sun_dev_error_groups_v1768(integer,integer) from public,anon;
|
|
|
|
grant execute on function public.sun_dev_list_companies_v1768() to authenticated;
|
|
grant execute on function public.sun_dev_delete_company_v1768(uuid,text) to authenticated;
|
|
grant execute on function public.sun_dev_error_groups_v1768(integer,integer) to authenticated;
|