maglevcms 1.2.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/app/components/maglev/content/builder.rb +3 -1
  3. data/app/components/maglev/content/checkbox.rb +7 -1
  4. data/app/components/maglev/content/void.rb +11 -0
  5. data/app/controllers/concerns/maglev/fetchers_concern.rb +2 -1
  6. data/app/controllers/concerns/maglev/rendering_concern.rb +0 -2
  7. data/app/controllers/maglev/editor_controller.rb +4 -0
  8. data/app/frontend/admin/controllers/screenshot_controller.js +1 -1
  9. data/app/frontend/editor/components/dynamic-form/dynamic-input.vue +30 -10
  10. data/app/frontend/editor/components/dynamic-form/index.vue +2 -0
  11. data/app/frontend/editor/components/kit/color-input/core-input.vue +1 -1
  12. data/app/frontend/editor/components/kit/color-input.vue +1 -1
  13. data/app/frontend/editor/components/kit/divider.vue +22 -0
  14. data/app/frontend/editor/components/kit/hint.vue +12 -0
  15. data/app/frontend/editor/components/kit/index.js +4 -0
  16. data/app/frontend/editor/components/page/form/seo.vue +1 -1
  17. data/app/frontend/editor/components/section-block-pane/setting-list.vue +4 -0
  18. data/app/frontend/editor/components/section-highlighter/top-left-actions.vue +7 -1
  19. data/app/frontend/editor/components/section-list/list-item.vue +6 -1
  20. data/app/frontend/editor/components/section-pane/index.vue +2 -1
  21. data/app/frontend/editor/components/section-pane/setting-list.vue +4 -0
  22. data/app/frontend/editor/components/style-pane/index.vue +4 -0
  23. data/app/frontend/editor/locales/editor.fr.json +8 -2
  24. data/app/frontend/editor/locales/editor.pt-BR.json +257 -0
  25. data/app/frontend/editor/locales/index.js +3 -0
  26. data/app/frontend/editor/mixins/global.js +16 -0
  27. data/app/frontend/editor/router/index.js +1 -2
  28. data/app/frontend/editor/views/content-pane.vue +2 -2
  29. data/app/models/concerns/maglev/sections_concern.rb +17 -13
  30. data/app/models/concerns/maglev/translatable.rb +4 -0
  31. data/app/models/maglev/page.rb +6 -0
  32. data/app/models/maglev/section/setting.rb +22 -25
  33. data/app/models/maglev/setting_types/base.rb +10 -0
  34. data/app/models/maglev/setting_types/checkbox.rb +9 -0
  35. data/app/models/maglev/setting_types/collection_item.rb +13 -0
  36. data/app/models/maglev/setting_types/color.rb +6 -0
  37. data/app/models/maglev/setting_types/divider.rb +9 -0
  38. data/app/models/maglev/setting_types/hint.rb +9 -0
  39. data/app/models/maglev/setting_types/icon.rb +9 -0
  40. data/app/models/maglev/setting_types/image.rb +13 -0
  41. data/app/models/maglev/setting_types/link.rb +13 -0
  42. data/app/models/maglev/setting_types/select.rb +6 -0
  43. data/app/models/maglev/setting_types/text.rb +6 -0
  44. data/app/models/maglev/site/locales_concern.rb +12 -1
  45. data/app/models/maglev/site.rb +4 -0
  46. data/app/models/maglev/theme/style_setting.rb +1 -1
  47. data/app/models/maglev/theme.rb +35 -0
  48. data/app/services/maglev/add_site_locale.rb +64 -0
  49. data/app/services/maglev/app_container.rb +1 -0
  50. data/app/services/maglev/change_site_locales.rb +1 -1
  51. data/app/services/maglev/fetch_page.rb +7 -1
  52. data/app/services/maglev/fetch_section_screenshot_path.rb +1 -1
  53. data/app/services/maglev/get_page_fullpath.rb +5 -1
  54. data/app/services/maglev/persist_page.rb +15 -11
  55. data/lib/maglev/active_storage.rb +2 -2
  56. data/lib/maglev/engine.rb +6 -2
  57. data/lib/maglev/errors.rb +7 -0
  58. data/lib/maglev/preview_constraint.rb +15 -1
  59. data/lib/maglev/version.rb +1 -1
  60. metadata +23 -7
