alchemy_cms 6.0.1 → 6.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ccd47bae7272d0d8cb44b6d9c63cd8b72df01f086eff929819164d267af6bf1
4
- data.tar.gz: d18a5f8105f242cef352e0c57d6d21743aedfdd75cc373bbf4205fd3d2cac5f1
3
+ metadata.gz: e9bfd92678d3b4ae867e8c3938a0277d7698fb6fbcfb80a0210f0c4371990486
4
+ data.tar.gz: ce854781846eadaecdbe717ab435a38d357cda54863707b2c62a61cf4730884b
5
5
  SHA512:
6
- metadata.gz: 81b2e1e18d80a8cce6316286e91063e9363ded99c991de526f0155d98f9954a3986487bec834205847f364c883ecb8959777a55fbe14fdfdb9409f32818376fa
7
- data.tar.gz: 39086e8836ff34ec6eb7abf76403b2f6a0515e6d46e6f77f76fe81b480f6a9cba65ae1ba3e0af390f79d8234d42f5ab218fd50ea14643e3ac8d89594de8bb1a2
6
+ metadata.gz: 51391e56da530c900189d8c16b756d9084fac351cfc50ebc2ee9b7181d7148c826daf39bdd284100261aa6e4ae5c1a4f28eb266c1a31d9fd1ad31f21e2cda398
7
+ data.tar.gz: 244eb43ca4783a572c5885c69571264a50d4154a5ccfc8b5af806f1343497cc38a8157a1b8c039262d60ea8f4cd6a3a19777943ca9b1c0654a6cd473d3f9f025
@@ -20,6 +20,7 @@ jobs:
20
20
  database:
21
21
  - mysql
22
22
  - postgresql
23
+ - mariadb
23
24
  exclude:
24
25
  - rails: "6.0"
25
26
  ruby: "3.1"
@@ -27,12 +28,18 @@ jobs:
27
28
  - rails: "6.0"
28
29
  ruby: "3.1"
29
30
  database: postgresql
31
+ - rails: "6.0"
32
+ ruby: "3.1"
33
+ database: mariadb
30
34
  - rails: "7.0"
31
35
  ruby: "2.6"
32
36
  database: mysql
33
37
  - rails: "7.0"
34
38
  ruby: "2.6"
35
39
  database: postgresql
40
+ - rails: "7.0"
41
+ ruby: "2.6"
42
+ database: mariadb
36
43
  env:
37
44
  DB: ${{ matrix.database }}
38
45
  DB_USER: alchemy_user
@@ -58,6 +65,15 @@ jobs:
58
65
  MYSQL_DATABASE: alchemy_cms_dummy_test
59
66
  MYSQL_ROOT_PASSWORD: password
60
67
  options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5
68
+ mariadb:
69
+ image: mariadb:latest
70
+ ports: ["3307:3306"]
71
+ env:
72
+ MARIADB_USER: alchemy_user
73
+ MARIADB_PASSWORD: password
74
+ MARIADB_DATABASE: alchemy_cms_dummy_test
75
+ MARIADB_ROOT_PASSWORD: password
76
+ options: --health-cmd="mariadb-admin ping" --health-interval=10s --health-timeout=5s --health-retries=5
61
77
  steps:
62
78
  - uses: actions/checkout@v2.3.4
63
79
  - name: Set up Ruby
@@ -81,7 +97,7 @@ jobs:
81
97
  sudo apt install -qq --fix-missing libpq-dev -o dir::cache::archives="/home/runner/apt/cache"
82
98
  sudo chown -R runner /home/runner/apt/cache
83
99
  - name: Install MySQL headers
84
- if: matrix.database == 'mysql'
100
+ if: matrix.database == 'mysql' || matrix.database == 'mariadb'
85
101
  run: |
86
102
  mkdir -p /home/runner/apt/cache
87
103
  sudo apt update -qq
