alchemy_cms 5.2.0 → 6.0.0.b3

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 (289) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -14
  3. data/.gitignore +0 -1
  4. data/.hound.yml +1 -1
  5. data/.rubocop.yml +46 -4
  6. data/CHANGELOG.md +114 -5
  7. data/Gemfile +8 -1
  8. data/README.md +5 -2
  9. data/alchemy_cms.gemspec +78 -65
  10. data/app/assets/javascripts/alchemy/admin.js +0 -2
  11. data/app/assets/javascripts/alchemy/alchemy.base.js.coffee +0 -27
  12. data/app/assets/javascripts/alchemy/alchemy.confirm_dialog.js.coffee +2 -1
  13. data/app/assets/javascripts/alchemy/alchemy.dialog.js.coffee +1 -1
  14. data/app/assets/javascripts/alchemy/alchemy.dragndrop.js.coffee +0 -25
  15. data/app/assets/javascripts/alchemy/alchemy.element_editors.js.coffee +1 -1
  16. data/app/assets/javascripts/alchemy/alchemy.elements_window.js.coffee +2 -0
  17. data/app/assets/javascripts/alchemy/alchemy.fixed_elements.js +1 -1
  18. data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +3 -1
  19. data/app/assets/javascripts/alchemy/alchemy.image_overlay.coffee +1 -1
  20. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +40 -27
  21. data/app/assets/javascripts/alchemy/templates/node_folder.hbs +1 -1
  22. data/app/assets/stylesheets/alchemy/_extends.scss +15 -2
  23. data/app/assets/stylesheets/alchemy/admin.scss +1 -1
  24. data/app/assets/stylesheets/alchemy/archive.scss +20 -5
  25. data/app/assets/stylesheets/alchemy/buttons.scss +0 -4
  26. data/app/assets/stylesheets/alchemy/elements.scss +73 -61
  27. data/app/assets/stylesheets/alchemy/images.scss +8 -0
  28. data/app/assets/stylesheets/alchemy/node-select.scss +4 -3
  29. data/app/assets/stylesheets/alchemy/page-select.scss +1 -0
  30. data/app/controllers/alchemy/admin/attachments_controller.rb +8 -4
  31. data/app/controllers/alchemy/admin/base_controller.rb +5 -7
  32. data/app/controllers/alchemy/admin/elements_controller.rb +59 -34
  33. data/app/controllers/alchemy/admin/essence_audios_controller.rb +30 -0
  34. data/app/controllers/alchemy/admin/essence_files_controller.rb +0 -14
  35. data/app/controllers/alchemy/admin/essence_pictures_controller.rb +8 -79
  36. data/app/controllers/alchemy/admin/essence_videos_controller.rb +33 -0
  37. data/app/controllers/alchemy/admin/ingredients_controller.rb +30 -0
  38. data/app/controllers/alchemy/admin/layoutpages_controller.rb +0 -1
  39. data/app/controllers/alchemy/admin/pages_controller.rb +7 -22
  40. data/app/controllers/alchemy/admin/pictures_controller.rb +56 -17
  41. data/app/controllers/alchemy/admin/resources_controller.rb +84 -10
  42. data/app/controllers/alchemy/api/elements_controller.rb +13 -4
  43. data/app/controllers/alchemy/api/pages_controller.rb +4 -3
  44. data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +13 -3
  45. data/app/controllers/concerns/alchemy/admin/crop_action.rb +26 -0
  46. data/app/decorators/alchemy/element_editor.rb +26 -1
  47. data/app/decorators/alchemy/ingredient_editor.rb +158 -0
  48. data/app/helpers/alchemy/admin/elements_helper.rb +1 -0
  49. data/app/helpers/alchemy/admin/essences_helper.rb +1 -1
  50. data/app/helpers/alchemy/admin/ingredients_helper.rb +42 -0
  51. data/app/helpers/alchemy/elements_block_helper.rb +23 -6
  52. data/app/helpers/alchemy/elements_helper.rb +12 -5
  53. data/app/helpers/alchemy/pages_helper.rb +3 -11
  54. data/app/jobs/alchemy/base_job.rb +11 -0
  55. data/app/jobs/alchemy/publish_page_job.rb +11 -0
  56. data/app/models/alchemy/attachment.rb +24 -7
  57. data/app/models/alchemy/content.rb +1 -6
  58. data/app/models/alchemy/content/factory.rb +23 -27
  59. data/app/models/alchemy/element.rb +39 -72
  60. data/app/models/alchemy/element/definitions.rb +29 -27
  61. data/app/models/alchemy/element/element_contents.rb +131 -122
  62. data/app/models/alchemy/element/element_essences.rb +111 -98
  63. data/app/models/alchemy/element/element_ingredients.rb +184 -0
  64. data/app/models/alchemy/element/presenters.rb +104 -85
  65. data/app/models/alchemy/elements_repository.rb +126 -0
  66. data/app/models/alchemy/essence_audio.rb +12 -0
  67. data/app/models/alchemy/essence_headline.rb +40 -0
  68. data/app/models/alchemy/essence_picture.rb +4 -116
  69. data/app/models/alchemy/essence_richtext.rb +12 -0
  70. data/app/models/alchemy/essence_video.rb +12 -0
  71. data/app/models/alchemy/image_cropper_settings.rb +87 -0
  72. data/app/models/alchemy/ingredient.rb +183 -0
  73. data/app/models/alchemy/ingredient_validator.rb +97 -0
  74. data/app/models/alchemy/ingredients/audio.rb +29 -0
  75. data/app/models/alchemy/ingredients/boolean.rb +21 -0
  76. data/app/models/alchemy/ingredients/datetime.rb +20 -0
  77. data/app/models/alchemy/ingredients/file.rb +30 -0
  78. data/app/models/alchemy/ingredients/headline.rb +42 -0
  79. data/app/models/alchemy/ingredients/html.rb +19 -0
  80. data/app/models/alchemy/ingredients/link.rb +16 -0
  81. data/app/models/alchemy/ingredients/node.rb +23 -0
  82. data/app/models/alchemy/ingredients/page.rb +23 -0
  83. data/app/models/alchemy/ingredients/picture.rb +41 -0
  84. data/app/models/alchemy/ingredients/richtext.rb +57 -0
  85. data/app/models/alchemy/ingredients/select.rb +10 -0
  86. data/app/models/alchemy/ingredients/text.rb +17 -0
  87. data/app/models/alchemy/ingredients/video.rb +33 -0
  88. data/app/models/alchemy/language.rb +0 -11
  89. data/app/models/alchemy/page.rb +76 -33
  90. data/app/models/alchemy/page/fixed_attributes.rb +53 -51
  91. data/app/models/alchemy/page/page_elements.rb +186 -205
  92. data/app/models/alchemy/page/page_naming.rb +66 -64
  93. data/app/models/alchemy/page/page_natures.rb +139 -142
  94. data/app/models/alchemy/page/page_scopes.rb +117 -102
  95. data/app/models/alchemy/page/publisher.rb +50 -0
  96. data/app/models/alchemy/page/url_path.rb +1 -1
  97. data/app/models/alchemy/page_version.rb +58 -0
  98. data/app/models/alchemy/picture.rb +18 -40
  99. data/app/models/alchemy/picture/calculations.rb +2 -8
  100. data/app/models/alchemy/picture/preprocessor.rb +2 -0
  101. data/app/models/alchemy/picture/transformations.rb +24 -96
  102. data/app/models/concerns/alchemy/picture_thumbnails.rb +181 -0
  103. data/app/models/concerns/alchemy/touch_elements.rb +2 -2
  104. data/app/presenters/alchemy/picture_view.rb +88 -0
  105. data/app/serializers/alchemy/element_serializer.rb +5 -0
  106. data/app/serializers/alchemy/page_tree_serializer.rb +3 -2
  107. data/app/services/alchemy/delete_elements.rb +44 -0
  108. data/app/services/alchemy/duplicate_element.rb +56 -0
  109. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +2 -3
  110. data/app/views/alchemy/admin/attachments/_file_to_assign.html.erb +3 -3
  111. data/app/views/alchemy/admin/attachments/assign.js.erb +11 -0
  112. data/app/views/alchemy/admin/attachments/index.html.erb +2 -3
  113. data/app/views/alchemy/admin/crop.html.erb +36 -0
  114. data/app/views/alchemy/admin/elements/_element.html.erb +14 -10
  115. data/app/views/alchemy/admin/elements/{_element_footer.html.erb → _footer.html.erb} +0 -0
  116. data/app/views/alchemy/admin/elements/{_new_element_form.html.erb → _form.html.erb} +1 -1
  117. data/app/views/alchemy/admin/elements/{_element_header.html.erb → _header.html.erb} +1 -1
  118. data/app/views/alchemy/admin/elements/{_element_toolbar.html.erb → _toolbar.html.erb} +5 -6
  119. data/app/views/alchemy/admin/elements/create.js.erb +1 -1
  120. data/app/views/alchemy/admin/elements/{trash.js.erb → destroy.js.erb} +2 -6
  121. data/app/views/alchemy/admin/elements/fold.js.erb +2 -2
  122. data/app/views/alchemy/admin/elements/new.html.erb +3 -3
  123. data/app/views/alchemy/admin/elements/order.js.erb +0 -17
  124. data/app/views/alchemy/admin/elements/update.js.erb +3 -2
  125. data/app/views/alchemy/admin/essence_audios/edit.html.erb +7 -0
  126. data/app/views/alchemy/admin/essence_pictures/update.js.erb +0 -1
  127. data/app/views/alchemy/admin/essence_videos/edit.html.erb +11 -0
  128. data/app/views/alchemy/admin/ingredients/_audio_fields.html.erb +4 -0
  129. data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +18 -0
  130. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +25 -0
  131. data/app/views/alchemy/admin/ingredients/_video_fields.html.erb +8 -0
  132. data/app/views/alchemy/admin/ingredients/edit.html.erb +4 -0
  133. data/app/views/alchemy/admin/layoutpages/edit.html.erb +0 -5
  134. data/app/views/alchemy/admin/nodes/_node.html.erb +2 -2
  135. data/app/views/alchemy/admin/pages/_anchor_link.html.erb +1 -1
  136. data/app/views/alchemy/admin/pages/_external_link.html.erb +1 -1
  137. data/app/views/alchemy/admin/pages/_file_link.html.erb +1 -1
  138. data/app/views/alchemy/admin/pages/_form.html.erb +0 -6
  139. data/app/views/alchemy/admin/pages/_internal_link.html.erb +1 -1
  140. data/app/views/alchemy/admin/pages/_tinymce_custom_config.html.erb +5 -2
  141. data/app/views/alchemy/admin/pages/_toolbar.html.erb +1 -1
  142. data/app/views/alchemy/admin/pages/edit.html.erb +36 -24
  143. data/app/views/alchemy/admin/pages/index.html.erb +2 -9
  144. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +2 -4
  145. data/app/views/alchemy/admin/partials/_routes.html.erb +7 -11
  146. data/app/views/alchemy/admin/partials/_search_form.html.erb +9 -0
  147. data/app/views/alchemy/admin/pictures/_archive.html.erb +1 -1
  148. data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +1 -1
  149. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +5 -7
  150. data/app/views/alchemy/admin/pictures/_infos.html.erb +0 -1
  151. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +4 -4
  152. data/app/views/alchemy/admin/pictures/assign.js.erb +10 -0
  153. data/app/views/alchemy/admin/pictures/index.html.erb +8 -3
  154. data/app/views/alchemy/admin/resources/_filter.html.erb +12 -0
  155. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +14 -17
  156. data/app/views/alchemy/admin/resources/_form.html.erb +3 -0
  157. data/app/views/alchemy/admin/resources/_table_header.html.erb +15 -0
  158. data/app/views/alchemy/admin/resources/index.html.erb +3 -11
  159. data/app/views/alchemy/essences/_essence_audio_editor.html.erb +4 -0
  160. data/app/views/alchemy/essences/_essence_audio_view.html.erb +15 -0
  161. data/app/views/alchemy/essences/_essence_file_editor.html.erb +15 -6
  162. data/app/views/alchemy/essences/_essence_headline_editor.html.erb +36 -0
  163. data/app/views/alchemy/essences/_essence_headline_view.html.erb +10 -0
  164. data/app/views/alchemy/essences/_essence_link_editor.html.erb +8 -4
  165. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +27 -12
  166. data/app/views/alchemy/essences/_essence_picture_view.html.erb +3 -3
  167. data/app/views/alchemy/essences/_essence_text_editor.html.erb +12 -4
  168. data/app/views/alchemy/essences/_essence_video_editor.html.erb +4 -0
  169. data/app/views/alchemy/essences/_essence_video_view.html.erb +18 -0
  170. data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +21 -16
  171. data/app/views/alchemy/essences/shared/_linkable_essence_tools.html.erb +2 -2
  172. data/app/views/alchemy/ingredients/_audio_editor.html.erb +5 -0
  173. data/app/views/alchemy/ingredients/_audio_view.html.erb +14 -0
  174. data/app/views/alchemy/ingredients/_boolean_editor.html.erb +11 -0
  175. data/app/views/alchemy/ingredients/_boolean_view.html.erb +1 -0
  176. data/app/views/alchemy/ingredients/_datetime_editor.html.erb +17 -0
  177. data/app/views/alchemy/ingredients/_datetime_view.html.erb +9 -0
  178. data/app/views/alchemy/ingredients/_file_editor.html.erb +52 -0
  179. data/app/views/alchemy/ingredients/_file_view.html.erb +17 -0
  180. data/app/views/alchemy/ingredients/_headline_editor.html.erb +30 -0
  181. data/app/views/alchemy/ingredients/_headline_view.html.erb +9 -0
  182. data/app/views/alchemy/ingredients/_html_editor.html.erb +8 -0
  183. data/app/views/alchemy/ingredients/_html_view.html.erb +1 -0
  184. data/app/views/alchemy/ingredients/_link_editor.html.erb +24 -0
  185. data/app/views/alchemy/ingredients/_link_view.html.erb +9 -0
  186. data/app/views/alchemy/ingredients/_node_editor.html.erb +26 -0
  187. data/app/views/alchemy/ingredients/_node_view.html.erb +1 -0
  188. data/app/views/alchemy/ingredients/_page_editor.html.erb +25 -0
  189. data/app/views/alchemy/ingredients/_page_view.html.erb +4 -0
  190. data/app/views/alchemy/ingredients/_picture_editor.html.erb +60 -0
  191. data/app/views/alchemy/ingredients/_picture_view.html.erb +5 -0
  192. data/app/views/alchemy/ingredients/_richtext_editor.html.erb +12 -0
  193. data/app/views/alchemy/ingredients/_richtext_view.html.erb +3 -0
  194. data/app/views/alchemy/ingredients/_select_editor.html.erb +30 -0
  195. data/app/views/alchemy/ingredients/_select_view.html.erb +1 -0
  196. data/app/views/alchemy/ingredients/_text_editor.html.erb +20 -0
  197. data/app/views/alchemy/ingredients/_text_view.html.erb +16 -0
  198. data/app/views/alchemy/ingredients/_video_editor.html.erb +5 -0
  199. data/app/views/alchemy/ingredients/_video_view.html.erb +17 -0
  200. data/app/views/alchemy/ingredients/shared/_link_tools.html.erb +20 -0
  201. data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +57 -0
  202. data/config/brakeman.ignore +66 -159
  203. data/config/initializers/dragonfly.rb +10 -0
  204. data/config/locales/alchemy.en.yml +108 -64
  205. data/config/routes.rb +17 -22
  206. data/db/migrate/20201207131309_create_page_versions.rb +19 -0
  207. data/db/migrate/20201207135820_add_page_version_id_to_alchemy_elements.rb +76 -0
  208. data/db/migrate/20210205143548_rename_public_on_and_public_until_on_alchemy_pages.rb +10 -0
  209. data/db/migrate/20210326105046_add_sanitized_body_to_alchemy_essence_richtexts.rb +7 -0
  210. data/db/migrate/20210406093436_add_alchemy_essence_headlines.rb +12 -0
  211. data/db/migrate/20210506135919_create_essence_audios.rb +19 -0
  212. data/db/migrate/20210506140258_create_essence_videos.rb +23 -0
  213. data/db/migrate/20210508091432_create_alchemy_ingredients.rb +22 -0
  214. data/lib/alchemy/admin/preview_url.rb +2 -0
  215. data/lib/alchemy/deprecation.rb +1 -1
  216. data/lib/alchemy/dragonfly/processors/auto_orient.rb +18 -0
  217. data/lib/alchemy/dragonfly/processors/crop_resize.rb +35 -0
  218. data/lib/alchemy/elements_finder.rb +14 -60
  219. data/lib/alchemy/essence.rb +1 -2
  220. data/lib/alchemy/forms/builder.rb +21 -1
  221. data/lib/alchemy/hints.rb +8 -4
  222. data/lib/alchemy/page_layout.rb +0 -13
  223. data/lib/alchemy/permissions.rb +30 -29
  224. data/lib/alchemy/resource.rb +13 -3
  225. data/lib/alchemy/resource_filter.rb +40 -0
  226. data/lib/alchemy/resources_helper.rb +1 -16
  227. data/lib/alchemy/tasks/tidy.rb +29 -0
  228. data/lib/alchemy/test_support.rb +2 -11
  229. data/lib/alchemy/test_support/essence_shared_examples.rb +0 -1
  230. data/lib/alchemy/test_support/factories/element_factory.rb +8 -8
  231. data/lib/alchemy/test_support/factories/essence_audio_factory.rb +7 -0
  232. data/lib/alchemy/test_support/factories/essence_video_factory.rb +7 -0
  233. data/lib/alchemy/test_support/factories/ingredient_factory.rb +25 -0
  234. data/lib/alchemy/test_support/factories/page_factory.rb +20 -1
  235. data/lib/alchemy/test_support/factories/page_version_factory.rb +23 -0
  236. data/lib/alchemy/test_support/having_crop_action_examples.rb +170 -0
  237. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +646 -0
  238. data/lib/alchemy/test_support/shared_ingredient_editor_examples.rb +21 -0
  239. data/lib/alchemy/test_support/shared_ingredient_examples.rb +75 -0
  240. data/lib/alchemy/tinymce.rb +17 -0
  241. data/lib/alchemy/upgrader/six_point_zero.rb +21 -0
  242. data/lib/alchemy/upgrader/tasks/add_page_versions.rb +33 -0
  243. data/lib/alchemy/upgrader/tasks/ingredients_migrator.rb +62 -0
  244. data/lib/alchemy/version.rb +1 -1
  245. data/lib/alchemy_cms.rb +1 -0
  246. data/lib/generators/alchemy/elements/elements_generator.rb +1 -0
  247. data/lib/generators/alchemy/elements/templates/view.html.erb +9 -0
  248. data/lib/generators/alchemy/elements/templates/view.html.haml +9 -0
  249. data/lib/generators/alchemy/elements/templates/view.html.slim +9 -0
  250. data/lib/generators/alchemy/ingredient/ingredient_generator.rb +38 -0
  251. data/lib/generators/alchemy/ingredient/templates/editor.html.erb +14 -0
  252. data/lib/generators/alchemy/ingredient/templates/model.rb.tt +13 -0
  253. data/lib/generators/alchemy/ingredient/templates/view.html.erb +1 -0
  254. data/lib/generators/alchemy/install/templates/dragonfly.rb.tt +1 -1
  255. data/lib/generators/alchemy/menus/templates/node.html.erb +1 -1
  256. data/lib/generators/alchemy/menus/templates/node.html.haml +1 -1
  257. data/lib/generators/alchemy/menus/templates/node.html.slim +1 -1
  258. data/lib/generators/alchemy/menus/templates/wrapper.html.erb +1 -1
  259. data/lib/generators/alchemy/menus/templates/wrapper.html.haml +1 -1
  260. data/lib/generators/alchemy/menus/templates/wrapper.html.slim +1 -1
  261. data/lib/tasks/alchemy/thumbnails.rake +4 -2
  262. data/lib/tasks/alchemy/tidy.rake +12 -0
  263. data/lib/tasks/alchemy/upgrade.rake +26 -0
  264. data/package.json +3 -2
  265. data/package/admin.js +11 -1
  266. data/package/src/__tests__/i18n.spec.js +23 -0
  267. data/package/src/file_editors.js +28 -0
  268. data/package/src/i18n.js +1 -3
  269. data/package/src/image_cropper.js +103 -0
  270. data/package/src/image_loader.js +58 -0
  271. data/package/src/node_tree.js +5 -5
  272. data/package/src/picture_editors.js +169 -0
  273. data/package/src/utils/__tests__/ajax.spec.js +20 -12
  274. data/package/src/utils/ajax.js +8 -3
  275. data/vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js +3 -18
  276. data/vendor/assets/stylesheets/jquery.Jcrop.min.scss +2 -28
  277. metadata +292 -55
  278. data/app/assets/javascripts/alchemy/alchemy.image_cropper.js.coffee +0 -44
  279. data/app/assets/javascripts/alchemy/alchemy.trash_window.js.coffee +0 -30
  280. data/app/assets/stylesheets/alchemy/trash.scss +0 -8
  281. data/app/controllers/alchemy/admin/trash_controller.rb +0 -44
  282. data/app/views/alchemy/admin/attachments/_filter_bar.html.erb +0 -29
  283. data/app/views/alchemy/admin/essence_files/assign.js.erb +0 -3
  284. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +0 -4
  285. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +0 -48
  286. data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +0 -30
  287. data/app/views/alchemy/admin/trash/clear.js.erb +0 -4
  288. data/app/views/alchemy/admin/trash/index.html.erb +0 -31
  289. data/lib/alchemy/test_support/factories.rb +0 -16