@@ -21,5 +21,9 @@ module Maglev
21
21
  def find_section(type)
22
22
  sections&.find { |section| section['type'] == type }
23
23
  end
24
+
25
+ def translate_in(locale, source_locale)
26
+ translate_attr_in(:sections, locale, source_locale)
27
+ end
24
28
  end
25
29
  end
@@ -10,7 +10,7 @@ class Maglev::Theme::StyleSetting
10
10
 
11
11
  ## validations ##
12
12
  validates :id, :label, :type, :default, 'maglev/presence': true
13
- validates :type, inclusion: { in: %w[text color select checkbox] }
13
+ validates :type, inclusion: { in: %w[text color select checkbox divider hint] }
14
14
 
15
15
  ## methods ##
16
16
 
@@ -12,5 +12,40 @@ module Maglev
12
12
  validates :id, :name, presence: true
13
13
 
14
14
  ## methods ##
15
+
16
+ def find_setting!(section_id, block_id, setting_id)
17
+ setting = find_setting(section_id, block_id, setting_id)
18
+ raise Maglev::Errors::UnknownSetting.new(section_id, block_id, setting_id) if setting.nil?
19
+
20
+ setting
21
+ end
22
+
23
+ def find_setting(section_id, block_id, setting_id)
24
+ key = [section_id, block_id, setting_id].compact.join('.')
25
+ section_setting_types[key]
26
+ end
27
+
28
+ private
29
+
30
+ def section_setting_types
31
+ @section_setting_types ||= build_section_setting_types
32
+ end
33
+
34
+ def build_section_setting_types
35
+ hash = {}
36
+ sections.each do |section|
37
+ build_section_setting_types_from_settings(hash, section.id, section.settings)
38
+ section.blocks.each do |block|
39
+ build_section_setting_types_from_settings(hash, "#{section.id}.#{block.type}", block.settings)
40
+ end
41
+ end
42
+ hash
43
+ end
44
+
45
+ def build_section_setting_types_from_settings(hash, parent_key, settings)
46
+ settings.each do |setting|
47
+ hash["#{parent_key}.#{setting.id}"] = setting
48
+ end
49
+ end
15
50
  end
16
51
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Maglev
4
+ # Add a locale (instace of Maglev::Site::Locale) to a site
5
+ class AddSiteLocale
6
+ include Injectable
7
+
8
+ argument :site
9
+ argument :locale
10
+
11
+ def call
12
+ return if locale.blank? || !site.add_locale(locale)
13
+
14
+ ActiveRecord::Base.transaction do
15
+ unsafe_call
16
+ end
17
+ end
18
+
19
+ protected
20
+
21
+ def unsafe_call
22
+ # Set a default content for site_scoped sections
23
+ apply_to_site
24
+
25
+ site.save! # persist the new locale
26
+
27
+ # add a default content in the new locale to all the pages of the site
28
+ # based on the default locale. Also take care of the path.
29
+ apply_to_pages
30
+
31
+ true
32
+ end
33
+
34
+ def apply_to_site
35
+ Maglev::I18n.with_locale(locale.prefix) do
36
+ site.translate_in(locale.prefix, site.default_locale_prefix)
37
+ end
38
+ end
39
+
40
+ def apply_to_pages
41
+ resources.find_each do |page|
42
+ # the path will be the same as in the default locale
43
+ Maglev::I18n.with_locale(locale.prefix) do
44
+ page.path = default_page_path(page)
45
+ end
46
+
47
+ # set a default content which will be the same as in the default locale
48
+ page.translate_in(locale.prefix, site.default_locale_prefix)
49
+
50
+ page.save!
51
+ end
52
+ end
53
+
54
+ def default_page_path(page)
55
+ # we can't rely on page.default_path because the service can be called outside a HTTP request
56
+ # and so we don't know for sure if Maglev::I18n.default_locale has been correctly set.
57
+ page.paths.find_by(locale: site.default_locale.prefix)&.value
58
+ end
59
+
60
+ def resources
61
+ ::Maglev::Page
62
+ end
63
+ end
64
+ end
@@ -31,6 +31,7 @@ module Maglev
31
31
  dependency :persist_section_screenshot, class: Maglev::PersistSectionScreenshot,
