panda-cms 0.7.0

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 (233) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +73 -0
  3. data/Rakefile +7 -0
  4. data/app/assets/builds/panda.cms.css +2808 -0
  5. data/app/assets/config/panda_cms_manifest.js +4 -0
  6. data/app/assets/stylesheets/panda/cms/application.tailwind.css +162 -0
  7. data/app/assets/stylesheets/panda/cms/editor.css +120 -0
  8. data/app/builders/panda/cms/form_builder.rb +234 -0
  9. data/app/components/panda/cms/admin/button_component.rb +70 -0
  10. data/app/components/panda/cms/admin/container_component.html.erb +13 -0
  11. data/app/components/panda/cms/admin/container_component.rb +13 -0
  12. data/app/components/panda/cms/admin/flash_message_component.html.erb +31 -0
  13. data/app/components/panda/cms/admin/flash_message_component.rb +47 -0
  14. data/app/components/panda/cms/admin/heading_component.rb +45 -0
  15. data/app/components/panda/cms/admin/panel_component.html.erb +7 -0
  16. data/app/components/panda/cms/admin/panel_component.rb +13 -0
  17. data/app/components/panda/cms/admin/slideover_component.html.erb +9 -0
  18. data/app/components/panda/cms/admin/slideover_component.rb +15 -0
  19. data/app/components/panda/cms/admin/statistics_component.html.erb +4 -0
  20. data/app/components/panda/cms/admin/statistics_component.rb +17 -0
  21. data/app/components/panda/cms/admin/tab_bar_component.html.erb +35 -0
  22. data/app/components/panda/cms/admin/tab_bar_component.rb +15 -0
  23. data/app/components/panda/cms/admin/table_component.html.erb +29 -0
  24. data/app/components/panda/cms/admin/table_component.rb +46 -0
  25. data/app/components/panda/cms/admin/tag_component.rb +35 -0
  26. data/app/components/panda/cms/admin/user_activity_component.html.erb +5 -0
  27. data/app/components/panda/cms/admin/user_activity_component.rb +33 -0
  28. data/app/components/panda/cms/admin/user_display_component.html.erb +17 -0
  29. data/app/components/panda/cms/admin/user_display_component.rb +21 -0
  30. data/app/components/panda/cms/code_component.rb +64 -0
  31. data/app/components/panda/cms/grid_component.html.erb +6 -0
  32. data/app/components/panda/cms/grid_component.rb +15 -0
  33. data/app/components/panda/cms/menu_component.html.erb +6 -0
  34. data/app/components/panda/cms/menu_component.rb +58 -0
  35. data/app/components/panda/cms/page_menu_component.html.erb +21 -0
  36. data/app/components/panda/cms/page_menu_component.rb +38 -0
  37. data/app/components/panda/cms/rich_text_component.html.erb +6 -0
  38. data/app/components/panda/cms/rich_text_component.rb +84 -0
  39. data/app/components/panda/cms/text_component.rb +72 -0
  40. data/app/constraints/panda/cms/admin_constraint.rb +18 -0
  41. data/app/controllers/panda/cms/admin/block_contents_controller.rb +52 -0
  42. data/app/controllers/panda/cms/admin/dashboard_controller.rb +20 -0
  43. data/app/controllers/panda/cms/admin/files_controller.rb +21 -0
  44. data/app/controllers/panda/cms/admin/forms_controller.rb +53 -0
  45. data/app/controllers/panda/cms/admin/menus_controller.rb +30 -0
  46. data/app/controllers/panda/cms/admin/pages_controller.rb +91 -0
  47. data/app/controllers/panda/cms/admin/posts_controller.rb +146 -0
  48. data/app/controllers/panda/cms/admin/sessions_controller.rb +94 -0
  49. data/app/controllers/panda/cms/admin/settings/bulk_editor_controller.rb +37 -0
  50. data/app/controllers/panda/cms/admin/settings_controller.rb +20 -0
  51. data/app/controllers/panda/cms/application_controller.rb +57 -0
  52. data/app/controllers/panda/cms/errors_controller.rb +33 -0
  53. data/app/controllers/panda/cms/form_submissions_controller.rb +23 -0
  54. data/app/controllers/panda/cms/pages_controller.rb +72 -0
  55. data/app/controllers/panda/cms/posts_controller.rb +13 -0
  56. data/app/helpers/panda/cms/admin/files_helper.rb +6 -0
  57. data/app/helpers/panda/cms/admin/pages_helper.rb +6 -0
  58. data/app/helpers/panda/cms/admin/posts_helper.rb +48 -0
  59. data/app/helpers/panda/cms/application_helper.rb +120 -0
  60. data/app/helpers/panda/cms/pages_helper.rb +6 -0
  61. data/app/helpers/panda/cms/theme_helper.rb +18 -0
  62. data/app/javascript/panda/cms/@editorjs--editorjs.js +2577 -0
  63. data/app/javascript/panda/cms/@hotwired--stimulus.js +4 -0
  64. data/app/javascript/panda/cms/@hotwired--turbo.js +160 -0
  65. data/app/javascript/panda/cms/@rails--actioncable--src.js +4 -0
  66. data/app/javascript/panda/cms/application_panda_cms.js +39 -0
  67. data/app/javascript/panda/cms/controllers/dashboard_controller.js +7 -0
  68. data/app/javascript/panda/cms/controllers/editor_form_controller.js +77 -0
  69. data/app/javascript/panda/cms/controllers/editor_iframe_controller.js +320 -0
  70. data/app/javascript/panda/cms/controllers/index.js +48 -0
  71. data/app/javascript/panda/cms/controllers/slug_controller.js +87 -0
  72. data/app/javascript/panda/cms/editor/css_extractor.js +80 -0
  73. data/app/javascript/panda/cms/editor/editor_js_config.js +177 -0
  74. data/app/javascript/panda/cms/editor/editor_js_initializer.js +285 -0
  75. data/app/javascript/panda/cms/editor/plain_text_editor.js +110 -0
  76. data/app/javascript/panda/cms/editor/resource_loader.js +115 -0
  77. data/app/javascript/panda/cms/tailwindcss-stimulus-components.js +4 -0
  78. data/app/jobs/panda/cms/application_job.rb +6 -0
  79. data/app/jobs/panda/cms/record_visit_job.rb +31 -0
  80. data/app/mailers/panda/cms/application_mailer.rb +8 -0
  81. data/app/mailers/panda/cms/form_mailer.rb +21 -0
  82. data/app/models/action_text/rich_text_version.rb +6 -0
  83. data/app/models/panda/cms/application_record.rb +7 -0
  84. data/app/models/panda/cms/block.rb +34 -0
  85. data/app/models/panda/cms/block_content.rb +18 -0
  86. data/app/models/panda/cms/block_content_version.rb +8 -0
  87. data/app/models/panda/cms/breadcrumb.rb +12 -0
  88. data/app/models/panda/cms/current.rb +17 -0
  89. data/app/models/panda/cms/form.rb +9 -0
  90. data/app/models/panda/cms/form_submission.rb +7 -0
  91. data/app/models/panda/cms/menu.rb +52 -0
  92. data/app/models/panda/cms/menu_item.rb +58 -0
  93. data/app/models/panda/cms/page.rb +96 -0
  94. data/app/models/panda/cms/page_version.rb +8 -0
  95. data/app/models/panda/cms/post.rb +60 -0
  96. data/app/models/panda/cms/post_version.rb +8 -0
  97. data/app/models/panda/cms/redirect.rb +11 -0
  98. data/app/models/panda/cms/template.rb +124 -0
  99. data/app/models/panda/cms/template_version.rb +8 -0
  100. data/app/models/panda/cms/user.rb +31 -0
  101. data/app/models/panda/cms/version.rb +8 -0
  102. data/app/models/panda/cms/visit.rb +9 -0
  103. data/app/services/panda/cms/html_to_editor_js_converter.rb +200 -0
  104. data/app/views/active_storage/blobs/blobs/_blob.html.erb +14 -0
  105. data/app/views/layouts/action_text/contents/_content.html.erb +3 -0
  106. data/app/views/layouts/panda/cms/application.html.erb +41 -0
  107. data/app/views/layouts/panda/cms/public.html.erb +3 -0
  108. data/app/views/panda/cms/admin/dashboard/show.html.erb +12 -0
  109. data/app/views/panda/cms/admin/files/index.html.erb +124 -0
  110. data/app/views/panda/cms/admin/files/show.html.erb +2 -0
  111. data/app/views/panda/cms/admin/forms/edit.html.erb +0 -0
  112. data/app/views/panda/cms/admin/forms/index.html.erb +13 -0
  113. data/app/views/panda/cms/admin/forms/new.html.erb +15 -0
  114. data/app/views/panda/cms/admin/forms/show.html.erb +35 -0
  115. data/app/views/panda/cms/admin/menus/index.html.erb +8 -0
  116. data/app/views/panda/cms/admin/pages/edit.html.erb +36 -0
  117. data/app/views/panda/cms/admin/pages/index.html.erb +22 -0
  118. data/app/views/panda/cms/admin/pages/new.html.erb +15 -0
  119. data/app/views/panda/cms/admin/pages/show.html.erb +1 -0
  120. data/app/views/panda/cms/admin/posts/_form.html.erb +29 -0
  121. data/app/views/panda/cms/admin/posts/edit.html.erb +6 -0
  122. data/app/views/panda/cms/admin/posts/index.html.erb +18 -0
  123. data/app/views/panda/cms/admin/posts/new.html.erb +6 -0
  124. data/app/views/panda/cms/admin/sessions/new.html.erb +17 -0
  125. data/app/views/panda/cms/admin/settings/bulk_editor/new.html.erb +68 -0
  126. data/app/views/panda/cms/admin/settings/index.html.erb +21 -0
  127. data/app/views/panda/cms/admin/settings/insta.html +4 -0
  128. data/app/views/panda/cms/admin/shared/_breadcrumbs.html.erb +28 -0
  129. data/app/views/panda/cms/admin/shared/_flash.html.erb +5 -0
  130. data/app/views/panda/cms/admin/shared/_sidebar.html.erb +41 -0
  131. data/app/views/panda/cms/form_mailer/notification_email.html.erb +11 -0
  132. data/app/views/panda/cms/shared/_editor.html.erb +0 -0
  133. data/app/views/panda/cms/shared/_favicons.html.erb +9 -0
  134. data/app/views/panda/cms/shared/_footer.html.erb +2 -0
  135. data/app/views/panda/cms/shared/_header.html.erb +15 -0
  136. data/app/views/panda/cms/shared/_importmap.html.erb +33 -0
  137. data/config/importmap.rb +13 -0
  138. data/config/initializers/inflections.rb +3 -0
  139. data/config/initializers/panda/cms/form_errors.rb +38 -0
  140. data/config/initializers/panda/cms/healthcheck_log_silencer.rb +11 -0
  141. data/config/initializers/panda/cms/paper_trail.rb +7 -0
  142. data/config/initializers/panda/cms.rb +10 -0
  143. data/config/initializers/zeitwork.rb +3 -0
  144. data/config/locales/en.yml +49 -0
  145. data/config/puma/test.rb +9 -0
  146. data/config/routes.rb +48 -0
  147. data/config/tailwind.config.js +37 -0
  148. data/db/migrate/20240205223709_create_panda_cms_pages.rb +9 -0
  149. data/db/migrate/20240219213327_create_panda_cms_page_versions.rb +14 -0
  150. data/db/migrate/20240303002805_create_panda_cms_templates.rb +11 -0
  151. data/db/migrate/20240303003434_create_panda_cms_template_versions.rb +14 -0
  152. data/db/migrate/20240303022441_create_panda_cms_blocks.rb +13 -0
  153. data/db/migrate/20240303024256_create_panda_cms_block_contents.rb +10 -0
  154. data/db/migrate/20240303024746_create_panda_cms_block_content_versions.rb +14 -0
  155. data/db/migrate/20240303233238_add_panda_cms_menu_table.rb +10 -0
  156. data/db/migrate/20240303234724_add_panda_cms_menu_item_table.rb +12 -0
  157. data/db/migrate/20240304134343_add_parent_id_to_panda_cms_pages.rb +5 -0
  158. data/db/migrate/20240305000000_convert_html_content_to_editor_js.rb +82 -0
  159. data/db/migrate/20240315125411_add_status_to_panda_cms_pages.rb +9 -0
  160. data/db/migrate/20240315125421_add_nested_sets_to_panda_cms_pages.rb +16 -0
  161. data/db/migrate/20240316212822_add_kind_to_panda_cms_menus.rb +6 -0
  162. data/db/migrate/20240316221425_add_start_page_to_panda_cms_menus.rb +5 -0
  163. data/db/migrate/20240316230706_add_nested_to_panda_cms_menu_items.rb +24 -0
  164. data/db/migrate/20240317010532_create_panda_cms_users.rb +12 -0
  165. data/db/migrate/20240317161534_add_max_uses_to_panda_cms_template.rb +7 -0
  166. data/db/migrate/20240317163053_reset_counter_cache_on_panda_cms_template.rb +5 -0
  167. data/db/migrate/20240317214827_create_panda_cms_redirects.rb +14 -0
  168. data/db/migrate/20240317230622_create_panda_cms_visits.rb +13 -0
  169. data/db/migrate/20240324205703_create_active_storage_tables.active_storage.rb +58 -0
  170. data/db/migrate/20240408084718_default_panda_cms_users_admin_to_false.rb +5 -0
  171. data/db/migrate/20240701225422_add_service_name_to_active_storage_blobs.active_storage.rb +22 -0
  172. data/db/migrate/20240701225423_create_active_storage_variant_records.active_storage.rb +28 -0
  173. data/db/migrate/20240701225424_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb +8 -0
  174. data/db/migrate/20240804235210_create_panda_cms_forms.rb +11 -0
  175. data/db/migrate/20240805013612_create_panda_cms_form_submissions.rb +9 -0
  176. data/db/migrate/20240805121123_create_panda_cms_posts.rb +27 -0
  177. data/db/migrate/20240805123104_create_panda_cms_post_versions.rb +14 -0
  178. data/db/migrate/20240806112735_fix_panda_cms_visits_column_names.rb +13 -0
  179. data/db/migrate/20240806204412_add_completion_path_to_panda_cms_forms.rb +5 -0
  180. data/db/migrate/20240820081917_change_form_submissions_to_submission_count.rb +5 -0
  181. data/db/migrate/20240904200605_create_action_text_tables.action_text.rb +24 -0
  182. data/db/migrate/20240923234535_add_depth_to_panda_cms_menus.rb +11 -0
  183. data/db/migrate/20241031205109_add_cached_content_to_panda_cms_block_contents.rb +5 -0
  184. data/db/migrate/20241119214548_convert_post_content_to_editor_js.rb +35 -0
  185. data/db/migrate/20241119214549_remove_action_text_from_posts.rb +9 -0
  186. data/db/migrate/20241120000419_remove_post_tag_references.rb +19 -0
  187. data/db/migrate/20241120110943_add_editor_js_to_posts.rb +27 -0
  188. data/db/migrate/20241120113859_add_cached_content_to_panda_cms_posts.rb +5 -0
  189. data/db/migrate/20241123234140_remove_post_tag_id_from_posts.rb +5 -0
  190. data/db/migrate/migrate +1 -0
  191. data/db/seeds.rb +5 -0
  192. data/lib/generators/panda/cms/install_generator.rb +29 -0
  193. data/lib/panda/cms/bulk_editor.rb +171 -0
  194. data/lib/panda/cms/demo_site_generator.rb +67 -0
  195. data/lib/panda/cms/editor_js/blocks/alert.rb +34 -0
  196. data/lib/panda/cms/editor_js/blocks/base.rb +33 -0
  197. data/lib/panda/cms/editor_js/blocks/header.rb +15 -0
  198. data/lib/panda/cms/editor_js/blocks/image.rb +36 -0
  199. data/lib/panda/cms/editor_js/blocks/list.rb +32 -0
  200. data/lib/panda/cms/editor_js/blocks/paragraph.rb +15 -0
  201. data/lib/panda/cms/editor_js/blocks/quote.rb +41 -0
  202. data/lib/panda/cms/editor_js/blocks/table.rb +50 -0
  203. data/lib/panda/cms/editor_js/renderer.rb +124 -0
  204. data/lib/panda/cms/editor_js.rb +16 -0
  205. data/lib/panda/cms/editor_js_content.rb +21 -0
  206. data/lib/panda/cms/engine.rb +257 -0
  207. data/lib/panda/cms/exceptions_app.rb +26 -0
  208. data/lib/panda/cms/railtie.rb +11 -0
  209. data/lib/panda/cms/slug.rb +24 -0
  210. data/lib/panda/cms.rb +0 -0
  211. data/lib/panda-cms/version.rb +5 -0
  212. data/lib/panda-cms.rb +81 -0
  213. data/lib/tasks/panda_cms.rake +54 -0
  214. data/lib/templates/erb/scaffold/_form.html.erb.tt +43 -0
  215. data/lib/templates/erb/scaffold/edit.html.erb.tt +8 -0
  216. data/lib/templates/erb/scaffold/index.html.erb.tt +14 -0
  217. data/lib/templates/erb/scaffold/new.html.erb.tt +7 -0
  218. data/lib/templates/erb/scaffold/partial.html.erb.tt +22 -0
  219. data/lib/templates/erb/scaffold/show.html.erb.tt +15 -0
  220. data/public/panda-cms-assets/favicons/android-chrome-192x192.png +0 -0
  221. data/public/panda-cms-assets/favicons/android-chrome-512x512.png +0 -0
  222. data/public/panda-cms-assets/favicons/apple-touch-icon.png +0 -0
  223. data/public/panda-cms-assets/favicons/browserconfig.xml +9 -0
  224. data/public/panda-cms-assets/favicons/favicon-16x16.png +0 -0
  225. data/public/panda-cms-assets/favicons/favicon-32x32.png +0 -0
  226. data/public/panda-cms-assets/favicons/favicon.ico +0 -0
  227. data/public/panda-cms-assets/favicons/mstile-150x150.png +0 -0
  228. data/public/panda-cms-assets/favicons/safari-pinned-tab.svg +61 -0
  229. data/public/panda-cms-assets/favicons/site.webmanifest +14 -0
  230. data/public/panda-cms-assets/panda-logo-screenprint.png +0 -0
  231. data/public/panda-cms-assets/panda-nav.png +0 -0
  232. data/public/panda-cms-assets/rich_text_editor.css +568 -0
  233. metadata +654 -0
