@orion-studios/cms 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server/index.js
CHANGED
|
@@ -2204,6 +2204,9 @@ function runRpc(store, fn, args = {}) {
|
|
|
2204
2204
|
}
|
|
2205
2205
|
const version = reviewedVersion(page, args.p_expected_version_id);
|
|
2206
2206
|
if (!version) return versionConflict("the expected draft is missing or stale");
|
|
2207
|
+
if (page.published_version_id === version.id) {
|
|
2208
|
+
return versionConflict("the expected draft is already published");
|
|
2209
|
+
}
|
|
2207
2210
|
page.publish_at = args.p_publish_at;
|
|
2208
2211
|
page.scheduled_version_id = version.id;
|
|
2209
2212
|
page.updated_at = nowIso();
|
package/package.json
CHANGED
package/sql/bootstrap.sql
CHANGED
|
@@ -152,6 +152,16 @@ set publish_at = null,
|
|
|
152
152
|
where publish_at is not null
|
|
153
153
|
and scheduled_version_id is null;
|
|
154
154
|
|
|
155
|
+
-- A published version is not a future publication candidate. Clear invalid
|
|
156
|
+
-- schedules left by versions of the scheduling function that omitted this
|
|
157
|
+
-- guard, so repeated bootstrap runs repair existing databases fail closed.
|
|
158
|
+
update cms_pages
|
|
159
|
+
set publish_at = null,
|
|
160
|
+
scheduled_version_id = null,
|
|
161
|
+
updated_at = now()
|
|
162
|
+
where scheduled_version_id is not null
|
|
163
|
+
and scheduled_version_id = published_version_id;
|
|
164
|
+
|
|
155
165
|
create unique index if not exists cms_page_versions_page_id_id_idx
|
|
156
166
|
on cms_page_versions (page_id, id);
|
|
157
167
|
create index if not exists cms_pages_scheduled_publish_due_idx
|
|
@@ -624,6 +634,10 @@ begin
|
|
|
624
634
|
raise exception 'Page version conflict: expected draft is missing or stale';
|
|
625
635
|
end if;
|
|
626
636
|
|
|
637
|
+
if current_page.published_version_id = p_expected_version_id then
|
|
638
|
+
raise exception 'Page version conflict: expected draft is already published';
|
|
639
|
+
end if;
|
|
640
|
+
|
|
627
641
|
update cms_pages
|
|
628
642
|
set publish_at = p_publish_at,
|
|
629
643
|
scheduled_version_id = reviewed.id,
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
-- SEC-005: reject scheduling a version that is already published.
|
|
2
|
+
|
|
3
|
+
-- Repair schedules accepted by the 0.5.2 function. The version is already
|
|
4
|
+
-- public, so there is no future immutable draft to publish. Editors must
|
|
5
|
+
-- explicitly select a newer draft.
|
|
6
|
+
update cms_pages
|
|
7
|
+
set publish_at = null,
|
|
8
|
+
scheduled_version_id = null,
|
|
9
|
+
updated_at = now()
|
|
10
|
+
where scheduled_version_id is not null
|
|
11
|
+
and scheduled_version_id = published_version_id;
|
|
12
|
+
|
|
13
|
+
create or replace function cms_schedule_page_publish(
|
|
14
|
+
p_page_id uuid,
|
|
15
|
+
p_expected_version_id bigint,
|
|
16
|
+
p_publish_at timestamptz,
|
|
17
|
+
p_actor uuid
|
|
18
|
+
) returns cms_pages
|
|
19
|
+
language plpgsql
|
|
20
|
+
security definer
|
|
21
|
+
set search_path = public
|
|
22
|
+
as $$
|
|
23
|
+
declare
|
|
24
|
+
current_page cms_pages;
|
|
25
|
+
reviewed cms_page_versions;
|
|
26
|
+
result cms_pages;
|
|
27
|
+
begin
|
|
28
|
+
select * into current_page
|
|
29
|
+
from cms_pages
|
|
30
|
+
where id = p_page_id
|
|
31
|
+
for update;
|
|
32
|
+
|
|
33
|
+
if current_page.id is null then
|
|
34
|
+
raise exception 'page % not found', p_page_id;
|
|
35
|
+
end if;
|
|
36
|
+
|
|
37
|
+
if p_publish_at is null then
|
|
38
|
+
update cms_pages
|
|
39
|
+
set publish_at = null,
|
|
40
|
+
scheduled_version_id = null,
|
|
41
|
+
updated_at = now()
|
|
42
|
+
where id = p_page_id
|
|
43
|
+
returning * into result;
|
|
44
|
+
return result;
|
|
45
|
+
end if;
|
|
46
|
+
|
|
47
|
+
select * into reviewed
|
|
48
|
+
from cms_page_versions
|
|
49
|
+
where id = p_expected_version_id
|
|
50
|
+
and page_id = p_page_id;
|
|
51
|
+
|
|
52
|
+
if reviewed.id is null
|
|
53
|
+
or current_page.draft_version_id is distinct from p_expected_version_id
|
|
54
|
+
or reviewed.title is distinct from current_page.title
|
|
55
|
+
or reviewed.seo is distinct from current_page.seo
|
|
56
|
+
or reviewed.layout is distinct from current_page.draft_layout then
|
|
57
|
+
raise exception 'Page version conflict: expected draft is missing or stale';
|
|
58
|
+
end if;
|
|
59
|
+
|
|
60
|
+
if current_page.published_version_id = p_expected_version_id then
|
|
61
|
+
raise exception 'Page version conflict: expected draft is already published';
|
|
62
|
+
end if;
|
|
63
|
+
|
|
64
|
+
update cms_pages
|
|
65
|
+
set publish_at = p_publish_at,
|
|
66
|
+
scheduled_version_id = reviewed.id,
|
|
67
|
+
updated_at = now()
|
|
68
|
+
where id = p_page_id
|
|
69
|
+
returning * into result;
|
|
70
|
+
|
|
71
|
+
return result;
|
|
72
|
+
end;
|
|
73
|
+
$$;
|
|
74
|
+
|
|
75
|
+
do $fn_lockdown$
|
|
76
|
+
begin
|
|
77
|
+
revoke execute on function cms_schedule_page_publish(uuid, bigint, timestamptz, uuid) from public;
|
|
78
|
+
if exists (select 1 from pg_roles where rolname = 'anon') then
|
|
79
|
+
revoke execute on function cms_schedule_page_publish(uuid, bigint, timestamptz, uuid) from anon;
|
|
80
|
+
end if;
|
|
81
|
+
if exists (select 1 from pg_roles where rolname = 'authenticated') then
|
|
82
|
+
revoke execute on function cms_schedule_page_publish(uuid, bigint, timestamptz, uuid) from authenticated;
|
|
83
|
+
end if;
|
|
84
|
+
if exists (select 1 from pg_roles where rolname = 'service_role') then
|
|
85
|
+
grant execute on function cms_schedule_page_publish(uuid, bigint, timestamptz, uuid) to service_role;
|
|
86
|
+
end if;
|
|
87
|
+
end
|
|
88
|
+
$fn_lockdown$;
|