alchemy_cms 8.0.7 → 8.1.1

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 (280) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -10
  3. data/app/assets/builds/alchemy/admin.css +1 -1
  4. data/app/assets/builds/alchemy/dark-theme.css +1 -1
  5. data/app/assets/builds/alchemy/light-theme.css +1 -1
  6. data/app/assets/builds/alchemy/preview.min.js +1 -1
  7. data/app/assets/builds/alchemy/theme.css +1 -1
  8. data/app/{views/alchemy/admin/elements/_element.html.erb → components/alchemy/admin/element_editor.html.erb} +34 -29
  9. data/app/components/alchemy/admin/element_editor.rb +115 -0
  10. data/app/components/alchemy/admin/element_select.rb +12 -9
  11. data/app/components/alchemy/admin/ingredient_editor.rb +54 -0
  12. data/app/components/alchemy/admin/list_filter.rb +16 -5
  13. data/app/components/alchemy/admin/page_node.html.erb +215 -0
  14. data/app/components/alchemy/admin/page_node.rb +70 -0
  15. data/app/components/alchemy/admin/picture_thumbnail.rb +36 -0
  16. data/app/components/alchemy/admin/publish_page_button.html.erb +15 -0
  17. data/app/components/alchemy/admin/publish_page_button.rb +54 -0
  18. data/app/{helpers/alchemy/admin/tags_helper.rb → components/alchemy/admin/tags_list.rb} +19 -11
  19. data/app/components/alchemy/admin/toolbar_button.rb +16 -12
  20. data/app/components/alchemy/ingredients/audio_editor.rb +8 -0
  21. data/app/components/alchemy/ingredients/base_editor.rb +222 -0
  22. data/app/components/alchemy/ingredients/boolean_editor.rb +21 -0
  23. data/app/components/alchemy/ingredients/color_editor.rb +80 -0
  24. data/app/components/alchemy/ingredients/color_view.rb +13 -0
  25. data/app/components/alchemy/ingredients/datetime_editor.rb +28 -0
  26. data/app/components/alchemy/ingredients/file_editor.rb +69 -0
  27. data/app/components/alchemy/ingredients/headline_editor.rb +88 -0
  28. data/app/components/alchemy/ingredients/html_editor.rb +11 -0
  29. data/app/components/alchemy/ingredients/link_editor.rb +29 -0
  30. data/app/components/alchemy/ingredients/node_editor.rb +23 -0
  31. data/app/components/alchemy/ingredients/number_editor.rb +28 -0
  32. data/app/components/alchemy/ingredients/page_editor.rb +19 -0
  33. data/app/components/alchemy/ingredients/picture_editor.rb +81 -0
  34. data/app/components/alchemy/ingredients/richtext_editor.rb +31 -0
  35. data/app/components/alchemy/ingredients/select_editor.rb +37 -0
  36. data/app/components/alchemy/ingredients/select_view.rb +7 -0
  37. data/app/components/alchemy/ingredients/text_editor.rb +41 -0
  38. data/app/components/alchemy/ingredients/video_editor.rb +8 -0
  39. data/app/controllers/alchemy/admin/attachments_controller.rb +8 -6
  40. data/app/controllers/alchemy/admin/base_controller.rb +7 -18
  41. data/app/controllers/alchemy/admin/clipboard_controller.rb +15 -11
  42. data/app/controllers/alchemy/admin/dashboard_controller.rb +2 -2
  43. data/app/controllers/alchemy/admin/elements_controller.rb +34 -32
  44. data/app/controllers/alchemy/admin/ingredients_controller.rb +1 -0
  45. data/app/controllers/alchemy/admin/layoutpages_controller.rb +2 -1
  46. data/app/controllers/alchemy/admin/legacy_page_urls_controller.rb +1 -1
  47. data/app/controllers/alchemy/admin/nodes_controller.rb +24 -1
  48. data/app/controllers/alchemy/admin/pages_controller.rb +31 -41
  49. data/app/controllers/alchemy/admin/pictures_controller.rb +2 -5
  50. data/app/controllers/alchemy/admin/resources_controller.rb +1 -1
  51. data/app/controllers/alchemy/api/ingredients_controller.rb +1 -1
  52. data/app/controllers/alchemy/api/pages_controller.rb +5 -3
  53. data/app/controllers/alchemy/base_controller.rb +6 -6
  54. data/app/controllers/alchemy/pages_controller.rb +12 -6
  55. data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +0 -1
  56. data/app/controllers/concerns/alchemy/admin/clipboard.rb +57 -0
  57. data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +2 -2
  58. data/app/controllers/concerns/alchemy/site_redirects.rb +1 -1
  59. data/app/decorators/alchemy/ingredient_editor.rb +37 -4
  60. data/app/helpers/alchemy/admin/base_helper.rb +10 -6
  61. data/app/helpers/alchemy/admin/ingredients_helper.rb +6 -3
  62. data/app/helpers/alchemy/base_helper.rb +1 -1
  63. data/app/helpers/alchemy/pages_helper.rb +1 -1
  64. data/app/javascript/alchemy_admin/components/action.js +5 -1
  65. data/app/javascript/alchemy_admin/components/color_select.js +73 -0
  66. data/app/javascript/alchemy_admin/components/element_editor/delete_element_button.js +11 -3
  67. data/app/javascript/alchemy_admin/components/element_editor/publish_element_button.js +7 -2
  68. data/app/javascript/alchemy_admin/components/element_editor.js +11 -12
  69. data/app/javascript/alchemy_admin/components/element_select.js +39 -17
  70. data/app/javascript/alchemy_admin/components/elements_window.js +0 -2
  71. data/app/javascript/alchemy_admin/components/file_editor.js +26 -0
  72. data/app/javascript/alchemy_admin/components/index.js +9 -0
  73. data/app/javascript/alchemy_admin/components/list_filter.js +57 -8
  74. data/app/javascript/alchemy_admin/components/message.js +9 -3
  75. data/app/javascript/alchemy_admin/components/page_node.js +119 -0
  76. data/app/javascript/alchemy_admin/{page_publication_fields.js → components/page_publication_fields.js} +9 -8
  77. data/app/javascript/alchemy_admin/{picture_editors.js → components/picture_editor.js} +30 -45
  78. data/app/javascript/alchemy_admin/components/picture_thumbnail.js +107 -0
  79. data/app/javascript/alchemy_admin/components/publish_page_button.js +41 -0
  80. data/app/javascript/alchemy_admin/components/select.js +3 -1
  81. data/app/javascript/alchemy_admin/components/sitemap.js +210 -0
  82. data/app/javascript/alchemy_admin/{sortable_elements.js → components/sortable_elements.js} +22 -25
  83. data/app/javascript/alchemy_admin/components/tinymce.js +10 -5
  84. data/app/javascript/alchemy_admin/components/update_check.js +1 -1
  85. data/app/javascript/alchemy_admin/components/uploader.js +30 -0
  86. data/app/javascript/alchemy_admin/image_overlay.js +0 -2
  87. data/app/javascript/alchemy_admin/initializer.js +0 -3
  88. data/app/javascript/alchemy_admin/templates/compiled.js +1 -1
  89. data/app/javascript/alchemy_admin/utils/ajax.js +15 -3
  90. data/app/javascript/alchemy_admin.js +0 -6
  91. data/app/models/alchemy/attachment.rb +4 -4
  92. data/app/models/alchemy/element/definitions.rb +1 -2
  93. data/app/models/alchemy/element/element_ingredients.rb +6 -2
  94. data/app/models/alchemy/element.rb +54 -13
  95. data/app/models/alchemy/element_definition.rb +4 -1
  96. data/app/models/alchemy/elements_repository.rb +6 -0
  97. data/app/models/alchemy/folded_page.rb +2 -2
  98. data/app/models/alchemy/ingredient.rb +38 -1
  99. data/app/models/alchemy/ingredient_definition.rb +4 -1
  100. data/app/models/alchemy/ingredient_validator.rb +6 -2
  101. data/app/models/alchemy/ingredients/color.rb +10 -0
  102. data/app/models/alchemy/ingredients/headline.rb +2 -17
  103. data/app/models/alchemy/ingredients/picture.rb +4 -4
  104. data/app/models/alchemy/ingredients/select.rb +19 -0
  105. data/app/models/alchemy/node.rb +28 -1
  106. data/app/models/alchemy/page/page_naming.rb +0 -7
  107. data/app/models/alchemy/page/page_natures.rb +7 -3
  108. data/app/models/alchemy/page/page_scopes.rb +1 -1
  109. data/app/models/alchemy/page/publisher.rb +14 -2
  110. data/app/models/alchemy/page.rb +102 -23
  111. data/app/models/alchemy/page_definition.rb +4 -1
  112. data/app/models/alchemy/page_version.rb +22 -6
  113. data/app/models/alchemy/picture.rb +10 -11
  114. data/app/models/alchemy/picture_variant.rb +1 -3
  115. data/app/models/alchemy/resource.rb +1 -1
  116. data/app/models/alchemy/storage_adapter/active_storage.rb +14 -2
  117. data/app/models/alchemy/storage_adapter/dragonfly.rb +12 -0
  118. data/app/models/alchemy/storage_adapter.rb +2 -0
  119. data/app/models/concerns/alchemy/picture_thumbnails.rb +4 -4
  120. data/app/models/concerns/alchemy/publishable.rb +54 -0
  121. data/app/serializers/alchemy/page_tree_serializer.rb +11 -31
  122. data/app/services/alchemy/copy_page.rb +17 -0
  123. data/app/services/alchemy/duplicate_element.rb +1 -1
  124. data/app/services/alchemy/page_tree_preloader.rb +105 -0
  125. data/app/stylesheets/alchemy/_extends.scss +3 -9
  126. data/app/stylesheets/alchemy/_mixins.scss +3 -1
  127. data/app/stylesheets/alchemy/_themes.scss +19 -10
  128. data/app/stylesheets/alchemy/admin/archive.scss +1 -0
  129. data/app/stylesheets/alchemy/admin/base.scss +5 -2
  130. data/app/stylesheets/alchemy/admin/buttons.scss +3 -3
  131. data/app/stylesheets/alchemy/admin/element-select.scss +18 -0
  132. data/app/stylesheets/alchemy/admin/elements.scss +123 -23
  133. data/app/stylesheets/alchemy/admin/errors.scss +17 -9
  134. data/app/stylesheets/alchemy/admin/flash.scss +6 -4
  135. data/app/stylesheets/alchemy/admin/images.scss +9 -5
  136. data/app/stylesheets/alchemy/admin/list_filter.scss +4 -4
  137. data/app/stylesheets/alchemy/admin/notices.scss +1 -2
  138. data/app/stylesheets/alchemy/admin/selects.scss +36 -21
  139. data/app/stylesheets/alchemy/admin/shoelace.scss +14 -1
  140. data/app/stylesheets/alchemy/admin/sitemap.scss +11 -3
  141. data/app/stylesheets/alchemy/admin/tags.scss +3 -1
  142. data/app/stylesheets/alchemy/admin/toolbar.scss +1 -1
  143. data/app/views/alchemy/_edit_mode.html.erb +1 -1
  144. data/app/views/alchemy/_menubar.html.erb +1 -1
  145. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +35 -31
  146. data/app/views/alchemy/admin/attachments/_library_sidebar.html.erb +6 -0
  147. data/app/views/alchemy/admin/attachments/_overlay_file_list.html.erb +1 -1
  148. data/app/views/alchemy/admin/attachments/_replace_button.html.erb +1 -8
  149. data/app/views/alchemy/admin/attachments/_sorting_select.html.erb +13 -0
  150. data/app/views/alchemy/admin/attachments/_tag_list.html.erb +2 -3
  151. data/app/views/alchemy/admin/attachments/index.html.erb +5 -11
  152. data/app/views/alchemy/admin/attachments/show.html.erb +1 -1
  153. data/app/views/alchemy/admin/clipboard/_button.html.erb +1 -0
  154. data/app/views/alchemy/admin/clipboard/index.html.erb +4 -5
  155. data/app/views/alchemy/admin/clipboard/insert.turbo_stream.erb +1 -1
  156. data/app/views/alchemy/admin/crop.html.erb +5 -7
  157. data/app/views/alchemy/admin/elements/_add_nested_element_form.html.erb +6 -6
  158. data/app/views/alchemy/admin/elements/_fixed_element.html.erb +1 -1
  159. data/app/views/alchemy/admin/elements/_footer.html.erb +7 -1
  160. data/app/views/alchemy/admin/elements/_header.html.erb +5 -5
  161. data/app/views/alchemy/admin/elements/_toolbar.html.erb +33 -8
  162. data/app/views/alchemy/admin/elements/create.turbo_stream.erb +10 -10
  163. data/app/views/alchemy/admin/elements/index.html.erb +29 -16
  164. data/app/views/alchemy/admin/elements/new.html.erb +2 -2
  165. data/app/views/alchemy/admin/ingredients/update.turbo_stream.erb +3 -5
  166. data/app/views/alchemy/admin/leave.html.erb +1 -1
  167. data/app/views/alchemy/admin/nodes/_node.html.erb +19 -0
  168. data/app/views/alchemy/admin/nodes/edit.html.erb +1 -1
  169. data/app/views/alchemy/admin/nodes/index.html.erb +3 -1
  170. data/app/views/alchemy/admin/nodes/new.html.erb +14 -1
  171. data/app/views/alchemy/admin/pages/_current_page.html.erb +3 -1
  172. data/app/views/alchemy/admin/pages/_form.html.erb +21 -9
  173. data/app/views/alchemy/admin/pages/_page_status.html.erb +1 -1
  174. data/app/views/alchemy/admin/pages/_publication_fields.html.erb +28 -26
  175. data/app/views/alchemy/admin/pages/_table.html.erb +0 -7
  176. data/app/views/alchemy/admin/pages/_toolbar.html.erb +3 -5
  177. data/app/views/alchemy/admin/pages/edit.html.erb +5 -11
  178. data/app/views/alchemy/admin/pages/flush.turbo_stream.erb +2 -0
  179. data/app/views/alchemy/admin/pages/fold.turbo_stream.erb +5 -0
  180. data/app/views/alchemy/admin/pages/index.html.erb +5 -3
  181. data/app/views/alchemy/admin/pages/new.html.erb +2 -12
  182. data/app/views/alchemy/admin/pages/publish.turbo_stream.erb +12 -0
  183. data/app/views/alchemy/admin/pages/tree.html.erb +13 -0
  184. data/app/views/alchemy/admin/pages/update.turbo_stream.erb +5 -16
  185. data/app/views/alchemy/admin/partials/_flash_notices.html.erb +1 -1
  186. data/app/views/alchemy/admin/partials/{_remote_search_form.html.erb → _overlay_search_form.html.erb} +1 -2
  187. data/app/views/alchemy/admin/partials/_paste_from_clipboard_form.html.erb +12 -0
  188. data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +24 -21
  189. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +18 -26
  190. data/app/views/alchemy/admin/pictures/_picture.html.erb +11 -15
  191. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +3 -6
  192. data/app/views/alchemy/admin/pictures/_tag_list.html.erb +2 -3
  193. data/app/views/alchemy/admin/pictures/index.html.erb +0 -1
  194. data/app/views/alchemy/admin/pictures/update.turbo_stream.erb +1 -1
  195. data/app/views/alchemy/admin/resources/_resource_usage_info.html.erb +1 -1
  196. data/app/views/alchemy/admin/resources/_tag_list.html.erb +2 -3
  197. data/app/views/alchemy/admin/styleguide/index.html.erb +25 -20
  198. data/app/views/alchemy/admin/tags/edit.html.erb +1 -1
  199. data/app/views/alchemy/admin/tinymce/_setup.html.erb +2 -2
  200. data/app/views/alchemy/admin/uploader/_button.html.erb +1 -15
  201. data/app/views/alchemy/attachments/show.html.erb +1 -1
  202. data/app/views/alchemy/base/permission_denied.js.erb +1 -1
  203. data/app/views/alchemy/ingredients/shared/_anchor.html.erb +9 -7
  204. data/app/views/alchemy/ingredients/shared/_link_tools.html.erb +12 -5
  205. data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +10 -11
  206. data/app/views/alchemy/language_links/_spacer.html.erb +1 -1
  207. data/app/views/alchemy/messages_mailer/new.html.erb +1 -1
  208. data/app/views/alchemy/welcome.html.erb +1 -1
  209. data/config/locales/alchemy.en.yml +12 -2
  210. data/config/routes.rb +2 -2
  211. data/db/migrate/20230123112425_add_searchable_to_alchemy_pages.rb +1 -1
  212. data/db/migrate/20230505132743_add_indexes_to_alchemy_pictures.rb +1 -1
  213. data/db/migrate/20231113104432_create_page_mutexes.rb +1 -1
  214. data/db/migrate/20240314105244_create_alchemy_picture_descriptions.rb +1 -1
  215. data/db/migrate/20250626160259_add_unique_index_to_picture_descriptions.rb +1 -1
  216. data/db/migrate/20250905140323_add_created_at_index_to_pictures_and_attachments.rb +1 -1
  217. data/db/migrate/20251106150010_convert_select_value_for_multiple.rb +11 -0
  218. data/db/migrate/20260102121232_add_metadata_to_page_versions.rb +9 -0
  219. data/db/migrate/20260115164704_add_publication_timestamps_to_alchemy_elements.rb +30 -0
  220. data/db/migrate/20260115164705_add_index_to_element_publication_timestamps.rb +13 -0
  221. data/lib/alchemy/ability_helper.rb +1 -3
  222. data/lib/alchemy/auth_accessors.rb +51 -117
  223. data/lib/alchemy/configuration.rb +1 -0
  224. data/lib/alchemy/configurations/main.rb +63 -0
  225. data/lib/alchemy/controller_actions.rb +1 -1
  226. data/lib/alchemy/engine.rb +9 -12
  227. data/lib/alchemy/error_tracking/error_logger.rb +1 -1
  228. data/lib/alchemy/errors.rb +1 -1
  229. data/lib/alchemy/logger.rb +34 -4
  230. data/lib/alchemy/name_conversions.rb +0 -6
  231. data/lib/alchemy/seeder.rb +2 -2
  232. data/lib/alchemy/tasks/usage.rb +4 -4
  233. data/lib/alchemy/test_support/factories/page_version_factory.rb +3 -0
  234. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +30 -0
  235. data/lib/alchemy/test_support/shared_ingredient_editor_examples.rb +26 -6
  236. data/lib/alchemy/test_support/shared_publishable_examples.rb +114 -0
  237. data/lib/alchemy/upgrader/eight_one.rb +56 -0
  238. data/lib/alchemy/upgrader.rb +9 -1
  239. data/lib/alchemy/version.rb +1 -1
  240. data/lib/alchemy.rb +1 -4
  241. data/lib/alchemy_cms.rb +0 -1
  242. data/lib/generators/alchemy/elements/templates/view.html.erb +3 -3
  243. data/lib/generators/alchemy/ingredient/ingredient_generator.rb +6 -8
  244. data/lib/generators/alchemy/ingredient/templates/editor_component.rb.tt +22 -0
  245. data/lib/generators/alchemy/page_layouts/templates/layout.html.erb +1 -1
  246. data/lib/generators/alchemy/site_layouts/templates/layout.html.erb +1 -1
  247. data/lib/tasks/alchemy/upgrade.rake +21 -7
  248. data/vendor/javascript/shoelace.min.js +713 -31
  249. data/vendor/javascript/tinymce.min.js +1 -1
  250. metadata +103 -83
  251. data/app/decorators/alchemy/element_editor.rb +0 -90
  252. data/app/helpers/alchemy/admin/pictures_helper.rb +0 -14
  253. data/app/javascript/alchemy_admin/file_editors.js +0 -28
  254. data/app/javascript/alchemy_admin/image_loader.js +0 -54
  255. data/app/javascript/alchemy_admin/page_sorter.js +0 -71
  256. data/app/javascript/alchemy_admin/sitemap.js +0 -154
  257. data/app/javascript/alchemy_admin/templates/page_folder.hbs +0 -3
  258. data/app/views/alchemy/admin/attachments/archive_overlay.js.erb +0 -4
  259. data/app/views/alchemy/admin/pages/_page.html.erb +0 -163
  260. data/app/views/alchemy/admin/pages/_sitemap.html.erb +0 -30
  261. data/app/views/alchemy/admin/pages/flush.js.erb +0 -2
  262. data/app/views/alchemy/admin/pictures/archive_overlay.js.erb +0 -5
  263. data/app/views/alchemy/admin/pictures/index.js.erb +0 -2
  264. data/app/views/alchemy/ingredients/_audio_editor.html.erb +0 -5
  265. data/app/views/alchemy/ingredients/_boolean_editor.html.erb +0 -11
  266. data/app/views/alchemy/ingredients/_datetime_editor.html.erb +0 -20
  267. data/app/views/alchemy/ingredients/_file_editor.html.erb +0 -52
  268. data/app/views/alchemy/ingredients/_headline_editor.html.erb +0 -44
  269. data/app/views/alchemy/ingredients/_html_editor.html.erb +0 -8
  270. data/app/views/alchemy/ingredients/_link_editor.html.erb +0 -30
  271. data/app/views/alchemy/ingredients/_node_editor.html.erb +0 -13
  272. data/app/views/alchemy/ingredients/_number_editor.html.erb +0 -24
  273. data/app/views/alchemy/ingredients/_page_editor.html.erb +0 -13
  274. data/app/views/alchemy/ingredients/_picture_editor.html.erb +0 -59
  275. data/app/views/alchemy/ingredients/_richtext_editor.html.erb +0 -15
  276. data/app/views/alchemy/ingredients/_select_editor.html.erb +0 -31
  277. data/app/views/alchemy/ingredients/_text_editor.html.erb +0 -29
  278. data/app/views/alchemy/ingredients/_video_editor.html.erb +0 -5
  279. data/lib/generators/alchemy/ingredient/templates/editor.html.erb +0 -14
  280. /data/{lib → app/models}/alchemy/permissions.rb +0 -0
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples_for "being publishable" do |factory_name|
4
+ describe ".draft" do
5
+ let!(:draft_versions) { create_list(factory_name, 2, public_on: nil) }
6
+
7
+ subject { described_class.draft.map(&:public_on) }
8
+
9
+ before do
10
+ create(factory_name, public_on: Time.current)
11
+ subject.uniq!
12
+ end
13
+
14
+ it "only includes records without public_on date" do
15
+ expect(subject).to eq [nil]
16
+ end
17
+ end
18
+
19
+ describe ".scheduled" do
20
+ subject { described_class.scheduled }
21
+
22
+ let!(:public_one) { create(factory_name, public_on: Date.yesterday) }
23
+ let!(:public_two) { create(factory_name, public_on: Time.current) }
24
+ let!(:non_public) { create(factory_name, public_on: nil) }
25
+
26
+ it "returns currently scheduled records" do
27
+ # Filter to test records only, as factories may create additional records as side effects
28
+ scheduled = subject.where(id: [public_one.id, public_two.id, non_public.id])
29
+ expect(scheduled).to match_array([
30
+ public_one,
31
+ public_two
32
+ ])
33
+ end
34
+ end
35
+
36
+ describe ".published" do
37
+ let!(:public_one) { create(factory_name, public_on: Date.yesterday) }
38
+ let!(:public_two) { create(factory_name, public_on: Date.tomorrow) }
39
+ let!(:non_public) { create(factory_name, public_on: nil) }
40
+
41
+ context "without time given" do
42
+ subject { described_class.published }
43
+
44
+ it "returns records currently public" do
45
+ # Filter to test records only, as factories may create additional records as side effects
46
+ published = subject.where(id: [public_one.id, public_two.id, non_public.id])
47
+ expect(published).to match_array([
48
+ public_one
49
+ ])
50
+ end
51
+ end
52
+
53
+ context "with time given" do
54
+ subject { described_class.published(at: Date.tomorrow + 1.day) }
55
+
56
+ it "returns records public on that time" do
57
+ # Filter to test records only, as factories may create additional records as side effects
58
+ published = subject.where(id: [public_one.id, public_two.id, non_public.id])
59
+ expect(published).to match_array([
60
+ public_one,
61
+ public_two
62
+ ])
63
+ end
64
+ end
65
+ end
66
+
67
+ describe "#public?" do
68
+ subject { page_version.public? }
69
+
70
+ context "when public_on is not set" do
71
+ let(:page_version) { build(factory_name, public_on: nil) }
72
+
73
+ it { is_expected.to be(false) }
74
+ end
75
+
76
+ context "when public_on is set to past date" do
77
+ context "and public_until is set to nil" do
78
+ let(:page_version) do
79
+ build(factory_name,
80
+ public_on: Time.current - 2.days,
81
+ public_until: nil)
82
+ end
83
+
84
+ it { is_expected.to be(true) }
85
+ end
86
+
87
+ context "and public_until is set to future date" do
88
+ let(:page_version) do
89
+ build(factory_name,
90
+ public_on: Time.current - 2.days,
91
+ public_until: Time.current + 2.days)
92
+ end
93
+
94
+ it { is_expected.to be(true) }
95
+ end
96
+
97
+ context "and public_until is set to past date" do
98
+ let(:page_version) do
99
+ build(factory_name,
100
+ public_on: Time.current - 2.days,
101
+ public_until: Time.current - 1.days)
102
+ end
103
+
104
+ it { is_expected.to be(false) }
105
+ end
106
+ end
107
+
108
+ context "when public_on is set to future date" do
109
+ let(:page_version) { build(factory_name, public_on: Time.current + 2.days) }
110
+
111
+ it { is_expected.to be(false) }
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ class Upgrader
5
+ module EightOne
6
+ def migrate_page_metadata
7
+ desc "Migrating page metadata to page versions"
8
+
9
+ connection = ActiveRecord::Base.connection
10
+ pages_table = Alchemy::Page.table_name
11
+ versions_table = Alchemy::PageVersion.table_name
12
+
13
+ unmigrated_count = connection.select_value(<<-SQL.strip_heredoc).to_i
14
+ SELECT COUNT(*) FROM #{versions_table}
15
+ WHERE title IS NULL
16
+ AND meta_description IS NULL
17
+ AND meta_keywords IS NULL
18
+ SQL
19
+
20
+ if unmigrated_count == 0
21
+ log "All page versions have meta data.", :skip
22
+ return
23
+ end
24
+
25
+ sql = if connection.adapter_name.downcase.match?(/mysql|trilogy/)
26
+ <<-SQL.strip_heredoc
27
+ UPDATE #{versions_table} pv
28
+ INNER JOIN #{pages_table} p ON pv.page_id = p.id
29
+ SET pv.title = p.title,
30
+ pv.meta_description = p.meta_description,
31
+ pv.meta_keywords = p.meta_keywords
32
+ WHERE pv.title IS NULL
33
+ AND pv.meta_description IS NULL
34
+ AND pv.meta_keywords IS NULL
35
+ SQL
36
+ else
37
+ <<-SQL.strip_heredoc
38
+ UPDATE #{versions_table}
39
+ SET title = p.title,
40
+ meta_description = p.meta_description,
41
+ meta_keywords = p.meta_keywords
42
+ FROM #{pages_table} p
43
+ WHERE #{versions_table}.page_id = p.id
44
+ AND #{versions_table}.title IS NULL
45
+ AND #{versions_table}.meta_description IS NULL
46
+ AND #{versions_table}.meta_keywords IS NULL
47
+ SQL
48
+ end
49
+
50
+ migrated_count = connection.update(sql)
51
+
52
+ log "Migrated metadata for #{migrated_count} page versions."
53
+ end
54
+ end
55
+ end
56
+ end
@@ -12,11 +12,19 @@ module Alchemy
12
12
  Dir["#{File.dirname(__FILE__)}/upgrader/*.rb"].sort.each { require(_1) }
