@nextblock-cms/db 0.2.8 → 0.2.10
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/lib/supabase/client.d.ts +9 -0
- package/lib/supabase/middleware.d.ts +2 -0
- package/lib/supabase/server.d.ts +7 -0
- package/lib/supabase/ssg-client.d.ts +2 -0
- package/lib/supabase/types.d.ts +635 -0
- package/package.json +3 -13
- package/supabase/config.toml +0 -319
- package/supabase/migrations/20250513194738_setup_roles_and_profiles.sql +0 -41
- package/supabase/migrations/20250513194910_auto_create_profile_trigger.sql +0 -48
- package/supabase/migrations/20250513194916_rls_for_profiles.sql +0 -85
- package/supabase/migrations/20250514125634_fix_recursive_rls_policies.sql +0 -51
- package/supabase/migrations/20250514143016_setup_languages_table.sql +0 -66
- package/supabase/migrations/20250514171549_create_pages_table.sql +0 -73
- package/supabase/migrations/20250514171550_create_posts_table.sql +0 -61
- package/supabase/migrations/20250514171552_create_media_table.sql +0 -45
- package/supabase/migrations/20250514171553_create_blocks_table.sql +0 -54
- package/supabase/migrations/20250514171615_create_navigation_table.sql +0 -56
- package/supabase/migrations/20250514171627_rls_policies_for_content_tables.sql +0 -70
- package/supabase/migrations/20250515194800_add_translation_group_id.sql +0 -39
- package/supabase/migrations/20250520171900_add_translation_group_to_nav_items.sql +0 -21
- package/supabase/migrations/20250521143933_seed_homepage_and_nav.sql +0 -64
- package/supabase/migrations/20250523145833_add_feature_image_to_posts.sql +0 -8
- package/supabase/migrations/20250523151737_add_rls_to_media_table.sql +0 -18
- package/supabase/migrations/20250526110400_add_image_dimensions_to_media.sql +0 -14
- package/supabase/migrations/20250526153321_optimize_rls_policies.sql +0 -188
- package/supabase/migrations/20250526172513_resolve_select_policy_overlaps.sql +0 -96
- package/supabase/migrations/20250526172853_resolve_remaining_rls_v5.sql +0 -107
- package/supabase/migrations/20250526173538_finalize_rls_cleanup_v7.sql +0 -110
- package/supabase/migrations/20250526174710_separate_write_policies_v8.sql +0 -147
- package/supabase/migrations/20250526175359_fix_languages_select_rls_v9.sql +0 -81
- package/supabase/migrations/20250526182940_fix_nav_read_policy_v10.sql +0 -27
- package/supabase/migrations/20250526183239_fix_posts_read_rls_v11.sql +0 -59
- package/supabase/migrations/20250526183746_fix_media_select_rls_v12.sql +0 -39
- package/supabase/migrations/20250526184205_consolidate_content_read_rls_v13.sql +0 -61
- package/supabase/migrations/20250526185854_optimize_indexes.sql +0 -47
- package/supabase/migrations/20250526190900_debug_blocks_rls.sql +0 -56
- package/supabase/migrations/20250526191217_consolidate_blocks_select_rls.sql +0 -79
- package/supabase/migrations/20250526192822_fix_handle_languages_update_search_path.sql +0 -32
- package/supabase/migrations/20250527150500_fix_blocks_rls_policy.sql +0 -54
- package/supabase/migrations/20250602150602_add_blur_data_url_to_media.sql +0 -4
- package/supabase/migrations/20250602150959_add_variants_to_media.sql +0 -4
- package/supabase/migrations/20250618124000_create_get_my_claim_function.sql +0 -5
- package/supabase/migrations/20250618124100_create_logos_table.sql +0 -29
- package/supabase/migrations/20250618130000_fix_linter_warnings.sql +0 -58
- package/supabase/migrations/20250618151500_revert_storage_rls.sql +0 -6
- package/supabase/migrations/20250619084800_reinstate_storage_rls.sql +0 -13
- package/supabase/migrations/20250619092430_widen_logo_insert_policy.sql +0 -6
- package/supabase/migrations/20250619093122_fix_get_my_claim_volatility.sql +0 -5
- package/supabase/migrations/20250619104249_consolidated_logo_rls_fix.sql +0 -56
- package/supabase/migrations/20250619110700_fix_logo_rls_again.sql +0 -59
- package/supabase/migrations/20250619113200_add_file_path_to_media.sql +0 -4
- package/supabase/migrations/20250619124100_fix_rls_performance_warnings.sql +0 -74
- package/supabase/migrations/20250619195500_create_site_settings_table.sql +0 -28
- package/supabase/migrations/20250619201500_add_anon_read_to_site_settings.sql +0 -7
- package/supabase/migrations/20250619202000_add_is_active_to_languages.sql +0 -5
- package/supabase/migrations/20250620085700_fix_site_settings_write_rls.sql +0 -27
- package/supabase/migrations/20250620095500_fix_profiles_read_rls.sql +0 -11
- package/supabase/migrations/20250620100000_use_security_definer_for_rls.sql +0 -39
- package/supabase/migrations/20250620130000_add_public_read_to_logos.sql +0 -4
- package/supabase/migrations/20250708091700_create_translations_table.sql +0 -55
- package/supabase/migrations/20250708093403_seed_translations_table.sql +0 -20
- package/supabase/migrations/20250708110600_fix_translations_rls_policies.sql +0 -11
- package/supabase/migrations/20250708112300_add_new_translations.sql +0 -9
- package/supabase/migrations/20250709120000_create_revisions_tables.sql +0 -109
- package/supabase/migrations/20251001113000_add_folder_to_media.sql +0 -14
- package/supabase/migrations/20251112113736_fix_search_path_functions.sql +0 -74
- package/supabase/migrations/20251112124444_fix_rls_performance.sql +0 -63
- package/supabase/migrations/20251112125935_fix_combined_policies.sql +0 -194
- package/supabase/migrations/20251112132146_fix_foreign_key_indexes.sql +0 -21
- package/supabase/migrations/20251112132525_cleanup_unused_indexes.sql +0 -10
- package/supabase/migrations/20251112132822_fix_final_indexes.sql +0 -14
- package/supabase/migrations/20251112140000_scaffold_foundational_content.sql +0 -95
- package/supabase/migrations/20251112141000_seed_homepage_blocks.sql +0 -656
- package/supabase/migrations/20251112142000_seed_how_it_works_post_blocks.sql +0 -100
- package/supabase/migrations/20251112143000_seed_additional_translations.sql +0 -102
- package/supabase/migrations/20251112145000_grant_public_schema_usage.sql +0 -6
- package/supabase/migrations/20251112145500_grant_select_on_public_tables.sql +0 -19
- package/supabase/migrations/20251117093000_add_admin_created_flag.sql +0 -21
- package/supabase/migrations/20251117103000_relax_profile_username_constraint.sql +0 -6
- package/supabase/migrations/20251117110000_relax_profiles_site_settings_rls_for_signup.sql +0 -20
- package/supabase/migrations/20251117112000_fix_handle_new_user_role_enum.sql +0 -45
- package/supabase/migrations/20251117113000_cleanup_rls_duplicates.sql +0 -20
- package/supabase/migrations/20251117200000_media_service_role_insert.sql +0 -14
- package/supabase/migrations/20251117201500_media_service_role_select.sql +0 -11
- package/supabase/migrations/20251117203000_media_admin_writer_select.sql +0 -11
- package/supabase/migrations/20251117204500_fix_media_permissions.sql +0 -43
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
-- lowercase sql
|
|
2
|
-
|
|
3
|
-
create table public.posts (
|
|
4
|
-
id bigint generated by default as identity primary key,
|
|
5
|
-
language_id bigint not null references public.languages(id) on delete cascade,
|
|
6
|
-
author_id uuid references public.profiles(id) on delete set null,
|
|
7
|
-
title text not null,
|
|
8
|
-
slug text not null,
|
|
9
|
-
excerpt text,
|
|
10
|
-
status public.page_status not null default 'draft', -- reuse page_status
|
|
11
|
-
published_at timestamp with time zone,
|
|
12
|
-
meta_title text,
|
|
13
|
-
meta_description text,
|
|
14
|
-
created_at timestamp with time zone not null default now(),
|
|
15
|
-
updated_at timestamp with time zone not null default now()
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
comment on table public.posts is 'stores blog posts or news articles.';
|
|
19
|
-
comment on column public.posts.slug is 'url-friendly identifier, unique per language.';
|
|
20
|
-
comment on column public.posts.excerpt is 'a short summary of the post.';
|
|
21
|
-
comment on column public.posts.published_at is 'date and time for publication.';
|
|
22
|
-
|
|
23
|
-
alter table public.posts
|
|
24
|
-
add constraint posts_language_id_slug_key unique (language_id, slug);
|
|
25
|
-
|
|
26
|
-
alter table public.posts enable row level security;
|
|
27
|
-
|
|
28
|
-
create policy "posts_are_publicly_readable_when_published"
|
|
29
|
-
on public.posts for select
|
|
30
|
-
to anon, authenticated
|
|
31
|
-
using (status = 'published' and (published_at is null or published_at <= now()));
|
|
32
|
-
|
|
33
|
-
create policy "authors_writers_admins_can_read_own_draft_posts"
|
|
34
|
-
on public.posts for select
|
|
35
|
-
to authenticated
|
|
36
|
-
using (
|
|
37
|
-
(status <> 'published' and author_id = auth.uid()) or
|
|
38
|
-
(status <> 'published'and public.get_current_user_role() in ('ADMIN', 'WRITER'))
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
create policy "admins_and_writers_can_manage_posts"
|
|
42
|
-
on public.posts for all
|
|
43
|
-
to authenticated
|
|
44
|
-
using (public.get_current_user_role() in ('ADMIN', 'WRITER'))
|
|
45
|
-
with check (public.get_current_user_role() in ('ADMIN', 'WRITER'));
|
|
46
|
-
|
|
47
|
-
create or replace function public.handle_posts_update()
|
|
48
|
-
returns trigger
|
|
49
|
-
language plpgsql
|
|
50
|
-
security definer set search_path = public
|
|
51
|
-
as $$
|
|
52
|
-
begin
|
|
53
|
-
new.updated_at = now();
|
|
54
|
-
return new;
|
|
55
|
-
end;
|
|
56
|
-
$$;
|
|
57
|
-
|
|
58
|
-
create trigger on_posts_update
|
|
59
|
-
before update on public.posts
|
|
60
|
-
for each row
|
|
61
|
-
execute procedure public.handle_posts_update();
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
-- lowercase sql
|
|
2
|
-
|
|
3
|
-
create table public.media (
|
|
4
|
-
id uuid primary key default gen_random_uuid(),
|
|
5
|
-
uploader_id uuid references public.profiles(id) on delete set null,
|
|
6
|
-
file_name text not null,
|
|
7
|
-
object_key text not null unique,
|
|
8
|
-
file_type text,
|
|
9
|
-
size_bytes bigint,
|
|
10
|
-
description text,
|
|
11
|
-
created_at timestamp with time zone not null default now(),
|
|
12
|
-
updated_at timestamp with time zone not null default now()
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
comment on table public.media is 'stores information about uploaded media assets.';
|
|
16
|
-
comment on column public.media.object_key is 'unique key (path) in cloudflare r2.';
|
|
17
|
-
|
|
18
|
-
alter table public.media enable row level security;
|
|
19
|
-
|
|
20
|
-
create policy "media_is_readable_by_all"
|
|
21
|
-
on public.media for select
|
|
22
|
-
to anon, authenticated
|
|
23
|
-
using (true);
|
|
24
|
-
|
|
25
|
-
create policy "admins_and_writers_can_manage_media"
|
|
26
|
-
on public.media for all
|
|
27
|
-
to authenticated
|
|
28
|
-
using (public.get_current_user_role() in ('ADMIN', 'WRITER'))
|
|
29
|
-
with check (public.get_current_user_role() in ('ADMIN', 'WRITER'));
|
|
30
|
-
|
|
31
|
-
create or replace function public.handle_media_update()
|
|
32
|
-
returns trigger
|
|
33
|
-
language plpgsql
|
|
34
|
-
security definer set search_path = public
|
|
35
|
-
as $$
|
|
36
|
-
begin
|
|
37
|
-
new.updated_at = now();
|
|
38
|
-
return new;
|
|
39
|
-
end;
|
|
40
|
-
$$;
|
|
41
|
-
|
|
42
|
-
create trigger on_media_update
|
|
43
|
-
before update on public.media
|
|
44
|
-
for each row
|
|
45
|
-
execute procedure public.handle_media_update();
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
-- lowercase sql
|
|
2
|
-
|
|
3
|
-
create table public.blocks (
|
|
4
|
-
id bigint generated by default as identity primary key,
|
|
5
|
-
page_id bigint references public.pages(id) on delete cascade,
|
|
6
|
-
post_id bigint references public.posts(id) on delete cascade,
|
|
7
|
-
language_id bigint not null references public.languages(id) on delete cascade,
|
|
8
|
-
block_type text not null,
|
|
9
|
-
content jsonb,
|
|
10
|
-
"order" integer not null default 0,
|
|
11
|
-
created_at timestamp with time zone not null default now(),
|
|
12
|
-
updated_at timestamp with time zone not null default now(),
|
|
13
|
-
constraint check_exactly_one_parent check (
|
|
14
|
-
(page_id is not null and post_id is null) or
|
|
15
|
-
(post_id is not null and page_id is null)
|
|
16
|
-
)
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
comment on table public.blocks is 'stores content blocks for pages and posts.';
|
|
20
|
-
comment on column public.blocks.block_type is 'type of the block, e.g., "text", "image".';
|
|
21
|
-
comment on column public.blocks.content is 'jsonb content specific to the block_type.';
|
|
22
|
-
comment on column public.blocks.order is 'sort order of the block.';
|
|
23
|
-
|
|
24
|
-
alter table public.blocks enable row level security;
|
|
25
|
-
|
|
26
|
-
create policy "blocks_are_readable_if_parent_is_published"
|
|
27
|
-
on public.blocks for select
|
|
28
|
-
to anon, authenticated
|
|
29
|
-
using (
|
|
30
|
-
(page_id is not null and exists(select 1 from public.pages p where p.id = blocks.page_id and p.status = 'published')) or
|
|
31
|
-
(post_id is not null and exists(select 1 from public.posts pt where pt.id = blocks.post_id and pt.status = 'published' and (pt.published_at is null or pt.published_at <= now())))
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
create policy "admins_and_writers_can_manage_blocks"
|
|
35
|
-
on public.blocks for all
|
|
36
|
-
to authenticated
|
|
37
|
-
using (public.get_current_user_role() in ('ADMIN', 'WRITER'))
|
|
38
|
-
with check (public.get_current_user_role() in ('ADMIN', 'WRITER'));
|
|
39
|
-
|
|
40
|
-
create or replace function public.handle_blocks_update()
|
|
41
|
-
returns trigger
|
|
42
|
-
language plpgsql
|
|
43
|
-
security definer set search_path = public
|
|
44
|
-
as $$
|
|
45
|
-
begin
|
|
46
|
-
new.updated_at = now();
|
|
47
|
-
return new;
|
|
48
|
-
end;
|
|
49
|
-
$$;
|
|
50
|
-
|
|
51
|
-
create trigger on_blocks_update
|
|
52
|
-
before update on public.blocks
|
|
53
|
-
for each row
|
|
54
|
-
execute procedure public.handle_blocks_update();
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
-- lowercase sql
|
|
2
|
-
|
|
3
|
-
do $$
|
|
4
|
-
begin
|
|
5
|
-
if not exists (select 1 from pg_type where typname = 'menu_location') then
|
|
6
|
-
create type public.menu_location as enum ('HEADER', 'FOOTER', 'SIDEBAR');
|
|
7
|
-
end if;
|
|
8
|
-
end
|
|
9
|
-
$$;
|
|
10
|
-
|
|
11
|
-
create table public.navigation_items (
|
|
12
|
-
id bigint generated by default as identity primary key,
|
|
13
|
-
language_id bigint not null references public.languages(id) on delete cascade,
|
|
14
|
-
menu_key public.menu_location not null,
|
|
15
|
-
label text not null,
|
|
16
|
-
url text not null,
|
|
17
|
-
parent_id bigint references public.navigation_items(id) on delete cascade,
|
|
18
|
-
"order" integer not null default 0,
|
|
19
|
-
page_id bigint references public.pages(id) on delete set null,
|
|
20
|
-
created_at timestamp with time zone not null default now(),
|
|
21
|
-
updated_at timestamp with time zone not null default now()
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
comment on table public.navigation_items is 'stores navigation menu items.';
|
|
25
|
-
comment on column public.navigation_items.menu_key is 'identifies the menu this item belongs to.';
|
|
26
|
-
|
|
27
|
-
create index idx_navigation_items_menu_lang_order on public.navigation_items (menu_key, language_id, "order");
|
|
28
|
-
|
|
29
|
-
alter table public.navigation_items enable row level security;
|
|
30
|
-
|
|
31
|
-
create policy "navigation_is_publicly_readable"
|
|
32
|
-
on public.navigation_items for select
|
|
33
|
-
to anon, authenticated
|
|
34
|
-
using (true);
|
|
35
|
-
|
|
36
|
-
create policy "admins_can_manage_navigation"
|
|
37
|
-
on public.navigation_items for all
|
|
38
|
-
to authenticated
|
|
39
|
-
using (public.get_current_user_role() = 'ADMIN')
|
|
40
|
-
with check (public.get_current_user_role() = 'ADMIN');
|
|
41
|
-
|
|
42
|
-
create or replace function public.handle_navigation_items_update()
|
|
43
|
-
returns trigger
|
|
44
|
-
language plpgsql
|
|
45
|
-
security definer set search_path = public
|
|
46
|
-
as $$
|
|
47
|
-
begin
|
|
48
|
-
new.updated_at = now();
|
|
49
|
-
return new;
|
|
50
|
-
end;
|
|
51
|
-
$$;
|
|
52
|
-
|
|
53
|
-
create trigger on_navigation_items_update
|
|
54
|
-
before update on public.navigation_items
|
|
55
|
-
for each row
|
|
56
|
-
execute procedure public.handle_navigation_items_update();
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
-- supabase/migrations/YYYYMMDDHHMMSS_rls_policies_for_content_tables.sql
|
|
2
|
-
-- lowercase sql
|
|
3
|
-
|
|
4
|
-
begin;
|
|
5
|
-
|
|
6
|
-
--
|
|
7
|
-
-- Pages Table RLS
|
|
8
|
-
--
|
|
9
|
-
alter table public.pages enable row level security;
|
|
10
|
-
|
|
11
|
-
drop policy if exists "authors_writers_admins_can_read_own_or_all_drafts" on public.pages;
|
|
12
|
-
-- allow authenticated users (authors, writers, admins) to read their own or all non-published pages
|
|
13
|
-
create policy "authors_writers_admins_can_read_own_or_all_drafts"
|
|
14
|
-
on public.pages for select
|
|
15
|
-
to authenticated
|
|
16
|
-
using (
|
|
17
|
-
(status <> 'published' and author_id = auth.uid()) or -- author can read their own non-published
|
|
18
|
-
(status <> 'published' and public.get_current_user_role() in ('ADMIN', 'WRITER')) -- admins/writers can read all non-published
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
--
|
|
22
|
-
-- Posts Table RLS
|
|
23
|
-
--
|
|
24
|
-
alter table public.posts enable row level security;
|
|
25
|
-
|
|
26
|
-
drop policy if exists "authors_writers_admins_can_read_own_or_all_draft_posts" on public.posts;
|
|
27
|
-
-- allow authenticated users (authors, writers, admins) to read their own or all non-published posts
|
|
28
|
-
create policy "authors_writers_admins_can_read_own_or_all_draft_posts"
|
|
29
|
-
on public.posts for select
|
|
30
|
-
to authenticated
|
|
31
|
-
using (
|
|
32
|
-
(status <> 'published' and author_id = auth.uid()) or
|
|
33
|
-
(status <> 'published'and public.get_current_user_role() in ('ADMIN', 'WRITER'))
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
--
|
|
37
|
-
-- Media Table RLS
|
|
38
|
-
--
|
|
39
|
-
alter table public.media enable row level security;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
--
|
|
43
|
-
-- Blocks Table RLS
|
|
44
|
-
--
|
|
45
|
-
alter table public.blocks enable row level security;
|
|
46
|
-
|
|
47
|
-
drop policy if exists "blocks_are_readable_if_parent_is_published" on public.blocks;
|
|
48
|
-
-- allow anonymous and authenticated users to read blocks if their parent page/post is published
|
|
49
|
-
create policy "blocks_are_readable_if_parent_is_published"
|
|
50
|
-
on public.blocks for select
|
|
51
|
-
to anon, authenticated
|
|
52
|
-
using (
|
|
53
|
-
(page_id is not null and exists(select 1 from public.pages p where p.id = blocks.page_id and p.status = 'published')) or
|
|
54
|
-
(post_id is not null and exists(select 1 from public.posts pt where pt.id = blocks.post_id and pt.status = 'published' and (pt.published_at is null or pt.published_at <= now())))
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
-- allow admins and writers to insert, update, delete blocks
|
|
58
|
-
drop policy if exists "admins_and_writers_can_manage_blocks" on public.blocks;
|
|
59
|
-
create policy "admins_and_writers_can_manage_blocks"
|
|
60
|
-
on public.blocks for all
|
|
61
|
-
to authenticated
|
|
62
|
-
using (public.get_current_user_role() in ('ADMIN', 'WRITER'))
|
|
63
|
-
with check (public.get_current_user_role() in ('ADMIN', 'WRITER'));
|
|
64
|
-
|
|
65
|
-
--
|
|
66
|
-
-- Navigation Items Table RLS
|
|
67
|
-
--
|
|
68
|
-
alter table public.navigation_items enable row level security;
|
|
69
|
-
|
|
70
|
-
commit;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
-- supabase/migrations/YYYYMMDDHHMMSS_add_translation_group_id.sql
|
|
2
|
-
|
|
3
|
-
ALTER TABLE public.pages
|
|
4
|
-
ADD COLUMN translation_group_id UUID DEFAULT gen_random_uuid() NOT NULL;
|
|
5
|
-
|
|
6
|
-
COMMENT ON COLUMN public.pages.translation_group_id IS 'Groups different language versions of the same conceptual page.';
|
|
7
|
-
|
|
8
|
-
CREATE INDEX IF NOT EXISTS idx_pages_translation_group_id ON public.pages(translation_group_id);
|
|
9
|
-
|
|
10
|
-
-- For existing pages, you'll need to manually group them.
|
|
11
|
-
-- Example: If page ID 1 (EN) and page ID 10 (FR) are the same conceptual page:
|
|
12
|
-
-- UPDATE public.pages SET translation_group_id = (SELECT translation_group_id FROM public.pages WHERE id = 1) WHERE id = 10;
|
|
13
|
-
-- Or, for all pages that share a slug currently (from the previous model):
|
|
14
|
-
-- WITH slug_groups AS (
|
|
15
|
-
-- SELECT slug, MIN(id) as first_id, gen_random_uuid() as new_group_id
|
|
16
|
-
-- FROM public.pages
|
|
17
|
-
-- GROUP BY slug
|
|
18
|
-
-- HAVING COUNT(*) > 1 -- Only for slugs that were shared
|
|
19
|
-
-- )
|
|
20
|
-
-- UPDATE public.pages p
|
|
21
|
-
-- SET translation_group_id = sg.new_group_id
|
|
22
|
-
-- FROM slug_groups sg
|
|
23
|
-
-- WHERE p.slug = sg.slug;
|
|
24
|
-
--
|
|
25
|
-
-- UPDATE public.pages p
|
|
26
|
-
-- SET translation_group_id = gen_random_uuid()
|
|
27
|
-
-- WHERE p.translation_group_id IS NULL AND EXISTS (
|
|
28
|
-
-- SELECT 1 FROM (
|
|
29
|
-
-- SELECT slug, COUNT(*) as c FROM public.pages GROUP BY slug
|
|
30
|
-
-- ) counts WHERE counts.slug = p.slug AND counts.c = 1
|
|
31
|
-
-- );
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
ALTER TABLE public.posts
|
|
35
|
-
ADD COLUMN translation_group_id UUID DEFAULT gen_random_uuid() NOT NULL;
|
|
36
|
-
|
|
37
|
-
COMMENT ON COLUMN public.posts.translation_group_id IS 'Groups different language versions of the same conceptual post.';
|
|
38
|
-
|
|
39
|
-
CREATE INDEX IF NOT EXISTS idx_posts_translation_group_id ON public.posts(translation_group_id);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
-- supabase/migrations/YYYYMMDDHHMMSS_add_translation_group_to_nav_items.sql
|
|
2
|
-
-- Replace YYYYMMDDHHMMSS with the actual timestamp, e.g., 20250520171700
|
|
3
|
-
|
|
4
|
-
ALTER TABLE public.navigation_items
|
|
5
|
-
ADD COLUMN translation_group_id UUID DEFAULT gen_random_uuid() NOT NULL;
|
|
6
|
-
|
|
7
|
-
COMMENT ON COLUMN public.navigation_items.translation_group_id IS 'Groups different language versions of the same conceptual navigation item.';
|
|
8
|
-
|
|
9
|
-
CREATE INDEX IF NOT EXISTS idx_navigation_items_translation_group_id ON public.navigation_items(translation_group_id);
|
|
10
|
-
|
|
11
|
-
-- Note: For existing navigation items, you will need to manually group them if they are translations of each other.
|
|
12
|
-
-- For example, if item ID 5 (EN) and item ID 25 (FR) are the same conceptual link:
|
|
13
|
-
-- UPDATE public.navigation_items SET translation_group_id = (SELECT translation_group_id FROM public.navigation_items WHERE id = 5 LIMIT 1) WHERE id = 25;
|
|
14
|
-
-- Or, assign a new group ID to both if they weren't grouped yet:
|
|
15
|
-
-- WITH new_group AS (SELECT gen_random_uuid() as new_id)
|
|
16
|
-
-- UPDATE public.navigation_items
|
|
17
|
-
-- SET translation_group_id = (SELECT new_id FROM new_group)
|
|
18
|
-
-- WHERE id IN (5, 25);
|
|
19
|
-
--
|
|
20
|
-
-- It's recommended to do this grouping manually based on your existing data logic.
|
|
21
|
-
-- New items created through the updated CMS logic will automatically get grouped.
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
-- supabase/migrations/YYYYMMDDHHMMSS_seed_homepage_and_nav.sql
|
|
2
|
-
-- Replace YYYYMMDDHHMMSS with the actual timestamp, e.g., 20250521100000
|
|
3
|
-
|
|
4
|
-
DO $$
|
|
5
|
-
DECLARE
|
|
6
|
-
en_lang_id BIGINT;
|
|
7
|
-
fr_lang_id BIGINT;
|
|
8
|
-
admin_user_id UUID;
|
|
9
|
-
home_page_translation_group UUID;
|
|
10
|
-
home_nav_translation_group UUID;
|
|
11
|
-
en_home_page_id BIGINT;
|
|
12
|
-
fr_home_page_id BIGINT;
|
|
13
|
-
BEGIN
|
|
14
|
-
-- Get language IDs
|
|
15
|
-
SELECT id INTO en_lang_id FROM public.languages WHERE code = 'en' LIMIT 1;
|
|
16
|
-
SELECT id INTO fr_lang_id FROM public.languages WHERE code = 'fr' LIMIT 1;
|
|
17
|
-
|
|
18
|
-
-- Get an admin user ID to set as author (optional, fallback to NULL)
|
|
19
|
-
SELECT id INTO admin_user_id FROM public.profiles WHERE role = 'ADMIN' LIMIT 1;
|
|
20
|
-
|
|
21
|
-
-- Check if languages were found
|
|
22
|
-
IF en_lang_id IS NULL THEN
|
|
23
|
-
RAISE EXCEPTION 'English language (en) not found. Please seed languages first.';
|
|
24
|
-
END IF;
|
|
25
|
-
IF fr_lang_id IS NULL THEN
|
|
26
|
-
RAISE EXCEPTION 'French language (fr) not found. Please seed languages first.';
|
|
27
|
-
END IF;
|
|
28
|
-
|
|
29
|
-
-- Generate translation group UUIDs
|
|
30
|
-
home_page_translation_group := gen_random_uuid();
|
|
31
|
-
home_nav_translation_group := gen_random_uuid();
|
|
32
|
-
|
|
33
|
-
-- Seed English Homepage
|
|
34
|
-
INSERT INTO public.pages (language_id, author_id, title, slug, status, meta_title, meta_description, translation_group_id)
|
|
35
|
-
VALUES (en_lang_id, admin_user_id, 'Home', 'home', 'published', 'Homepage', 'This is the homepage.', home_page_translation_group)
|
|
36
|
-
RETURNING id INTO en_home_page_id;
|
|
37
|
-
|
|
38
|
-
-- Seed French Homepage (Accueil)
|
|
39
|
-
INSERT INTO public.pages (language_id, author_id, title, slug, status, meta_title, meta_description, translation_group_id)
|
|
40
|
-
VALUES (fr_lang_id, admin_user_id, 'Accueil', 'accueil', 'published', 'Page d''accueil', 'Ceci est la page d''accueil.', home_page_translation_group)
|
|
41
|
-
RETURNING id INTO fr_home_page_id;
|
|
42
|
-
|
|
43
|
-
-- Seed initial content block for English Homepage (optional)
|
|
44
|
-
IF en_home_page_id IS NOT NULL THEN
|
|
45
|
-
INSERT INTO public.blocks (page_id, language_id, block_type, content, "order")
|
|
46
|
-
VALUES (en_home_page_id, en_lang_id, 'text', '{"html_content": "<p>Welcome to the English homepage!</p><p>This content is dynamically managed by the CMS.</p>"}', 0);
|
|
47
|
-
END IF;
|
|
48
|
-
|
|
49
|
-
-- Seed initial content block for French Homepage (optional)
|
|
50
|
-
IF fr_home_page_id IS NOT NULL THEN
|
|
51
|
-
INSERT INTO public.blocks (page_id, language_id, block_type, content, "order")
|
|
52
|
-
VALUES (fr_home_page_id, fr_lang_id, 'text', '{"html_content": "<p>Bienvenue sur la page d''accueil en français !</p><p>Ce contenu est géré dynamiquement par le CMS.</p>"}', 0);
|
|
53
|
-
END IF;
|
|
54
|
-
|
|
55
|
-
-- Seed English Navigation Item for Homepage (linked to the English page, but URL is root)
|
|
56
|
-
INSERT INTO public.navigation_items (language_id, menu_key, label, url, "order", page_id, translation_group_id)
|
|
57
|
-
VALUES (en_lang_id, 'HEADER', 'Home', '/', 0, en_home_page_id, home_nav_translation_group);
|
|
58
|
-
|
|
59
|
-
-- Seed French Navigation Item for Homepage (linked to the French page, but URL is root)
|
|
60
|
-
INSERT INTO public.navigation_items (language_id, menu_key, label, url, "order", page_id, translation_group_id)
|
|
61
|
-
VALUES (fr_lang_id, 'HEADER', 'Accueil', '/', 0, fr_home_page_id, home_nav_translation_group);
|
|
62
|
-
|
|
63
|
-
RAISE NOTICE 'Homepage and navigation links seeded for EN and FR.';
|
|
64
|
-
END $$;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
ALTER TABLE public.posts
|
|
2
|
-
ADD COLUMN feature_image_id UUID,
|
|
3
|
-
ADD CONSTRAINT fk_feature_image
|
|
4
|
-
FOREIGN KEY (feature_image_id)
|
|
5
|
-
REFERENCES public.media(id)
|
|
6
|
-
ON DELETE SET NULL;
|
|
7
|
-
|
|
8
|
-
COMMENT ON COLUMN public.posts.feature_image_id IS 'ID of the media item to be used as the post''s feature image.';
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
-- Drop existing policies if they exist, then recreate them.
|
|
2
|
-
|
|
3
|
-
-- Policy for public read access
|
|
4
|
-
DROP POLICY IF EXISTS "media_are_publicly_readable" ON public.media;
|
|
5
|
-
|
|
6
|
-
CREATE POLICY "media_are_publicly_readable"
|
|
7
|
-
ON public.media FOR SELECT
|
|
8
|
-
TO anon, authenticated
|
|
9
|
-
USING (true);
|
|
10
|
-
|
|
11
|
-
-- Policy for admin/writer management
|
|
12
|
-
DROP POLICY IF EXISTS "admins_and_writers_can_manage_media" ON public.media;
|
|
13
|
-
|
|
14
|
-
CREATE POLICY "admins_and_writers_can_manage_media"
|
|
15
|
-
ON public.media FOR ALL
|
|
16
|
-
TO authenticated
|
|
17
|
-
USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'))
|
|
18
|
-
WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
ALTER TABLE public.media
|
|
2
|
-
ADD COLUMN width INTEGER,
|
|
3
|
-
ADD COLUMN height INTEGER;
|
|
4
|
-
|
|
5
|
-
-- Optional: Add a comment to describe the new columns
|
|
6
|
-
COMMENT ON COLUMN public.media.width IS 'Width of the image in pixels.';
|
|
7
|
-
COMMENT ON COLUMN public.media.height IS 'Height of the image in pixels.';
|
|
8
|
-
|
|
9
|
-
-- Backfill existing image media with nulls, or you might want to run a script later to populate them if possible
|
|
10
|
-
-- For now, they will be NULL by default.
|
|
11
|
-
|
|
12
|
-
-- Re-apply RLS policies if necessary, though ADD COLUMN usually doesn't require it unless policies are column-specific
|
|
13
|
-
-- and these new columns need to be included or excluded.
|
|
14
|
-
-- For simplicity, assuming existing policies are fine.
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
-- supabase/migrations/YYYYMMDDHHMMSS_optimize_rls_policies_v2.sql
|
|
2
|
-
-- Replace YYYYMMDDHHMMSS with the actual timestamp of this migration file.
|
|
3
|
-
|
|
4
|
-
BEGIN;
|
|
5
|
-
|
|
6
|
-
-- == PROFILES ==
|
|
7
|
-
DROP POLICY IF EXISTS "users_can_select_own_profile" ON public.profiles;
|
|
8
|
-
DROP POLICY IF EXISTS "users_can_update_own_profile" ON public.profiles;
|
|
9
|
-
DROP POLICY IF EXISTS "admins_can_select_any_profile" ON public.profiles;
|
|
10
|
-
DROP POLICY IF EXISTS "admins_can_update_any_profile" ON public.profiles;
|
|
11
|
-
|
|
12
|
-
CREATE POLICY "authenticated_can_read_profiles" ON public.profiles
|
|
13
|
-
FOR SELECT
|
|
14
|
-
TO authenticated
|
|
15
|
-
USING (
|
|
16
|
-
(id = (SELECT auth.uid())) OR
|
|
17
|
-
(public.get_current_user_role() = 'ADMIN')
|
|
18
|
-
);
|
|
19
|
-
COMMENT ON POLICY "authenticated_can_read_profiles" ON public.profiles IS 'Authenticated users can read their own profile, and admins can read any profile.';
|
|
20
|
-
|
|
21
|
-
CREATE POLICY "authenticated_can_update_profiles" ON public.profiles
|
|
22
|
-
FOR UPDATE
|
|
23
|
-
TO authenticated
|
|
24
|
-
USING (
|
|
25
|
-
(id = (SELECT auth.uid())) OR
|
|
26
|
-
(public.get_current_user_role() = 'ADMIN')
|
|
27
|
-
)
|
|
28
|
-
WITH CHECK (
|
|
29
|
-
(id = (SELECT auth.uid())) OR
|
|
30
|
-
(public.get_current_user_role() = 'ADMIN')
|
|
31
|
-
);
|
|
32
|
-
COMMENT ON POLICY "authenticated_can_update_profiles" ON public.profiles IS 'Authenticated users can update their own profile, and admins can update any profile.';
|
|
33
|
-
|
|
34
|
-
-- Ensure admin insert policy is present and correct (it typically uses WITH CHECK on the role, not USING for insert)
|
|
35
|
-
DROP POLICY IF EXISTS "admins_can_insert_profiles" ON public.profiles;
|
|
36
|
-
CREATE POLICY "admins_can_insert_profiles" ON public.profiles
|
|
37
|
-
FOR INSERT TO authenticated
|
|
38
|
-
WITH CHECK (public.get_current_user_role() = 'ADMIN');
|
|
39
|
-
COMMENT ON POLICY "admins_can_insert_profiles" ON public.profiles IS 'Admin users can insert new profiles.';
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
-- == PAGES ==
|
|
43
|
-
DROP POLICY IF EXISTS "pages_are_publicly_readable_when_published" ON public.pages;
|
|
44
|
-
DROP POLICY IF EXISTS "authors_writers_admins_can_read_own_drafts" ON public.pages;
|
|
45
|
-
DROP POLICY IF EXISTS "authors_writers_admins_can_read_own_or_all_drafts" ON public.pages;
|
|
46
|
-
DROP POLICY IF EXISTS "admins_and_writers_can_manage_pages" ON public.pages;
|
|
47
|
-
|
|
48
|
-
CREATE POLICY "pages_anon_can_read_published" ON public.pages
|
|
49
|
-
FOR SELECT
|
|
50
|
-
TO anon
|
|
51
|
-
USING (status = 'published');
|
|
52
|
-
COMMENT ON POLICY "pages_anon_can_read_published" ON public.pages IS 'Anonymous users can read published pages.';
|
|
53
|
-
|
|
54
|
-
CREATE POLICY "pages_authenticated_access" ON public.pages
|
|
55
|
-
FOR SELECT
|
|
56
|
-
TO authenticated
|
|
57
|
-
USING (
|
|
58
|
-
(status = 'published') OR
|
|
59
|
-
(author_id = (SELECT auth.uid()) AND status <> 'published') OR
|
|
60
|
-
(public.get_current_user_role() IN ('ADMIN', 'WRITER'))
|
|
61
|
-
);
|
|
62
|
-
COMMENT ON POLICY "pages_authenticated_access" ON public.pages IS 'Authenticated users can read published pages, their own drafts, or all pages if admin/writer.';
|
|
63
|
-
|
|
64
|
-
CREATE POLICY "pages_admin_writer_management" ON public.pages
|
|
65
|
-
FOR ALL -- Changed from INSERT, UPDATE, DELETE
|
|
66
|
-
TO authenticated
|
|
67
|
-
USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'))
|
|
68
|
-
WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
|
|
69
|
-
COMMENT ON POLICY "pages_admin_writer_management" ON public.pages IS 'Admins and Writers can manage pages.';
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
-- == POSTS ==
|
|
73
|
-
DROP POLICY IF EXISTS "posts_are_publicly_readable_when_published" ON public.posts;
|
|
74
|
-
DROP POLICY IF EXISTS "authors_writers_admins_can_read_own_draft_posts" ON public.posts;
|
|
75
|
-
DROP POLICY IF EXISTS "authors_writers_admins_can_read_own_or_all_draft_posts" ON public.posts;
|
|
76
|
-
DROP POLICY IF EXISTS "admins_and_writers_can_manage_posts" ON public.posts;
|
|
77
|
-
|
|
78
|
-
CREATE POLICY "posts_anon_can_read_published" ON public.posts
|
|
79
|
-
FOR SELECT
|
|
80
|
-
TO anon
|
|
81
|
-
USING (status = 'published' AND (published_at IS NULL OR published_at <= now()));
|
|
82
|
-
COMMENT ON POLICY "posts_anon_can_read_published" ON public.posts IS 'Anonymous users can read published posts.';
|
|
83
|
-
|
|
84
|
-
CREATE POLICY "posts_authenticated_access" ON public.posts
|
|
85
|
-
FOR SELECT
|
|
86
|
-
TO authenticated
|
|
87
|
-
USING (
|
|
88
|
-
(status = 'published' AND (published_at IS NULL OR published_at <= now())) OR
|
|
89
|
-
(author_id = (SELECT auth.uid()) AND status <> 'published') OR
|
|
90
|
-
(public.get_current_user_role() IN ('ADMIN', 'WRITER'))
|
|
91
|
-
);
|
|
92
|
-
COMMENT ON POLICY "posts_authenticated_access" ON public.posts IS 'Authenticated users can read published posts, their own drafts, or all posts if admin/writer.';
|
|
93
|
-
|
|
94
|
-
CREATE POLICY "posts_admin_writer_management" ON public.posts
|
|
95
|
-
FOR ALL -- Changed from INSERT, UPDATE, DELETE
|
|
96
|
-
TO authenticated
|
|
97
|
-
USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'))
|
|
98
|
-
WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
|
|
99
|
-
COMMENT ON POLICY "posts_admin_writer_management" ON public.posts IS 'Admins and Writers can manage posts.';
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
-- == BLOCKS ==
|
|
103
|
-
DROP POLICY IF EXISTS "blocks_are_readable_if_parent_is_published" ON public.blocks;
|
|
104
|
-
DROP POLICY IF EXISTS "admins_and_writers_can_manage_blocks" ON public.blocks;
|
|
105
|
-
|
|
106
|
-
CREATE POLICY "blocks_anon_can_read_published" ON public.blocks
|
|
107
|
-
FOR SELECT
|
|
108
|
-
TO anon
|
|
109
|
-
USING (
|
|
110
|
-
(page_id IS NOT NULL AND EXISTS(SELECT 1 FROM public.pages p WHERE p.id = blocks.page_id AND p.status = 'published')) OR
|
|
111
|
-
(post_id IS NOT NULL AND EXISTS(SELECT 1 FROM public.posts pt WHERE pt.id = blocks.post_id AND pt.status = 'published' AND (pt.published_at IS NULL OR pt.published_at <= now())))
|
|
112
|
-
);
|
|
113
|
-
COMMENT ON POLICY "blocks_anon_can_read_published" ON public.blocks IS 'Anonymous users can read blocks of published parent pages/posts.';
|
|
114
|
-
|
|
115
|
-
CREATE POLICY "blocks_authenticated_access" ON public.blocks
|
|
116
|
-
FOR SELECT
|
|
117
|
-
TO authenticated
|
|
118
|
-
USING (
|
|
119
|
-
(public.get_current_user_role() IN ('ADMIN', 'WRITER')) OR
|
|
120
|
-
(
|
|
121
|
-
(public.get_current_user_role() = 'USER') AND (
|
|
122
|
-
(page_id IS NOT NULL AND EXISTS(SELECT 1 FROM public.pages p WHERE p.id = blocks.page_id AND p.status = 'published')) OR
|
|
123
|
-
(post_id IS NOT NULL AND EXISTS(SELECT 1 FROM public.posts pt WHERE pt.id = blocks.post_id AND pt.status = 'published' AND (pt.published_at IS NULL OR pt.published_at <= now())))
|
|
124
|
-
)
|
|
125
|
-
)
|
|
126
|
-
);
|
|
127
|
-
COMMENT ON POLICY "blocks_authenticated_access" ON public.blocks IS 'Admins/Writers can read all blocks; Users can read blocks of published parents.';
|
|
128
|
-
|
|
129
|
-
CREATE POLICY "blocks_admin_writer_management" ON public.blocks
|
|
130
|
-
FOR ALL -- Changed from INSERT, UPDATE, DELETE
|
|
131
|
-
TO authenticated
|
|
132
|
-
USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'))
|
|
133
|
-
WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
|
|
134
|
-
COMMENT ON POLICY "blocks_admin_writer_management" ON public.blocks IS 'Admins and Writers can manage blocks.';
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
-- == LANGUAGES ==
|
|
138
|
-
DROP POLICY IF EXISTS "languages_are_publicly_readable" ON public.languages;
|
|
139
|
-
DROP POLICY IF EXISTS "admins_can_manage_languages" ON public.languages;
|
|
140
|
-
|
|
141
|
-
CREATE POLICY "languages_are_publicly_readable_by_all" ON public.languages
|
|
142
|
-
FOR SELECT
|
|
143
|
-
USING (true);
|
|
144
|
-
COMMENT ON POLICY "languages_are_publicly_readable_by_all" ON public.languages IS 'All users (anon and authenticated) can read languages.';
|
|
145
|
-
|
|
146
|
-
CREATE POLICY "languages_admin_management" ON public.languages
|
|
147
|
-
FOR ALL -- Changed from INSERT, UPDATE, DELETE
|
|
148
|
-
TO authenticated
|
|
149
|
-
USING (public.get_current_user_role() = 'ADMIN')
|
|
150
|
-
WITH CHECK (public.get_current_user_role() = 'ADMIN');
|
|
151
|
-
COMMENT ON POLICY "languages_admin_management" ON public.languages IS 'Admins can manage languages.';
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
-- == MEDIA ==
|
|
155
|
-
DROP POLICY IF EXISTS "media_is_readable_by_all" ON public.media;
|
|
156
|
-
DROP POLICY IF EXISTS "media_are_publicly_readable" ON public.media;
|
|
157
|
-
DROP POLICY IF EXISTS "admins_and_writers_can_manage_media" ON public.media;
|
|
158
|
-
|
|
159
|
-
CREATE POLICY "media_is_publicly_readable_by_all" ON public.media
|
|
160
|
-
FOR SELECT
|
|
161
|
-
USING (true);
|
|
162
|
-
COMMENT ON POLICY "media_is_publicly_readable_by_all" ON public.media IS 'All users (anon and authenticated) can read media records.';
|
|
163
|
-
|
|
164
|
-
CREATE POLICY "media_admin_writer_management" ON public.media
|
|
165
|
-
FOR ALL -- Changed from INSERT, UPDATE, DELETE
|
|
166
|
-
TO authenticated
|
|
167
|
-
USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'))
|
|
168
|
-
WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
|
|
169
|
-
COMMENT ON POLICY "media_admin_writer_management" ON public.media IS 'Admins and Writers can manage media records.';
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
-- == NAVIGATION ITEMS ==
|
|
173
|
-
DROP POLICY IF EXISTS "navigation_is_publicly_readable" ON public.navigation_items;
|
|
174
|
-
DROP POLICY IF EXISTS "admins_can_manage_navigation" ON public.navigation_items;
|
|
175
|
-
|
|
176
|
-
CREATE POLICY "nav_items_are_publicly_readable_by_all" ON public.navigation_items
|
|
177
|
-
FOR SELECT
|
|
178
|
-
USING (true);
|
|
179
|
-
COMMENT ON POLICY "nav_items_are_publicly_readable_by_all" ON public.navigation_items IS 'All users (anon and authenticated) can read navigation items.';
|
|
180
|
-
|
|
181
|
-
CREATE POLICY "nav_items_admin_management" ON public.navigation_items
|
|
182
|
-
FOR ALL -- Changed from INSERT, UPDATE, DELETE
|
|
183
|
-
TO authenticated
|
|
184
|
-
USING (public.get_current_user_role() = 'ADMIN')
|
|
185
|
-
WITH CHECK (public.get_current_user_role() = 'ADMIN');
|
|
186
|
-
COMMENT ON POLICY "nav_items_admin_management" ON public.navigation_items IS 'Admins can manage navigation items.';
|
|
187
|
-
|
|
188
|
-
COMMIT;
|