alchemy_cms 5.1.0 → 5.2.0

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.

Potentially problematic release.


This version of alchemy_cms might be problematic. Click here for more details.

Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -1
  3. data/CHANGELOG.md +51 -0
  4. data/Gemfile +2 -1
  5. data/alchemy_cms.gemspec +2 -2
  6. data/app/assets/stylesheets/alchemy/_variables.scss +2 -0
  7. data/app/assets/stylesheets/alchemy/elements.scss +38 -5
  8. data/app/controllers/alchemy/admin/base_controller.rb +1 -0
  9. data/app/controllers/alchemy/admin/trash_controller.rb +2 -0
  10. data/app/decorators/alchemy/content_editor.rb +64 -0
  11. data/app/decorators/alchemy/element_editor.rb +67 -0
  12. data/app/helpers/alchemy/admin/contents_helper.rb +3 -8
  13. data/app/helpers/alchemy/elements_helper.rb +0 -18
  14. data/app/helpers/alchemy/pages_helper.rb +3 -1
  15. data/app/models/alchemy/attachment.rb +4 -0
  16. data/app/models/alchemy/content.rb +7 -0
  17. data/app/models/alchemy/element.rb +38 -0
  18. data/app/models/alchemy/element/definitions.rb +5 -22
  19. data/app/models/alchemy/page/page_elements.rb +9 -2
  20. data/app/models/alchemy/picture_variant.rb +1 -1
  21. data/app/views/alchemy/admin/elements/_element.html.erb +1 -1
  22. data/app/views/alchemy/admin/elements/_element_footer.html.erb +1 -1
  23. data/app/views/alchemy/admin/elements/_element_header.html.erb +2 -0
  24. data/app/views/alchemy/admin/elements/_element_toolbar.html.erb +1 -1
  25. data/config/brakeman.ignore +305 -17
  26. data/config/locales/alchemy.en.yml +40 -24
  27. data/lib/alchemy/deprecation.rb +1 -1
  28. data/lib/alchemy/element_definition.rb +70 -0
  29. data/lib/alchemy/elements_finder.rb +6 -2
  30. data/lib/alchemy/essence.rb +4 -4
  31. data/lib/alchemy/filetypes.rb +13 -0
  32. data/lib/alchemy/forms/builder.rb +1 -1
  33. data/lib/alchemy/i18n.rb +4 -5
  34. data/lib/alchemy/page_layout.rb +1 -0
  35. data/lib/alchemy/resource.rb +5 -3
  36. data/lib/alchemy/test_support.rb +18 -0
  37. data/lib/alchemy/test_support/essence_shared_examples.rb +0 -3
  38. data/lib/alchemy/test_support/factories.rb +11 -0
  39. data/lib/alchemy/test_support/factories/attachment_factory.rb +0 -2
  40. data/lib/alchemy/test_support/factories/content_factory.rb +0 -6
  41. data/lib/alchemy/test_support/factories/dummy_user_factory.rb +0 -2
  42. data/lib/alchemy/test_support/factories/element_factory.rb +0 -3
  43. data/lib/alchemy/test_support/factories/essence_file_factory.rb +0 -3
  44. data/lib/alchemy/test_support/factories/essence_page_factory.rb +0 -3
  45. data/lib/alchemy/test_support/factories/essence_picture_factory.rb +0 -4
  46. data/lib/alchemy/test_support/factories/essence_text_factory.rb +0 -2
  47. data/lib/alchemy/test_support/factories/language_factory.rb +0 -3
  48. data/lib/alchemy/test_support/factories/node_factory.rb +0 -4
  49. data/lib/alchemy/test_support/factories/page_factory.rb +0 -3
  50. data/lib/alchemy/test_support/factories/picture_factory.rb +0 -2
  51. data/lib/alchemy/test_support/factories/picture_thumb_factory.rb +0 -3
  52. data/lib/alchemy/test_support/factories/site_factory.rb +0 -2
  53. data/lib/alchemy/test_support/integration_helpers.rb +5 -5
  54. data/lib/alchemy/version.rb +1 -1
  55. data/lib/alchemy_cms.rb +1 -0
  56. metadata +8 -6