13
13
 
14
14
  VERSION_MODULE_MAP = {
15
- "8.0" => "Alchemy::Upgrader::EightZero"
15
+ "8.0" => "Alchemy::Upgrader::EightZero",
16
+ "8.1" => "Alchemy::Upgrader::EightOne"
16
17
  }
17
18
 
18
19
  source_root Alchemy::Engine.root.join("lib/generators/alchemy/install")
19
20
 
21
+ # Returns a memoized upgrader instance for the given version.
22
+ # This ensures todos are accumulated across rake tasks.
23
+ def self.[](version)
24
+ @instances ||= {}
25
+ @instances[version.to_s] ||= new(version)
26
+ end
27
+
20
28
  def initialize(version)
21
29
  super()
22
30
  self.class.include VERSION_MODULE_MAP[version.to_s].constantize
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "8.0.7"
4
+ VERSION = "8.1.1"
5
5
 
6
6
  def self.version
7
7
  VERSION
data/lib/alchemy.rb CHANGED
@@ -21,10 +21,7 @@ module Alchemy
21
21
  def config
22
22
  @_config ||= Alchemy::Configurations::Main.new
23
23
  end
24
-
25
- def configure(&blk)
26
- yield config
27
- end
24
+ delegate :configure, to: :config
28
25
 
