File size: 6,061 Bytes
3493993
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
-- 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;