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
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Admin
5
+ class EssenceVideosController < Alchemy::Admin::BaseController
6
+ authorize_resource class: Alchemy::EssenceVideo
7
+ before_action :load_essence
8
+
9
+ def update
10
+ @essence_video.update(essence_video_params)
11
+ end
12
+
13
+ private
14
+
15
+ def load_essence
16
+ @essence_video = EssenceVideo.find(params[:id])
17
+ end
18
+
19
+ def essence_video_params
20
+ params.require(:essence_video).permit(
21
+ :width,
22
+ :height,
23
+ :autoplay,
24
+ :controls,
25
+ :loop,
26
+ :muted,
27
+ :preload,
28
+ :attachment_id
29
+ )
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module Admin
5
+ class IngredientsController < Alchemy::Admin::BaseController
6
+ load_and_authorize_resource class: Alchemy::Ingredient
7
+
8
+ include CropAction
9
+
10
+ helper "Alchemy::Admin::Ingredients"
11
+
12
+ def edit
13
+ end
14
+
15
+ def update
16
+ @ingredient.update(ingredient_params)
17
+ end
18
+
19
+ private
20
+
21
+ def ingredient_params
22
+ params.require(:ingredient).permit(@ingredient.class.stored_attributes[:data])
23
+ end
24
+
25
+ def load_croppable_resource
26
+ @croppable_resource = @ingredient
27
+ end
28
+ end
29
+ end
30
+ end
@@ -16,7 +16,6 @@ module Alchemy
16
16
 
17
17
  def edit
18
18
  @page = Page.find(params[:id])
19
- @page_layouts = PageLayout.layouts_with_own_for_select(@page.page_layout, @current_language.id, true)
20
19
  end
21
20
  end
22
21
  end
@@ -33,6 +33,8 @@ module Alchemy
33
33
 
34
34
  before_action :set_view, only: [:index]
35
35
 
36
+ before_action :set_page_version, only: [:show, :edit]
37
+
36
38
  def index
37
39
  @query = @current_language.pages.contentpages.ransack(search_filter_params[:q])
38
40
 
@@ -45,11 +47,7 @@ module Alchemy
45
47
  end
46
48
 
47
49
  if search_filter_params[:filter].present?
48
- items = items.public_send(sanitized_filter_params)
49
- end
50
-
51
- if search_filter_params[:page_layout].present?
52
- items = items.where(page_layout: search_filter_params[:page_layout])
50
+ items = apply_filters(items)
53
51
  end
54
52
 
55
53
  items = items.page(params[:page] || 1).per(items_per_page)
@@ -118,7 +116,6 @@ module Alchemy
118
116
 
119
117
  # Set page configuration like page names, meta tags and states.
120
118
  def configure
121
- @page_layouts = PageLayout.layouts_with_own_for_select(@page.page_layout, @current_language.id, @page.layoutpage?)
122
119
  end
123
120
 
124
121
  # Updates page
@@ -191,24 +188,12 @@ module Alchemy
191
188
  end
192
189
  end
193
190
 
194
- def visit
195
- @page.unlock!
196
- redirect_to show_page_url(
197
- urlname: @page.urlname,
198
- locale: prefix_locale? ? @page.language_code : nil,
199
- host: @page.site.host == "*" ? request.host : @page.site.host,
200
- )
201
- end
202
-
203
191
  # Sets the page public and updates the published_at attribute that is used as cache_key
204
192
  #
205
193
  def publish
206
194
  # fetching page via before filter
207
195
  @page.publish!
208
196
 
209
- # Send publish notification to all registered publish targets
210
- Alchemy.publish_targets.each { |p| p.perform_later(@page) }
211
-
212
197
  flash[:notice] = Alchemy.t(:page_published, name: @page.name)
213
198
  redirect_back(fallback_location: admin_pages_path)
214
199
  end
@@ -255,10 +240,6 @@ module Alchemy
255
240
  @_resource_handler ||= Alchemy::Resource.new(controller_path, alchemy_module, Alchemy::Page)