29
26
  enable_searchable_deprecation_msg = "Use `Alchemy.config.show_page_searchable_checkbox` instead."
30
27
  def enable_searchable = config.show_page_searchable_checkbox
data/lib/alchemy_cms.rb CHANGED
@@ -42,7 +42,6 @@ require_relative "alchemy/name_conversions"
42
42
  require_relative "alchemy/on_page_layout"
43
43
  require_relative "alchemy/on_page_layout/callbacks_runner"
44
44
  require_relative "alchemy/paths"
45
- require_relative "alchemy/permissions"
46
45
  require_relative "alchemy/tinymce"
47
46
  require_relative "alchemy/taggable"
48
47
  require_relative "alchemy/version"
@@ -1,4 +1,4 @@
1
- <%%- cache(<%= @element_name %>) do -%>
1
+ <%% cache(<%= @element_name %>) do -%>
2
2
  <%%= element_view_for(<%= @element_name %>) do |el| -%>
3
3
  <%- @ingredients.each do |ingredient| -%>
4
4
  <%- if @ingredients.length > 1 -%>
@@ -12,5 +12,5 @@
12
12
  <%- if @element['nestable_elements'].present? -%>
13
13
  <%%= render <%= @element_name %>.nested_elements.published %>
14
14
  <%- end -%>