@@ -1,85 +1,87 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- module Page::PageNaming
5
- extend ActiveSupport::Concern
6
- include NameConversions
7
- RESERVED_URLNAMES = %w(admin messages new)
4
+ class Page < BaseRecord
5
+ module PageNaming
6
+ extend ActiveSupport::Concern
7
+ include NameConversions
8
+ RESERVED_URLNAMES = %w(admin messages new)
8
9
 
9
- included do
10
- before_validation :set_urlname,
11
- if: :renamed?,
12
- unless: -> { name.blank? }
10
+ included do
11
+ before_validation :set_urlname,
12
+ if: :renamed?,
13
+ unless: -> { name.blank? }
13
14
 
14
- validates :name,
15
- presence: true
16
- validates :urlname,
17
- uniqueness: { scope: [:language_id, :layoutpage], if: -> { urlname.present? } },
18
- exclusion: { in: RESERVED_URLNAMES },
19
- length: { minimum: 3, if: -> { urlname.present? } }
15
+ validates :name,
16
+ presence: true
17
+ validates :urlname,
18
+ uniqueness: { scope: [:language_id, :layoutpage], if: -> { urlname.present? } },
19
+ exclusion: { in: RESERVED_URLNAMES },
20
+ length: { minimum: 3, if: -> { urlname.present? } }
20
21
 