256
241
  end
257
242
 
258
- def common_search_filter_includes
259
- super.push(:page_layout, :view)
260
- end
261
-
262
243
  def set_view
263
244
  @view = params[:view] || session[:alchemy_pages_view] || "tree"
264
245
  session[:alchemy_pages_view] = @view
@@ -403,6 +384,10 @@ module Alchemy
403
384
  @page_root = @current_language.root_page
404
385
  end
405
386
 
387
+ def set_page_version
388
+ @page_version = @page.draft_version
389
+ end
390
+
406
391
  def serialized_page_tree
407
392
  PageTreeSerializer.new(@page, ability: current_ability,
408
393
  user: current_alchemy_user,
@@ -9,20 +9,19 @@ module Alchemy
9
9
  helper "alchemy/admin/tags"
10
10
 
11
11
  before_action :load_resource,
12
- only: [:show, :edit, :update, :destroy, :info]
12
+ only: [:show, :edit, :update, :url, :destroy, :info]
13
13
 
14
14
  before_action :set_size, only: [:index, :show, :edit_multiple]
15
15
 
16
16
  authorize_resource class: Alchemy::Picture
17
17
 
18
+ before_action(only: :assign) do
19
+ @picture = Picture.find(params[:id])
20
+ end
21
+
18
22
  def index
19
23
  @query = Picture.ransack(search_filter_params[:q])
20
- @pictures = Picture.search_by(
21
- search_filter_params,
22
- @query,
23
- items_per_page,
24
- )
25
- @pictures = @pictures.includes(:thumbs)
24
+ @pictures = filtered_pictures.includes(:thumbs)
26
25
 
27
26
  if in_overlay?
28
27
  archive_overlay
@@ -30,12 +29,25 @@ module Alchemy
30
29
  end
31
30
 
32
31
  def show
33
- @previous = @picture.previous(params)
34
- @next = @picture.next(params)
35
- @assignments = @picture.essence_pictures.joins(content: {element: :page})
32
+ @query = Picture.ransack(params[:q])
33
+ @previous = filtered_pictures.where("name < ?", @picture.name).last
34
+ @next = filtered_pictures.where("name > ?", @picture.name).first
35
+ @assignments = @picture.essence_pictures.joins(content: { element: :page })
36
+
36
37
  render action: "show"
37
38
  end
38
39
 
40
+ def url
41
+ options = picture_url_params.to_h.symbolize_keys.transform_values! do |value|
42
+ value.in?(%w[true false]) ? value == "true" : value
43
+ end
44
+ render json: {
45
+ url: @picture.url(options),
46
+ alt: @picture.name,
47
+ title: Alchemy.t(:image_name, name: @picture.name),
48
+ }
49
+ end
50
+
39
51
  def create
40
52
  @picture = Picture.new(picture_params)
41
53
  @picture.name = @picture.humanized_name
@@ -115,6 +127,22 @@ module Alchemy
115
127
  redirect_to_index
116
128
  end
117
129
 
130
+ def filtered_pictures
131
+ pictures = @query.result
132
+
133
+ if params[:tagged_with].present?
134
+ pictures = pictures.tagged_with(params[:tagged_with])
135
+ end
136
+
137
+ if search_filter_params[:filter].present?
138
+ pictures = apply_filters(pictures)
139
+ end
140
+
141
+ pictures = pictures.page(params[:page] || 1).per(items_per_page)
142
+
143
+ pictures.order(:name)
144
+ end
145
+
118
146
  def items_per_page
119
147
  if in_overlay?
120
148
  case @size
@@ -125,8 +153,8 @@ module Alchemy
125
153
  end
126
154
  else
127
155
  cookies[:alchemy_pictures_per_page] = params[:per_page] ||
128
- cookies[:alchemy_pictures_per_page] ||
129
- pictures_per_page_for_size
156
+ cookies[:alchemy_pictures_per_page] ||
157
+ pictures_per_page_for_size
130
158
  end
131
159
  end
132
160
 
@@ -158,17 +186,28 @@ module Alchemy
158
186
  def search_filter_params
159
187
  @_search_filter_params ||= params.except(*COMMON_SEARCH_FILTER_EXCLUDES + [:picture_ids]).permit(
160
188
  *common_search_filter_includes + [
161
- :size,
162
- :element_id,
163
- :swap,
164
- :content_id,
165
- ],
189
+ :size,
190
+ :form_field_id,
191
+ ],
166
192
  )
