alchemy_cms 5.2.0.rc1 → 6.0.0.b2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (286) 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 +105 -2
  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/admin.scss +1 -1
  23. data/app/assets/stylesheets/alchemy/archive.scss +18 -4
  24. data/app/assets/stylesheets/alchemy/buttons.scss +0 -4
  25. data/app/assets/stylesheets/alchemy/elements.scss +73 -61
  26. data/app/assets/stylesheets/alchemy/images.scss +8 -0
  27. data/app/assets/stylesheets/alchemy/node-select.scss +4 -3
  28. data/app/assets/stylesheets/alchemy/page-select.scss +1 -0
  29. data/app/controllers/alchemy/admin/attachments_controller.rb +8 -4
  30. data/app/controllers/alchemy/admin/base_controller.rb +5 -7
  31. data/app/controllers/alchemy/admin/elements_controller.rb +58 -34
  32. data/app/controllers/alchemy/admin/essence_audios_controller.rb +30 -0
  33. data/app/controllers/alchemy/admin/essence_files_controller.rb +0 -14
  34. data/app/controllers/alchemy/admin/essence_pictures_controller.rb +8 -79
  35. data/app/controllers/alchemy/admin/essence_videos_controller.rb +33 -0
  36. data/app/controllers/alchemy/admin/ingredients_controller.rb +30 -0
  37. data/app/controllers/alchemy/admin/layoutpages_controller.rb +0 -1
  38. data/app/controllers/alchemy/admin/pages_controller.rb +7 -22
  39. data/app/controllers/alchemy/admin/pictures_controller.rb +56 -17
  40. data/app/controllers/alchemy/admin/resources_controller.rb +84 -10
  41. data/app/controllers/alchemy/api/elements_controller.rb +13 -4
  42. data/app/controllers/alchemy/api/pages_controller.rb +4 -3
  43. data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +13 -3
  44. data/app/controllers/concerns/alchemy/admin/crop_action.rb +26 -0
  45. data/app/decorators/alchemy/element_editor.rb +48 -1
  46. data/app/decorators/alchemy/ingredient_editor.rb +154 -0
  47. data/app/helpers/alchemy/admin/elements_helper.rb +1 -0
  48. data/app/helpers/alchemy/admin/essences_helper.rb +1 -1
  49. data/app/helpers/alchemy/admin/ingredients_helper.rb +42 -0
  50. data/app/helpers/alchemy/elements_block_helper.rb +22 -7
  51. data/app/helpers/alchemy/elements_helper.rb +12 -5
  52. data/app/helpers/alchemy/pages_helper.rb +3 -9
  53. data/app/jobs/alchemy/base_job.rb +11 -0
  54. data/app/jobs/alchemy/publish_page_job.rb +11 -0
  55. data/app/models/alchemy/attachment.rb +24 -7
  56. data/app/models/alchemy/content.rb +1 -6
  57. data/app/models/alchemy/content/factory.rb +23 -27
  58. data/app/models/alchemy/element.rb +39 -72
  59. data/app/models/alchemy/element/definitions.rb +29 -27
  60. data/app/models/alchemy/element/element_contents.rb +131 -122
  61. data/app/models/alchemy/element/element_essences.rb +100 -98
  62. data/app/models/alchemy/element/element_ingredients.rb +176 -0
  63. data/app/models/alchemy/element/presenters.rb +104 -85
  64. data/app/models/alchemy/elements_repository.rb +126 -0
  65. data/app/models/alchemy/essence_audio.rb +12 -0
  66. data/app/models/alchemy/essence_headline.rb +40 -0
  67. data/app/models/alchemy/essence_picture.rb +4 -116
  68. data/app/models/alchemy/essence_richtext.rb +12 -0
  69. data/app/models/alchemy/essence_video.rb +12 -0
  70. data/app/models/alchemy/image_cropper_settings.rb +87 -0
  71. data/app/models/alchemy/ingredient.rb +224 -0
  72. data/app/models/alchemy/ingredient_validator.rb +97 -0
  73. data/app/models/alchemy/ingredients/audio.rb +29 -0
  74. data/app/models/alchemy/ingredients/boolean.rb +21 -0
  75. data/app/models/alchemy/ingredients/datetime.rb +20 -0
  76. data/app/models/alchemy/ingredients/file.rb +30 -0
  77. data/app/models/alchemy/ingredients/headline.rb +42 -0
  78. data/app/models/alchemy/ingredients/html.rb +19 -0
  79. data/app/models/alchemy/ingredients/link.rb +16 -0
  80. data/app/models/alchemy/ingredients/node.rb +23 -0
  81. data/app/models/alchemy/ingredients/page.rb +23 -0
  82. data/app/models/alchemy/ingredients/picture.rb +41 -0
  83. data/app/models/alchemy/ingredients/richtext.rb +57 -0
  84. data/app/models/alchemy/ingredients/select.rb +10 -0
  85. data/app/models/alchemy/ingredients/text.rb +17 -0
  86. data/app/models/alchemy/ingredients/video.rb +33 -0
  87. data/app/models/alchemy/language.rb +0 -11
  88. data/app/models/alchemy/page.rb +76 -33
  89. data/app/models/alchemy/page/fixed_attributes.rb +53 -51
  90. data/app/models/alchemy/page/page_elements.rb +186 -205
  91. data/app/models/alchemy/page/page_naming.rb +66 -64
  92. data/app/models/alchemy/page/page_natures.rb +139 -142
  93. data/app/models/alchemy/page/page_scopes.rb +117 -102
  94. data/app/models/alchemy/page/publisher.rb +50 -0
  95. data/app/models/alchemy/page/url_path.rb +1 -1
  96. data/app/models/alchemy/page_version.rb +58 -0
  97. data/app/models/alchemy/picture.rb +18 -40
  98. data/app/models/alchemy/picture/calculations.rb +2 -8
  99. data/app/models/alchemy/picture/preprocessor.rb +2 -0
  100. data/app/models/alchemy/picture/transformations.rb +24 -96
  101. data/app/models/concerns/alchemy/picture_thumbnails.rb +181 -0
  102. data/app/models/concerns/alchemy/touch_elements.rb +2 -2
  103. data/app/presenters/alchemy/picture_view.rb +88 -0
  104. data/app/serializers/alchemy/element_serializer.rb +5 -0
  105. data/app/serializers/alchemy/page_tree_serializer.rb +3 -2
  106. data/app/services/alchemy/delete_elements.rb +44 -0
  107. data/app/services/alchemy/duplicate_element.rb +56 -0
  108. data/app/views/alchemy/admin/attachments/_archive_overlay.html.erb +2 -3
  109. data/app/views/alchemy/admin/attachments/_file_to_assign.html.erb +3 -3
  110. data/app/views/alchemy/admin/attachments/assign.js.erb +11 -0
  111. data/app/views/alchemy/admin/attachments/index.html.erb +2 -3
  112. data/app/views/alchemy/admin/crop.html.erb +36 -0
  113. data/app/views/alchemy/admin/elements/_element.html.erb +14 -10
  114. data/app/views/alchemy/admin/elements/{_element_footer.html.erb → _footer.html.erb} +0 -0
  115. data/app/views/alchemy/admin/elements/{_new_element_form.html.erb → _form.html.erb} +1 -1
  116. data/app/views/alchemy/admin/elements/{_element_header.html.erb → _header.html.erb} +1 -1
  117. data/app/views/alchemy/admin/elements/{_element_toolbar.html.erb → _toolbar.html.erb} +5 -6
  118. data/app/views/alchemy/admin/elements/{trash.js.erb → destroy.js.erb} +1 -3
  119. data/app/views/alchemy/admin/elements/new.html.erb +3 -3
  120. data/app/views/alchemy/admin/elements/order.js.erb +0 -17
  121. data/app/views/alchemy/admin/elements/update.js.erb +3 -2
  122. data/app/views/alchemy/admin/essence_audios/edit.html.erb +7 -0
  123. data/app/views/alchemy/admin/essence_pictures/update.js.erb +0 -1
  124. data/app/views/alchemy/admin/essence_videos/edit.html.erb +11 -0
  125. data/app/views/alchemy/admin/ingredients/_audio_fields.html.erb +4 -0
  126. data/app/views/alchemy/admin/ingredients/_file_fields.html.erb +18 -0
  127. data/app/views/alchemy/admin/ingredients/_picture_fields.html.erb +25 -0
  128. data/app/views/alchemy/admin/ingredients/_video_fields.html.erb +8 -0
  129. data/app/views/alchemy/admin/ingredients/edit.html.erb +4 -0
  130. data/app/views/alchemy/admin/layoutpages/edit.html.erb +0 -5
  131. data/app/views/alchemy/admin/nodes/_node.html.erb +2 -2
  132. data/app/views/alchemy/admin/pages/_anchor_link.html.erb +1 -1
  133. data/app/views/alchemy/admin/pages/_external_link.html.erb +1 -1
  134. data/app/views/alchemy/admin/pages/_file_link.html.erb +1 -1
  135. data/app/views/alchemy/admin/pages/_form.html.erb +0 -6
  136. data/app/views/alchemy/admin/pages/_internal_link.html.erb +1 -1
  137. data/app/views/alchemy/admin/pages/_tinymce_custom_config.html.erb +5 -2
  138. data/app/views/alchemy/admin/pages/_toolbar.html.erb +1 -1
  139. data/app/views/alchemy/admin/pages/edit.html.erb +36 -24
  140. data/app/views/alchemy/admin/pages/index.html.erb +2 -9
  141. data/app/views/alchemy/admin/partials/_remote_search_form.html.erb +2 -4
  142. data/app/views/alchemy/admin/partials/_routes.html.erb +7 -11
  143. data/app/views/alchemy/admin/partials/_search_form.html.erb +9 -0
  144. data/app/views/alchemy/admin/pictures/_archive.html.erb +1 -1
  145. data/app/views/alchemy/admin/pictures/_archive_overlay.html.erb +1 -1
  146. data/app/views/alchemy/admin/pictures/_filter_and_size_bar.html.erb +5 -7
  147. data/app/views/alchemy/admin/pictures/_infos.html.erb +0 -1
  148. data/app/views/alchemy/admin/pictures/_picture_to_assign.html.erb +4 -4
  149. data/app/views/alchemy/admin/pictures/assign.js.erb +10 -0
  150. data/app/views/alchemy/admin/pictures/index.html.erb +8 -3
  151. data/app/views/alchemy/admin/resources/_filter.html.erb +12 -0
  152. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +14 -17
  153. data/app/views/alchemy/admin/resources/_form.html.erb +3 -0
  154. data/app/views/alchemy/admin/resources/_table_header.html.erb +15 -0
  155. data/app/views/alchemy/admin/resources/index.html.erb +3 -11
  156. data/app/views/alchemy/essences/_essence_audio_editor.html.erb +4 -0
  157. data/app/views/alchemy/essences/_essence_audio_view.html.erb +15 -0
  158. data/app/views/alchemy/essences/_essence_file_editor.html.erb +15 -6
  159. data/app/views/alchemy/essences/_essence_headline_editor.html.erb +36 -0
  160. data/app/views/alchemy/essences/_essence_headline_view.html.erb +10 -0
  161. data/app/views/alchemy/essences/_essence_link_editor.html.erb +8 -4
  162. data/app/views/alchemy/essences/_essence_picture_editor.html.erb +27 -12
  163. data/app/views/alchemy/essences/_essence_picture_view.html.erb +3 -3
  164. data/app/views/alchemy/essences/_essence_text_editor.html.erb +12 -4
  165. data/app/views/alchemy/essences/_essence_video_editor.html.erb +4 -0
  166. data/app/views/alchemy/essences/_essence_video_view.html.erb +18 -0
  167. data/app/views/alchemy/essences/shared/_essence_picture_tools.html.erb +21 -16
  168. data/app/views/alchemy/essences/shared/_linkable_essence_tools.html.erb +2 -2
  169. data/app/views/alchemy/ingredients/_audio_editor.html.erb +5 -0
  170. data/app/views/alchemy/ingredients/_audio_view.html.erb +14 -0
  171. data/app/views/alchemy/ingredients/_boolean_editor.html.erb +11 -0
  172. data/app/views/alchemy/ingredients/_boolean_view.html.erb +1 -0
  173. data/app/views/alchemy/ingredients/_datetime_editor.html.erb +17 -0
  174. data/app/views/alchemy/ingredients/_datetime_view.html.erb +9 -0
  175. data/app/views/alchemy/ingredients/_file_editor.html.erb +50 -0
  176. data/app/views/alchemy/ingredients/_file_view.html.erb +17 -0
  177. data/app/views/alchemy/ingredients/_headline_editor.html.erb +30 -0
  178. data/app/views/alchemy/ingredients/_headline_view.html.erb +9 -0
  179. data/app/views/alchemy/ingredients/_html_editor.html.erb +8 -0
  180. data/app/views/alchemy/ingredients/_html_view.html.erb +1 -0
  181. data/app/views/alchemy/ingredients/_link_editor.html.erb +24 -0
  182. data/app/views/alchemy/ingredients/_link_view.html.erb +9 -0
  183. data/app/views/alchemy/ingredients/_node_editor.html.erb +25 -0
  184. data/app/views/alchemy/ingredients/_node_view.html.erb +1 -0
  185. data/app/views/alchemy/ingredients/_page_editor.html.erb +24 -0
  186. data/app/views/alchemy/ingredients/_page_view.html.erb +4 -0
  187. data/app/views/alchemy/ingredients/_picture_editor.html.erb +59 -0
  188. data/app/views/alchemy/ingredients/_picture_view.html.erb +5 -0
  189. data/app/views/alchemy/ingredients/_richtext_editor.html.erb +12 -0
  190. data/app/views/alchemy/ingredients/_richtext_view.html.erb +3 -0
  191. data/app/views/alchemy/ingredients/_select_editor.html.erb +29 -0
  192. data/app/views/alchemy/ingredients/_select_view.html.erb +1 -0
  193. data/app/views/alchemy/ingredients/_text_editor.html.erb +19 -0
  194. data/app/views/alchemy/ingredients/_text_view.html.erb +16 -0
  195. data/app/views/alchemy/ingredients/_video_editor.html.erb +5 -0
  196. data/app/views/alchemy/ingredients/_video_view.html.erb +17 -0
  197. data/app/views/alchemy/ingredients/shared/_link_tools.html.erb +20 -0
  198. data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +57 -0
  199. data/config/brakeman.ignore +66 -159
  200. data/config/initializers/dragonfly.rb +10 -0
  201. data/config/locales/alchemy.en.yml +108 -64
  202. data/config/routes.rb +17 -22
  203. data/db/migrate/20201207131309_create_page_versions.rb +19 -0
  204. data/db/migrate/20201207135820_add_page_version_id_to_alchemy_elements.rb +76 -0
  205. data/db/migrate/20210205143548_rename_public_on_and_public_until_on_alchemy_pages.rb +10 -0
  206. data/db/migrate/20210326105046_add_sanitized_body_to_alchemy_essence_richtexts.rb +7 -0
  207. data/db/migrate/20210406093436_add_alchemy_essence_headlines.rb +12 -0
  208. data/db/migrate/20210506135919_create_essence_audios.rb +19 -0
  209. data/db/migrate/20210506140258_create_essence_videos.rb +23 -0
  210. data/db/migrate/20210508091432_create_alchemy_ingredients.rb +22 -0
  211. data/lib/alchemy/admin/preview_url.rb +2 -0
  212. data/lib/alchemy/deprecation.rb +1 -1
  213. data/lib/alchemy/dragonfly/processors/auto_orient.rb +18 -0
  214. data/lib/alchemy/dragonfly/processors/crop_resize.rb +35 -0
  215. data/lib/alchemy/elements_finder.rb +14 -60
  216. data/lib/alchemy/essence.rb +1 -2
  217. data/lib/alchemy/forms/builder.rb +21 -1
  218. data/lib/alchemy/hints.rb +8 -4
  219. data/lib/alchemy/page_layout.rb +0 -13
  220. data/lib/alchemy/permissions.rb +30 -29
  221. data/lib/alchemy/resource.rb +18 -6
  222. data/lib/alchemy/resource_filter.rb +40 -0
  223. data/lib/alchemy/resources_helper.rb +1 -16
  224. data/lib/alchemy/tasks/tidy.rb +29 -0
  225. data/lib/alchemy/test_support.rb +2 -4
  226. data/lib/alchemy/test_support/essence_shared_examples.rb +0 -1
  227. data/lib/alchemy/test_support/factories/element_factory.rb +8 -8
  228. data/lib/alchemy/test_support/factories/essence_audio_factory.rb +7 -0
  229. data/lib/alchemy/test_support/factories/essence_video_factory.rb +7 -0
  230. data/lib/alchemy/test_support/factories/ingredient_factory.rb +25 -0
  231. data/lib/alchemy/test_support/factories/page_factory.rb +20 -1
  232. data/lib/alchemy/test_support/factories/page_version_factory.rb +23 -0
  233. data/lib/alchemy/test_support/having_crop_action_examples.rb +170 -0
  234. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +646 -0
  235. data/lib/alchemy/test_support/shared_ingredient_editor_examples.rb +21 -0
  236. data/lib/alchemy/test_support/shared_ingredient_examples.rb +75 -0
  237. data/lib/alchemy/tinymce.rb +17 -0
  238. data/lib/alchemy/upgrader/six_point_zero.rb +21 -0
  239. data/lib/alchemy/upgrader/tasks/add_page_versions.rb +33 -0
  240. data/lib/alchemy/upgrader/tasks/ingredients_migrator.rb +59 -0
  241. data/lib/alchemy/version.rb +1 -1
  242. data/lib/alchemy_cms.rb +1 -0
  243. data/lib/generators/alchemy/elements/elements_generator.rb +1 -0
  244. data/lib/generators/alchemy/elements/templates/view.html.erb +9 -0
  245. data/lib/generators/alchemy/elements/templates/view.html.haml +9 -0
  246. data/lib/generators/alchemy/elements/templates/view.html.slim +9 -0
  247. data/lib/generators/alchemy/ingredient/ingredient_generator.rb +38 -0
  248. data/lib/generators/alchemy/ingredient/templates/editor.html.erb +14 -0
  249. data/lib/generators/alchemy/ingredient/templates/model.rb.tt +13 -0
  250. data/lib/generators/alchemy/ingredient/templates/view.html.erb +1 -0
  251. data/lib/generators/alchemy/install/templates/dragonfly.rb.tt +1 -1
  252. data/lib/generators/alchemy/menus/templates/node.html.erb +1 -1
  253. data/lib/generators/alchemy/menus/templates/node.html.haml +1 -1
  254. data/lib/generators/alchemy/menus/templates/node.html.slim +1 -1
  255. data/lib/generators/alchemy/menus/templates/wrapper.html.erb +1 -1
  256. data/lib/generators/alchemy/menus/templates/wrapper.html.haml +1 -1
  257. data/lib/generators/alchemy/menus/templates/wrapper.html.slim +1 -1
  258. data/lib/tasks/alchemy/thumbnails.rake +4 -2
  259. data/lib/tasks/alchemy/tidy.rake +12 -0
  260. data/lib/tasks/alchemy/upgrade.rake +26 -0
  261. data/package.json +3 -2
  262. data/package/admin.js +11 -1
  263. data/package/src/__tests__/i18n.spec.js +23 -0
  264. data/package/src/file_editors.js +28 -0
  265. data/package/src/i18n.js +1 -3
  266. data/package/src/image_cropper.js +103 -0
  267. data/package/src/image_loader.js +58 -0
  268. data/package/src/node_tree.js +5 -5
  269. data/package/src/picture_editors.js +169 -0
  270. data/package/src/utils/__tests__/ajax.spec.js +20 -12
  271. data/package/src/utils/ajax.js +8 -3
  272. data/vendor/assets/javascripts/jquery_plugins/jquery.Jcrop.min.js +3 -18
  273. data/vendor/assets/stylesheets/jquery.Jcrop.min.scss +2 -28
  274. metadata +290 -53
  275. data/app/assets/javascripts/alchemy/alchemy.image_cropper.js.coffee +0 -44
  276. data/app/assets/javascripts/alchemy/alchemy.trash_window.js.coffee +0 -30
  277. data/app/assets/stylesheets/alchemy/trash.scss +0 -8
  278. data/app/controllers/alchemy/admin/trash_controller.rb +0 -44
  279. data/app/views/alchemy/admin/attachments/_filter_bar.html.erb +0 -29
  280. data/app/views/alchemy/admin/essence_files/assign.js.erb +0 -3
  281. data/app/views/alchemy/admin/essence_pictures/assign.js.erb +0 -4
  282. data/app/views/alchemy/admin/essence_pictures/crop.html.erb +0 -48
  283. data/app/views/alchemy/admin/pictures/_filter_bar.html.erb +0 -30
  284. data/app/views/alchemy/admin/trash/clear.js.erb +0 -4
  285. data/app/views/alchemy/admin/trash/index.html.erb +0 -31
  286. 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
  ]