21
- before_save :set_title,
22
- if: -> { title.blank? }
22
+ before_save :set_title,
23
+ if: -> { title.blank? }
23
24
 
24
- after_update :update_descendants_urlnames,
25
- if: :saved_change_to_urlname?
25
+ after_update :update_descendants_urlnames,
26
+ if: :saved_change_to_urlname?
26
27
 
27
- after_move :update_urlname!
28
- end
28
+ after_move :update_urlname!
29
+ end
29
30
 
30
- # Returns true if name or urlname has changed.
31
- def renamed?
32
- name_changed? || urlname_changed?
33
- end
31
+ # Returns true if name or urlname has changed.
32
+ def renamed?
33
+ name_changed? || urlname_changed?
34
+ end
34
35
 
35
- # Makes a slug of all ancestors urlnames including mine and delimit them be slash.
36
- # So the whole path is stored as urlname in the database.
37
- def update_urlname!
38
- new_urlname = nested_url_name
39
- if urlname != new_urlname
40
- legacy_urls.create(urlname: urlname)
41
- update_column(:urlname, new_urlname)
36
+ # Makes a slug of all ancestors urlnames including mine and delimit them be slash.
37
+ # So the whole path is stored as urlname in the database.
38
+ def update_urlname!
39
+ new_urlname = nested_url_name
40
+ if urlname != new_urlname
41
+ legacy_urls.create(urlname: urlname)
42
+ update_column(:urlname, new_urlname)
43
+ end
42
44
  end
