alchemy_cms 7.0.0.pre.a → 7.0.0.pre.c

Sign up to get free protection for your applications and to get access to all the features.
Files changed (237) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/brakeman-analysis.yml +2 -2
  3. data/.github/workflows/lint.yml +37 -0
  4. data/.github/workflows/{ci.yml → test.yml} +8 -8
  5. data/.gitignore +0 -5
  6. data/.hound.yml +2 -3
  7. data/.rubocop.yml +4 -350
  8. data/.standard.yml +3 -0
  9. data/CHANGELOG.md +33 -0
  10. data/Gemfile +3 -2
  11. data/README.md +10 -12
  12. data/Rakefile +0 -19
  13. data/alchemy_cms.gemspec +4 -2
  14. data/app/assets/config/alchemy_manifest.js +1 -0
  15. data/app/assets/javascripts/alchemy/admin.js +0 -2
  16. data/app/assets/javascripts/alchemy/alchemy.dirty.js.coffee +1 -1
  17. data/app/assets/javascripts/alchemy/alchemy.initializer.js.coffee +5 -12
  18. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +6 -1
  19. data/app/assets/stylesheets/alchemy/base.scss +2 -2
  20. data/app/components/alchemy/ingredients/audio_view.rb +37 -0
  21. data/app/components/alchemy/ingredients/base_view.rb +38 -0
  22. data/app/components/alchemy/ingredients/boolean_view.rb +13 -0
  23. data/app/components/alchemy/ingredients/datetime_view.rb +22 -0
  24. data/app/components/alchemy/ingredients/file_view.rb +40 -0
  25. data/app/components/alchemy/ingredients/headline_view.rb +20 -0
  26. data/app/components/alchemy/ingredients/html_view.rb +9 -0
  27. data/app/components/alchemy/ingredients/link_view.rb +25 -0
  28. data/app/components/alchemy/ingredients/node_view.rb +11 -0
  29. data/app/components/alchemy/ingredients/page_view.rb +15 -0
  30. data/app/components/alchemy/ingredients/picture_view.rb +108 -0
  31. data/app/components/alchemy/ingredients/richtext_view.rb +22 -0
  32. data/app/components/alchemy/ingredients/select_view.rb +6 -0
  33. data/app/components/alchemy/ingredients/text_view.rb +41 -0
  34. data/app/components/alchemy/ingredients/video_view.rb +39 -0
  35. data/app/controllers/alchemy/admin/attachments_controller.rb +3 -3
  36. data/app/controllers/alchemy/admin/base_controller.rb +7 -7
  37. data/app/controllers/alchemy/admin/clipboard_controller.rb +2 -2
  38. data/app/controllers/alchemy/admin/elements_controller.rb +26 -11
  39. data/app/controllers/alchemy/admin/languages_controller.rb +1 -1
  40. data/app/controllers/alchemy/admin/nodes_controller.rb +2 -2
  41. data/app/controllers/alchemy/admin/pages_controller.rb +10 -10
  42. data/app/controllers/alchemy/admin/pictures_controller.rb +14 -14
  43. data/app/controllers/alchemy/admin/resources_controller.rb +27 -28
  44. data/app/controllers/alchemy/admin/styleguide_controller.rb +1 -0
  45. data/app/controllers/alchemy/admin/tags_controller.rb +11 -11
  46. data/app/controllers/alchemy/api/base_controller.rb +2 -2
  47. data/app/controllers/alchemy/api/elements_controller.rb +11 -11
  48. data/app/controllers/alchemy/api/ingredients_controller.rb +1 -1
  49. data/app/controllers/alchemy/api/nodes_controller.rb +1 -1
  50. data/app/controllers/alchemy/api/pages_controller.rb +11 -11
  51. data/app/controllers/alchemy/attachments_controller.rb +3 -3
  52. data/app/controllers/alchemy/base_controller.rb +1 -8
  53. data/app/controllers/alchemy/messages_controller.rb +9 -9
  54. data/app/controllers/alchemy/pages_controller.rb +8 -19
  55. data/app/controllers/concerns/alchemy/admin/archive_overlay.rb +1 -0
  56. data/app/controllers/concerns/alchemy/admin/uploader_responses.rb +5 -7
  57. data/app/controllers/concerns/alchemy/legacy_page_redirects.rb +5 -5
  58. data/app/decorators/alchemy/element_editor.rb +4 -4
  59. data/app/decorators/alchemy/ingredient_editor.rb +6 -6
  60. data/app/helpers/alchemy/admin/attachments_helper.rb +1 -1
  61. data/app/helpers/alchemy/admin/base_helper.rb +21 -22
  62. data/app/helpers/alchemy/admin/elements_helper.rb +1 -1
  63. data/app/helpers/alchemy/admin/form_helper.rb +1 -1
  64. data/app/helpers/alchemy/admin/navigation_helper.rb +7 -7
  65. data/app/helpers/alchemy/admin/pages_helper.rb +2 -2
  66. data/app/helpers/alchemy/admin/tags_helper.rb +3 -3
  67. data/app/helpers/alchemy/base_helper.rb +2 -2
  68. data/app/helpers/alchemy/elements_block_helper.rb +9 -7
  69. data/app/helpers/alchemy/elements_helper.rb +12 -12
  70. data/app/helpers/alchemy/pages_helper.rb +11 -11
  71. data/app/helpers/alchemy/url_helper.rb +1 -1
  72. data/{package/src → app/javascript/alchemy_admin}/datepicker.js +1 -0
  73. data/{package/src → app/javascript/alchemy_admin}/node_tree.js +2 -2
  74. data/{package/src → app/javascript/alchemy_admin}/page_publication_fields.js +1 -1
  75. data/{package/src → app/javascript/alchemy_admin}/page_sorter.js +1 -1
  76. data/{package/src → app/javascript/alchemy_admin}/picture_editors.js +2 -2
  77. data/{package/src → app/javascript/alchemy_admin}/sitemap.js +4 -4
  78. data/app/javascript/alchemy_admin/tinymce.js +142 -0
  79. data/app/javascript/alchemy_admin.js +34 -0
  80. data/app/mailers/alchemy/messages_mailer.rb +1 -1
  81. data/app/models/alchemy/attachment.rb +6 -6
  82. data/app/models/alchemy/base_record.rb +1 -0
  83. data/app/models/alchemy/eager_loading.rb +6 -6
  84. data/app/models/alchemy/element/definitions.rb +1 -1
  85. data/app/models/alchemy/element/element_ingredients.rb +3 -3
  86. data/app/models/alchemy/element.rb +2 -2
  87. data/app/models/alchemy/elements_repository.rb +1 -1
  88. data/app/models/alchemy/image_cropper_settings.rb +2 -2
  89. data/app/models/alchemy/ingredient.rb +14 -12
  90. data/app/models/alchemy/ingredient_validator.rb +1 -1
  91. data/app/models/alchemy/ingredients/datetime.rb +1 -1
  92. data/app/models/alchemy/ingredients/file.rb +5 -5
  93. data/app/models/alchemy/ingredients/headline.rb +4 -4
  94. data/app/models/alchemy/ingredients/picture.rb +27 -9
  95. data/app/models/alchemy/ingredients/richtext.rb +15 -12
  96. data/app/models/alchemy/ingredients/text.rb +6 -6
  97. data/app/models/alchemy/language/code.rb +1 -1
  98. data/app/models/alchemy/language.rb +4 -4
  99. data/app/models/alchemy/legacy_page_url.rb +1 -1
  100. data/app/models/alchemy/node.rb +2 -2
  101. data/app/models/alchemy/page/page_elements.rb +14 -14
  102. data/app/models/alchemy/page/page_naming.rb +4 -4
  103. data/app/models/alchemy/page/page_natures.rb +1 -1
  104. data/app/models/alchemy/page/page_scopes.rb +5 -5
  105. data/app/models/alchemy/page.rb +11 -11
  106. data/app/models/alchemy/picture/calculations.rb +2 -2
  107. data/app/models/alchemy/picture/transformations.rb +2 -2
  108. data/app/models/alchemy/picture/url.rb +4 -4
  109. data/app/models/alchemy/picture.rb +11 -10
  110. data/app/models/alchemy/picture_thumb/create.rb +1 -1
  111. data/app/models/alchemy/picture_thumb.rb +1 -1
  112. data/app/models/alchemy/picture_variant.rb +2 -3
  113. data/app/models/alchemy/tag.rb +8 -0
  114. data/app/models/concerns/alchemy/picture_thumbnails.rb +6 -6
  115. data/app/serializers/alchemy/base_serializer.rb +1 -1
  116. data/app/serializers/alchemy/page_tree_serializer.rb +7 -7
  117. data/app/services/alchemy/duplicate_element.rb +3 -3
  118. data/app/services/alchemy/tag_validations.rb +1 -1
  119. data/app/views/alchemy/_menubar.html.erb +1 -1
  120. data/app/views/alchemy/admin/attachments/_replace_button.html.erb +1 -1
  121. data/app/views/alchemy/admin/attachments/destroy.js.erb +1 -1
  122. data/app/views/alchemy/admin/elements/_element.html.erb +3 -0
  123. data/app/views/alchemy/admin/nodes/index.html.erb +4 -2
  124. data/app/views/alchemy/admin/pages/_page_layout_filter.html.erb +1 -1
  125. data/app/views/alchemy/admin/pages/edit.html.erb +3 -7
  126. data/app/views/alchemy/admin/pages/index.html.erb +1 -1
  127. data/app/views/alchemy/admin/pages/update.js.erb +12 -6
  128. data/app/views/alchemy/admin/pictures/_infos.html.erb +1 -1
  129. data/app/views/alchemy/admin/resources/_filter_bar.html.erb +1 -1
  130. data/app/views/alchemy/admin/styleguide/index.html.erb +1 -1
  131. data/app/views/alchemy/admin/uploader/_button.html.erb +1 -1
  132. data/app/views/alchemy/base/permission_denied.js.erb +1 -1
  133. data/app/views/alchemy/base/redirect.js.erb +1 -1
  134. data/app/views/alchemy/ingredients/_audio_view.html.erb +1 -14
  135. data/app/views/alchemy/ingredients/_boolean_view.html.erb +1 -1
  136. data/app/views/alchemy/ingredients/_datetime_view.html.erb +3 -9
  137. data/app/views/alchemy/ingredients/_file_view.html.erb +3 -16
  138. data/app/views/alchemy/ingredients/_headline_view.html.erb +4 -10
  139. data/app/views/alchemy/ingredients/_html_view.html.erb +1 -1
  140. data/app/views/alchemy/ingredients/_link_view.html.erb +4 -9
  141. data/app/views/alchemy/ingredients/_node_view.html.erb +1 -1
  142. data/app/views/alchemy/ingredients/_page_view.html.erb +1 -4
  143. data/app/views/alchemy/ingredients/_picture_view.html.erb +4 -5
  144. data/app/views/alchemy/ingredients/_richtext_editor.html.erb +11 -2
  145. data/app/views/alchemy/ingredients/_richtext_view.html.erb +3 -3
  146. data/app/views/alchemy/ingredients/_select_view.html.erb +1 -1
  147. data/app/views/alchemy/ingredients/_text_view.html.erb +3 -19
  148. data/app/views/alchemy/ingredients/_video_view.html.erb +3 -18
  149. data/app/views/alchemy/ingredients/shared/_link_tools.html.erb +1 -0
  150. data/app/views/alchemy/ingredients/shared/_picture_tools.html.erb +1 -0
  151. data/app/views/layouts/alchemy/admin.html.erb +9 -15
  152. data/bin/importmap +4 -0
  153. data/bin/setup +28 -0
  154. data/bin/start +17 -0
  155. data/config/brakeman.ignore +0 -46
  156. data/config/importmap.rb +8 -0
  157. data/config/initializers/assets.rb +1 -0
  158. data/config/initializers/dragonfly.rb +1 -0
  159. data/config/initializers/mime_types.rb +1 -0
  160. data/config/initializers/mini_profiler.rb +1 -0
  161. data/config/initializers/simple_form.rb +3 -2
  162. data/config/locales/alchemy.en.yml +1 -1
  163. data/config/routes.rb +21 -20
  164. data/config/spring.rb +1 -0
  165. data/db/migrate/20230121212637_alchemy_six_point_one.rb +8 -8
  166. data/db/migrate/20230505132743_add_indexes_to_alchemy_pictures.rb +6 -0
  167. data/lib/alchemy/admin/locale.rb +3 -3
  168. data/lib/alchemy/admin/preview_url.rb +2 -2
  169. data/lib/alchemy/auth_accessors.rb +1 -1
  170. data/lib/alchemy/config.rb +1 -1
  171. data/lib/alchemy/controller_actions.rb +4 -4
  172. data/lib/alchemy/deprecation.rb +1 -0
  173. data/lib/alchemy/dragonfly/processors/thumbnail.rb +1 -1
  174. data/lib/alchemy/element_definition.rb +2 -2
  175. data/lib/alchemy/engine.rb +16 -1
  176. data/lib/alchemy/filetypes.rb +7 -7
  177. data/lib/alchemy/forms/builder.rb +4 -4
  178. data/lib/alchemy/i18n.rb +6 -4
  179. data/lib/alchemy/install/tasks.rb +2 -1
  180. data/lib/alchemy/name_conversions.rb +1 -1
  181. data/lib/alchemy/page_layout.rb +1 -1
  182. data/lib/alchemy/permissions.rb +5 -4
  183. data/lib/alchemy/resource.rb +10 -10
  184. data/lib/alchemy/resources_helper.rb +7 -7
  185. data/lib/alchemy/routing_constraints.rb +2 -2
  186. data/lib/alchemy/seeder.rb +12 -5
  187. data/lib/alchemy/shell.rb +2 -1
  188. data/lib/alchemy/taggable.rb +3 -2
  189. data/lib/alchemy/tasks/tidy.rb +1 -0
  190. data/lib/alchemy/test_support/capybara_helpers.rb +1 -1
  191. data/lib/alchemy/test_support/config_stubbing.rb +1 -0
  192. data/lib/alchemy/test_support/factories/element_factory.rb +4 -0
  193. data/lib/alchemy/test_support/factories/page_factory.rb +2 -2
  194. data/lib/alchemy/test_support/having_crop_action_examples.rb +9 -9
  195. data/lib/alchemy/test_support/having_picture_thumbnails_examples.rb +33 -33
  196. data/lib/alchemy/test_support/integration_helpers.rb +4 -3
  197. data/lib/alchemy/test_support/shared_contexts.rb +2 -1
  198. data/lib/alchemy/test_support/shared_dom_ids_examples.rb +9 -9
  199. data/lib/alchemy/test_support/shared_ingredient_examples.rb +12 -6
  200. data/lib/alchemy/test_support/shared_uploader_examples.rb +1 -0
  201. data/lib/alchemy/tinymce.rb +3 -26
  202. data/lib/alchemy/upgrader/seven_point_zero.rb +13 -23
  203. data/lib/alchemy/upgrader.rb +1 -11
  204. data/lib/alchemy/version.rb +1 -1
  205. data/lib/alchemy.rb +5 -0
  206. data/lib/alchemy_cms.rb +3 -1
  207. data/lib/generators/alchemy/base.rb +3 -2
  208. data/lib/generators/alchemy/elements/elements_generator.rb +2 -1
  209. data/lib/generators/alchemy/ingredient/ingredient_generator.rb +1 -0
  210. data/lib/generators/alchemy/install/files/application.html.erb +2 -2
  211. data/lib/generators/alchemy/install/install_generator.rb +2 -25
  212. data/lib/generators/alchemy/module/module_generator.rb +1 -0
  213. data/lib/generators/alchemy/page_layouts/page_layouts_generator.rb +1 -0
  214. data/lib/generators/alchemy/site_layouts/site_layouts_generator.rb +1 -0
  215. data/lib/generators/alchemy/views/views_generator.rb +2 -1
  216. data/lib/tasks/alchemy/thumbnails.rake +5 -5
  217. data/lib/tasks/alchemy/tidy.rake +1 -0
  218. data/lib/tasks/alchemy/upgrade.rake +10 -15
  219. data/package.json +6 -26
  220. metadata +80 -31
  221. data/app/assets/javascripts/alchemy/alchemy.tinymce.js.coffee +0 -93
  222. data/app/presenters/alchemy/picture_view.rb +0 -88
  223. data/app/views/alchemy/admin/pages/_tinymce_custom_config.html.erb +0 -10
  224. data/package/admin.js +0 -32
  225. data/package/dist/admin.js +0 -16
  226. data/package/dist/admin.js.map +0 -7
  227. data/package/src/__tests__/i18n.spec.js +0 -93
  228. data/package/src/utils/__tests__/ajax.spec.js +0 -168
  229. data/package/src/utils/__tests__/events.spec.js +0 -38
  230. /data/{package/src → app/javascript/alchemy_admin}/file_editors.js +0 -0
  231. /data/{package/src → app/javascript/alchemy_admin}/i18n.js +0 -0
  232. /data/{package/src → app/javascript/alchemy_admin}/image_cropper.js +0 -0
  233. /data/{package/src → app/javascript/alchemy_admin}/image_loader.js +0 -0
  234. /data/{package/src → app/javascript/alchemy_admin}/ingredient_anchor_link.js +0 -0
  235. /data/{package/src → app/javascript/alchemy_admin}/translations.js +0 -0
  236. /data/{package/src → app/javascript/alchemy_admin}/utils/ajax.js +0 -0
  237. /data/{package/src → app/javascript/alchemy_admin}/utils/events.js +0 -0