167
193
  end
168
194
 
169
195
  def picture_params
170
196
  params.require(:picture).permit(:image_file, :upload_hash, :name, :tag_list)
171
197
  end
198
+
199
+ def picture_url_params
200
+ params.permit(
201
+ :crop_from,
202
+ :crop_size,
203
+ :crop,
204
+ :flatten,
205
+ :format,
206
+ :quality,
207
+ :size,
208
+ :upsample
209
+ )
210
+ end
172
211
  end
173
212
  end
174
213
  end
@@ -3,6 +3,7 @@
3
3
  require "csv"
4
4
  require "alchemy/resource"
5
5
  require "alchemy/resources_helper"
6
+ require "alchemy/resource_filter"
6
7
 
7
8
  module Alchemy
8
9
  module Admin
@@ -13,7 +14,8 @@ module Alchemy
13
14
 
14
15
  helper Alchemy::ResourcesHelper, TagsHelper
15
16
  helper_method :resource_handler, :search_filter_params,
16
- :items_per_page, :items_per_page_options
17
+ :items_per_page, :items_per_page_options, :resource_has_filters,
18
+ :resource_filters_for_select
17
19
 
18
20
  before_action :load_resource,
19
21
  only: [:show, :edit, :update, :destroy]
@@ -34,7 +36,7 @@ module Alchemy
34
36
  end
35
37
 
36
38
  if search_filter_params[:filter].present?
37
- items = items.public_send(sanitized_filter_params)
39
+ items = apply_filters(items)
38
40
  end
39
41
 
40
42
  respond_to do |format|
@@ -90,8 +92,79 @@ module Alchemy
90
92
  @_resource_handler ||= Alchemy::Resource.new(controller_path, alchemy_module)
91
93
  end
92
94
 
95
+ def resource_has_filters
96
+ resource_model.respond_to?(:alchemy_resource_filters)
97
+ end
98
+
99
+ def resource_has_deprecated_filters
100
+ resource_model.alchemy_resource_filters.any? { |f| !f.is_a?(Hash) }
101
+ end
102
+
103
+ def resource_filters
104
+ return unless resource_has_filters
105
+
106
+ @_resource_filters ||= deprecated_resource_filters || resource_model.alchemy_resource_filters
107
+ end
108
+
109
+ def resource_filters_for_select
110
+ resource_filters.map do |filter|
111
+ ResourceFilter.new(filter, resource_handler.resource_name)
112
+ end
113
+ end
114
+
93
115
  protected
94
116
 
117
+ def deprecated_resource_filters
118
+ if resource_has_deprecated_filters
119
+ Alchemy::Deprecation.warn(
120
+ "#{resource_model}.alchemy_resource_filters is using a legacy data structure. " \
121
+ "Please use an Array of Hashes instead. i.e. [{ name: 'foo', values: ['bar', 'baz'] }, ...] " \
122
+ "where values are scopes. With Alchemy 6.1 only the new structure will be supported."
123
+ )
124
+
125
+ @_resource_filters ||= [
126
+ {
127
+ name: :misc,
128
+ values: resource_model.alchemy_resource_filters,
129
+ },
130
+ ]
131
+ end
132
+ end
133
+
134
+ def apply_filters(items)
135
+ sanitize_filter_params!
136
+
137
+ search_filter_params[:filter].each do |filter|
138
+ if argument_scope_filter?(filter)
139
+ items = items.public_send(filter[0], filter[1])
140
+ elsif simple_scope_filter?(filter)
141
+ items = items.public_send(filter[1])
142
+ else
143
+ raise "Can't apply filter #{filter[0]}. Either the name or the values must be defined as class methods / scopes on the model."
144
+ end
145
+ end
146
+
147
+ items
148
+ end
149
+
150
+ def simple_scope_filter?(filter)
151
+ resource_model.respond_to?(filter[1])
152
+ end
153
+
154
+ def argument_scope_filter?(filter)
155
+ resource_model.respond_to?(filter[0])
156
+ end
157
+
158
+ def sanitize_filter_params!
159
+ search_filter_params[:filter].reject! do |_, v|
160
+ eligible_resource_filter_values.exclude?(v)
161
+ end
162
+ end
163
+
164
+ def eligible_resource_filter_values
165
+ resource_filters.map(&:values).flatten
166
+ end
167
+
95
168
  # Returns a translated +flash[:notice]+.