43
- end
44
45
 
45
- # Returns always the last part of a urlname path
46
- def slug
47
- urlname.to_s.split("/").last
48
- end
46
+ # Returns always the last part of a urlname path
47
+ def slug
48
+ urlname.to_s.split("/").last
49
+ end
49
50
 
50
- private
51
+ private
51
52
 
52
- def update_descendants_urlnames
53
- reload
54
- descendants.each(&:update_urlname!)
55
- end
53
+ def update_descendants_urlnames
54
+ reload
55
+ descendants.each(&:update_urlname!)
56
+ end
56
57
 
57
- # Sets the urlname to a url friendly slug.
58
- # Either from name, or if present, from urlname.
59
- # The urlname contains the whole path including parent urlnames.
60
- def set_urlname
61
- self[:urlname] = nested_url_name
62
- end
58
+ # Sets the urlname to a url friendly slug.
59
+ # Either from name, or if present, from urlname.
60
+ # The urlname contains the whole path including parent urlnames.
61
+ def set_urlname
62
+ self[:urlname] = nested_url_name
63
+ end
63
64
 
64
- def set_title
65
- self[:title] = name
66
- end
65
+ def set_title
66
+ self[:title] = name
67
+ end
67
68
 
68
- # Converts the given name into an url friendly string.
69
- #
70
- # Names shorter than 3 will be filled up with dashes,
71
- # so it does not collidate with the language code.
72
- #
73
- def converted_url_name
74
- url_name = convert_to_urlname(slug.blank? ? name : slug)
75
- url_name.rjust(3, "-")
76
- end
69
+ # Converts the given name into an url friendly string.
70
+ #
71
+ # Names shorter than 3 will be filled up with dashes,
72
+ # so it does not collidate with the language code.
73
+ #
74
+ def converted_url_name
75
+ url_name = convert_to_urlname(slug.blank? ? name : slug)
76
+ url_name.rjust(3, "-")
77
+ end
77
78
 