@@ -10,10 +10,10 @@ module Alchemy
10
10
  :sanitized_body
11
11
 
12
12
  allow_settings %i[
13
- plain_text
14
- sanitizer
15
- tinymce
16
- ]
13
+ plain_text
14
+ sanitizer
15
+ tinymce
16
+ ]
17
17
 
18
18
  before_save :strip_content
19
19
  before_save :sanitize_content
@@ -28,15 +28,23 @@ module Alchemy
28
28
  stripped_body.to_s[0..max_length - 1]
29
29
  end
30
30
 
31
- # Returns css class names for the editor textarea.
32
- def tinymce_class_name
33
- "has_tinymce#{has_custom_tinymce_config? ? " #{element.name}_#{role}" : ""}"
31
+ def element_id
32
+ "tinymce_#{id}"
34
33
  end
35
34
 
36
35
  def has_tinymce?
37
36
  true
38
37
  end
39
38
 
39
+ # Returns true if there is a tinymce setting defined that contains settings.
40
+ def has_custom_tinymce_config?
41
+ custom_tinymce_config.is_a?(Hash)
42
+ end
43
+
44
+ def custom_tinymce_config
45
+ settings[:tinymce]
46
+ end
47
+
40
48
  private
41
49
 
42
50
  def strip_content
@@ -53,11 +61,6 @@ module Alchemy
53
61
  def sanitizer_settings