@@ -130,31 +130,45 @@ en:
130
130
  # == Mime Types translations
131
131
  # These are human readable mime types used for the document-type row in archive files.
132
132
  mime_types:
133
- audio/mp4: 'MP4-Audio'
134
- application/msword: 'Word-Document'
135
- application/rtf: 'RTF-Document'
136
- audio/mpeg: 'MP3-Audio'
137
- text/plain: 'Text-Document'
138
- video/mp4: 'MP4-Video'
139
- video/mpeg: 'MPEG-Video'
140
- application/pdf: 'PDF-Document'
141
- application/x-flash-video: 'Flash-Video'
142
- video/x-flv: 'Flash-Video'
143
- application/x-shockwave-flash: 'Flash-Movie'
144
- application/zip: 'ZIP-Archive'
145
- application/x-rar: 'RAR-Archive'
133
+ application/msexcel: Excel Spreadsheet
134
+ application/mspowerpoint: PowerPoint Presentation
135
+ application/msword: Word Document
136
+ application/pdf: PDF Document
137
+ application/rtf: RTF Document
138
+ application/vcard: vCard
146
139
  application/vnd:
147
- ms-excel: 'Excel-Document'
148
- video/quicktime: 'Quicktime-Video'
149
- image/x-psd: 'Photoshop-File'
150
- image/gif: 'GIF-Image'
151
- image/png: 'PNG-Image'
152
- image/jpeg: 'JPG-Image'
153
- video/x-msvideo: 'AVI-Video'
154
- video/x-ms-wmv: 'Windows Media Video'
155
- image/tiff: 'TIFF-Image'
156
- 'text/x-vcard': 'vCard'
157
- application/vcard: 'vCard'
140
+ ms-excel: Excel Spreadsheet
141
+ ms-powerpoint: PowerPoint Presentation
142
+ ms-word: Word Document
143
+ openxmlformats-officedocument:
144
+ presentationml:
145
+ presentation: PowerPoint 2007 Presentation
146
+ spreadsheetml:
147
+ sheet: Excel 2007 Spreadsheet
148
+ wordprocessingml:
149
+ document: Word 2007 Document
150
+ application/x-flash-video: Flash Video
151
+ application/x-rar: RAR Archive
152
+ application/x-shockwave-flash: Flash Movie
153
+ application/zip: ZIP Archive
154
+ audio/mp4: MPEG-4 Audio
155
+ audio/mpeg: MP3 Audio
156
+ audio/wav: WAV Audio
157
+ audio/x-wav: WAV Audio
158
+ image/gif: GIF Image
159
+ image/jpeg: JPG Image
160
+ image/png: PNG Image
161
+ image/tiff: TIFF Image
162
+ image/x-psd: Photoshop File
163
+ image/svg+xml: SVG Image
164
+ text/plain: Plain Text Document
165
+ text/x-vcard: vCard
166
+ video/mp4: MPEG-4 Video
167
+ video/mpeg: MPEG Video
168
+ video/quicktime: Quicktime Video
169
+ video/x-flv: Flash Video
170
+ video/x-ms-wmv: Windows Media Video
171
+ video/x-msvideo: AVI Video
158
172
 
159
173
  link_target_options:
160
174
  default: Same Window
@@ -295,7 +309,9 @@ en:
295
309
  "Visit page": "Visit page"
296
310
  "Warning!": "Warning!"
297
311
  content_definition_missing: "Warning: Content is missing its definition. Please check the elements.yml"
312
+ content_deprecated: "WARNING! This content is deprecated and will be removed soon. Please do not use it anymore."
298
313
  element_definition_missing: "WARNING! Missing element definition. Please check your elements.yml file."
314
+ element_deprecated: "WARNING! This element is deprecated and will be removed soon. Please do not use it anymore."
299
315
  page_definition_missing: "WARNING! Missing page layout definition. Please check your page_layouts.yml file."
300
316
  "Welcome to Alchemy": "Welcome to Alchemy"