78
- def nested_url_name
79
- if parent&.language_root?
80
- converted_url_name
81
- else
82
- [parent&.urlname, converted_url_name].compact.join("/")
79
+ def nested_url_name
80
+ if parent&.language_root?
81
+ converted_url_name
82
+ else
83
+ [parent&.urlname, converted_url_name].compact.join("/")
84
+ end
83
85
  end
84
86
  end
85
87
  end
@@ -1,171 +1,168 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- module Page::PageNatures
5
- extend ActiveSupport::Concern
6
-
7
- def public?
8
- current_time = Time.current
9
- already_public_for?(current_time) && still_public_for?(current_time)
10
- end
11
-
12
- def expiration_time
13
- public_until? ? public_until - Time.current : nil
14
- end
15
-
16
- def taggable?
17
- definition["taggable"] == true
18
- end
4
+ class Page < BaseRecord
5
+ module PageNatures
6
+ extend ActiveSupport::Concern
7
+
8
+ # Determines if this page has a public version and this version is public.
9
+ #
10
+ # @see PageVersion#public?
11
+ # @returns Boolean
12
+ def public?
13
+ language.public? && !!public_version&.public?
14
+ end
19
15
 
20
- deprecate :taggable?, deprecator: Alchemy::Deprecation
16
+ def expiration_time
17
+ public_until ? public_until - Time.current : nil
18
+ end
21
19
 