54
62
  settings[:sanitizer] || {}
55
63
  end
56
-
57
- # Returns true if there is a tinymce setting defined that contains settings.
58
- def has_custom_tinymce_config?
59
- settings[:tinymce].is_a?(Hash)
60
- end
61
64
  end
62
65
  end
63
66
  end
@@ -17,12 +17,12 @@ module Alchemy
17
17
  :link_class_name
18
18
 
19
19
  allow_settings %i[
20
- anchor
21
- disable_link
22
- display_inline
23
- input_type
24
- linkable
25
- ]
20
+ anchor
21
+ disable_link
22
+ display_inline
23
+ input_type
24
+ linkable
25
+ ]
26
26
  end
27
27
  end
28
28
  end
@@ -17,7 +17,7 @@ module Alchemy::Language::Code
17
17
  codes << "" if codes.length == 1
18
18
  on_current_site.find_by(
19
19
  language_code: codes[0],
20
- country_code: codes[1],
20
+ country_code: codes[1]
21
21
  )
22
22
  end
23
23
  end
@@ -38,11 +38,11 @@ module Alchemy
38
38
 
39
39
  validates :language_code,
40
40
  presence: true,
41
- uniqueness: { scope: [:site_id, :country_code], case_sensitive: false },
42
- format: { with: /\A[a-z]{2}\z/, if: -> { language_code.present? } }
41
+ uniqueness: {scope: [:site_id, :country_code], case_sensitive: false},
42
+ format: {with: /\A[a-z]{2}\z/, if: -> { language_code.present? }}
43
43
 