32
32
  depends_on: %i[fetch_theme fetch_section_screenshot_path]
33
33
 
34
+ dependency :add_site_locale, class: Maglev::AddSiteLocale
34
35
  dependency :change_site_locales, class: Maglev::ChangeSiteLocales
35
36
 
36
37
  dependency :fetch_page, class: Maglev::FetchPage, depends_on: :fetch_site
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Maglev
4
4
  # Change the locales of a site.
5
- # The new locales are an array of maps with 2 required keys: :name & :prefix.
5
+ # The new locales are an array of Maglev::Site::Locale objects
6
6
  class ChangeSiteLocales
7
7
  include Injectable
8
8
 
@@ -10,6 +10,7 @@ module Maglev
10
10
  argument :locale
11
11
  argument :default_locale
12
12
  argument :fallback_to_default_locale, default: false
13
+ argument :only_visible, default: false
13
14
 
14
15
  def call
15
16
  page = fetch_page(path, locale)
@@ -20,7 +21,12 @@ module Maglev
20
21
  protected
21
22
 
22
23
  def fetch_page(path, locale)
23
- Maglev::Page.by_path(path || 'index', locale).first
24
+ page = pages.by_path(path || 'index', locale).first
25
+ !only_visible || (page&.visible? && only_visible) ? page : nil
26
+ end
27
+
28
+ def pages
29
+ Maglev::Page
24
30
  end
25
31
  end
26
32
  end
@@ -11,7 +11,7 @@ module Maglev
11
11
 
12
12
  def call
13
13
  path = "#{fetch_sections_path.call(theme: theme)}/#{section.category}/#{section.id}.jpg"
14
- absolute ? "#{Rails.root}/public/#{path}" : "/#{path}"
14
+ absolute ? Rails.root.join("public/#{path}").to_s : "/#{path}"
15
15
  end
16
16
  end
17
17
  end
@@ -44,7 +44,7 @@ module Maglev
44
44
 
45
45
  def build_fullpath(base_url, path)
46
46
  fullpath = [base_url]
47
- fullpath.push(locale) unless same_as_default_locale?
47
+ fullpath.push(locale) if prefix_by_default_locale?
48
48
  fullpath.push(path) unless path == 'index' # for SEO purpose)
49
49
  fullpath.push(nil) if fullpath == [nil] # avoid "" as the fullpath
50
50
  fullpath.join('/')
@@ -54,6 +54,10 @@ module Maglev
54
54
  @site ||= fetch_site.call
55
55
  end
56
56
 
57
+ def prefix_by_default_locale?
58
+ !same_as_default_locale?
59
+ end
60
+
57
61
  def same_as_default_locale?
58
62
  locale.to_s == default_locale.to_s
59
63
  end
@@ -29,9 +29,9 @@ module Maglev
29
29
  # the sections_translations attribute is put by the SetupPages service
30
30
  # when we generate a brand new site
31
31
  if page_attributes.key?(:sections_translations)
32
- page.prepare_sections_translations
32
+ page.prepare_sections_translations(theme)
33
33
  else
34
- page.prepare_sections
34
+ page.prepare_sections(theme)
35
35
  end
36
36
 
37
37
  page.save!
@@ -40,15 +40,7 @@ module Maglev
40
40
  def persist_site!
41
41
  return unless can_persist_site?
42
42
 
43
- # the sections_translations attribute is put by the SetupPages service
44
- # when we generate a brand new site
45
- if site_attributes.key?(:sections_translations)
46
- site.attributes = site_attributes
47
- site.prepare_sections_translations
48
- else
49
- site.attributes = site_attributes_with_consistent_sections
50
- site.prepare_sections
51
- end
43
+ assign_sections_to_site
52
44
 
53
45
  site.save!
54
46
  end
@@ -89,5 +81,17 @@ module Maglev
89
81
  site_attributes[:sections_translations].present?
90
82
  )
91
83
  end