22
- def rootpage?
23
- !new_record? && parent_id.blank?
24
- end
20
+ def taggable?
21
+ definition["taggable"] == true
22
+ end
25
23
 
26
- def folded?(user_id)
27
- return unless Alchemy.user_class < ActiveRecord::Base
24
+ deprecate :taggable?, deprecator: Alchemy::Deprecation
28
25
 
29
- folded_pages.where(user_id: user_id, folded: true).any?
30
- end
26
+ def rootpage?
27
+ !new_record? && parent_id.blank?
28
+ end
31
29
 
32
- def contains_feed?
33
- definition["feed"]
34
- end
30
+ def folded?(user_id)
31
+ return unless Alchemy.user_class < ActiveRecord::Base
35
32
 
36
- # Returns an Array of Alchemy roles which are able to edit this template
37
- #
38
- # # config/alchemy/page_layouts.yml
39
- # - name: contact
40
- # editable_by:
41
- # - freelancer
42
- # - admin
43
- #
44
- # @returns Array
45
- #
46
- def has_limited_editors?
47
- definition["editable_by"].present?
48
- end
33
+ folded_pages.where(user_id: user_id, folded: true).any?
34
+ end
49
35
 
50
- def editor_roles
51
- return unless has_limited_editors?
36
+ def contains_feed?
37
+ definition["feed"]
38
+ end
52
39
 