301
317
  "Who else is online": "Who else is online"
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Alchemy
3
- Deprecation = ActiveSupport::Deprecation.new("5.1", "Alchemy")
3
+ Deprecation = ActiveSupport::Deprecation.new("6.0", "Alchemy")
4
4
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ class ElementDefinition
5
+ class << self
6
+ # Returns the definitions from elements.yml file.
7
+ #
8
+ # Place a +elements.yml+ file inside your apps +config/alchemy+ folder to define
9
+ # your own set of elements
10
+ #
11
+ def all
12
+ @definitions ||= read_definitions_file.map(&:with_indifferent_access)
13
+ end
14
+
15
+ # Add additional page definitions to collection.
16
+ #
17
+ # Useful for extending the elements from an Alchemy module.
18
+ #
19
+ # === Usage Example
20
+ #
21
+ # Call +Alchemy::ElementDefinition.add(your_definition)+ in your engine.rb file.
22
+ #
23
+ # @param [Array || Hash]
24
+ # You can pass a single element definition as Hash, or a collection of elements as Array.
25
+ #
26
+ def add(element)
27
+ all
28
+ if element.is_a?(Array)
29
+ @definitions += element
30
+ elsif element.is_a?(Hash)
31
+ @definitions << element
32
+ else
33
+ raise TypeError
34
+ end
35
+ end
36
+
37
+ # Returns one element definition by given name.
38
+ #
39
+ def get(name)
40
+ return {} if name.blank?
41
+
42
+ all.detect { |a| a["name"] == name }
43
+ end
44
+
45
+ private
46
+
47
+ # Reads the element definitions from +config/alchemy/elements.yml+.
48
+ #
49
+ def read_definitions_file
50
+ if File.exist?(definitions_file_path)
51
+ YAML.safe_load(
52
+ ERB.new(File.read(definitions_file_path)).result,
53
+ YAML_WHITELIST_CLASSES,
54
+ [],
55
+ true
56
+ ) || []
57
+ else
58
+ raise LoadError,
59
+ "Could not find elements.yml file! Please run `rails generate alchemy:install`"
60
+ end
61
+ end
62
+
63
+ # Returns the elements.yml file path
64
+ #
65
+ def definitions_file_path
66
+ Rails.root.join "config/alchemy/elements.yml"
67
+ end
68
+ end
69
+ end
70
+ end
@@ -26,8 +26,6 @@ module Alchemy
26
26
  # Randomize the output of elements
27
27
  # @option options [Boolean] :reverse (false)
28
28
  # Reverse the load order
29
- # @option options [Hash] :fallback
30
- # Define elements that are loaded from another page if no element was found on given page.
31
29
  def initialize(options = {})
32
30
  @options = options
33
31
  end
@@ -83,6 +81,9 @@ module Alchemy
83
81
  when Alchemy::Page
84
82
  page_or_layout
85
83
  when String