84
+
85
+ def assign_sections_to_site
86
+ # the sections_translations attribute is put by the SetupPages service
87
+ # when we generate a brand new site
88
+ if site_attributes.key?(:sections_translations)
89
+ site.attributes = site_attributes
90
+ site.prepare_sections_translations(theme)
91
+ else
92
+ site.attributes = site_attributes_with_consistent_sections
93
+ site.prepare_sections(theme)
94
+ end
95
+ end
92
96
  end
93
97
  end
@@ -5,10 +5,10 @@ module Maglev
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- after_commit :save_metadata_now, on: :create
9
-
10
8
  has_one_attached :file
11
9
 
10
+ after_commit :save_metadata_now, on: :create, prepend: true
11
+
12
12
  delegate :url, :download, to: :file
13
13
  end
14
14
 
data/lib/maglev/engine.rb CHANGED
@@ -54,7 +54,9 @@ module Maglev
54
54
  urls: ["/#{vite_ruby.config.public_output_dir}"],
55
55
  root: root.join(vite_ruby.config.public_dir),
56
56
  header_rules: [
57
- [:all, { "Access-Control-Allow-Origin": '*' }]
57
+ # rubocop:disable Style/StringHashKeys
58
+ [:all, { 'Access-Control-Allow-Origin' => '*' }]
59
+ # rubocop:enable Style/StringHashKeys
58
60
  ]
59
61
  else
60
62
  # mostly when running the application in production behind NGINX or APACHE
@@ -63,7 +65,9 @@ module Maglev
63
65
  urls: ["/#{vite_ruby.config.public_output_dir}"],
64
66
  root: root.join(vite_ruby.config.public_dir),
65
67
  header_rules: [
66
- [:all, { "Access-Control-Allow-Origin": '*' }]
68
+ # rubocop:disable Style/StringHashKeys
69
+ [:all, { 'Access-Control-Allow-Origin' => '*' }]
70
+ # rubocop:enable Style/StringHashKeys
67
71
  ]
68
72
  end
69
73
  end
data/lib/maglev/errors.rb CHANGED
@@ -4,5 +4,12 @@ module Maglev
4
4
  module Errors
5
5
  class NotAuthorized < StandardError; end
6
6
  class UnknownSection < StandardError; end
7
+
8
+ class UnknownSetting < StandardError
9
+ def initialize(section_id, block_id, setting_id)
10
+ key = [section_id, block_id].compact.join('.')
11
+ super("[#{key}] The #{setting_id} setting is undeclared OR its type is unknown.")
12
+ end
13
+ end
7
14
  end
8
15
  end
@@ -4,6 +4,8 @@ require 'uri'
4
4
 
5
5
  module Maglev
6
6
  class PreviewConstraint
7
+ CRAWLER_USER_AGENTS = /Googlebot|Twitterbot|facebookexternalhit/o.freeze
8
+
7
9
  attr_reader :preview_host
8
10
 
9
11
  def initialize(preview_host: nil)
@@ -11,7 +13,7 @@ module Maglev
11
13
  end
12
14
 
13
15
  def matches?(request)
14
- %i[html xml].include?(request.format.symbol) && (!preview_host || preview_host == request.host)
16
+ (accepted_format?(request) || crawler?(request)) && match_host?(request)
15
17
  end
16
18
 
17
19
  protected
@@ -21,5 +23,17 @@ module Maglev
21
23
 
22
24
  URI.parse(Maglev.config.preview_host).host # make sure we get only the host here
23
25
  end
26
+
27
+ def accepted_format?(request)
28
+ %i[html xml].include?(request.format.symbol)
29
+ end
30
+
31
+ def crawler?(request)
32
+ request.format.symbol.nil? && CRAWLER_USER_AGENTS.match?(request.user_agent)
33
+ end
34
+
35
+ def match_host?(request)
36
+ !preview_host || preview_host == request.host
37
+ end
24
38
  end
25
39
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Maglev
4
- VERSION = '1.2.2'
4
+ VERSION = '1.4.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maglevcms
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Didier Lafforgue
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-08 00:00:00.000000000 Z
11
+ date: 2023-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jbuilder
@@ -56,9 +56,9 @@ dependencies:
56
56
  name: rails
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "<="
59
+ - - "<"
60
60
  - !ruby/object:Gem::Version