53
- definition["editable_by"]
54
- end
40
+ # Returns an Array of Alchemy roles which are able to edit this template
41
+ #
42
+ # # config/alchemy/page_layouts.yml
43
+ # - name: contact
44
+ # editable_by:
45
+ # - freelancer
46
+ # - admin
47
+ #
48
+ # @returns Array
49
+ #
50
+ def has_limited_editors?
51
+ definition["editable_by"].present?
52
+ end
55
53
 
56
- # True if page locked_at timestamp and locked_by id are set
57
- def locked?
58
- locked_by? && locked_at?
59
- end
54
+ def editor_roles
55
+ return unless has_limited_editors?
60
56
 
61
- # Returns a Hash describing the status of the Page.
62
- #
63
- def status
64
- {
65
- public: public?,
66
- locked: locked?,
67
- restricted: restricted?,
68
- }
69
- end
57
+ definition["editable_by"]
58
+ end
70
59
 
71
- # Returns the translated status for given status type.
72
- #
73
- # @param [Symbol] status_type
74
- #
75
- def status_title(status_type)
76
- Alchemy.t(status[status_type].to_s, scope: "page_states.#{status_type}")
77
- end
60
+ # True if page locked_at timestamp and locked_by id are set
61
+ def locked?
62
+ locked_by? && locked_at?
63
+ end
78
64
 
79
- # Returns the self#page_layout definition from config/alchemy/page_layouts.yml file.
80
- def definition
81
- definition = PageLayout.get(page_layout)
82
- if definition.nil?
83
- log_warning "Page definition for `#{page_layout}` not found. Please check `page_layouts.yml` file."
84
- return {}
65
+ # Returns a Hash describing the status of the Page.
66
+ #
67
+ def status
68
+ {
69
+ public: public?,
70
+ locked: locked?,
71
+ restricted: restricted?,
72
+ }
85
73
  end
86
- definition
87
- end
88
74
 
89
- # Returns translated name of the pages page_layout value.
90
- # Page layout names are defined inside the config/alchemy/page_layouts.yml file.
91
- # Translate the name in your config/locales language yml file.
92
- def layout_display_name
93
- Alchemy.t(page_layout, scope: "page_layout_names")
94
- end
75
+ # Returns the translated status for given status type.
76
+ #
77
+ # @param [Symbol] status_type
78
+ #
79
+ def status_title(status_type)
80
+ Alchemy.t(status[status_type].to_s, scope: "page_states.#{status_type}")
81
+ end
95
82
 
96
- # Returns the name for the layout partial
97
- #
98
- def layout_partial_name
99
- page_layout.parameterize.underscore
100
- end
83
+ # Returns the self#page_layout definition from config/alchemy/page_layouts.yml file.
84
+ def definition
85
+ definition = PageLayout.get(page_layout)
86
+ if definition.nil?
87
+ log_warning "Page definition for `#{page_layout}` not found. Please check `page_layouts.yml` file."
88
+ return {}
89
+ end
90
+ definition
91
+ end
101
92
 