15
- <%%- end -%>
16
- <%%- end -%>
15
+ <%% end -%>
16
+ <%% end -%>
@@ -11,20 +11,18 @@ module Alchemy
11
11
 
12
12
  def init
13
13
  @class_name = class_name.classify
14
- @ingredients_view_path = "app/views/alchemy/ingredients"
15
- end
16
-
17
- def create_view_component
18
- template "view_component.rb.tt", "app/components/alchemy/ingredients/#{file_name}_view.rb"
19
14
  end
20
15
 
21
16
  def create_model
22
17
  template "model.rb.tt", "app/models/alchemy/ingredients/#{file_name}.rb"
23
18
  end
24
19
 
25
- def copy_templates
26
- @ingredient_editor_local = "#{file_name}_editor"
27
- template "editor.html.erb", "#{@ingredients_view_path}/_#{file_name}_editor.html.erb"
20
+ def create_view_component
21
+ template "view_component.rb.tt", "app/components/alchemy/ingredients/#{file_name}_view.rb"
22
+ end
23
+
24
+ def create_editor_component
25
+ template "editor_component.rb.tt", "app/components/alchemy/ingredients/#{file_name}_editor.rb"
28
26
  end
29
27
 
30
28
  def show_todo
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Ingredients
5
+ class <%= @class_name %>Editor < BaseEditor
6
+ # Override the input_field method to customize the editor input.
7
+ # The base implementation renders a text field.
8
+ #
9
+ # def input_field
10
+ # tag.div(class: "input-field") do
11
+ # text_field_tag(form_field_name,
12
+ # value,
13
+ # id: form_field_id,
14
+ # minlength: length_validation&.fetch(:minimum, nil),
15
+ # maxlength: length_validation&.fetch(:maximum, nil),
16
+ # required: presence_validation?,
17
+ # pattern: format_validation)
18
+ # end
19
+ # end
20
+ end
21
+ end
22
+ end
@@ -1 +1 @@
1
- <%%= render_elements %>
1
+ <%%= render_elements %>
@@ -1 +1 @@
1
- <%%= yield %>
1
+ <%%= yield %>
@@ -3,16 +3,15 @@
3
3
  require "alchemy/upgrader"