44
44
  validates :country_code,
45
- format: { with: /\A[a-zA-Z]{2}\z/, if: -> { country_code.present? } }
45
+ format: {with: /\A[a-zA-Z]{2}\z/, if: -> { country_code.present? }}
46
46
 
47
47
  validate :presence_of_default_language
48
48
  validate :publicity_of_default_language
@@ -60,7 +60,7 @@ module Alchemy
60
60
  end
61
61
 
62
62
  scope :published, -> { where(public: true) }
63
- scope :with_root_page, -> { joins(:pages).where(Page.table_name => { language_root: true }) }
63
+ scope :with_root_page, -> { joins(:pages).where(Page.table_name => {language_root: true}) }
64
64
 
65
65
  class << self
66
66
  def on_site(site)
@@ -18,5 +18,5 @@ class Alchemy::LegacyPageUrl < ActiveRecord::Base
18
18
 
19
19
  validates :urlname,
20
20
  presence: true,
21
- format: {with: /\A[:\.\w\-+_\/\?&%;=#]*\z/}
21
+ format: {with: /\A[:.\w\-+_\/?&%;=#]*\z/}
22
22
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Alchemy
4
4
  class Node < BaseRecord
5
- VALID_URL_REGEX = /\A(\/|\D[a-z\+\d\.\-]+:)/
5
+ VALID_URL_REGEX = /\A(\/|\D[a-z+\d.-]+:)/
6
6
 
7
7
  before_destroy :check_if_related_node_ingredients_present
8
8
 
@@ -24,7 +24,7 @@ module Alchemy
24
24
 
25
25
  validates :menu_type, presence: true
26
26
  validates :name, presence: true, if: -> { page.nil? }
27
- validates :url, format: { with: VALID_URL_REGEX }, unless: -> { url.nil? }
27
+ validates :url, format: {with: VALID_URL_REGEX}, unless: -> { url.nil? }
28
28
 
29
29
  # Returns the name
30
30
  #
@@ -12,7 +12,7 @@ module Alchemy
12
12
  class_name: "Alchemy::Element",
13
13
  through: :public_version,
14
14
  inverse_of: :page,
15
- source: :elements,
15
+ source: :elements
16
16
  ) do
17
17
  has_many :all_elements
18
18
  has_many :elements, -> { not_nested.unfixed.published }
@@ -42,7 +42,7 @@ module Alchemy
42
42
  repository.not_nested.each.with_index(1) do |element, position|
43
43
  Alchemy::DuplicateElement.new(element, repository: repository).call(
44
44
  page_version_id: target.draft_version.id,
45
- position: position,
45
+ position: position
46
46
  )
47
47
  end
48
48
  end
@@ -72,11 +72,11 @@ module Alchemy
72
72
  #
73
73
  def available_element_definitions(only_element_named = nil)
74
74
  @_element_definitions ||= if only_element_named
75
- definition = Element.definition_by_name(only_element_named)
76
- element_definitions_by_name(definition["nestable_elements"])
77
- else
78
- element_definitions
79
- end
75
+ definition = Element.definition_by_name(only_element_named)
76
+ element_definitions_by_name(definition["nestable_elements"])
77
+ else
78
+ element_definitions
79
+ end
80
80
 
81
81
  return [] if @_element_definitions.blank?
82
82
 
@@ -98,13 +98,13 @@ module Alchemy
98
98
  #
99
99
  def available_elements_within_current_scope(parent)
100
100
  @_available_elements = if parent
101
- parents_unique_nested_elements = parent.nested_elements.where(unique: true).pluck(:name)
102
- available_element_definitions(parent.name).reject do |e|
103
- parents_unique_nested_elements.include? e["name"]
104
- end
105
- else
106
- available_element_definitions
101
+ parents_unique_nested_elements = parent.nested_elements.where(unique: true).pluck(:name)
102
+ available_element_definitions(parent.name).reject do |e|
103
+ parents_unique_nested_elements.include? e["name"]
107
104
  end
105
+ else
106
+ available_element_definitions
107
+ end
108
108
  end
109
109
 
110
110
  # All element definitions defined for page's page layout
@@ -160,7 +160,7 @@ module Alchemy
160
160
  #
161
161
  def richtext_ingredients_ids
162
162
  Alchemy::Ingredient.richtexts.joins(:element)
163
- .where(Element.table_name => { page_version_id: draft_version.id, folded: false })
163
+ .where(Element.table_name => {page_version_id: draft_version.id, folded: false})
164
164
  .select(&:has_tinymce?)
165
165
  .collect(&:id)
166
166
  end
@@ -5,7 +5,7 @@ module Alchemy
5
5
  module PageNaming
6
6
  extend ActiveSupport::Concern
7
7
  include NameConversions
8
- RESERVED_URLNAMES = %w(admin messages new)
8
+ RESERVED_URLNAMES = %w[admin messages new]
9
9
 
10
10
  included do
11
11
  before_validation :set_urlname,
@@ -15,9 +15,9 @@ module Alchemy
15
15
  validates :name,
16
16
  presence: true
17
17
  validates :urlname,
18
- uniqueness: { scope: [:language_id, :layoutpage], if: -> { urlname.present? }, case_sensitive: false },
19
- exclusion: { in: RESERVED_URLNAMES },
20
- length: { minimum: 3, if: -> { urlname.present? } }
18
+ uniqueness: {scope: [:language_id, :layoutpage], if: -> { urlname.present? }, case_sensitive: false},
19
+ exclusion: {in: RESERVED_URLNAMES},
20
+ length: {minimum: 3, if: -> { urlname.present? }}
21
21
 
22
22
  before_save :set_title,
23
23
  if: -> { title.blank? }
@@ -58,7 +58,7 @@ module Alchemy
58
58
  {
59
59
  public: public?,
60
60
  locked: locked?,
61
- restricted: restricted?,
61
+ restricted: restricted?
62
62
  }
63
63
  end
64
64
 
@@ -49,9 +49,9 @@ module Alchemy
49
49
  #
50
50
  scope :published,
51
51
  -> {
52
- joins(:language, :versions).
53
- merge(Language.published).
54
- merge(PageVersion.public_on(Time.current))
52
+ joins(:language, :versions)
53
+ .merge(Language.published)
54
+ .merge(PageVersion.public_on(Time.current))
55
55
  }
56
56
 
57
57
  # All pages that are a published language root
@@ -59,7 +59,7 @@ module Alchemy
59
59
  scope :public_language_roots,
60
60
  -> {
61
61
  published.language_roots.where(
62
- language_code: Language.published.pluck(:language_code),
62
+ language_code: Language.published.pluck(:language_code)
63
63
  )
64
64
  }
65
65
 
@@ -98,7 +98,7 @@ module Alchemy
98
98
  #
99
99
  scope :from_current_site,
100
100
  -> {
101
- where(Language.table_name => { site_id: Site.current || Site.default }).joins(:language)
101
+ where(Language.table_name => {site_id: Site.current || Site.default}).joins(:language)
102
102
  }
103
103
 
104
104
  # All pages for xml sitemap
@@ -53,10 +53,10 @@ module Alchemy
53
53
  public_on: nil,
54
54
  public_until: nil,
55
55
  locked_at: nil,
56
- locked_by: nil,
56
+ locked_by: nil
57
57
  }
58
58
 
59
- SKIPPED_ATTRIBUTES_ON_COPY = %w(
59
+ SKIPPED_ATTRIBUTES_ON_COPY = %w[
60
60
  id
61
61
  updated_at
62
62
  created_at
@@ -67,7 +67,7 @@ module Alchemy
67
67
  depth
68
68
  urlname
69
69
  cached_tag_list
70
- )
70
+ ]
71
71
 
72
72
  PERMITTED_ATTRIBUTES = [
73
73
  :meta_description,
@@ -85,7 +85,7 @@ module Alchemy
85
85
  :title,
86
86
  :urlname,
87
87
  :layoutpage,
88
- :menu_id,
88
+ :menu_id
89
89
  ]
90
90
 
91
91
  acts_as_nested_set(dependent: :destroy, scope: [:layoutpage, :language_id])
@@ -185,12 +185,12 @@ module Alchemy
185
185
  [
186
186
  {
187
187
  name: :by_page_layout,
188
- values: PageLayout.all.map { |p| [Alchemy.t(p["name"], scope: "page_layout_names"), p["name"]] },
188
+ values: PageLayout.all.map { |p| [Alchemy.t(p["name"], scope: "page_layout_names"), p["name"]] }
189
189
  },
190
190
  {
191
191
  name: :status,
192
- values: %w[published not_public restricted],
193
- },
192
+ values: %w[published not_public restricted]
193
+ }
194
194
  ]
195
195
  end
196
196
 
@@ -248,7 +248,7 @@ module Alchemy
248
248
  parent: new_parent,
249
249
  language: new_parent&.language,
250
250
  name: new_name,
251
- title: new_name,
251
+ title: new_name
252
252
  })