96
169
  # The key should look like "Modelname successfully created|updated|destroyed."
97
170
  def flash_notice_for_resource_action(action = params[:action])
@@ -136,27 +209,28 @@ module Alchemy
136
209
  params.require(resource_handler.namespaced_resource_name).permit!
137
210
  end
138
211
 
139
- def sanitized_filter_params
140
- resource_model.alchemy_resource_filters.detect do |filter|
141
- filter == search_filter_params[:filter]
142
- end || :all
143
- end
144
-
145
212
  def search_filter_params
146
213
  @_search_filter_params ||= params.except(*COMMON_SEARCH_FILTER_EXCLUDES).permit(*common_search_filter_includes).to_h
147
214
  end
148
215
 
149
216
  def common_search_filter_includes
150
- [
217
+ search_filters = [
151
218
  { q: [
152
219
  resource_handler.search_field_name,
153
220
  :s,
154
221
  ] },
155
222
  :tagged_with,
156
- :filter,
157
223
  :page,
158
224
  :per_page,
159
225
  ]
226
+
227
+ if resource_has_filters
228
+ search_filters << {
229
+ filter: resource_filters.map { |f| f[:name] },
230
+ }
231
+ end
232
+
233
+ search_filters
160
234
  end
161
235
 
162
236
  def items_per_page
@@ -9,18 +9,25 @@ module Alchemy
9
9
  # If you want to only load a specific type of element pass ?named=an_element_name
10
10
  #
11
11
  def index
12
- @elements = Element.not_nested
13
12
  # Fix for cancancan not able to merge multiple AR scopes for logged in users
14
13
  if cannot? :manage, Alchemy::Element
15
- @elements = @elements.accessible_by(current_ability, :index)
14
+ @elements = Alchemy::Element.accessible_by(current_ability, :index)
15
+ else
16
+ @elements = Alchemy::Element.all
16
17
  end
18
+
19
+ @elements = @elements.not_nested.joins(:page_version).merge(PageVersion.published)
20
+
17
21
  if params[:page_id].present?
18
- @elements = @elements.where(page_id: params[:page_id])
22
+ @elements = @elements.includes(:page).where(alchemy_pages: { id: params[:page_id] })
23
+ else
24
+ @elements = @elements.includes(*element_includes)
19
25
  end
26
+
20
27
  if params[:named].present?
21
28
  @elements = @elements.named(params[:named])
22
29
  end
23
- @elements = @elements.includes(*element_includes)
30
+ @elements = @elements.order(:position)
24
31
 
25
32
  render json: @elements, adapter: :json, root: "elements"
26
33
  end
@@ -43,6 +50,7 @@ module Alchemy
43
50
  contents: {
44
51
  essence: :ingredient_association,
45
52
  },
53
+ ingredients: :related_object,
46
54
  },
47
55
  :tags,
48
56
  ],
@@ -51,6 +59,7 @@ module Alchemy
51
59
  contents: {
52
60
  essence: :ingredient_association,
53
61
  },
62
+ ingredients: :related_object,
54
63
  },
55
64
  :tags,
56
65
  ]