Per organized-ideas.md §8: the storage layer (DiagramRepository etc.) was already renamed in an earlier phase; this finishes it everywhere else. - domain/types.ts: Project -> Diagram. domain/project.ts -> domain/diagram.ts (createEmptyProject -> createEmptyDiagram, default name "Untitled Diagram"). - domain/compatibility.ts, domain/bom.ts: Project param/type -> Diagram. - data/exportImport.ts: ProjectImportError -> DiagramImportError, projectToJson/downloadProjectFile/readProjectFile/normalizeProject -> their Diagram equivalents. - state/projectStore.ts -> state/diagramStore.ts: useProjectStore -> useDiagramStore, the `project` field -> `diagram`, newProject/renameProject/ importProject/applyRestoredProject -> *Diagram, restoredProjectUpdatedAt -> restoredDiagramUpdatedAt. - Every component updated to match, compiler-guided (tsc -b enumerated each remaining call site after the core rename, the same approach used for the earlier catalog-parameter refactor). - README updated for the terminology, and to match the repository class names (which had already been renamed but the README hadn't caught up). No backend/schema changes: the JSON shape stored in diagrams.data never changed, only TypeScript-side identifiers, so existing diagrams are unaffected. One SQL comment fixed for accuracy (no migration needed). Verified: tsc -b and oxlint clean; grepped src/ for any remaining Project/project reference (none) after the sweep.
115 lines
4.8 KiB
PL/PgSQL
115 lines
4.8 KiB
PL/PgSQL
-- Admin review queue support, per organized-ideas.md §3:
|
|
-- * a soft per-user cap on pending submissions (abuse prevention, §2)
|
|
-- * an impact-check an Admin can run before approving an edit to an
|
|
-- already-public entry — "how many diagrams reference this, and a short
|
|
-- sample" — computed by a privileged, aggregate-only function so regular
|
|
-- Admins (who don't have diagram visibility, only Super Admins do, per
|
|
-- §6) never see raw diagram content, just the blast-radius numbers.
|
|
|
|
-- ----------------------------------------------------------------------
|
|
-- Per-user pending-submission cap (10 — organized-ideas.md §3's "exact
|
|
-- number TBD when this is built").
|
|
-- ----------------------------------------------------------------------
|
|
|
|
drop policy "catalog_submissions_insert" on public.catalog_submissions;
|
|
|
|
create policy "catalog_submissions_insert" on public.catalog_submissions for insert
|
|
with check (
|
|
submitter_id = auth.uid()
|
|
and status = 'pending'
|
|
and (
|
|
select count(*) from public.catalog_submissions
|
|
where submitter_id = auth.uid() and status = 'pending'
|
|
) < 10
|
|
);
|
|
|
|
-- ----------------------------------------------------------------------
|
|
-- Usage-impact aggregate function.
|
|
--
|
|
-- A diagram's `data` JSONB mirrors the exported Diagram shape (see
|
|
-- data/exportImport.ts / domain/types.ts): devices[].templateId,
|
|
-- devices[].category, devices[].ports[].portTypeId, and
|
|
-- connections[].cableTypeId are the four places a catalog entity id can be
|
|
-- referenced. security definer so it can read every diagram regardless of
|
|
-- the caller's own diagrams RLS visibility — the is_admin() check below is
|
|
-- what keeps this from being an open door, and the return shape (a count
|
|
-- plus up to 5 {id, name, ownerUsername} samples) is deliberately far short
|
|
-- of full diagram content.
|
|
-- ----------------------------------------------------------------------
|
|
|
|
create or replace function public.catalog_entity_usage_impact(p_entity_type text, p_entity_id text)
|
|
returns table(diagram_count integer, sample jsonb)
|
|
language plpgsql
|
|
stable
|
|
security definer
|
|
set search_path = public
|
|
as $$
|
|
begin
|
|
if not public.is_admin() then
|
|
raise exception 'insufficient_privilege' using errcode = '42501';
|
|
end if;
|
|
|
|
return query
|
|
select count(*)::int, coalesce(jsonb_agg(jsonb_build_object('id', s.id, 'name', s.name, 'ownerUsername', s.owner_username) order by s.rn) filter (where s.rn <= 5), '[]'::jsonb)
|
|
from (
|
|
select d.id, d.name, p.username as owner_username,
|
|
row_number() over (order by d.updated_at desc) as rn
|
|
from public.diagrams d
|
|
join public.profiles p on p.id = d.owner_id
|
|
where case p_entity_type
|
|
when 'device_template' then exists (
|
|
select 1 from jsonb_array_elements(coalesce(d.data -> 'devices', '[]'::jsonb)) dev
|
|
where dev ->> 'templateId' = p_entity_id
|
|
)
|
|
when 'device_category' then exists (
|
|
select 1 from jsonb_array_elements(coalesce(d.data -> 'devices', '[]'::jsonb)) dev
|
|
where dev ->> 'category' = p_entity_id
|
|
)
|
|
when 'port_type' then exists (
|
|
select 1
|
|
from jsonb_array_elements(coalesce(d.data -> 'devices', '[]'::jsonb)) dev,
|
|
jsonb_array_elements(coalesce(dev -> 'ports', '[]'::jsonb)) port
|
|
where port ->> 'portTypeId' = p_entity_id
|
|
)
|
|
when 'cable_type' then exists (
|
|
select 1 from jsonb_array_elements(coalesce(d.data -> 'connections', '[]'::jsonb)) conn
|
|
where conn ->> 'cableTypeId' = p_entity_id
|
|
)
|
|
else false
|
|
end
|
|
) s;
|
|
end;
|
|
$$;
|
|
|
|
-- ----------------------------------------------------------------------
|
|
-- Batched submitter-username lookup for the review queue list.
|
|
--
|
|
-- profiles_select_self_or_super_admin deliberately keeps a regular Admin
|
|
-- from browsing other users' profiles directly — but an Admin reviewing a
|
|
-- submission already sees its content, so knowing *who* submitted it isn't
|
|
-- a bigger exposure than the usage-impact function's owner usernames
|
|
-- above; it's just gated the same way (admin-only, minimal fields, no
|
|
-- broader profile browsing). Batched (array in, rows out) so listing a
|
|
-- whole queue costs one round trip, not one per submission.
|
|
-- ----------------------------------------------------------------------
|
|
|
|
create or replace function public.catalog_submission_submitters(p_submission_ids uuid[])
|
|
returns table(submission_id uuid, username text)
|
|
language plpgsql
|
|
stable
|
|
security definer
|
|
set search_path = public
|
|
as $$
|
|
begin
|
|
if not public.is_admin() then
|
|
raise exception 'insufficient_privilege' using errcode = '42501';
|
|
end if;
|
|
|
|
return query
|
|
select s.id, p.username
|
|
from public.catalog_submissions s
|
|
join public.profiles p on p.id = s.submitter_id
|
|
where s.id = any(p_submission_ids);
|
|
end;
|
|
$$;
|