253
253
  if source.children.any?
254
254
  source.copy_children_to(page)
@@ -276,7 +276,7 @@ module Alchemy
276
276
  link_target_options = Config.get(:link_target_options)
277
277
  link_target_options.each do |option|
278
278
  options << [Alchemy.t(option, scope: "link_target_options",
279
- default: option.to_s.humanize), option]
279
+ default: option.to_s.humanize), option]
280
280
  end
281
281
  options
282
282
  end
@@ -450,7 +450,7 @@ module Alchemy
450
450
  new_child = Page.copy(child, {
451
451
  parent_id: new_parent.id,
452
452
  language_id: new_parent.language_id,
453
- language_code: new_parent.language_code,
453
+ language_code: new_parent.language_code
454
454
  })
455
455
  new_child.move_to_child_of(new_parent)
456
456
  child.copy_children_to(new_child) unless child.children.blank?
@@ -491,7 +491,7 @@ module Alchemy
491
491
  # A tree node with new lft, rgt, depth, url, parent_id and restricted indexes to be updated
492
492
  #
493
493
  def update_node!(node)
494
- hash = { lft: node.left, rgt: node.right, parent_id: node.parent, depth: node.depth, restricted: node.restricted }
494
+ hash = {lft: node.left, rgt: node.right, parent_id: node.parent, depth: node.depth, restricted: node.restricted}
495
495
 