@@ -0,0 +1,13 @@
1
+ class CreatePandaCMSBlocks < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_enum :panda_cms_block_kind, ["plain_text", "rich_text", "image", "video", "audio", "file", "code", "iframe", "quote", "list", "table", "form"]
4
+
5
+ create_table :panda_cms_blocks, id: :uuid do |t|
6
+ t.enum :kind, enum_type: :panda_cms_block_kind, default: "plain_text", null: false
7
+ t.string :name
8
+ t.string :key
9
+ t.references :panda_cms_template, type: :uuid, foreign_key: {to_table: :panda_cms_templates}, null: false
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ class CreatePandaCMSBlockContents < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :panda_cms_block_contents, id: :uuid do |t|
4
+ t.references :panda_cms_page, null: false, foreign_key: true, type: :uuid
5
+ t.references :panda_cms_block, null: false, foreign_key: true, type: :uuid
6
+ t.jsonb :content, null: false, default: {}
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ class CreatePandaCMSBlockContentVersions < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :panda_cms_block_content_versions, id: :uuid do |t|
4
+ t.string :item_type, null: false
5
+ t.string :item_id, null: false
6
+ t.string :event, null: false
7
+ t.string :whodunnit
8
+ t.jsonb :object
9
+ t.jsonb :object_changes
10
+ t.datetime :created_at
11
+ end
12
+ add_index :panda_cms_block_content_versions, %i[item_type item_id]
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ class AddPandaCMSMenuTable < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :panda_cms_menus, id: :uuid do |t|
4
+ t.string :name, null: false
5
+ t.timestamps
6
+ end
7
+
8
+ add_index :panda_cms_menus, :name, unique: true
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ class AddPandaCMSMenuItemTable < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :panda_cms_menu_items, id: :uuid do |t|
4
+ t.string :text, null: false
5
+ t.references :panda_cms_menu, null: false, foreign_key: true, type: :uuid
6
+ t.references :panda_cms_page, null: true, foreign_key: true, type: :uuid
7
+ t.string :external_url, null: true
8
+ t.integer :sort_order, default: 1
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ class AddParentIdToPandaCMSPages < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_reference :panda_cms_pages, :parent, type: :uuid, foreign_key: {to_table: :panda_cms_pages}
4
+ end
5
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ConvertHtmlContentToEditorJs < ActiveRecord::Migration[7.1]
4
+ def up
5
+ # First, let's ensure we have the converter available in the migration
6
+ require Panda::CMS::Engine.root.join("app/services/panda/cms/html_to_editor_js_converter")
7
+
8
+ # Check if we have any existing valid EditorJS content
9
+ existing_editor_js = Panda::CMS::BlockContent.find_each.any? do |block_content|
10
+ valid_editor_js_content?(block_content.content)
11
+ end
12
+
13
+ if existing_editor_js
14
+ Rails.logger.warn "Found existing valid EditorJS content. Skipping migration to prevent data loss."
15
+ return
16
+ end
17
+
18
+ Rails.logger.info "Starting conversion of HTML content to EditorJS format..."
19
+
20
+ # Get all block contents that need conversion
21
+ Panda::CMS::BlockContent.find_each do |block_content|
22
+ next if block_content.content.blank?
23
+
24
+ begin
25
+ Rails.logger.info "Converting content for BlockContent ##{block_content.id}"
26
+
27
+ # Convert the content
28
+ editor_js_content = Panda::CMS::HtmlToEditorJsConverter.convert(block_content.content)
29
+
30
+ # Validate the converted content
31
+ unless valid_editor_js_content?(editor_js_content)
32
+ Rails.logger.error "Skipping BlockContent ##{block_content.id}: Conversion resulted in invalid or empty content"
33
+ next
34
+ end
35
+
36
+ # Update the record directly to avoid callbacks
37
+ block_content.update_columns(
38
+ content: editor_js_content,
39
+ updated_at: Time.current
40
+ )
41
+
42
+ Rails.logger.info "Successfully converted BlockContent ##{block_content.id}"
43
+ rescue => e
44
+ Rails.logger.error "Failed to convert BlockContent ##{block_content.id}: #{e.message}"
45
+ # Continue with the next record instead of failing the entire migration
46
+ end
47
+ end
48
+
49
+ Rails.logger.info "Completed conversion to EditorJS format"
50
+ end
51
+
52
+ def down
53
+ Rails.logger.warn "This migration cannot be reversed as it would require original HTML content"
54
+ end
55
+
56
+ private
57
+
58
+ def valid_editor_js_content?(content)
59
+ return false unless content.is_a?(Hash)
60
+ return false unless content["blocks"].is_a?(Array)
61
+ return false if content["blocks"].empty?
62
+
63
+ # Check if there are any non-empty blocks
64
+ content["blocks"].any? do |block|
65
+ next false unless block.is_a?(Hash)
66
+ next false unless block["data"].is_a?(Hash)
67
+
68
+ case block["type"]
69
+ when "paragraph"
70
+ block["data"]["text"].present?
71
+ when "header"
72
+ block["data"]["text"].present?
73
+ when "list"
74
+ block["data"]["items"].present? && block["data"]["items"].any?(&:present?)
75
+ when "quote"
76
+ block["data"]["text"].present?
77
+ else
78
+ false
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,9 @@
1
+ class AddStatusToPandaCMSPages < ActiveRecord::Migration[7.1]
2
+ def change
3
+ unless column_exists?(:panda_cms_pages, :status)
4
+ create_enum :panda_cms_page_status, ["active", "draft", "hidden", "archived"]
5
+ add_column :panda_cms_pages, :status, :panda_cms_page_status, default: "active", null: false
6
+ add_index :panda_cms_pages, :status
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ class AddNestedSetsToPandaCMSPages < ActiveRecord::Migration[7.1]
2
+ def self.up
3
+ Panda::CMS::Page.where(parent_id: 0).update_all(parent_id: nil)
4
+ add_column :panda_cms_pages, :lft, :integer
5
+ add_column :panda_cms_pages, :rgt, :integer
6
+
7
+ # This is necessary to update :lft and :rgt columns
8
+ Panda::CMS::Page.reset_column_information
9
+ Panda::CMS::Page.rebuild!
10
+ end
11
+
12
+ def self.down
13
+ remove_column :panda_cms_pages, :lft
14
+ remove_column :panda_cms_pages, :rgt
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ class AddKindToPandaCMSMenus < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_enum :panda_cms_menu_kind, ["static", "auto"]
4
+ add_column :panda_cms_menus, :kind, :enum, enum_type: :panda_cms_menu_kind, default: "static", null: false
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ class AddStartPageToPandaCMSMenus < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_reference :panda_cms_menus, :start_page, type: :uuid, foreign_key: {to_table: :panda_cms_pages}
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ class AddNestedToPandaCMSMenuItems < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_column :panda_cms_menu_items, :parent_id, :uuid
4
+ add_column :panda_cms_menu_items, :lft, :integer
5
+ add_column :panda_cms_menu_items, :rgt, :integer
6
+ add_column :panda_cms_menu_items, :depth, :integer
7
+ add_column :panda_cms_menu_items, :children_count, :integer, null: false, default: 0
8
+
9
+ add_index :panda_cms_menu_items, :lft
10
+ add_index :panda_cms_menu_items, :rgt
11
+
12
+ Panda::CMS::MenuItem.reset_column_information
13
+ Panda::CMS::MenuItem.rebuild!
14
+
15
+ # Update pages whilst we're at it
16
+ add_column :panda_cms_pages, :depth, :integer
17
+ add_column :panda_cms_pages, :children_count, :integer, null: false, default: 0
18
+ add_index :panda_cms_pages, :lft
19
+ add_index :panda_cms_pages, :rgt
20
+
21
+ Panda::CMS::Page.reset_column_information
22
+ Panda::CMS::Page.rebuild!
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ class CreatePandaCMSUsers < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :panda_cms_users, id: :uuid do |t|
4
+ t.string :firstname
5
+ t.string :lastname
6
+ t.string :email
7
+ t.string :image_url
8
+ t.boolean :admin
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ class AddMaxUsesToPandaCMSTemplate < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_column :panda_cms_templates, :max_uses, :integer, null: true, default: nil
4
+ add_column :panda_cms_templates, :pages_count, :integer, default: 0
5
+ Panda::CMS::Template.find_by(name: "Homepage")&.update(max_uses: 1)
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class ResetCounterCacheOnPandaCMSTemplate < ActiveRecord::Migration[7.1]
2
+ def change
3
+ Panda::CMS::Template.find_each { |t| Panda::CMS::Template.reset_counters(t.id, :pages) }
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ class CreatePandaCMSRedirects < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :panda_cms_redirects, id: :uuid do |t|
4
+ t.string :origin_path, null: true
5
+ t.string :destination_path, null: true
6
+ t.references :origin_panda_cms_page, null: true, foreign_key: {to_table: :panda_cms_pages}, type: :uuid
7
+ t.references :destination_panda_cms_page, null: true, foreign_key: {to_table: :panda_cms_pages}, type: :uuid
8
+ t.integer :status_code, default: 301, null: false
9
+ t.integer :visits, default: 0, null: false
10
+ t.datetime :last_visited_at, null: true
11
+ t.timestamps
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ class CreatePandaCMSVisits < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :panda_cms_visits, id: :uuid do |t|
4
+ t.string :ip_address, null: true
5
+ t.string :user_agent, null: true
6
+
7
+ t.references :panda_cms_page, null: true, foreign_key: true, type: :uuid
8
+ t.references :panda_cms_redirect, null: true, foreign_key: true, type: :uuid
9
+ t.references :panda_cms_user, null: true, foreign_key: true, type: :uuid
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,58 @@
1
+ # This migration comes from active_storage (originally 20170806125915)
2
+ class CreateActiveStorageTables < ActiveRecord::Migration[7.0]
3
+ def change
4
+ # Use Active Record's configured type for primary and foreign keys
5
+ primary_key_type, foreign_key_type = primary_and_foreign_key_types
6
+
7
+ create_table :active_storage_blobs, id: primary_key_type do |t|
8
+ t.string :key, null: false
9
+ t.string :filename, null: false
10
+ t.string :content_type
11
+ t.text :metadata
12
+ t.string :service_name, null: false
13
+ t.bigint :byte_size, null: false
14
+ t.string :checksum
15
+
16
+ if connection.supports_datetime_with_precision?
17
+ t.datetime :created_at, precision: 6, null: false
18
+ else
19
+ t.datetime :created_at, null: false
20
+ end
21
+
22
+ t.index [:key], unique: true
23
+ end
24
+
25
+ create_table :active_storage_attachments, id: primary_key_type do |t|
26
+ t.string :name, null: false
27
+ t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
28
+ t.references :blob, null: false, type: foreign_key_type
29
+
30
+ if connection.supports_datetime_with_precision?
31
+ t.datetime :created_at, precision: 6, null: false
32
+ else
33
+ t.datetime :created_at, null: false
34
+ end
35
+
36
+ t.index [:record_type, :record_id, :name, :blob_id], name: :index_active_storage_attachments_uniqueness, unique: true
37
+ t.foreign_key :active_storage_blobs, column: :blob_id
38
+ end
39
+
40
+ create_table :active_storage_variant_records, id: primary_key_type do |t|
41
+ t.belongs_to :blob, null: false, index: false, type: foreign_key_type
42
+ t.string :variation_digest, null: false
43
+
44
+ t.index [:blob_id, :variation_digest], name: :index_active_storage_variant_records_uniqueness, unique: true
45
+ t.foreign_key :active_storage_blobs, column: :blob_id
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def primary_and_foreign_key_types
52
+ config = Rails.configuration.generators
53
+ setting = config.options[config.orm][:primary_key_type]
54
+ primary_key_type = setting || :primary_key
55
+ foreign_key_type = setting || :bigint
56
+ [primary_key_type, foreign_key_type]
57
+ end
58
+ end
@@ -0,0 +1,5 @@
1
+ class DefaultPandaCMSUsersAdminToFalse < ActiveRecord::Migration[7.1]
2
+ def change
3
+ change_column :panda_cms_users, :admin, :boolean, default: false
4
+ end
5
+ end
@@ -0,0 +1,22 @@
1
+ # This migration comes from active_storage (originally 20190112182829)
2
+ class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0]
3
+ def up
4
+ return unless table_exists?(:active_storage_blobs)
5
+
6
+ unless column_exists?(:active_storage_blobs, :service_name)
7
+ add_column :active_storage_blobs, :service_name, :string
8
+
9
+ if (configured_service = ActiveStorage::Blob.service.name)
10
+ ActiveStorage::Blob.unscoped.update_all(service_name: configured_service)
11
+ end
12
+
13
+ change_column :active_storage_blobs, :service_name, :string, null: false
14
+ end
15
+ end
16
+
17
+ def down
18
+ return unless table_exists?(:active_storage_blobs)
19
+
20
+ remove_column :active_storage_blobs, :service_name
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ # This migration comes from active_storage (originally 20191206030411)
2
+ class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0]
3
+ def change
4
+ return unless table_exists?(:active_storage_blobs)
5
+
6
+ # Use Active Record's configured type for primary key
7
+ create_table :active_storage_variant_records, id: primary_key_type, if_not_exists: true do |t|
8
+ t.belongs_to :blob, null: false, index: false, type: blobs_primary_key_type
9
+ t.string :variation_digest, null: false
10
+
11
+ t.index %i[blob_id variation_digest], name: "index_active_storage_variant_records_uniqueness", unique: true
12
+ t.foreign_key :active_storage_blobs, column: :blob_id
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def primary_key_type
19
+ config = Rails.configuration.generators
20
+ config.options[config.orm][:primary_key_type] || :primary_key
21
+ end
22
+
23
+ def blobs_primary_key_type
24
+ pkey_name = connection.primary_key(:active_storage_blobs)
25
+ pkey_column = connection.columns(:active_storage_blobs).find { |c| c.name == pkey_name }
26
+ pkey_column.bigint? ? :bigint : pkey_column.type
27
+ end
28
+ end
@@ -0,0 +1,8 @@
1
+ # This migration comes from active_storage (originally 20211119233751)
2
+ class RemoveNotNullOnActiveStorageBlobsChecksum < ActiveRecord::Migration[6.0]
3
+ def change
4
+ return unless table_exists?(:active_storage_blobs)
5
+
6
+ change_column_null(:active_storage_blobs, :checksum, true)
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ class CreatePandaCMSForms < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :panda_cms_forms, id: :uuid do |t|
4
+ t.string :name
5
+ t.integer :submissions, default: 0
6
+ t.timestamps
7
+ end
8
+
9
+ add_index :panda_cms_forms, :name, unique: true
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ class CreatePandaCMSFormSubmissions < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :panda_cms_form_submissions, id: :uuid do |t|
4
+ t.references :form, type: :uuid, null: false, foreign_key: {to_table: :panda_cms_forms}
5
+ t.jsonb :data, null: false, default: {}
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,27 @@
1
+ class CreatePandaCMSPosts < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :panda_cms_post_tags, id: :uuid do |t|
4
+ t.string :tag
5
+ t.string :description
6
+ t.string :slug
7
+ t.timestamps
8
+ t.index :tag, unique: true
9
+ t.index :slug, unique: true
10
+ end
11
+
12
+ create_table :panda_cms_posts, id: :uuid do |t|
13
+ t.string :title
14
+ t.string :slug
15
+ t.text :content
16
+ t.datetime :published_at
17
+ t.references :post_tag, type: :uuid, null: false, foreign_key: {to_table: :panda_cms_post_tags}
18
+ t.references :user, type: :uuid, null: false, foreign_key: {to_table: :panda_cms_users}
19
+ t.timestamps
20
+ t.index :slug, unique: true
21
+ end
22
+
23
+ create_enum :panda_cms_post_status, ["active", "draft", "hidden", "archived"]
24
+ add_column :panda_cms_posts, :status, :panda_cms_post_status, default: "draft", null: false
25
+ add_index :panda_cms_posts, :status
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ class CreatePandaCMSPostVersions < ActiveRecord::Migration[7.1]
2
+ def change
3
+ create_table :panda_cms_post_versions, id: :uuid do |t|
4
+ t.string :item_type, null: false
5
+ t.string :item_id, null: false
6
+ t.string :event, null: false
7
+ t.string :whodunnit
8
+ t.jsonb :object
9
+ t.jsonb :object_changes
10
+ t.datetime :created_at
11
+ end
12
+ add_index :panda_cms_post_versions, %i[item_type item_id]
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ class FixPandaCMSVisitsColumnNames < ActiveRecord::Migration[7.1]
2
+ def change
3
+ change_table :panda_cms_visits do |t|
4
+ t.rename :panda_cms_page_id, :page_id
5
+ t.rename :panda_cms_redirect_id, :redirect_id
6
+ t.rename :panda_cms_user_id, :user_id
7
+ t.string :referrer, null: true
8
+ t.datetime :visited_at
9
+ t.string :url, null: true
10
+ t.jsonb :params, null: true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class AddCompletionPathToPandaCMSForms < ActiveRecord::Migration[7.1]
2
+ def change
3
+ add_column :panda_cms_forms, :completion_path, :string
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class ChangeFormSubmissionsToSubmissionCount < ActiveRecord::Migration[7.2]
2
+ def change
3
+ rename_column :panda_cms_forms, :submissions, :submission_count
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ # This migration comes from action_text (originally 20180528164100)
2
+ class CreateActionTextTables < ActiveRecord::Migration[7.2]
3
+ def change
4
+ create_table :action_text_rich_texts, id: :uuid do |t|
5
+ t.string :name, null: false
6
+ t.text :body, limit: 16.megabytes - 1
7
+ t.references :record, null: false, polymorphic: true, index: false, type: :uuid
8
+ t.timestamps
9
+ t.index [:record_type, :record_id, :name], name: "index_action_text_rich_texts_uniqueness", unique: true
10
+ end
11
+
12
+ create_table :action_text_rich_text_versions, id: :uuid do |t|
13
+ t.string :item_type, null: false
14
+ t.string :item_id, null: false
15
+ t.string :event, null: false
16
+ t.string :whodunnit
17
+ t.jsonb :object
18
+ t.jsonb :object_changes
19
+ t.datetime :created_at
20
+ end
21
+
22
+ add_index :action_text_rich_text_versions, %i[item_type item_id]
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ class AddDepthToPandaCMSMenus < ActiveRecord::Migration[7.2]
2
+ def change
3
+ add_column :panda_cms_menus, :depth, :integer, null: true, default: nil
4
+
5
+ homepage = Panda::CMS::Page.find_by(path: "/")
6
+ if homepage
7
+ main_menu = Panda::CMS::Menu.find_by(start_page_id: homepage.id, kind: :auto)
8
+ main_menu&.update(depth: 2)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ class AddCachedContentToPandaCMSBlockContents < ActiveRecord::Migration[7.2]
2
+ def change
3
+ add_column :panda_cms_block_contents, :cached_content, :jsonb
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ class ConvertPostContentToEditorJs < ActiveRecord::Migration[7.1]
2
+ def up
3
+ Panda::CMS::Post.find_each do |post|
4
+ next if post.post_content.blank?
5
+
6
+ editor_content = {
7
+ time: Time.current.to_i,
8
+ version: "2.28.2",
9
+ blocks: [
10
+ {
11
+ type: "paragraph",
12
+ data: {
13
+ text: post.post_content.to_plain_text
14
+ }
15
+ }
16
+ ]
17
+ }
18
+
19
+ post.update_column(:content, editor_content)
20
+ end
21
+ end
22
+
23
+ def down
24
+ Panda::CMS::Post.find_each do |post|
25
+ next if post.content.blank?
26
+
27
+ # Extract plain text from EditorJS format
28
+ plain_text = post.content["blocks"]
29
+ &.map { |block| block["data"]["text"] }
30
+ &.join("\n")
31
+
32
+ post.update_column(:content, plain_text)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,9 @@
1
+ class RemoveActionTextFromPosts < ActiveRecord::Migration[7.1]
2
+ def up
3
+ remove_column :panda_cms_posts, :post_content
4
+ end
5
+
6
+ def down
7
+ add_column :panda_cms_posts, :post_content, :text
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ class RemovePostTagReferences < ActiveRecord::Migration[8.0]
2
+ def up
3
+ remove_reference :panda_cms_posts, :post_tag, foreign_key: {to_table: :panda_cms_post_tags}, type: :uuid
4
+ drop_table :panda_cms_post_tags
5
+ end
6
+
7
+ def down
8
+ create_table :panda_cms_post_tags, id: :uuid do |t|
9
+ t.string :tag
10
+ t.string :description
11
+ t.string :slug
12
+ t.timestamps
13
+ t.index :tag, unique: true
14
+ t.index :slug, unique: true
15
+ end
16
+
17
+ add_reference :panda_cms_posts, :post_tag, type: :uuid, foreign_key: {to_table: :panda_cms_post_tags}
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ class AddEditorJsToPosts < ActiveRecord::Migration[7.0]
2
+ def up
3
+ # First, add a temporary column
4
+ add_column :panda_cms_posts, :content_jsonb, :jsonb, default: {}, null: false
5
+
6
+ # Copy data from the old column to the new one, converting to JSONB
7
+ execute <<-SQL
8
+ UPDATE panda_cms_posts
9
+ SET content_jsonb =
10
+ CASE
11
+ WHEN content IS NULL THEN '{}'::jsonb
12
+ WHEN content::text = '' THEN '{}'::jsonb
13
+ ELSE content::jsonb
14
+ END;
15
+ SQL
16
+
17
+ # Remove the old column
18
+ remove_column :panda_cms_posts, :content
19
+
20
+ # Rename the new column to the original name
21
+ rename_column :panda_cms_posts, :content_jsonb, :content
22
+ end
23
+
24
+ def down
25
+ change_column :panda_cms_posts, :content, :text
26
+ end
27
+ end
@@ -0,0 +1,5 @@
1
+ class AddCachedContentToPandaCMSPosts < ActiveRecord::Migration[8.0]
2
+ def change
3
+ add_column :panda_cms_posts, :cached_content, :text
4
+ end
5
+ end