alchemy_cms 6.0.0.pre.b6 → 6.0.0.pre.rc4
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.
- checksums.yaml +4 -4
- data/.github/workflows/brakeman-analysis.yml +46 -0
- data/.github/workflows/ci.yml +4 -3
- data/CHANGELOG.md +35 -0
- data/Gemfile +6 -1
- data/README.md +1 -1
- data/SECURITY.md +13 -0
- data/alchemy_cms.gemspec +3 -3
- data/app/assets/javascripts/alchemy/admin.js +0 -1
- data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +2 -2
- data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +7 -6
- data/app/assets/stylesheets/alchemy/_extends.scss +4 -4
- data/app/assets/stylesheets/alchemy/flatpickr.scss +182 -232
- data/app/assets/stylesheets/tinymce/skins/alchemy/content.min.css.scss +3 -3
- data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +7 -7
- data/app/controllers/alchemy/admin/base_controller.rb +9 -3
- data/app/models/alchemy/attachment.rb +1 -1
- data/app/models/alchemy/element.rb +1 -1
- data/app/models/alchemy/node.rb +1 -1
- data/app/models/alchemy/page.rb +1 -1
- data/app/models/alchemy/picture.rb +1 -1
- data/app/views/alchemy/ingredients/_picture_editor.html.erb +2 -2
- data/config/brakeman.ignore +25 -5
- data/lib/alchemy/engine.rb +8 -1
- data/lib/alchemy/error_tracking/airbrake_handler.rb +13 -0
- data/lib/alchemy/error_tracking.rb +14 -0
- data/lib/alchemy/taggable.rb +11 -4
- data/lib/alchemy/upgrader.rb +6 -0
- data/lib/alchemy/version.rb +1 -1
- data/lib/alchemy_cms.rb +1 -0
- data/lib/generators/alchemy/install/install_generator.rb +2 -1
- data/lib/tasks/alchemy/upgrade.rake +6 -0
- data/package/admin.js +3 -1
- data/package/src/datepicker.js +39 -0
- data/package.json +2 -1
- metadata +44 -39
- data/app/assets/javascripts/alchemy/alchemy.datepicker.js.coffee +0 -29
@@ -30,7 +30,7 @@ td,th {
|
|
30
30
|
|
31
31
|
.mce-object {
|
32
32
|
border: 1px dotted #3a3a3a;
|
33
|
-
background: #d5d5d5 url(img/object.gif) no-repeat center;
|
33
|
+
background: #d5d5d5 url('tinymce/skins/alchemy/fonts/img/object.gif') no-repeat center;
|
34
34
|
}
|
35
35
|
|
36
36
|
.mce-pagebreak {
|
@@ -55,7 +55,7 @@ td,th {
|
|
55
55
|
width: 9px!important;
|
56
56
|
height: 9px!important;
|
57
57
|
border: 1px dotted #3a3a3a;
|
58
|
-
background: #d5d5d5 url(img/anchor.gif) no-repeat center;
|
58
|
+
background: #d5d5d5 url('tinymce/skins/alchemy/fonts/img/anchor.gif') no-repeat center;
|
59
59
|
}
|
60
60
|
|
61
61
|
.mce-nbsp {
|
@@ -77,7 +77,7 @@ hr {
|
|
77
77
|
}
|
78
78
|
|
79
79
|
.mce-spellchecker-word {
|
80
|
-
background: url(img/wline.gif) repeat-x bottom left;
|
80
|
+
background: url('tinymce/skins/alchemy/fonts/img/wline.gif') repeat-x bottom left;
|
81
81
|
cursor: default;
|
82
82
|
}
|
83
83
|
|
@@ -1561,23 +1561,23 @@ i.mce-i-resize {
|
|
1561
1561
|
opacity: 0.6;
|
1562
1562
|
filter: alpha(opacity=60);
|
1563
1563
|
zoom: 1;
|
1564
|
-
background: #fff url('img/loader.gif') no-repeat center center;
|
1564
|
+
background: #fff url('tinymce/skins/alchemy/fonts/img/loader.gif') no-repeat center center;
|
1565
1565
|
}
|
1566
1566
|
|
1567
1567
|
@font-face {
|
1568
1568
|
font-family: 'tinymce';
|
1569
|
-
src: url('fonts/tinymce.woff') format('woff'),
|
1570
|
-
url('fonts/tinymce.ttf') format('truetype'),
|
1571
|
-
url('fonts/tinymce.svg#tinymce') format('svg');
|
1569
|
+
src: url('tinymce/skins/alchemy/fonts/tinymce.woff') format('woff'),
|
1570
|
+
url('tinymce/skins/alchemy/fonts/tinymce.ttf') format('truetype'),
|
1571
|
+
url('tinymce/skins/alchemy/fonts/tinymce.svg#tinymce') format('svg');
|
1572
1572
|
font-weight: normal;
|
1573
1573
|
font-style: normal;
|
1574
1574
|
}
|
1575
1575
|
|
1576
1576
|
@font-face {
|
1577
1577
|
font-family: 'tinymce-small';
|
1578
|
-
src: url('fonts/tinymce-small.woff') format('woff'),
|
1579
|
-
url('fonts/tinymce-small.ttf') format('truetype'),
|
1580
|
-
url('fonts/tinymce-small.svg#tinymce') format('svg');
|
1578
|
+
src: url('tinymce/skins/alchemy/fonts/tinymce-small.woff') format('woff'),
|
1579
|
+
url('tinymce/skins/alchemy/fonts/tinymce-small.ttf') format('truetype'),
|
1580
|
+
url('tinymce/skins/alchemy/fonts/tinymce-small.svg#tinymce') format('svg');
|
1581
1581
|
font-weight: normal;
|
1582
1582
|
font-style: normal;
|
1583
1583
|
}
|
@@ -40,9 +40,7 @@ module Alchemy
|
|
40
40
|
def exception_handler(error)
|
41
41
|
exception_logger(error)
|
42
42
|
show_error_notice(error)
|
43
|
-
|
44
|
-
notify_airbrake(error) unless Rails.env.development? || Rails.env.test?
|
45
|
-
end
|
43
|
+
notify_error_tracker(error)
|
46
44
|
end
|
47
45
|
|
48
46
|
# Displays an error notice in the Alchemy backend.
|
@@ -146,6 +144,14 @@ module Alchemy
|
|
146
144
|
site
|
147
145
|
end
|
148
146
|
end
|
147
|
+
|
148
|
+
def notify_error_tracker(exception)
|
149
|
+
if ::Alchemy::ErrorTracking.notification_handler.respond_to?(:call)
|
150
|
+
::Alchemy::ErrorTracking.notification_handler.call(exception)
|
151
|
+
else
|
152
|
+
Rails.logger.warn("To use the Alchemy::ErrorTracking.notification_handler, it must respond to #call.")
|
153
|
+
end
|
154
|
+
end
|
149
155
|
end
|
150
156
|
end
|
151
157
|
end
|
@@ -28,7 +28,7 @@ module Alchemy
|
|
28
28
|
after_assign { |f| write_attribute(:file_mime_type, f.mime_type) }
|
29
29
|
end
|
30
30
|
|
31
|
-
stampable stamper_class_name: Alchemy.
|
31
|
+
stampable stamper_class_name: Alchemy.user_class.name
|
32
32
|
|
33
33
|
has_many :essence_files, class_name: "Alchemy::EssenceFile", foreign_key: "attachment_id"
|
34
34
|
has_many :contents, through: :essence_files
|
@@ -57,7 +57,7 @@ module Alchemy
|
|
57
57
|
#
|
58
58
|
acts_as_list scope: [:page_version_id, :fixed, :parent_element_id]
|
59
59
|
|
60
|
-
stampable stamper_class_name: Alchemy.
|
60
|
+
stampable stamper_class_name: Alchemy.user_class.name
|
61
61
|
|
62
62
|
has_many :contents, dependent: :destroy, inverse_of: :element
|
63
63
|
|
data/app/models/alchemy/node.rb
CHANGED
@@ -7,7 +7,7 @@ module Alchemy
|
|
7
7
|
before_destroy :check_if_related_essence_nodes_present
|
8
8
|
|
9
9
|
acts_as_nested_set scope: "language_id", touch: true
|
10
|
-
stampable stamper_class_name: Alchemy.
|
10
|
+
stampable stamper_class_name: Alchemy.user_class.name
|
11
11
|
|
12
12
|
belongs_to :language, class_name: "Alchemy::Language"
|
13
13
|
belongs_to :page, class_name: "Alchemy::Page", optional: true, inverse_of: :nodes
|
data/app/models/alchemy/page.rb
CHANGED
@@ -110,7 +110,7 @@ module Alchemy
|
|
110
110
|
case_sensitive: false,
|
111
111
|
message: Alchemy.t("not a valid image")
|
112
112
|
|
113
|
-
stampable stamper_class_name: Alchemy.
|
113
|
+
stampable stamper_class_name: Alchemy.user_class.name
|
114
114
|
|
115
115
|
scope :named, ->(name) { where("#{table_name}.name LIKE ?", "%#{name}%") }
|
116
116
|
scope :recent, -> { where("#{table_name}.created_at > ?", Time.current - 24.hours).order(:created_at) }
|
@@ -54,7 +54,7 @@
|
|
54
54
|
<%= f.hidden_field :link_title, data: { link_title: true }, id: nil %>
|
55
55
|
<%= f.hidden_field :link_class_name, data: { link_class: true }, id: nil %>
|
56
56
|
<%= f.hidden_field :link_target, data: { link_target: true }, id: nil %>
|
57
|
-
<%= f.hidden_field :crop_from, data: { crop_from: true }, id:
|
58
|
-
<%= f.hidden_field :crop_size, data: { crop_size: true }, id:
|
57
|
+
<%= f.hidden_field :crop_from, data: { crop_from: true }, id: picture_editor.form_field_id(:crop_from) %>
|
58
|
+
<%= f.hidden_field :crop_size, data: { crop_size: true }, id: picture_editor.form_field_id(:crop_size) %>
|
59
59
|
<% end %>
|
60
60
|
<% end %>
|
data/config/brakeman.ignore
CHANGED
@@ -58,7 +58,7 @@
|
|
58
58
|
"check_name": "MassAssignment",
|
59
59
|
"message": "Specify exact keys allowed for mass assignment instead of using `permit!` which allows any keys",
|
60
60
|
"file": "app/controllers/alchemy/admin/resources_controller.rb",
|
61
|
-
"line":
|
61
|
+
"line": 209,
|
62
62
|
"link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
|
63
63
|
"code": "params.require(resource_handler.namespaced_resource_name).permit!",
|
64
64
|
"render_path": null,
|
@@ -86,7 +86,7 @@
|
|
86
86
|
"type": "controller",
|
87
87
|
"class": "Alchemy::Admin::ElementsController",
|
88
88
|
"method": "fold",
|
89
|
-
"line":
|
89
|
+
"line": 102,
|
90
90
|
"file": "app/controllers/alchemy/admin/elements_controller.rb",
|
91
91
|
"rendered": {
|
92
92
|
"name": "alchemy/admin/elements/fold",
|
@@ -109,7 +109,7 @@
|
|
109
109
|
"check_name": "MassAssignment",
|
110
110
|
"message": "Specify exact keys allowed for mass assignment instead of using `permit!` which allows any keys",
|
111
111
|
"file": "app/controllers/alchemy/admin/elements_controller.rb",
|
112
|
-
"line":
|
112
|
+
"line": 155,
|
113
113
|
"link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
|
114
114
|
"code": "params.fetch(:contents, {}).permit!",
|
115
115
|
"render_path": null,
|
@@ -122,6 +122,26 @@
|
|
122
122
|
"confidence": "Medium",
|
123
123
|
"note": "`Alchemy::Content` is a polymorphic association of any kind of model extending `Alchemy::Essence`. Since we can't know the attributes of all potential essences we need to permit all attributes. As this all happens inside the password protected /admin namespace this can be considered a false positive."
|
124
124
|
},
|
125
|
+
{
|
126
|
+
"warning_type": "Command Injection",
|
127
|
+
"warning_code": 14,
|
128
|
+
"fingerprint": "6addfcb9d23d2d6f699f2f3542169744ff749dc4d0a97f8ac783ab92593e1d84",
|
129
|
+
"check_name": "Execute",
|
130
|
+
"message": "Possible command injection",
|
131
|
+
"file": "lib/alchemy/upgrader.rb",
|
132
|
+
"line": 30,
|
133
|
+
"link": "https://brakemanscanner.org/docs/warning_types/command_injection/",
|
134
|
+
"code": "`yarn add @alchemy_cms/admin@~#{Alchemy.version}`",
|
135
|
+
"render_path": null,
|
136
|
+
"location": {
|
137
|
+
"type": "method",
|
138
|
+
"class": "Alchemy::Upgrader",
|
139
|
+
"method": "update_npm_package"
|
140
|
+
},
|
141
|
+
"user_input": "Alchemy.version",
|
142
|
+
"confidence": "Medium",
|
143
|
+
"note": "The alchemy version is safe"
|
144
|
+
},
|
125
145
|
{
|
126
146
|
"warning_type": "Cross-Site Scripting",
|
127
147
|
"warning_code": 4,
|
@@ -255,6 +275,6 @@
|
|
255
275
|
"note": ""
|
256
276
|
}
|
257
277
|
],
|
258
|
-
"updated": "2021-
|
259
|
-
"brakeman_version": "5.
|
278
|
+
"updated": "2021-10-26 21:44:59 +0200",
|
279
|
+
"brakeman_version": "5.1.1"
|
260
280
|
}
|
data/lib/alchemy/engine.rb
CHANGED
@@ -40,9 +40,16 @@ module Alchemy
|
|
40
40
|
if Alchemy.user_class
|
41
41
|
ActiveSupport.on_load(:active_record) do
|
42
42
|
Alchemy.user_class.model_stamper
|
43
|
-
Alchemy.user_class.stampable(stamper_class_name: Alchemy.
|
43
|
+
Alchemy.user_class.stampable(stamper_class_name: Alchemy.user_class.name)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
47
|
+
|
48
|
+
initializer "alchemy.error_tracking" do
|
49
|
+
if defined?(Airbrake)
|
50
|
+
require_relative "error_tracking/airbrake_handler"
|
51
|
+
Alchemy::ErrorTracking.notification_handler = Alchemy::ErrorTracking::AirbrakeHandler
|
52
|
+
end
|
53
|
+
end
|
47
54
|
end
|
48
55
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Alchemy
|
4
|
+
module ErrorTracking
|
5
|
+
class BaseHandler
|
6
|
+
def self.call(exception)
|
7
|
+
# implement your own notification method
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
mattr_accessor :notification_handler
|
12
|
+
@@notification_handler = BaseHandler
|
13
|
+
end
|
14
|
+
end
|
data/lib/alchemy/taggable.rb
CHANGED
@@ -22,13 +22,20 @@ module Alchemy
|
|
22
22
|
end
|
23
23
|
|
24
24
|
module ClassMethods
|
25
|
-
|
26
|
-
# Separate multiple tags by comma.
|
27
|
-
def tagged_with(names)
|
25
|
+
def tagged_with(names = [], **args)
|
28
26
|
if names.is_a? String
|
29
27
|
names = names.split(/,\s*/)
|
30
28
|
end
|
31
|
-
|
29
|
+
|
30
|
+
unless args[:match]
|
31
|
+
args.merge!(match: :all)
|
32
|
+
end
|
33
|
+
|
34
|
+
if names.any?
|
35
|
+
args.merge!(names: names)
|
36
|
+
end
|
37
|
+
|
38
|
+
super(args)
|
32
39
|
end
|
33
40
|
|
34
41
|
# Returns all unique tags
|
data/lib/alchemy/upgrader.rb
CHANGED
@@ -24,6 +24,12 @@ module Alchemy
|
|
24
24
|
todo "Check the default configuration file (./config/alchemy/config.yml.defaults) for new configuration options and insert them into your config file.", "Configuration has changed"
|
25
25
|
end
|
26
26
|
end
|
27
|
+
|
28
|
+
def update_npm_package
|
29
|
+
desc "Install new npm package."
|
30
|
+
`yarn add @alchemy_cms/admin@~#{Alchemy.version}`
|
31
|
+
log "Installed new npm package."
|
32
|
+
end
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|
data/lib/alchemy/version.rb
CHANGED
data/lib/alchemy_cms.rb
CHANGED
@@ -37,6 +37,7 @@ require_relative "alchemy/controller_actions"
|
|
37
37
|
require_relative "alchemy/deprecation"
|
38
38
|
require_relative "alchemy/element_definition"
|
39
39
|
require_relative "alchemy/elements_finder"
|
40
|
+
require_relative "alchemy/error_tracking"
|
40
41
|
require_relative "alchemy/errors"
|
41
42
|
require_relative "alchemy/essence"
|
42
43
|
require_relative "alchemy/filetypes"
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require "rails/generators"
|
3
3
|
require "alchemy/install/tasks"
|
4
|
+
require "alchemy/version"
|
4
5
|
|
5
6
|
module Alchemy
|
6
7
|
module Generators
|
@@ -88,7 +89,7 @@ module Alchemy
|
|
88
89
|
end
|
89
90
|
|
90
91
|
def add_npm_package
|
91
|
-
run "yarn add @alchemy_cms/admin"
|
92
|
+
run "yarn add @alchemy_cms/admin@~#{Alchemy.version}"
|
92
93
|
end
|
93
94
|
|
94
95
|
def copy_alchemy_entry_point
|
@@ -17,6 +17,7 @@ namespace :alchemy do
|
|
17
17
|
task prepare: [
|
18
18
|
"alchemy:upgrade:database",
|
19
19
|
"alchemy:upgrade:config",
|
20
|
+
"alchemy:upgrade:package",
|
20
21
|
]
|
21
22
|
|
22
23
|
desc "Alchemy Upgrader: Prepares the database."
|
@@ -30,6 +31,11 @@ namespace :alchemy do
|
|
30
31
|
Alchemy::Upgrader.copy_new_config_file
|
31
32
|
end
|
32
33
|
|
34
|
+
desc "Alchemy Upgrader: Install new Node package."
|
35
|
+
task package: [:environment] do
|
36
|
+
Alchemy::Upgrader.update_npm_package
|
37
|
+
end
|
38
|
+
|
33
39
|
desc "Upgrade Alchemy to v5.0"
|
34
40
|
task "5.0" => [
|
35
41
|
"alchemy:upgrade:prepare",
|
data/package/admin.js
CHANGED
@@ -5,6 +5,7 @@ import fileEditors from "./src/file_editors"
|
|
5
5
|
import pictureEditors from "./src/picture_editors"
|
6
6
|
import ImageLoader from "./src/image_loader"
|
7
7
|
import ImageCropper from "./src/image_cropper"
|
8
|
+
import Datepicker from "./src/datepicker"
|
8
9
|
|
9
10
|
// Global Alchemy object
|
10
11
|
if (typeof window.Alchemy === "undefined") {
|
@@ -20,5 +21,6 @@ Object.assign(Alchemy, {
|
|
20
21
|
fileEditors,
|
21
22
|
pictureEditors,
|
22
23
|
ImageLoader: ImageLoader.init,
|
23
|
-
ImageCropper
|
24
|
+
ImageCropper,
|
25
|
+
Datepicker
|
24
26
|
})
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import flatpickr from "flatpickr"
|
2
|
+
|
3
|
+
export default function Datepicker(scope = document) {
|
4
|
+
if (scope === "") {
|
5
|
+
scope = document
|
6
|
+
} else if (scope instanceof String) {
|
7
|
+
scope = document.querySelectorAll(scope)
|
8
|
+
}
|
9
|
+
|
10
|
+
const datepickerInputs = scope.querySelectorAll("input[data-datepicker-type]")
|
11
|
+
|
12
|
+
// Initializes the datepickers on the text inputs and sets the proper type
|
13
|
+
// to enable browsers default datepicker if the current OS is iOS.
|
14
|
+
if (Alchemy.isiOS) {
|
15
|
+
datepickerInputs.forEach((input) => {
|
16
|
+
input.attributes.type = input.dataset.datepickerType
|
17
|
+
})
|
18
|
+
} else {
|
19
|
+
datepickerInputs.forEach((input) => {
|
20
|
+
const type = input.dataset.datepickerType
|
21
|
+
const options = {
|
22
|
+
// alchemy_i18n supports `zh_CN` etc., but flatpickr only has two-letter codes (`zh`)
|
23
|
+
locale: Alchemy.locale.slice(0, 2),
|
24
|
+
altInput: true,
|
25
|
+
altFormat: Alchemy.t(`formats.${type}`),
|
26
|
+
altInputClass: "flatpickr-input",
|
27
|
+
enableTime: /time/.test(type),
|
28
|
+
noCalendar: type === "time",
|
29
|
+
time_24hr: Alchemy.t("formats.time_24hr"),
|
30
|
+
onValueUpdate(_selectedDates, _dateStr, instance) {
|
31
|
+
return Alchemy.setElementDirty(
|
32
|
+
instance.element.closest(".element-editor")
|
33
|
+
)
|
34
|
+
}
|
35
|
+
}
|
36
|
+
flatpickr(input, options)
|
37
|
+
})
|
38
|
+
}
|
39
|
+
}
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@alchemy_cms/admin",
|
3
|
-
"version": "6.0.0-
|
3
|
+
"version": "6.0.0-rc4",
|
4
4
|
"description": "AlchemyCMS",
|
5
5
|
"browser": "package/admin.js",
|
6
6
|
"files": [
|
@@ -24,6 +24,7 @@
|
|
24
24
|
},
|
25
25
|
"homepage": "https://github.com/AlchemyCMS/alchemy_cms#readme",
|
26
26
|
"dependencies": {
|
27
|
+
"flatpickr": "^4.6.9",
|
27
28
|
"lodash-es": "^4.17.21",
|
28
29
|
"sortablejs": "^1.10.2"
|
29
30
|
},
|