496
496
  if urlname != node.url
497
497
  LegacyPageUrl.create(page_id: id, urlname: urlname)
@@ -32,7 +32,7 @@ module Alchemy
32
32
 
33
33
  {
34
34
  width: width,
35
- height: height,
35
+ height: height
36
36
  }
37
37
  end
38
38
 
@@ -41,7 +41,7 @@ module Alchemy
41
41
  def image_size
42
42
  {
43
43
  width: image_file_width,
44
- height: image_file_height,
44
+ height: image_file_height
45
45
  }
46
46
  end
47
47
  end
@@ -59,7 +59,7 @@ module Alchemy
59
59
  y = 0 if y.nil?
60
60
  {
61
61
  x: x,
62
- y: y,
62
+ y: y
63
63
  }
64
64
  end
65
65
 
@@ -108,7 +108,7 @@ module Alchemy
108
108
  def reduce_to_image(dimensions)
109
109
  {
110
110
  width: [dimensions[:width].to_i, image_file_width.to_i].min,
111
- height: [dimensions[:height].to_i, image_file_height.to_i].min,
111
+ height: [dimensions[:height].to_i, image_file_height.to_i].min
112
112
  }
113
113
  end
114
114
  end
@@ -44,10 +44,10 @@ module Alchemy
44
44
 
45
45
  def find_thumb_by(signature)
46
46
  @thumb = if variant.picture.thumbs.loaded?
47
- variant.picture.thumbs.find { |t| t.signature == signature }
48
- else
49
- variant.picture.thumbs.find_by(signature: signature)
50
- end
47
+ variant.picture.thumbs.find { |t| t.signature == signature }
48
+ else
49
+ variant.picture.thumbs.find_by(signature: signature)
50
+ end
51
51
  end
52
52
  end
53
53
  end
@@ -25,7 +25,7 @@ module Alchemy
25
25
  THUMBNAIL_SIZES = {
26
26
  small: "80x60",
27
27
  medium: "160x120",
28
- large: "240x180",
28
+ large: "240x180"
29
29
  }.with_indifferent_access.freeze