84
+ Alchemy::Deprecation.warn "Passing a String as `from_page` option to " \
85
+ "`render_elements` is deprecated and will be removed with Alchemy 6.0. " \
86
+ "Please load the page beforehand and pass it as an object instead."
86
87
  Alchemy::Page.find_by(
87
88
  language: Alchemy::Language.current,
88
89
  page_layout: page_or_layout,
@@ -92,6 +93,9 @@ module Alchemy
92
93
  end
93
94
 
94
95
  def fallback_required?(elements)
96
+ if options[:fallback]
97
+ Alchemy::Deprecation.warn "Passing `fallback` options to `render_elements` is deprecated an will be removed with Alchemy 6.0."
98
+ end
95
99
  options[:fallback] && elements
96
100
  .where(Alchemy::Element.table_name => {name: options[:fallback][:for]})
97
101
  .none?
@@ -83,7 +83,7 @@ module Alchemy #:nodoc:
83
83
 
84
84
  if configuration[:belongs_to]
85
85
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
86
- belongs_to :ingredient_association, #{configuration[:belongs_to]}
86
+ belongs_to :ingredient_association, **#{configuration[:belongs_to]}
87
87
 
88
88
  alias_method :#{configuration[:ingredient_column]}, :ingredient_association
89
89
  alias_method :#{configuration[:ingredient_column]}=, :ingredient_association=
@@ -108,9 +108,9 @@ module Alchemy #:nodoc:
108
108
  # Register the current class as has_many association on +Alchemy::Page+ and +Alchemy::Element+ models
109
109
  def register_as_essence_association!
110
110
  klass_name = model_name.to_s
111
- arguments = [:has_many, klass_name.demodulize.tableize.to_sym, through: :contents,
112
- source: :essence, source_type: klass_name]
113
- %w(Page Element).each { |k| "Alchemy::#{k}".constantize.send(*arguments) }
111
+ arguments = [:has_many, klass_name.demodulize.tableize.to_sym]
112
+ kwargs = { through: :contents, source: :essence, source_type: klass_name }
113
+ %w(Page Element).each { |k| "Alchemy::#{k}".constantize.send(*arguments, **kwargs) }
114
114
  end
115
115
  end
116
116
 
@@ -40,7 +40,20 @@ module Alchemy
40
40
  EXCEL_FILE_TYPES = [
41
41
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
42
42
  "application/vnd.ms-excel",
43
+ "application/msexcel",
43
44
  "text/csv",
44
45
  ]
46
+
47
+ WORD_FILE_TYPES = [
48
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
49
+ "application/vnd.ms-word",
50
+ "application/msword",
51
+ ]
52
+
53
+ POWERPOINT_FILE_TYPES = [
54
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
55
+ "application/vnd.ms-powerpoint",
56
+ "application/mspowerpoint",
57
+ ]
45
58
  end
46
59
  end
@@ -11,7 +11,7 @@ module Alchemy
11
11
  if object.respond_to?(:attribute_fixed?) && object.attribute_fixed?(attribute_name)
12
12
  options[:disabled] = true
13
13
  options[:input_html] = options.fetch(:input_html, {}).merge(
14
- "data-alchemy-tooltip" => Alchemy.t(:attribute_fixed, attribute_name),
14
+ "data-alchemy-tooltip" => Alchemy.t(:attribute_fixed, attribute: attribute_name),
15
15
  )
16
16
  end
17
17
 
data/lib/alchemy/i18n.rb CHANGED
@@ -12,8 +12,8 @@ module Alchemy
12
12
  #
13
13
  # Alchemy.t(:hello)
14
14
  #
15
- def t(msg, *args)
16
- Alchemy::I18n.translate(msg, *args)
15
+ def t(msg, **kwargs)
16
+ Alchemy::I18n.translate(msg, **kwargs)
17
17
  end
18
18
  end
19
19
 
@@ -47,11 +47,10 @@ module Alchemy
47
47
  # world:
48
48
  # hello: Hallo
49
49
  #
50
- def translate(msg, *args)
51
- options = args.extract_options!
50
+ def translate(msg, **options)
52
51
  humanize_default_string!(msg, options)
53
52
  scope = alchemy_scoped_scope(options)
54
- ::I18n.t(msg, options.merge(scope: scope))
53
+ ::I18n.t(msg, **options.merge(scope: scope))
55
54
  end
56
55
 
57
56
  def available_locales
@@ -74,6 +74,7 @@ module Alchemy
74
74
  end
75
75
  mapped_layouts_for_select(layouts)
76
76
  end
77
+ deprecate :layouts_with_own_for_select, deprecator: Alchemy::Deprecation
77
78
 
78
79
  # Returns all layouts that can be used for creating a new page.
79
80
  #
@@ -132,7 +132,9 @@ module Alchemy
132
132
  end
133
133
 
134
134
  def namespaced_resource_name
135
- @_namespaced_resource_name ||= namespaced_resources_name.singularize
135
+ @_namespaced_resource_name ||= begin
136
+ namespaced_resources_name.to_s.singularize
137
+ end.to_sym # Rails >= 6.0.3.7 needs symbols in polymorphic routes
136
138
  end
137
139
 
138
140
  def namespaced_resources_name
@@ -140,13 +142,13 @@ module Alchemy
140
142
  resource_name_array = resource_array.dup
141
143
  resource_name_array.delete(engine_name) if in_engine?
142
144
  resource_name_array.join("_")
143
- end
145
+ end.to_sym # Rails >= 6.0.3.7 needs symbols in polymorphic routes
144
146
  end
145
147
 
146
148
  def namespace_for_scope
147
149
  namespace_array = namespace_diff
148
150
  namespace_array.delete(engine_name) if in_engine?
149
- namespace_array
151
+ namespace_array.map(&:to_sym) # Rails >= 6.0.3.7 needs symbols in polymorphic routes
150
152
  end
151
153
 
152
154
  # Returns an array of underscored association names
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module TestSupport
5
+ class << self
6
+ def factory_paths
7
+ Dir[
8
+ ::Alchemy::Engine.root.join("lib", "alchemy", "test_support", "factories", "*_factory.rb")
9
+ ].map { |path| path.sub(/.rb\z/, "") }
10
+ end
11
+ deprecate factory_paths: :factories_path, deprecator: Alchemy::Deprecation
12
+
13
+ def factories_path
14
+ ::Alchemy::Engine.root.join("lib", "alchemy", "test_support", "factories")
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "shoulda-matchers"
4
- require "alchemy/test_support/factories/page_factory"
5
- require "alchemy/test_support/factories/element_factory"
6
- require "alchemy/test_support/factories/content_factory"
7
4
 
8
5
  RSpec.shared_examples_for "an essence" do
9
6
  let(:element) { Alchemy::Element.new }
@@ -1,5 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ Alchemy::Deprecation.warn <<~MSG
4
+ Please require factories using FactoryBots preferred approach:
5
+
6
+ # spec/rails_helper.rb
7
+
8
+ require 'alchemy/test_support'
9
+
10
+ FactoryBot.definition_file_paths.append(Alchemy::TestSupport.factories_path)
11
+ FactoryBot.find_definitions
12
+ MSG
13
+
3
14
  Dir["#{File.dirname(__FILE__)}/factories/*.rb"].sort.each do |file|
4
15
  require file
5
16
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "factory_bot"
4
-
5
3
  FactoryBot.define do
6
4
  factory :alchemy_attachment, class: "Alchemy::Attachment" do
7
5
  file do
@@ -1,11 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "factory_bot"
4
- require "alchemy/test_support/factories/element_factory"
5
- require "alchemy/test_support/factories/essence_file_factory"
6
- require "alchemy/test_support/factories/essence_picture_factory"
7
- require "alchemy/test_support/factories/essence_text_factory"
8
-
9
3
  FactoryBot.define do
10
4
  factory :alchemy_content, class: "Alchemy::Content" do
11
5
  name { "text" }
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "factory_bot"
4
-
5
3
  FactoryBot.define do
6
4
  factory :alchemy_dummy_user, class: "DummyUser" do
7
5
  sequence(:email) { |n| "john.#{n}@doe.com" }
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "factory_bot"
4
- require "alchemy/test_support/factories/page_factory"
5
-
6
3
  FactoryBot.define do
7
4
  factory :alchemy_element, class: "Alchemy::Element" do
8
5
  name { "article" }
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "factory_bot"
4
- require "alchemy/test_support/factories/attachment_factory"
5
-
6
3
  FactoryBot.define do
7
4
  factory :alchemy_essence_file, class: "Alchemy::EssenceFile" do
8
5
  attachment factory: :alchemy_attachment
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "factory_bot"
4
- require "alchemy/test_support/factories/page_factory"
5
-
6
3
  FactoryBot.define do
7
4
  factory :alchemy_essence_page, class: "Alchemy::EssencePage" do
8
5
  page factory: :alchemy_page
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "factory_bot"
4
- require "alchemy/test_support/factories/content_factory"
5
- require "alchemy/test_support/factories/picture_factory"
6
-
7
3
  FactoryBot.define do
8
4
  factory :alchemy_essence_picture, class: "Alchemy::EssencePicture" do
9
5
  picture factory: :alchemy_picture
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "factory_bot"
4
-
5
3
  FactoryBot.define do
6
4
  factory :alchemy_essence_text, class: "Alchemy::EssenceText" do
7
5
  body { "This is a headline" }
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "factory_bot"
4
- require "alchemy/test_support/factories/site_factory"
5
-
6
3
  FactoryBot.define do
7
4
  factory :alchemy_language, class: "Alchemy::Language" do
8
5
  name { "Your Language" }