4
4
  require "alchemy/version"
5
5
 
6
- Upgrader = Alchemy::Upgrader.new("8.0")
7
-
8
6
  namespace :alchemy do
9
7
  desc "Upgrades your app to AlchemyCMS v#{Alchemy::VERSION}."
10
8
  task upgrade: [
11
9
  "alchemy:upgrade:prepare",
12
- "alchemy:upgrade:8.0:run"
10
+ "alchemy:upgrade:8.0:run",
11
+ "alchemy:upgrade:8.1:run"
13
12
  ] do
14
- Upgrader.run_migrations
15
- Upgrader.display_todos
13
+ Alchemy::Upgrader["8.1"].run_migrations
14
+ Alchemy::Upgrader["8.1"].display_todos
16
15
  end
17
16
 
18
17
  namespace :upgrade do
@@ -29,7 +28,7 @@ namespace :alchemy do
29
28
 
30
29
  desc "Alchemy Upgrader: Update configuration file."
31
30
  task config: [:environment] do
32
- Upgrader.update_config
31
+ Alchemy::Upgrader["8.0"].update_config
33
32
  end
34
33
 
35
34
  namespace "8.0" do
@@ -38,7 +37,22 @@ namespace :alchemy do
38
37
  ]
39
38
 
40
39
  task :mention_alchemy_config_initializer do
41
- Upgrader.mention_alchemy_config_initializer
40
+ Alchemy::Upgrader["8.0"].mention_alchemy_config_initializer
41
+ end
42
+ end
43
+
44
+ namespace "8.1" do
45
+ task "run" => [
46
+ "alchemy:upgrade:8.1:migrate_page_metadata"
47
+ ]
48
+
49
+ desc "Migrate page metadata to page versions"
50
+ task migrate_page_metadata: [
51
+ "alchemy:install:migrations",
52
+ "environment"
53
+ ] do
54
+ Alchemy::Upgrader["8.1"].run_migrations
55
+ Alchemy::Upgrader["8.1"].migrate_page_metadata
42
56
  end
43
57
  end
44
58
  end