30
30
 
31
31
  CONVERTIBLE_FILE_FORMATS = %w[gif jpg jpeg png webp].freeze
@@ -38,7 +38,7 @@ module Alchemy
38
38
  :format,
39
39
  :quality,
40
40
  :size,
41
- :upsample,
41
+ :upsample
42
42
  ]
43
43
 
44
44
  include Alchemy::Logger
@@ -64,7 +64,7 @@ module Alchemy
64
64
  # to ensure this runs before Dragonfly's before_destroy callback.
65
65
  #
66
66
  before_destroy unless: :deletable? do
67
- raise PictureInUseError, Alchemy.t(:cannot_delete_picture_notice) % { name: name }
67
+ raise PictureInUseError, Alchemy.t(:cannot_delete_picture_notice) % {name: name}
68
68
  end
69
69
 
70
70
  # Image preprocessing class
@@ -117,7 +117,7 @@ module Alchemy
117
117
  -> {
118
118
  where("#{table_name}.id NOT IN (SELECT related_object_id FROM alchemy_ingredients WHERE related_object_type = 'Alchemy::Picture')")
119
119
  }
120
- scope :without_tag, -> { left_outer_joins(:taggings).where(gutentag_taggings: { id: nil }) }
120
+ scope :without_tag, -> { left_outer_joins(:taggings).where(gutentag_taggings: {id: nil}) }
121
121
  scope :by_file_format, ->(format) { where(image_file_format: format) }
122
122
 
123
123
  # Class methods
@@ -138,20 +138,21 @@ module Alchemy
138
138
  end
139
139
 
140
140
  def alchemy_resource_filters
141
+ @_file_formats ||= distinct.pluck(:image_file_format).compact.presence || []
141
142
  [
142
143
  {
143
144
  name: :by_file_format,
144
- values: distinct.pluck(:image_file_format),
145
+ values: @_file_formats
145
146
  },
146
147
  {
147
148
  name: :misc,
148
- values: %w(recent last_upload without_tag),
149
- },
149
+ values: %w[recent last_upload without_tag deletable]
150
+ }
150
151
  ]
151
152
  end
152
153
 
153
154
  def searchable_alchemy_resource_attributes
154
- %w(name image_file_name)
155
+ %w[name image_file_name]
155
156
  end
156
157
 
157
158
  def last_upload
@@ -183,7 +184,7 @@ module Alchemy
183
184
  options.except(*TRANSFORMATION_OPTIONS).merge(
184
185
  basename: name,
185
186
  ext: variant.render_format,
186
- name: name,
187
+ name: name
187
188
  )
188
189
  )
189
190
  rescue ::Dragonfly::Job::Fetch::NotFound => e
@@ -211,7 +212,7 @@ module Alchemy
211
212
  {
212
213
  name: image_file_name,
213
214
  size: image_file_size,
214
- error: errors[:image_file].join,
215
+ error: errors[:image_file].join
215
216
  }
216
217
  end
217
218
 
@@ -27,7 +27,7 @@ module Alchemy
27
27
  end
28
28
  begin
29
29
  Alchemy::PictureThumb.storage_class.call(variant, uid)
30
- rescue StandardError => e
30
+ rescue => e
31
31
  ErrorTracking.notification_handler.call(e)
32
32
  # destroy the thumb if processing or storing fails
33
33
  @thumb&.destroy
@@ -42,7 +42,7 @@ module Alchemy
42
42
  Alchemy::Picture::THUMBNAIL_SIZES.values.each do |size|
43
43
  variant = Alchemy::PictureVariant.new(picture, {
44
44
  size: size,
45
- flatten: true,
45
+ flatten: true
46
46
  })
47
47
  signature = Alchemy::PictureThumb::Signature.call(variant)
48
48
  thumb = find_by(signature: signature)
@@ -54,8 +54,7 @@ module Alchemy
54
54
  raise MissingImageFileError, "Missing image file for #{picture.inspect}" if image.nil?
55
55
 
56
56
  image = processed_image(image, @options)
57
- image = encoded_image(image, @options)
58
- image
57
+ encoded_image(image, @options)
59
58
  rescue MissingImageFileError, WrongImageFormatError => e
60
59
  log_warning(e.message)
61
60
  nil
@@ -88,7 +87,7 @@ module Alchemy
88
87
  end
89
88
 
90
89
  options = {
91
- flatten: !render_format.in?(ANIMATED_IMAGE_FORMATS) && picture.image_file_format == "gif",
90
+ flatten: !render_format.in?(ANIMATED_IMAGE_FORMATS) && picture.image_file_format == "gif"
92
91
  }.with_indifferent_access.merge(options)
93
92
 
94
93
  encoding_options = []
@@ -13,6 +13,14 @@
13
13
  # The original Tag model is Gutentag::Tag
14
14
  module Alchemy
15
15
  class Tag < Gutentag::Tag
16
+ def self.ransackable_attributes(_auth_object = nil)
17
+ %w[created_at id name taggings_count updated_at]
18
+ end
19
+
20
+ def self.ransackable_associations(_auth_object = nil)
21
+ %w[taggings]
22
+ end
23
+
16
24
  # Replaces tag with new tag on all models tagged with tag.
17
25
  def self.replace(tag, new_tag)
18
26
  tag.taggings.collect(&:taggable).each do |taggable|
@@ -56,7 +56,7 @@ module Alchemy
56
56
  crop: crop,
57
57
  crop_from: crop && crop_from.presence || nil,
