Spaces:
Sleeping
Sleeping
| -- Minimum authoritative Project -> Asset / durable Generation Job links. | |
| -- Apply after projects/0001 and security/0003_generation_domain_postgres.sql. | |
| begin; | |
| alter table media_assets add column if not exists project_id text; | |
| do $$ | |
| begin | |
| if not exists ( | |
| select 1 from pg_constraint | |
| where conname = 'fk_media_assets_project' | |
| and conrelid = 'media_assets'::regclass | |
| ) then | |
| alter table media_assets | |
| add constraint fk_media_assets_project | |
| foreign key (project_id) references projects(id) on delete restrict; | |
| end if; | |
| end $$; | |
| create index if not exists ix_media_assets_workspace_project_created | |
| on media_assets(workspace_id, project_id, created_at desc); | |
| create or replace function mediarouter_assert_media_asset_project_workspace() | |
| returns trigger language plpgsql as $$ | |
| declare project_workspace text; | |
| declare project_status text; | |
| begin | |
| if tg_op = 'UPDATE' and new.workspace_id is distinct from old.workspace_id then | |
| raise exception 'canonical asset workspace is immutable' using errcode = '23514'; | |
| end if; | |
| if new.project_id is not null then | |
| select workspace_id, status into project_workspace, project_status from projects | |
| where id = new.project_id; | |
| if project_workspace is null or project_workspace is distinct from new.workspace_id then | |
| raise exception 'project asset must belong to its project workspace' | |
| using errcode = '23503'; | |
| end if; | |
| if project_status is distinct from 'active' then | |
| raise exception 'canonical assets cannot be attached to an archived project' | |
| using errcode = '23514'; | |
| end if; | |
| end if; | |
| return new; | |
| end; | |
| $$; | |
| drop trigger if exists mediarouter_media_asset_project_workspace on media_assets; | |
| create trigger mediarouter_media_asset_project_workspace | |
| before insert or update of workspace_id, project_id on media_assets | |
| for each row execute function mediarouter_assert_media_asset_project_workspace(); | |
| create table if not exists project_generation_jobs ( | |
| id text primary key default gen_random_uuid()::text, | |
| workspace_id text not null references workspaces(id) on delete restrict, | |
| project_id text not null references projects(id) on delete restrict, | |
| generation_job_id text not null references generation_jobs(id) on delete restrict, | |
| attached_by text not null references users(id) on delete restrict, | |
| created_at timestamptz not null default now(), | |
| constraint uq_project_generation_job unique (generation_job_id) | |
| ); | |
| create index if not exists ix_project_generation_jobs_workspace_project_created | |
| on project_generation_jobs(workspace_id, project_id, created_at desc); | |
| create or replace function mediarouter_assert_project_generation_job_workspace() | |
| returns trigger language plpgsql as $$ | |
| declare project_workspace text; | |
| declare project_status text; | |
| declare job_workspace text; | |
| begin | |
| if tg_op = 'UPDATE' and ( | |
| new.workspace_id is distinct from old.workspace_id | |
| or new.project_id is distinct from old.project_id | |
| or new.generation_job_id is distinct from old.generation_job_id | |
| or new.attached_by is distinct from old.attached_by | |
| ) then | |
| raise exception 'project generation job ownership is immutable' | |
| using errcode = '23514'; | |
| end if; | |
| select workspace_id, status into project_workspace, project_status | |
| from projects where id = new.project_id; | |
| select workspace_id into job_workspace | |
| from generation_jobs where id = new.generation_job_id; | |
| if project_workspace is null | |
| or job_workspace is null | |
| or project_workspace is distinct from new.workspace_id | |
| or job_workspace is distinct from new.workspace_id then | |
| raise exception 'project generation job resources must share a workspace' | |
| using errcode = '23503'; | |
| end if; | |
| if project_status is distinct from 'active' then | |
| raise exception 'generation jobs cannot be attached to an archived project' | |
| using errcode = '23514'; | |
| end if; | |
| if not exists ( | |
| select 1 from workspace_memberships m | |
| where m.workspace_id = new.workspace_id | |
| and m.user_id = new.attached_by | |
| and m.status = 'active' | |
| ) then | |
| raise exception 'generation job attachment requires active workspace membership' | |
| using errcode = '23503'; | |
| end if; | |
| return new; | |
| end; | |
| $$; | |
| drop trigger if exists mediarouter_project_generation_job_workspace | |
| on project_generation_jobs; | |
| create trigger mediarouter_project_generation_job_workspace | |
| before insert or update on project_generation_jobs | |
| for each row execute function mediarouter_assert_project_generation_job_workspace(); | |
| alter table project_generation_jobs enable row level security; | |
| alter table project_generation_jobs force row level security; | |
| drop policy if exists project_generation_jobs_select on project_generation_jobs; | |
| create policy project_generation_jobs_select on project_generation_jobs for select using ( | |
| workspace_id = current_setting('app.workspace_id', true) | |
| and exists ( | |
| select 1 from workspace_memberships m | |
| where m.workspace_id = project_generation_jobs.workspace_id | |
| and m.user_id = current_setting('app.user_id', true) | |
| and m.status = 'active' | |
| ) | |
| ); | |
| drop policy if exists project_generation_jobs_insert on project_generation_jobs; | |
| create policy project_generation_jobs_insert on project_generation_jobs for insert with check ( | |
| workspace_id = current_setting('app.workspace_id', true) | |
| and attached_by = current_setting('app.user_id', true) | |
| and exists ( | |
| select 1 from workspace_memberships m | |
| where m.workspace_id = project_generation_jobs.workspace_id | |
| and m.user_id = current_setting('app.user_id', true) | |
| and m.status = 'active' | |
| ) | |
| ); | |
| drop policy if exists project_generation_jobs_delete on project_generation_jobs; | |
| create policy project_generation_jobs_delete on project_generation_jobs for delete using ( | |
| workspace_id = current_setting('app.workspace_id', true) | |
| and exists ( | |
| select 1 from workspace_memberships m | |
| where m.workspace_id = project_generation_jobs.workspace_id | |
| and m.user_id = current_setting('app.user_id', true) | |
| and m.status = 'active' | |
| ) | |
| ); | |
| commit; | |