data/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## 6.0.4 (2022-05-06)
2
+
3
+ - Add support for Rails' recycable cache keys [#2334](https://github.com/AlchemyCMS/alchemy_cms/pull/2334) ([tvdeyen](https://github.com/tvdeyen))
4
+ - Make Alchemy::Content::Factory reloadable [#2333](https://github.com/AlchemyCMS/alchemy_cms/pull/2333) ([tvdeyen](https://github.com/tvdeyen))
5
+ - Wrap the result of rendering into an ActiveSupport::SafeBuffer [#2332](https://github.com/AlchemyCMS/alchemy_cms/pull/2332) ([mamhoff](https://github.com/mamhoff))
6
+ - Override Alchemy::Page.ransackable_scopes [#2328](https://github.com/AlchemyCMS/alchemy_cms/pull/2328) ([mamhoff](https://github.com/mamhoff))
7
+ - Default Link Format matcher: Allow tel: protocol [#2327](https://github.com/AlchemyCMS/alchemy_cms/pull/2327) ([mamhoff](https://github.com/mamhoff))
8
+
9
+ ## 6.0.3 (2022-05-02)
10
+
11
+ - Add Support for MariaDB [#2326](https://github.com/AlchemyCMS/alchemy_cms/pull/2326) ([mamhoff](https://github.com/mamhoff))
12
+ - Fix Alchemy::Content::Factory module definition [#2325](https://github.com/AlchemyCMS/alchemy_cms/pull/2325) ([tvdeyen](https://github.com/tvdeyen))
13
+
14
+ ## 6.0.2 (2022-04-27)
15
+
16
+ - Remove JSON decode from ingredient data store [#2323](https://github.com/AlchemyCMS/alchemy_cms/pull/2323) ([tvdeyen](https://github.com/tvdeyen))
17
+ - Eagerload at the controller or job layer [#2313](https://github.com/AlchemyCMS/alchemy_cms/pull/2313) ([mamhoff](https://github.com/mamhoff))
18
+
1
19
  ## 6.0.1 (2022-04-26)
2
20
 
3
21
  - Allow passing a different partial to `render_element` [#2322](https://github.com/AlchemyCMS/alchemy_cms/pull/2322) ([mamhoff](https://github.com/mamhoff))
data/Gemfile CHANGED
@@ -17,7 +17,9 @@ end
17
17
  if ENV["DB"].nil? || ENV["DB"] == "sqlite"
18
18
  gem "sqlite3", "~> 1.4.1"
19
19
  end
20
- gem "mysql2", "~> 0.5.1" if ENV["DB"] == "mysql"
20
+ if ENV["DB"] == "mysql" || ENV["DB"] == "mariadb"
21
+ gem "mysql2", "~> 0.5.1"
22
+ end
21
23
  gem "pg", "~> 1.0" if ENV["DB"] == "postgresql"
22
24
 
23
25
  group :development, :test do
@@ -87,11 +87,13 @@ module Alchemy
87
87
  elements = finder.elements(page_version: page_version)
88
88
 
89
89
  default_rendering = ->(element, i) { render_element(element, options, i + 1) }
90
- if block_given?
91
- elements.map.with_index(&blk)
92
- else
93
- elements.map.with_index(&default_rendering)
94
- end.join(options[:separator]).html_safe
90
+ capture do
91
+ if block_given?
92
+ elements.map.with_index(&blk)
93
+ else
94
+ elements.map.with_index(&default_rendering)
95
+ end.join(options[:separator]).html_safe
96
+ end
95
97
  end
96
98
 
97
99
  # This helper renders a {Alchemy::Element} view partial.
@@ -3,139 +3,141 @@
3
3
  module Alchemy
4
4
  # Holds everything concerning the building and creating of contents and the related essence object.
5
5
  #
6
- module Content::Factory
7
- extend ActiveSupport::Concern
6
+ class Content < BaseRecord
7
+ module Factory
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ SKIPPED_ATTRIBUTES_ON_COPY = %w(position created_at updated_at creator_id updater_id element_id id)
12
+
13
+ # Builds a new content as descriped in the elements.yml file.
14
+ #
15
+ # @param [Hash]
16
+ # The content definition used for finding the content in +elements.yml+ file
17
+ #
18
+ def new(attributes = {})
19
+ element = attributes[:element] || Element.find_by(id: attributes[:element_id])
20
+ return super if attributes.empty? || element.nil?
21
+
22
+ definition = element.content_definition_for(attributes[:name])
23
+ if definition.blank? && attributes[:essence_type].nil?
24
+ raise ContentDefinitionError, "No definition found in elements.yml for #{attributes.inspect} and #{element.inspect}"
25
+ end
26
+
27
+ super(
28
+ name: attributes[:name],
29
+ essence_type: attributes[:essence_type] || normalize_essence_type(definition[:type]),
30
+ element: element,
31
+ ).tap(&:build_essence)
32
+ end
8
33
 
9
- module ClassMethods
10
- SKIPPED_ATTRIBUTES_ON_COPY = %w(position created_at updated_at creator_id updater_id element_id id)
34
+ # Creates a new content from elements definition in the +elements.yml+ file.
35
+ #
36
+ # 1. It builds the content
37
+ # 2. It creates the essence record (content object gets saved)
38
+ #
39
+ # @return [Alchemy::Content]
40
+ #
41
+ def create(attributes = {})
42
+ new(attributes).tap do |content|
43
+ content.essence.save && content.save
44
+ end
45
+ end
11
46
 
12
- # Builds a new content as descriped in the elements.yml file.
13
- #
14
- # @param [Hash]
15
- # The content definition used for finding the content in +elements.yml+ file
16
- #
17
- def new(attributes = {})
18
- element = attributes[:element] || Element.find_by(id: attributes[:element_id])
19
- return super if attributes.empty? || element.nil?
47
+ # Creates a copy of source and also copies the associated essence.
48
+ #
49
+ # You can pass a differences hash to update the attributes of the copy.
50
+ #
51
+ # === Example
52
+ #
53
+ # @copy = Alchemy::Content.copy(@content, {element_id: 3})
54
+ # @copy.element_id # => 3
55
+ #
56
+ def copy(source, differences = {})
57
+ Content.new(
58
+ source.attributes.with_indifferent_access.
59
+ except(*SKIPPED_ATTRIBUTES_ON_COPY).
60
+ merge(differences.with_indifferent_access)
61
+ ).tap do |new_content|
62
+ new_content.build_essence(
63
+ source.essence.attributes.
64
+ except(*SKIPPED_ATTRIBUTES_ON_COPY)
65
+ )
66
+ new_content.save
67
+ end
68
+ end
20
69
 
21
- definition = element.content_definition_for(attributes[:name])
22
- if definition.blank? && attributes[:essence_type].nil?
23
- raise ContentDefinitionError, "No definition found in elements.yml for #{attributes.inspect} and #{element.inspect}"
70
+ # Returns all content definitions from elements.yml
71
+ #
72
+ def definitions
73
+ definitions = Element.definitions.flat_map { |e| e["contents"] }
74
+ definitions.compact!
75
+ definitions
24
76
  end
25
77
 
26
- super(
27
- name: attributes[:name],
28
- essence_type: attributes[:essence_type] || normalize_essence_type(definition[:type]),
29
- element: element
30
- ).tap(&:build_essence)
31
- end
78
+ # Returns a normalized Essence type
79
+ #
80
+ # Adds Alchemy module name in front of given essence type
81
+ # unless there is a Class with the specified name that is an essence.
82
+ #
83
+ # @param [String]
84
+ # the essence type to normalize
85
+ #
86
+ def normalize_essence_type(essence_type)
87
+ essence_type = essence_type.classify
88
+ return essence_type if is_an_essence?(essence_type)
89
+
90
+ "Alchemy::#{essence_type}"
91
+ end
32
92
 
33
- # Creates a new content from elements definition in the +elements.yml+ file.
34
- #
35
- # 1. It builds the content
36
- # 2. It creates the essence record (content object gets saved)
37
- #
38
- # @return [Alchemy::Content]
39
- #
40
- def create(attributes = {})
41
- new(attributes).tap do |content|
42
- content.essence.save && content.save
93
+ private
94
+
95
+ def is_an_essence?(essence_type)
96
+ klass = Module.const_get(essence_type)
97
+ klass.is_a?(Class) && klass.new.acts_as_essence?
98
+ rescue NameError
99
+ false
43
100
  end
44
101
  end
45
102
 
46
- # Creates a copy of source and also copies the associated essence.
47
- #
48
- # You can pass a differences hash to update the attributes of the copy.
49
- #
50
- # === Example
51
- #
52
- # @copy = Alchemy::Content.copy(@content, {element_id: 3})
53
- # @copy.element_id # => 3
103
+ # Instance Methods
104
+
105
+ # Returns the definition hash from +elements.yml+ file.
54
106
  #
55
- def copy(source, differences = {})
56
- Content.new(
57
- source.attributes.with_indifferent_access.
58
- except(*SKIPPED_ATTRIBUTES_ON_COPY).
59
- merge(differences.with_indifferent_access)
60
- ).tap do |new_content|
61
- new_content.build_essence(
62
- source.essence.attributes.
63
- except(*SKIPPED_ATTRIBUTES_ON_COPY)
64
- )
65
- new_content.save
107
+ def definition
108
+ if element.blank?
109
+ log_warning "Content with id #{id} is missing its Element."
110
+ return {}
66
111
  end
112
+ element.content_definition_for(name) || {}
67
113
  end
68
114
 
69
- # Returns all content definitions from elements.yml
115
+ # Build essence from definition.
70
116
  #
71
- def definitions
72
- definitions = Element.definitions.flat_map { |e| e["contents"] }
73
- definitions.compact!
74
- definitions
117
+ # If an optional type is passed, this type of essence gets created.
118
+ #
119
+ def build_essence(attributes = {})
120
+ self.essence = essence_class.new(
121
+ { content: self, ingredient: default_value }.merge(attributes)
122
+ )
75
123
  end
76
124
 
77
- # Returns a normalized Essence type
78
- #
79
- # Adds Alchemy module name in front of given essence type
80
- # unless there is a Class with the specified name that is an essence.
125
+ # Creates essence from definition.
81
126
  #
82
- # @param [String]
83
- # the essence type to normalize
127
+ # If an optional type is passed, this type of essence gets created.
84
128
  #
85
- def normalize_essence_type(essence_type)
86
- essence_type = essence_type.classify
87
- return essence_type if is_an_essence?(essence_type)
88
-
89
- "Alchemy::#{essence_type}"
129
+ def create_essence!(attrs = {})
130
+ build_essence(attrs).save!
131
+ save!
90
132
  end
91
133
 
92
134
  private
93
135
 
94
- def is_an_essence?(essence_type)
95
- klass = Module.const_get(essence_type)
96
- klass.is_a?(Class) && klass.new.acts_as_essence?
97
- rescue NameError
98
- false
99
- end
100
- end
101
-
102
- # Instance Methods
103
-
104
- # Returns the definition hash from +elements.yml+ file.
105
- #
106
- def definition
107
- if element.blank?
108
- log_warning "Content with id #{id} is missing its Element."
109
- return {}
136
+ # Returns a class constant from definition's type field or the essence_type column
137
+ #
138
+ def essence_class
139
+ (essence_type || Content.normalize_essence_type(definition["type"])).constantize
110
140
  end
111
- element.content_definition_for(name) || {}
112
- end
113
-
114
- # Build essence from definition.
115
- #
116
- # If an optional type is passed, this type of essence gets created.
117
- #
118
- def build_essence(attributes = {})
119
- self.essence = essence_class.new(
120
- { content: self, ingredient: default_value }.merge(attributes)
121
- )
122
- end
123
-
124
- # Creates essence from definition.
125
- #
126
- # If an optional type is passed, this type of essence gets created.
127
- #
128
- def create_essence!(attrs = {})
129
- build_essence(attrs).save!
130
- save!
131
- end
132
-
133
- private
134
-
135
- # Returns a class constant from definition's type field or the essence_type column
136
- #
137
- def essence_class
138
- (essence_type || Content.normalize_essence_type(definition["type"])).constantize
139
141
  end
140
142
  end
141
143
  end
@@ -16,13 +16,15 @@
16
16
  # updater_id :integer
17
17
  #
18
18
 
19
+ require_dependency "alchemy/content/factory"
20
+
19
21
  module Alchemy
20
22
  class Content < BaseRecord
21
23
  include Alchemy::Logger
22
24
  include Alchemy::Hints
23
25
 
24
26
  # Concerns
25
- include Alchemy::Content::Factory
27
+ include Factory
26
28
 
27
29
  belongs_to :essence, polymorphic: true, dependent: :destroy, inverse_of: :content
28
30
  belongs_to :element, touch: true, inverse_of: :contents
@@ -6,12 +6,10 @@ module Alchemy
6
6
 
7
7
  include Hints
8
8
 
9
- # MariaDB needs to be told explicitly to use `data` as a JSON store. All other databases
10
- # can do this natively.
11
- store :data, coder: JSON
12
-
13
9
  self.table_name = "alchemy_ingredients"
14
10
 
11
+ attribute :data, :json
12
+
15
13
  belongs_to :element, touch: true, class_name: "Alchemy::Element", inverse_of: :ingredients
16
14
  belongs_to :related_object, polymorphic: true, optional: true
17
15
 
@@ -103,17 +103,17 @@ module Alchemy
103
103
  page_layout.parameterize.underscore
104
104
  end
105
105
 
106
- # Returns the key that's taken for cache path.
106
+ # Returns the version that's taken for Rails' recycable cache key.
107
107
  #
108
108
  # Uses the +published_at+ value that's updated when the user publishes the page.
109
109
  #
110
- # If the page is the current preview it uses the updated_at value as cache key.
110
+ # If the page is the current preview it uses the +updated_at+ value as cache key.
111
111
  #
112
- def cache_key
112
+ def cache_version
113
113
  if Page.current_preview == id
114
- "alchemy/pages/#{id}-#{updated_at}"
114
+ updated_at.to_s
115
115
  else
116
- "alchemy/pages/#{id}-#{published_at}"
116
+ published_at.to_s
117
117
  end
118
118
  end
119
119
 
@@ -122,6 +122,10 @@ module Alchemy
122
122
  )
123
123
  SQL
124
124
  end
125
+
126
+ def ransackable_scopes(_auth_object)
127
+ [:published, :from_current_site, :searchables, :layoutpages]
128
+ end
125
129
  end
126
130
  end
127
131
  end
@@ -200,7 +200,7 @@ link_target_options: [blank]
200
200
  format_matchers:
201
201
  email: !ruby/regexp '/\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/'
202
202
  url: !ruby/regexp '/\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?\z/ix'
203
- link_url: !ruby/regexp '/^(mailto:|\/|[a-z]+:\/\/)/'
203
+ link_url: !ruby/regexp '/^(tel:|mailto:|\/|[a-z]+:\/\/)/'
204
204
 
205
205
  # The layout used for rendering the +alchemy/admin/pages#show+ action.
206
206
  admin_page_preview_layout: application
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "6.0.1"
4
+ VERSION = "6.0.4"
5
5
 
6
6
  def self.version
7
7
  VERSION
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alchemy_cms/admin",
3
- "version": "6.0.1",
3
+ "version": "6.0.4",
4
4
  "description": "AlchemyCMS",
5
5
  "browser": "package/admin.js",
6
6
  "files": [
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.1
4
+ version: 6.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas von Deyen
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2022-04-26 00:00:00.000000000 Z
16
+ date: 2022-05-06 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: actionmailer