58
58
  crop_size: crop && crop_size.presence || nil,
59
- size: settings[:size],
59
+ size: settings[:size]
60
60
  }.with_indifferent_access
61
61
  end
62
62
 
@@ -84,7 +84,7 @@ module Alchemy
84
84
  crop_from: crop && crop_from.presence || default_crop_from&.join("x"),
85
85
  crop_size: crop && crop_size.presence || default_crop_size&.join("x"),
86
86
  flatten: true,
87
- format: picture&.image_file_format || "jpg",
87
+ format: picture&.image_file_format || "jpg"
88
88
  }
89
89
  end
90
90
 
@@ -96,7 +96,7 @@ module Alchemy
96
96
  default_crop_size: default_crop_size,
97
97
  fixed_ratio: settings[:fixed_ratio],
98
98
  image_width: picture&.image_file_width,
99
- image_height: picture&.image_file_height,
99
+ image_height: picture&.image_file_height
100
100
  ).to_h
101
101
  end
102
102
 
@@ -105,7 +105,7 @@ module Alchemy
105
105
  settings[:crop] && picture &&
106
106
  picture.can_be_cropped_to?(
107
107
  settings[:size],
108
- settings[:upsample],
108
+ settings[:upsample]
109
109
  ) && !!picture.image_file
110
110
  end
111
111
 
@@ -124,7 +124,7 @@ module Alchemy
124
124
  def thumbnail_zoom_factor(mask)
125
125
  [
126
126
  mask[0].to_f / (image_file_width || 1),
127
- mask[1].to_f / (image_file_height || 1),
127
+ mask[1].to_f / (image_file_height || 1)
128
128
  ].max
129
129
  end
130
130
 
@@ -134,7 +134,7 @@ module Alchemy
134
134
 
135
135
  [
136
136
  ((image_file_width || 0) - default_crop_size[0]) / 2,
137
- ((image_file_height || 0) - default_crop_size[1]) / 2,
137
+ ((image_file_height || 0) - default_crop_size[1]) / 2
138
138
  ].map(&:round)
139
139
  end
140
140
 
@@ -14,7 +14,7 @@ module Alchemy
14
14
  # The attributes to be serialized. See ActiveModel::Serialization.
15
15
  # By default, serialize all columns from the AR object.
16
16
  def attributes
17
- Hash[object.class.column_names.map { |c| [c, nil] }]
17
+ object.class.column_names.map { |c| [c, nil] }.to_h
18
18
  end
19
19
 
20
20
  private
@@ -3,13 +3,13 @@
3
3
  module Alchemy
4
4
  class PageTreeSerializer < BaseSerializer
5
5
  def attributes
6
- { "pages" => nil }
6
+ {"pages" => nil}
7
7
  end
8
8
 
9
9
  def pages
10
10
  tree = []
11
- path = [{ id: object.parent_id, children: tree }]
12
- page_list = object.self_and_descendants.includes(:public_version, { language: :site })
11
+ path = [{id: object.parent_id, children: tree}]
12
+ page_list = object.self_and_descendants.includes(:public_version, {language: :site})
13
13
  base_level = object.level - 1
14
14
  # Load folded pages in advance
15
15
  folded_user_pages = FoldedPage.folded_for_user(opts[:user]).pluck(:page_id)
@@ -61,7 +61,7 @@ module Alchemy
61
61
  level: level,
62
62
  root: page.root?,
63
63
  root_or_leaf: page.root? || page.leaf?,
64
- children: [],
64
+ children: []
65
65
  }
66
66
 
67
67
  if opts[:elements]
@@ -75,7 +75,7 @@ module Alchemy
75
75
  locked: page.locked?,
76
76
  locked_notice: page.locked? ? Alchemy.t("This page is locked", name: page.locker_name) : nil,
77
77
  permissions: page_permissions(page, opts[:ability]),
78
- status_titles: page_status_titles(page),
78
+ status_titles: page_status_titles(page)
79
79
  })
80
80
  else
81
81
  p_hash
@@ -98,14 +98,14 @@ module Alchemy
98
98
  copy: ability.can?(:copy, page),
99
99
  destroy: ability.can?(:destroy, page),
100
100
  create: ability.can?(:create, Alchemy::Page),
101
- edit_content: ability.can?(:edit_content, page),
101
+ edit_content: ability.can?(:edit_content, page)
102
102
  }
103
103
  end
104
104
 
105
105
  def page_status_titles(page)
106
106
  {
107
107
  public: page.status_title(:public),
108
- restricted: page.status_title(:restricted),
108
+ restricted: page.status_title(:restricted)
109
109
  }
110
110
  end
111
111
  end
@@ -10,7 +10,7 @@ module Alchemy
10
10
  "id",
11
11
  "folded",
12
12
  "updated_at",
13
- "updater_id",
13
+ "updater_id"
14
14
  ].freeze
15
15
 
16
16
  attr_reader :source_element, :repository
@@ -27,7 +27,7 @@ module Alchemy
27
27
  .merge(
28
28
  autogenerate_ingredients: false,
29
29
  autogenerate_nested_elements: false,
30
- tags: source_element.tags,
30
+ tags: source_element.tags
31
31
  )
32
32
 
33
33
  new_element = Element.new(attributes)
@@ -40,7 +40,7 @@ module Alchemy
40
40
  self.class.new(nested_element, repository: repository).call(
41
41
  parent_element: new_element,
42
42
  page_version: new_element.page_version,
43
- position: position,
43
+ position: position
44
44
  )
45
45
  end
46
46
  end