102
- # Returns the key that's taken for cache path.
103
- #
104
- # Uses the +published_at+ value that's updated when the user publishes the page.
105
- #
106
- # If the page is the current preview it uses the updated_at value as cache key.
107
- #
108
- def cache_key
109
- if Page.current_preview == self
110
- "alchemy/pages/#{id}-#{updated_at}"
111
- else
112
- "alchemy/pages/#{id}-#{published_at}"
93
+ # Returns translated name of the pages page_layout value.
94
+ # Page layout names are defined inside the config/alchemy/page_layouts.yml file.
95
+ # Translate the name in your config/locales language yml file.
96
+ def layout_display_name
97
+ Alchemy.t(page_layout, scope: "page_layout_names")
113
98
  end
114
- end
115
99
 
116
- # We use the published_at value for the cache_key.
117
- #
118
- # If no published_at value is set yet, i.e. because it was never published,
119
- # we return the updated_at value.
120
- #
121
- def published_at
122
- read_attribute(:published_at) || updated_at
123
- end
100
+ # Returns the name for the layout partial
101
+ #
102
+ def layout_partial_name
103
+ page_layout.parameterize.underscore
104
+ end
124
105
 
125
- # Returns true if the page cache control headers should be set.
126
- #
127
- # == Disable Alchemy's page caching globally
128
- #
129
- # # config/alchemy/config.yml
130
- # ...
131
- # cache_pages: false
132
- #
133
- # == Disable caching on page layout level
134
- #
135
- # # config/alchemy/page_layouts.yml
136
- # - name: contact
137
- # cache: false
138
- #
139
- # == Note:
140
- #
141
- # This only sets the cache control headers and skips rendering of the page body,
142
- # if the cache is fresh.
143
- # This does not disable the fragment caching in the views.
144
- # So if you don't want a page and it's elements to be cached,
145
- # then be sure to not use <% cache element %> in the views.
146
- #
147
- # @returns Boolean
148
- #
149
- def cache_page?
150
- return false unless caching_enabled?
151
-
152
- page_layout = PageLayout.get(self.page_layout)
153
- page_layout["cache"] != false && page_layout["searchresults"] != true
154
- end
106
+ # Returns the key that's taken for cache path.
107
+ #
108
+ # Uses the +published_at+ value that's updated when the user publishes the page.
109
+ #
110
+ # If the page is the current preview it uses the updated_at value as cache key.
111
+ #
112
+ def cache_key
113
+ if Page.current_preview == self
114
+ "alchemy/pages/#{id}-#{updated_at}"
115
+ else
116
+ "alchemy/pages/#{id}-#{published_at}"
117
+ end
118
+ end
155
119
 
156
- private
120
+ # We use the published_at value for the cache_key.
121
+ #
122
+ # If no published_at value is set yet, i.e. because it was never published,
123
+ # we return the updated_at value.
124
+ #
125
+ def published_at
126
+ read_attribute(:published_at) || updated_at
127
+ end
157
128
 
158
- def caching_enabled?
159
- Alchemy::Config.get(:cache_pages) &&
160
- Rails.application.config.action_controller.perform_caching
161
- end
129
+ # Returns true if the page cache control headers should be set.
130
+ #
131
+ # == Disable Alchemy's page caching globally
132
+ #
133
+ # # config/alchemy/config.yml
134
+ # ...
135
+ # cache_pages: false
136
+ #
137
+ # == Disable caching on page layout level
138
+ #
139
+ # # config/alchemy/page_layouts.yml
140
+ # - name: contact
141
+ # cache: false
142
+ #
143
+ # == Note:
144
+ #
145
+ # This only sets the cache control headers and skips rendering of the page body,
146
+ # if the cache is fresh.
147
+ # This does not disable the fragment caching in the views.
148
+ # So if you don't want a page and it's elements to be cached,
149
+ # then be sure to not use <% cache element %> in the views.
150
+ #
151
+ # @returns Boolean
152
+ #
153
+ def cache_page?
154
+ return false unless caching_enabled?
155
+
156
+ page_layout = PageLayout.get(self.page_layout)
157
+ page_layout["cache"] != false && page_layout["searchresults"] != true
158
+ end
162
159
 
163
- def already_public_for?(time)
164
- !public_on.nil? && public_on <= time
165
- end
160
+ private
166
161
 
167
- def still_public_for?(time)
168
- public_until.nil? || public_until >= time
162
+ def caching_enabled?
163
+ Alchemy::Config.get(:cache_pages) &&
164
+ Rails.application.config.action_controller.perform_caching
165
+ end
169
166
  end
170
167
  end
171
168
  end