61
- version: '7.1'
61
+ version: '7.2'
62
62
  - - ">="
63
63
  - !ruby/object:Gem::Version
64
64
  version: '6'
@@ -66,9 +66,9 @@ dependencies:
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
68
68
  requirements:
69
- - - "<="
69
+ - - "<"
70
70
  - !ruby/object:Gem::Version
71
- version: '7.1'
71
+ version: '7.2'
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: '6'
@@ -133,6 +133,7 @@ files:
133
133
  - app/components/maglev/content/link.rb
134
134
  - app/components/maglev/content/select.rb
135
135
  - app/components/maglev/content/text.rb
136
+ - app/components/maglev/content/void.rb
136
137
  - app/components/maglev/page_component.rb
137
138
  - app/components/maglev/section_component.rb
138
139
  - app/components/maglev/tag_helper.rb
@@ -551,7 +552,9 @@ files:
551
552
  - app/frontend/editor/components/kit/color-input/preset-button.vue
552
553
  - app/frontend/editor/components/kit/color-input/preset-dropdown.vue
553
554
  - app/frontend/editor/components/kit/confirmation-button.vue
555
+ - app/frontend/editor/components/kit/divider.vue
554
556
  - app/frontend/editor/components/kit/dropdown.vue
557
+ - app/frontend/editor/components/kit/hint.vue
555
558
  - app/frontend/editor/components/kit/icon-input.vue
556
559
  - app/frontend/editor/components/kit/icon.vue
557
560
  - app/frontend/editor/components/kit/image-input.vue
@@ -625,6 +628,7 @@ files:
625
628
  - app/frontend/editor/locales/editor.en.json
626
629
  - app/frontend/editor/locales/editor.es.json
627
630
  - app/frontend/editor/locales/editor.fr.json
631
+ - app/frontend/editor/locales/editor.pt-BR.json
628
632
  - app/frontend/editor/locales/index.js
629
633
  - app/frontend/editor/main.js
630
634
  - app/frontend/editor/misc/__tests__/utils.spec.js
@@ -719,6 +723,17 @@ files:
719
723
  - app/models/maglev/section/block.rb
720
724
  - app/models/maglev/section/content_concern.rb
721
725
  - app/models/maglev/section/setting.rb
726
+ - app/models/maglev/setting_types/base.rb
727
+ - app/models/maglev/setting_types/checkbox.rb
728
+ - app/models/maglev/setting_types/collection_item.rb
729
+ - app/models/maglev/setting_types/color.rb
730
+ - app/models/maglev/setting_types/divider.rb
731
+ - app/models/maglev/setting_types/hint.rb
732
+ - app/models/maglev/setting_types/icon.rb
733
+ - app/models/maglev/setting_types/image.rb
734
+ - app/models/maglev/setting_types/link.rb
735
+ - app/models/maglev/setting_types/select.rb
736
+ - app/models/maglev/setting_types/text.rb
722
737
  - app/models/maglev/site.rb
723
738
  - app/models/maglev/site/locale.rb
724
739
  - app/models/maglev/site/locales_concern.rb
@@ -730,6 +745,7 @@ files:
730
745
  - app/services/concerns/maglev/get_page_sections/transform_collection_item_concern.rb
731
746
  - app/services/concerns/maglev/get_page_sections/transform_link_concern.rb
732
747
  - app/services/concerns/maglev/get_page_sections/transform_text_concern.rb
748
+ - app/services/maglev/add_site_locale.rb
733
749
  - app/services/maglev/app_container.rb
734
750
  - app/services/maglev/change_site_locales.rb
735
751
  - app/services/maglev/clone_page.rb
@@ -845,7 +861,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
845
861
  - !ruby/object:Gem::Version
846
862
  version: '0'
847
863
  requirements: []
848
- rubygems_version: 3.2.32
864
+ rubygems_version: 3.3.26
849
865
  signing_key:
850
866
  specification_version: 4
851
867
  summary: Page builder Ruby on Rails