@nextblock-cms/db 0.2.10 → 0.2.13

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.
Files changed (86) hide show
  1. package/package.json +13 -3
  2. package/supabase/config.toml +319 -0
  3. package/supabase/migrations/20250513194738_setup_roles_and_profiles.sql +41 -0
  4. package/supabase/migrations/20250513194910_auto_create_profile_trigger.sql +48 -0
  5. package/supabase/migrations/20250513194916_rls_for_profiles.sql +85 -0
  6. package/supabase/migrations/20250514125634_fix_recursive_rls_policies.sql +51 -0
  7. package/supabase/migrations/20250514143016_setup_languages_table.sql +66 -0
  8. package/supabase/migrations/20250514171549_create_pages_table.sql +73 -0
  9. package/supabase/migrations/20250514171550_create_posts_table.sql +61 -0
  10. package/supabase/migrations/20250514171552_create_media_table.sql +45 -0
  11. package/supabase/migrations/20250514171553_create_blocks_table.sql +54 -0
  12. package/supabase/migrations/20250514171615_create_navigation_table.sql +56 -0
  13. package/supabase/migrations/20250514171627_rls_policies_for_content_tables.sql +70 -0
  14. package/supabase/migrations/20250515194800_add_translation_group_id.sql +39 -0
  15. package/supabase/migrations/20250520171900_add_translation_group_to_nav_items.sql +21 -0
  16. package/supabase/migrations/20250521143933_seed_homepage_and_nav.sql +64 -0
  17. package/supabase/migrations/20250523145833_add_feature_image_to_posts.sql +8 -0
  18. package/supabase/migrations/20250523151737_add_rls_to_media_table.sql +18 -0
  19. package/supabase/migrations/20250526110400_add_image_dimensions_to_media.sql +14 -0
  20. package/supabase/migrations/20250526153321_optimize_rls_policies.sql +188 -0
  21. package/supabase/migrations/20250526172513_resolve_select_policy_overlaps.sql +96 -0
  22. package/supabase/migrations/20250526172853_resolve_remaining_rls_v5.sql +107 -0
  23. package/supabase/migrations/20250526173538_finalize_rls_cleanup_v7.sql +110 -0
  24. package/supabase/migrations/20250526174710_separate_write_policies_v8.sql +147 -0
  25. package/supabase/migrations/20250526175359_fix_languages_select_rls_v9.sql +81 -0
  26. package/supabase/migrations/20250526182940_fix_nav_read_policy_v10.sql +27 -0
  27. package/supabase/migrations/20250526183239_fix_posts_read_rls_v11.sql +59 -0
  28. package/supabase/migrations/20250526183746_fix_media_select_rls_v12.sql +39 -0
  29. package/supabase/migrations/20250526184205_consolidate_content_read_rls_v13.sql +61 -0
  30. package/supabase/migrations/20250526185854_optimize_indexes.sql +47 -0
  31. package/supabase/migrations/20250526190900_debug_blocks_rls.sql +56 -0
  32. package/supabase/migrations/20250526191217_consolidate_blocks_select_rls.sql +79 -0
  33. package/supabase/migrations/20250526192822_fix_handle_languages_update_search_path.sql +32 -0
  34. package/supabase/migrations/20250527150500_fix_blocks_rls_policy.sql +54 -0
  35. package/supabase/migrations/20250602150602_add_blur_data_url_to_media.sql +4 -0
  36. package/supabase/migrations/20250602150959_add_variants_to_media.sql +4 -0
  37. package/supabase/migrations/20250618124000_create_get_my_claim_function.sql +5 -0
  38. package/supabase/migrations/20250618124100_create_logos_table.sql +29 -0
  39. package/supabase/migrations/20250618130000_fix_linter_warnings.sql +58 -0
  40. package/supabase/migrations/20250618151500_revert_storage_rls.sql +6 -0
  41. package/supabase/migrations/20250619084800_reinstate_storage_rls.sql +13 -0
  42. package/supabase/migrations/20250619092430_widen_logo_insert_policy.sql +6 -0
  43. package/supabase/migrations/20250619093122_fix_get_my_claim_volatility.sql +5 -0
  44. package/supabase/migrations/20250619104249_consolidated_logo_rls_fix.sql +56 -0
  45. package/supabase/migrations/20250619110700_fix_logo_rls_again.sql +59 -0
  46. package/supabase/migrations/20250619113200_add_file_path_to_media.sql +4 -0
  47. package/supabase/migrations/20250619124100_fix_rls_performance_warnings.sql +74 -0
  48. package/supabase/migrations/20250619195500_create_site_settings_table.sql +28 -0
  49. package/supabase/migrations/20250619201500_add_anon_read_to_site_settings.sql +7 -0
  50. package/supabase/migrations/20250619202000_add_is_active_to_languages.sql +5 -0
  51. package/supabase/migrations/20250620085700_fix_site_settings_write_rls.sql +27 -0
  52. package/supabase/migrations/20250620095500_fix_profiles_read_rls.sql +11 -0
  53. package/supabase/migrations/20250620100000_use_security_definer_for_rls.sql +39 -0
  54. package/supabase/migrations/20250620130000_add_public_read_to_logos.sql +4 -0
  55. package/supabase/migrations/20250708091700_create_translations_table.sql +55 -0
  56. package/supabase/migrations/20250708093403_seed_translations_table.sql +20 -0
  57. package/supabase/migrations/20250708110600_fix_translations_rls_policies.sql +11 -0
  58. package/supabase/migrations/20250708112300_add_new_translations.sql +9 -0
  59. package/supabase/migrations/20250709120000_create_revisions_tables.sql +109 -0
  60. package/supabase/migrations/20251001113000_add_folder_to_media.sql +14 -0
  61. package/supabase/migrations/20251112113736_fix_search_path_functions.sql +74 -0
  62. package/supabase/migrations/20251112124444_fix_rls_performance.sql +63 -0
  63. package/supabase/migrations/20251112125935_fix_combined_policies.sql +194 -0
  64. package/supabase/migrations/20251112132146_fix_foreign_key_indexes.sql +21 -0
  65. package/supabase/migrations/20251112132525_cleanup_unused_indexes.sql +10 -0
  66. package/supabase/migrations/20251112132822_fix_final_indexes.sql +14 -0
  67. package/supabase/migrations/20251112140000_scaffold_foundational_content.sql +95 -0
  68. package/supabase/migrations/20251112141000_seed_homepage_blocks.sql +656 -0
  69. package/supabase/migrations/20251112142000_seed_how_it_works_post_blocks.sql +100 -0
  70. package/supabase/migrations/20251112143000_seed_additional_translations.sql +102 -0
  71. package/supabase/migrations/20251112145000_grant_public_schema_usage.sql +6 -0
  72. package/supabase/migrations/20251112145500_grant_select_on_public_tables.sql +19 -0
  73. package/supabase/migrations/20251117093000_add_admin_created_flag.sql +21 -0
  74. package/supabase/migrations/20251117103000_relax_profile_username_constraint.sql +6 -0
  75. package/supabase/migrations/20251117110000_relax_profiles_site_settings_rls_for_signup.sql +20 -0
  76. package/supabase/migrations/20251117112000_fix_handle_new_user_role_enum.sql +45 -0
  77. package/supabase/migrations/20251117113000_cleanup_rls_duplicates.sql +20 -0
  78. package/supabase/migrations/20251117200000_media_service_role_insert.sql +14 -0
  79. package/supabase/migrations/20251117201500_media_service_role_select.sql +11 -0
  80. package/supabase/migrations/20251117203000_media_admin_writer_select.sql +11 -0
  81. package/supabase/migrations/20251117204500_fix_media_permissions.sql +43 -0
  82. package/lib/supabase/client.d.ts +0 -9
  83. package/lib/supabase/middleware.d.ts +0 -2
  84. package/lib/supabase/server.d.ts +0 -7
  85. package/lib/supabase/ssg-client.d.ts +0 -2
  86. package/lib/supabase/types.d.ts +0 -635
@@ -0,0 +1,188 @@
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;
@@ -0,0 +1,96 @@
1
+ -- supabase/migrations/YYYYMMDDHHMMSS_resolve_select_policy_overlaps.sql
2
+ -- (Ensure YYYYMMDDHHMMSS is the current timestamp)
3
+
4
+ BEGIN;
5
+
6
+ -- == BLOCKS ==
7
+ -- Assuming "blocks_admin_writer_management" is FOR ALL and covers SELECT for ADMIN/WRITER.
8
+ -- Make "blocks_authenticated_access" specific to non-ADMIN/WRITER authenticated users.
9
+ DROP POLICY IF EXISTS "blocks_authenticated_access" ON public.blocks;
10
+ CREATE POLICY "blocks_authenticated_user_access" ON public.blocks -- Renamed for clarity
11
+ FOR SELECT
12
+ TO authenticated
13
+ USING (
14
+ (public.get_current_user_role() NOT IN ('ADMIN', 'WRITER')) AND -- This is the key change
15
+ (
16
+ (page_id IS NOT NULL AND EXISTS(SELECT 1 FROM public.pages p WHERE p.id = blocks.page_id AND p.status = 'published')) OR
17
+ (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())))
18
+ )
19
+ );
20
+ COMMENT ON POLICY "blocks_authenticated_user_access" ON public.blocks IS 'Authenticated USERS (non-admin/writer) can read blocks of published parents. Admin/Writer SELECT via their management policy.';
21
+ -- Note: "blocks_anon_can_read_published" (FOR SELECT TO anon) should remain unchanged.
22
+ -- Note: "blocks_admin_writer_management" (FOR ALL TO authenticated USING role IN (ADMIN,WRITER)) should remain unchanged.
23
+
24
+ -- == LANGUAGES ==
25
+ -- Assuming "languages_admin_management" is FOR ALL and covers SELECT for ADMIN.
26
+ -- Make "languages_are_publicly_readable_by_all" not apply to authenticated ADMINs.
27
+ DROP POLICY IF EXISTS "languages_are_publicly_readable_by_all" ON public.languages;
28
+ CREATE POLICY "languages_readable_by_anon_and_non_admins" ON public.languages -- Renamed
29
+ FOR SELECT
30
+ USING (
31
+ NOT (auth.role() = 'authenticated' AND public.get_current_user_role() = 'ADMIN')
32
+ );
33
+ COMMENT ON POLICY "languages_readable_by_anon_and_non_admins" ON public.languages IS 'Anonymous users and authenticated non-admins can read languages. Admin SELECT via management policy.';
34
+ -- Note: "languages_admin_management" (FOR ALL TO authenticated USING role = ADMIN) should remain unchanged.
35
+
36
+ -- == MEDIA ==
37
+ -- Assuming "media_admin_writer_management" is FOR ALL and covers SELECT for ADMIN/WRITER.
38
+ -- Make "media_is_publicly_readable_by_all" not apply to authenticated ADMIN/WRITERs.
39
+ DROP POLICY IF EXISTS "media_is_publicly_readable_by_all" ON public.media;
40
+ CREATE POLICY "media_readable_by_anon_and_non_privileged_users" ON public.media -- Renamed
41
+ FOR SELECT
42
+ USING (
43
+ NOT (auth.role() = 'authenticated' AND public.get_current_user_role() IN ('ADMIN', 'WRITER'))
44
+ );
45
+ COMMENT ON POLICY "media_readable_by_anon_and_non_privileged_users" ON public.media IS 'Anonymous users and authenticated non-admin/writer users can read media. Admin/Writer SELECT via management policy.';
46
+ -- Note: "media_admin_writer_management" (FOR ALL TO authenticated USING role IN (ADMIN,WRITER)) should remain unchanged.
47
+
48
+ -- == NAVIGATION ITEMS ==
49
+ -- Assuming "nav_items_admin_management" is FOR ALL and covers SELECT for ADMIN.
50
+ -- Make "nav_items_are_publicly_readable_by_all" not apply to authenticated ADMINs.
51
+ DROP POLICY IF EXISTS "nav_items_are_publicly_readable_by_all" ON public.navigation_items;
52
+ CREATE POLICY "nav_items_readable_by_anon_and_non_admins" ON public.navigation_items -- Renamed
53
+ FOR SELECT
54
+ USING (
55
+ NOT (auth.role() = 'authenticated' AND public.get_current_user_role() = 'ADMIN')
56
+ );
57
+ COMMENT ON POLICY "nav_items_readable_by_anon_and_non_admins" ON public.navigation_items IS 'Anonymous users and authenticated non-admins can read nav items. Admin SELECT via management policy.';
58
+ -- Note: "nav_items_admin_management" (FOR ALL TO authenticated USING role = ADMIN) should remain unchanged.
59
+
60
+ -- == PAGES ==
61
+ -- Assuming "pages_admin_writer_management" is FOR ALL and covers SELECT for ADMIN/WRITER.
62
+ -- Make "pages_authenticated_access" specific to non-ADMIN/WRITER authenticated users.
63
+ DROP POLICY IF EXISTS "pages_authenticated_access" ON public.pages;
64
+ CREATE POLICY "pages_user_authenticated_access" ON public.pages -- Renamed
65
+ FOR SELECT
66
+ TO authenticated
67
+ USING (
68
+ (public.get_current_user_role() NOT IN ('ADMIN', 'WRITER')) AND -- This is the key change
69
+ (
70
+ (status = 'published') OR
71
+ (author_id = (SELECT auth.uid()) AND status <> 'published')
72
+ )
73
+ );
74
+ COMMENT ON POLICY "pages_user_authenticated_access" ON public.pages IS 'Authenticated USERS (non-admin/writer) can read published pages or their own drafts. Admin/Writer SELECT via their management policy.';
75
+ -- Note: "pages_anon_can_read_published" (FOR SELECT TO anon) should remain unchanged.
76
+ -- Note: "pages_admin_writer_management" (FOR ALL TO authenticated USING role IN (ADMIN,WRITER)) should remain unchanged.
77
+
78
+ -- == POSTS ==
79
+ -- Assuming "posts_admin_writer_management" is FOR ALL and covers SELECT for ADMIN/WRITER.
80
+ -- Make "posts_authenticated_access" specific to non-ADMIN/WRITER authenticated users.
81
+ DROP POLICY IF EXISTS "posts_authenticated_access" ON public.posts;
82
+ CREATE POLICY "posts_user_authenticated_access" ON public.posts -- Renamed
83
+ FOR SELECT
84
+ TO authenticated
85
+ USING (
86
+ (public.get_current_user_role() NOT IN ('ADMIN', 'WRITER')) AND -- This is the key change
87
+ (
88
+ (status = 'published' AND (published_at IS NULL OR published_at <= now())) OR
89
+ (author_id = (SELECT auth.uid()) AND status <> 'published')
90
+ )
91
+ );
92
+ COMMENT ON POLICY "posts_user_authenticated_access" ON public.posts IS 'Authenticated USERS (non-admin/writer) can read published posts or their own drafts. Admin/Writer SELECT via their management policy.';
93
+ -- Note: "posts_anon_can_read_published" (FOR SELECT TO anon) should remain unchanged.
94
+ -- Note: "posts_admin_writer_management" (FOR ALL TO authenticated USING role IN (ADMIN,WRITER)) should remain unchanged.
95
+
96
+ COMMIT;
@@ -0,0 +1,107 @@
1
+ -- supabase/migrations/YYYYMMDDHHMMSS_resolve_remaining_rls_v5.sql
2
+ -- (Ensure YYYYMMDDHHMMSS is the current timestamp)
3
+
4
+ BEGIN;
5
+
6
+ -- == LANGUAGES ==
7
+ -- Drop the policy from v4 that needs auth.role() fix and better role targeting.
8
+ DROP POLICY IF EXISTS "languages_readable_by_anon_and_non_admins" ON public.languages;
9
+ -- Policy for anon
10
+ CREATE POLICY "languages_anon_can_read" ON public.languages
11
+ FOR SELECT TO anon USING (true);
12
+ COMMENT ON POLICY "languages_anon_can_read" ON public.languages IS 'Anonymous users can read languages.';
13
+ -- Policy for authenticated USERS (non-admins)
14
+ CREATE POLICY "languages_user_can_read" ON public.languages
15
+ FOR SELECT TO authenticated
16
+ USING (public.get_current_user_role() <> 'ADMIN'); -- Allows USER and WRITER (if writer isn't admin)
17
+ COMMENT ON POLICY "languages_user_can_read" ON public.languages IS 'Authenticated non-admin users can read languages.';
18
+ -- "languages_admin_management" (FOR ALL TO authenticated USING role = ADMIN) is assumed to be current and handles admin SELECT.
19
+
20
+
21
+ -- == MEDIA ==
22
+ -- Drop the policy from v4
23
+ DROP POLICY IF EXISTS "media_readable_by_anon_and_non_privileged_users" ON public.media;
24
+ -- Policy for anon
25
+ CREATE POLICY "media_anon_can_read" ON public.media
26
+ FOR SELECT TO anon USING (true);
27
+ COMMENT ON POLICY "media_anon_can_read" ON public.media IS 'Anonymous users can read media records.';
28
+ -- Policy for authenticated USERS (non-admin/writer)
29
+ CREATE POLICY "media_user_can_read" ON public.media
30
+ FOR SELECT TO authenticated
31
+ USING (public.get_current_user_role() NOT IN ('ADMIN', 'WRITER'));
32
+ COMMENT ON POLICY "media_user_can_read" ON public.media IS 'Authenticated USERS (non-admin/writer) can read media records.';
33
+ -- "media_admin_writer_management" (FOR ALL TO authenticated USING role IN (ADMIN,WRITER)) is assumed current.
34
+
35
+
36
+ -- == NAVIGATION ITEMS ==
37
+ -- Drop the policy from v4
38
+ DROP POLICY IF EXISTS "nav_items_readable_by_anon_and_non_admins" ON public.navigation_items;
39
+ -- Policy for anon
40
+ CREATE POLICY "nav_items_anon_can_read" ON public.navigation_items
41
+ FOR SELECT TO anon USING (true);
42
+ COMMENT ON POLICY "nav_items_anon_can_read" ON public.navigation_items IS 'Anonymous users can read navigation items.';
43
+ -- Policy for authenticated USERS (non-admins)
44
+ CREATE POLICY "nav_items_user_can_read" ON public.navigation_items
45
+ FOR SELECT TO authenticated
46
+ USING (public.get_current_user_role() <> 'ADMIN'); -- Allows USER and WRITER
47
+ COMMENT ON POLICY "nav_items_user_can_read" ON public.navigation_items IS 'Authenticated non-admin users can read navigation items.';
48
+ -- "nav_items_admin_management" (FOR ALL TO authenticated USING role = ADMIN) is assumed current.
49
+
50
+
51
+ -- == BLOCKS ==
52
+ -- Drop the "blocks_authenticated_user_access" from v4
53
+ DROP POLICY IF EXISTS "blocks_authenticated_user_access" ON public.blocks;
54
+ -- Recreate explicitly for USER role to avoid overlap with admin/writer FOR ALL policy
55
+ CREATE POLICY "blocks_user_role_can_read_published_parents" ON public.blocks
56
+ FOR SELECT
57
+ TO authenticated
58
+ USING (
59
+ (public.get_current_user_role() = 'USER') AND
60
+ (
61
+ (page_id IS NOT NULL AND EXISTS(SELECT 1 FROM public.pages p WHERE p.id = blocks.page_id AND p.status = 'published')) OR
62
+ (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())))
63
+ )
64
+ );
65
+ COMMENT ON POLICY "blocks_user_role_can_read_published_parents" ON public.blocks IS 'Authenticated USERS can read blocks of published parents. Admin/Writer SELECT via their management policy.';
66
+ -- "blocks_anon_can_read_published" (FOR SELECT TO anon) from previous migrations is assumed to be fine.
67
+ -- "blocks_admin_writer_management" (FOR ALL TO authenticated USING role IN (ADMIN,WRITER)) is assumed current.
68
+
69
+
70
+ -- == PAGES ==
71
+ -- Drop "pages_user_authenticated_access" from v4
72
+ DROP POLICY IF EXISTS "pages_user_authenticated_access" ON public.pages;
73
+ -- Recreate explicitly for USER role
74
+ CREATE POLICY "pages_user_role_access" ON public.pages
75
+ FOR SELECT
76
+ TO authenticated
77
+ USING (
78
+ (public.get_current_user_role() = 'USER') AND
79
+ (
80
+ (status = 'published') OR
81
+ (author_id = (SELECT auth.uid()) AND status <> 'published') -- auth.uid() is fine here as it's specific to USER
82
+ )
83
+ );
84
+ COMMENT ON POLICY "pages_user_role_access" ON public.pages IS 'Authenticated USERS can read published pages or their own drafts. Admin/Writer SELECT via their management policy.';
85
+ -- "pages_anon_can_read_published" (FOR SELECT TO anon) is assumed fine.
86
+ -- "pages_admin_writer_management" (FOR ALL TO authenticated USING role IN (ADMIN,WRITER)) is assumed current.
87
+
88
+ -- == POSTS ==
89
+ -- Drop "posts_user_authenticated_access" from v4
90
+ DROP POLICY IF EXISTS "posts_user_authenticated_access" ON public.posts;
91
+ -- Recreate explicitly for USER role
92
+ CREATE POLICY "posts_user_role_access" ON public.posts
93
+ FOR SELECT
94
+ TO authenticated
95
+ USING (
96
+ (public.get_current_user_role() = 'USER') AND
97
+ (
98
+ (status = 'published' AND (published_at IS NULL OR published_at <= now())) OR
99
+ (author_id = (SELECT auth.uid()) AND status <> 'published') -- auth.uid() is fine here
100
+ )
101
+ );
102
+ COMMENT ON POLICY "posts_user_role_access" ON public.posts IS 'Authenticated USERS can read published posts or their own drafts. Admin/Writer SELECT via their management policy.';
103
+ -- "posts_anon_can_read_published" (FOR SELECT TO anon) is assumed fine.
104
+ -- "posts_admin_writer_management" (FOR ALL TO authenticated USING role IN (ADMIN,WRITER)) is assumed current.
105
+
106
+
107
+ COMMIT;
@@ -0,0 +1,110 @@
1
+ -- supabase/migrations/YYYYMMDDHHMMSS_final_rls_cleanup_v7.sql
2
+ -- (Ensure YYMMDDHHMMSS is the current timestamp)
3
+
4
+ BEGIN;
5
+
6
+ -- == BLOCKS ==
7
+ -- Conflicting: {blocks_admin_writer_management, blocks_user_role_can_read_published_parents}
8
+ -- "blocks_admin_writer_management" is FOR ALL and covers SELECT for ADMIN/WRITER.
9
+ -- "blocks_user_role_can_read_published_parents" is for 'USER' role.
10
+ -- This structure *should* be fine. The linter might be overly cautious.
11
+ -- To be absolutely sure, we ensure "blocks_user_role_can_read_published_parents" only targets 'USER'.
12
+ DROP POLICY IF EXISTS "blocks_user_role_can_read_published_parents" ON public.blocks;
13
+ CREATE POLICY "blocks_user_role_can_read_published_parents" ON public.blocks
14
+ FOR SELECT
15
+ TO authenticated
16
+ USING (
17
+ (public.get_current_user_role() = 'USER') AND
18
+ (
19
+ (page_id IS NOT NULL AND EXISTS(SELECT 1 FROM public.pages p WHERE p.id = blocks.page_id AND p.status = 'published')) OR
20
+ (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())))
21
+ )
22
+ );
23
+ COMMENT ON POLICY "blocks_user_role_can_read_published_parents" ON public.blocks IS 'Authenticated USERS can read blocks of published parents. Admin/Writer SELECT via their FOR ALL management policy.';
24
+ -- Assuming "blocks_anon_can_read_published" and "blocks_admin_writer_management" (FOR ALL) are correct from previous migrations.
25
+
26
+
27
+ -- == LANGUAGES ==
28
+ -- Conflicting: {languages_admin_management, languages_user_can_read}
29
+ -- "languages_admin_management" is FOR ALL and covers SELECT for ADMIN.
30
+ -- "languages_user_can_read" (from v5) was: TO authenticated USING (public.get_current_user_role() <> 'ADMIN');
31
+ -- This should be fine, as an ADMIN would make the USING clause false.
32
+ -- To be very explicit for the linter:
33
+ DROP POLICY IF EXISTS "languages_user_can_read" ON public.languages;
34
+ CREATE POLICY "languages_authenticated_non_admin_can_read" ON public.languages
35
+ FOR SELECT
36
+ TO authenticated
37
+ USING (
38
+ public.get_current_user_role() IN ('USER', 'WRITER') -- Explicitly target USER and WRITER
39
+ );
40
+ COMMENT ON POLICY "languages_authenticated_non_admin_can_read" ON public.languages IS 'Authenticated USER and WRITER roles can read languages. Admin SELECT via their FOR ALL management policy.';
41
+ -- Assuming "languages_anon_can_read" and "languages_admin_management" (FOR ALL) are correct.
42
+
43
+
44
+ -- == MEDIA ==
45
+ -- Conflicting: {media_admin_writer_management, media_user_can_read}
46
+ -- "media_admin_writer_management" is FOR ALL and covers SELECT for ADMIN/WRITER.
47
+ -- "media_user_can_read" (from v5) was: TO authenticated USING (public.get_current_user_role() NOT IN ('ADMIN', 'WRITER'));
48
+ -- This should be fine. To be very explicit:
49
+ DROP POLICY IF EXISTS "media_user_can_read" ON public.media;
50
+ CREATE POLICY "media_user_role_can_read" ON public.media
51
+ FOR SELECT
52
+ TO authenticated
53
+ USING (
54
+ public.get_current_user_role() = 'USER' -- Explicitly target USER role
55
+ );
56
+ COMMENT ON POLICY "media_user_role_can_read" ON public.media IS 'Authenticated USER role can read media. Admin/Writer SELECT via their FOR ALL management policy.';
57
+ -- Assuming "media_anon_can_read" and "media_admin_writer_management" (FOR ALL) are correct.
58
+
59
+
60
+ -- == NAVIGATION ITEMS ==
61
+ -- Conflicting: {nav_items_admin_management, nav_items_user_can_read}
62
+ -- "nav_items_admin_management" is FOR ALL and covers SELECT for ADMIN.
63
+ -- "nav_items_user_can_read" (from v5) was: TO authenticated USING (public.get_current_user_role() <> 'ADMIN');
64
+ DROP POLICY IF EXISTS "nav_items_user_can_read" ON public.navigation_items;
65
+ CREATE POLICY "nav_items_authenticated_non_admin_can_read" ON public.navigation_items
66
+ FOR SELECT
67
+ TO authenticated
68
+ USING (
69
+ public.get_current_user_role() IN ('USER', 'WRITER') -- Explicitly target USER and WRITER
70
+ );
71
+ COMMENT ON POLICY "nav_items_authenticated_non_admin_can_read" ON public.navigation_items IS 'Authenticated USER and WRITER roles can read nav items. Admin SELECT via their FOR ALL management policy.';
72
+ -- Assuming "nav_items_anon_can_read" and "nav_items_admin_management" (FOR ALL) are correct.
73
+
74
+
75
+ -- == PAGES ==
76
+ -- Conflicting: {pages_admin_writer_management, pages_user_role_access}
77
+ -- This structure is identical to blocks and should be fine if "pages_user_role_access" correctly targets only USER.
78
+ DROP POLICY IF EXISTS "pages_user_role_access" ON public.pages;
79
+ CREATE POLICY "pages_user_role_can_read" ON public.pages -- Consistent naming
80
+ FOR SELECT
81
+ TO authenticated
82
+ USING (
83
+ (public.get_current_user_role() = 'USER') AND
84
+ (
85
+ (status = 'published') OR
86
+ (author_id = (SELECT auth.uid()) AND status <> 'published')
87
+ )
88
+ );
89
+ COMMENT ON POLICY "pages_user_role_can_read" ON public.pages IS 'Authenticated USERS can read published pages or their own drafts. Admin/Writer SELECT via their FOR ALL management policy.';
90
+ -- Assuming "pages_anon_can_read_published" and "pages_admin_writer_management" (FOR ALL) are correct.
91
+
92
+
93
+ -- == POSTS ==
94
+ -- Conflicting: {posts_admin_writer_management, posts_user_role_access}
95
+ -- This structure is identical to blocks/pages and should be fine if "posts_user_role_access" correctly targets only USER.
96
+ DROP POLICY IF EXISTS "posts_user_role_access" ON public.posts;
97
+ CREATE POLICY "posts_user_role_can_read" ON public.posts -- Consistent naming
98
+ FOR SELECT
99
+ TO authenticated
100
+ USING (
101
+ (public.get_current_user_role() = 'USER') AND
102
+ (
103
+ (status = 'published' AND (published_at IS NULL OR published_at <= now())) OR
104
+ (author_id = (SELECT auth.uid()) AND status <> 'published')
105
+ )
106
+ );
107
+ COMMENT ON POLICY "posts_user_role_can_read" ON public.posts IS 'Authenticated USERS can read published posts or their own drafts. Admin/Writer SELECT via their FOR ALL management policy.';
108
+ -- Assuming "posts_anon_can_read_published" and "posts_admin_writer_management" (FOR ALL) are correct.
109
+
110
+ COMMIT;
@@ -0,0 +1,147 @@
1
+ -- supabase/migrations/YYYYMMDDHHMMSS_separate_write_policies_v8.sql
2
+
3
+ BEGIN;
4
+
5
+ -- == PROFILES ==
6
+ -- Assuming "authenticated_can_read_profiles" (FOR SELECT) is correctly in place.
7
+ -- Define explicit INSERT and leave UPDATE to the existing "authenticated_can_update_profiles" policy.
8
+ DROP POLICY IF EXISTS "admins_can_insert_profiles" ON public.profiles;
9
+ CREATE POLICY "admins_can_insert_profiles" ON public.profiles
10
+ FOR INSERT
11
+ TO authenticated
12
+ WITH CHECK (public.get_current_user_role() = 'ADMIN');
13
+ COMMENT ON POLICY "admins_can_insert_profiles" ON public.profiles IS 'Admins can insert new profiles.';
14
+ -- "authenticated_can_update_profiles" (FOR UPDATE) is assumed to be in place and correct.
15
+
16
+
17
+ -- == BLOCKS ==
18
+ -- Drop the old "FOR ALL" or "FOR INSERT, UPDATE, DELETE" management policy
19
+ DROP POLICY IF EXISTS "blocks_admin_writer_management" ON public.blocks;
20
+
21
+ -- Create separate policies for INSERT, UPDATE, DELETE for Admins/Writers
22
+ CREATE POLICY "blocks_admin_writer_can_insert" ON public.blocks
23
+ FOR INSERT
24
+ TO authenticated
25
+ WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
26
+ COMMENT ON POLICY "blocks_admin_writer_can_insert" ON public.blocks IS 'Admins/Writers can insert blocks.';
27
+
28
+ CREATE POLICY "blocks_admin_writer_can_update" ON public.blocks
29
+ FOR UPDATE
30
+ TO authenticated
31
+ USING (public.get_current_user_role() IN ('ADMIN', 'WRITER')) -- USING is relevant for UPDATE
32
+ WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
33
+ COMMENT ON POLICY "blocks_admin_writer_can_update" ON public.blocks IS 'Admins/Writers can update blocks.';
34
+
35
+ CREATE POLICY "blocks_admin_writer_can_delete" ON public.blocks
36
+ FOR DELETE
37
+ TO authenticated
38
+ USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
39
+ COMMENT ON POLICY "blocks_admin_writer_can_delete" ON public.blocks IS 'Admins/Writers can delete blocks.';
40
+ -- Assumed SELECT policies: "blocks_anon_can_read_published" and "blocks_user_role_can_read_published_parents" are in place.
41
+
42
+
43
+ -- == LANGUAGES ==
44
+ DROP POLICY IF EXISTS "languages_admin_management" ON public.languages;
45
+
46
+ CREATE POLICY "languages_admin_can_insert" ON public.languages
47
+ FOR INSERT TO authenticated
48
+ WITH CHECK (public.get_current_user_role() = 'ADMIN');
49
+ COMMENT ON POLICY "languages_admin_can_insert" ON public.languages IS 'Admins can insert languages.';
50
+
51
+ CREATE POLICY "languages_admin_can_update" ON public.languages
52
+ FOR UPDATE TO authenticated
53
+ USING (public.get_current_user_role() = 'ADMIN')
54
+ WITH CHECK (public.get_current_user_role() = 'ADMIN');
55
+ COMMENT ON POLICY "languages_admin_can_update" ON public.languages IS 'Admins can update languages.';
56
+
57
+ CREATE POLICY "languages_admin_can_delete" ON public.languages
58
+ FOR DELETE TO authenticated
59
+ USING (public.get_current_user_role() = 'ADMIN');
60
+ COMMENT ON POLICY "languages_admin_can_delete" ON public.languages IS 'Admins can delete languages.';
61
+ -- Assumed SELECT policies: "languages_anon_can_read" and "languages_authenticated_non_admin_can_read" are in place.
62
+
63
+
64
+ -- == MEDIA ==
65
+ DROP POLICY IF EXISTS "media_admin_writer_management" ON public.media;
66
+
67
+ CREATE POLICY "media_admin_writer_can_insert" ON public.media
68
+ FOR INSERT TO authenticated
69
+ WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
70
+ COMMENT ON POLICY "media_admin_writer_can_insert" ON public.media IS 'Admins/Writers can insert media.';
71
+
72
+ CREATE POLICY "media_admin_writer_can_update" ON public.media
73
+ FOR UPDATE TO authenticated
74
+ USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'))
75
+ WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
76
+ COMMENT ON POLICY "media_admin_writer_can_update" ON public.media IS 'Admins/Writers can update media.';
77
+
78
+ CREATE POLICY "media_admin_writer_can_delete" ON public.media
79
+ FOR DELETE TO authenticated
80
+ USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
81
+ COMMENT ON POLICY "media_admin_writer_can_delete" ON public.media IS 'Admins/Writers can delete media.';
82
+ -- Assumed SELECT policies: "media_anon_can_read" and "media_user_role_can_read" are in place.
83
+
84
+
85
+ -- == NAVIGATION ITEMS ==
86
+ DROP POLICY IF EXISTS "nav_items_admin_management" ON public.navigation_items;
87
+
88
+ CREATE POLICY "nav_items_admin_can_insert" ON public.navigation_items
89
+ FOR INSERT TO authenticated
90
+ WITH CHECK (public.get_current_user_role() = 'ADMIN');
91
+ COMMENT ON POLICY "nav_items_admin_can_insert" ON public.navigation_items IS 'Admins can insert navigation items.';
92
+
93
+ CREATE POLICY "nav_items_admin_can_update" ON public.navigation_items
94
+ FOR UPDATE TO authenticated
95
+ USING (public.get_current_user_role() = 'ADMIN')
96
+ WITH CHECK (public.get_current_user_role() = 'ADMIN');
97
+ COMMENT ON POLICY "nav_items_admin_can_update" ON public.navigation_items IS 'Admins can update navigation items.';
98
+
99
+ CREATE POLICY "nav_items_admin_can_delete" ON public.navigation_items
100
+ FOR DELETE TO authenticated
101
+ USING (public.get_current_user_role() = 'ADMIN');
102
+ COMMENT ON POLICY "nav_items_admin_can_delete" ON public.navigation_items IS 'Admins can delete navigation items.';
103
+ -- Assumed SELECT policies: "nav_items_anon_can_read" and "nav_items_authenticated_non_admin_can_read" are in place.
104
+
105
+
106
+ -- == PAGES ==
107
+ DROP POLICY IF EXISTS "pages_admin_writer_management" ON public.pages;
108
+
109
+ CREATE POLICY "pages_admin_writer_can_insert" ON public.pages
110
+ FOR INSERT TO authenticated
111
+ WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
112
+ COMMENT ON POLICY "pages_admin_writer_can_insert" ON public.pages IS 'Admins/Writers can insert pages.';
113
+
114
+ CREATE POLICY "pages_admin_writer_can_update" ON public.pages
115
+ FOR UPDATE TO authenticated
116
+ USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'))
117
+ WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
118
+ COMMENT ON POLICY "pages_admin_writer_can_update" ON public.pages IS 'Admins/Writers can update pages.';
119
+
120
+ CREATE POLICY "pages_admin_writer_can_delete" ON public.pages
121
+ FOR DELETE TO authenticated
122
+ USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
123
+ COMMENT ON POLICY "pages_admin_writer_can_delete" ON public.pages IS 'Admins/Writers can delete pages.';
124
+ -- Assumed SELECT policies: "pages_anon_can_read_published" and "pages_user_role_can_read" are in place.
125
+
126
+
127
+ -- == POSTS ==
128
+ DROP POLICY IF EXISTS "posts_admin_writer_management" ON public.posts;
129
+
130
+ CREATE POLICY "posts_admin_writer_can_insert" ON public.posts
131
+ FOR INSERT TO authenticated
132
+ WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
133
+ COMMENT ON POLICY "posts_admin_writer_can_insert" ON public.posts IS 'Admins/Writers can insert posts.';
134
+
135
+ CREATE POLICY "posts_admin_writer_can_update" ON public.posts
136
+ FOR UPDATE TO authenticated
137
+ USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'))
138
+ WITH CHECK (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
139
+ COMMENT ON POLICY "posts_admin_writer_can_update" ON public.posts IS 'Admins/Writers can update posts.';
140
+
141
+ CREATE POLICY "posts_admin_writer_can_delete" ON public.posts
142
+ FOR DELETE TO authenticated
143
+ USING (public.get_current_user_role() IN ('ADMIN', 'WRITER'));
144
+ COMMENT ON POLICY "posts_admin_writer_can_delete" ON public.posts IS 'Admins/Writers can delete posts.';
145
+ -- Assumed SELECT policies: "posts_anon_can_read_published" and "posts_user_role_can_read" are in place.
146
+
147
+ COMMIT;