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.

Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/brakeman-analysis.yml +46 -0
  3. data/.github/workflows/ci.yml +4 -3
  4. data/CHANGELOG.md +35 -0
  5. data/Gemfile +6 -1
  6. data/README.md +1 -1
  7. data/SECURITY.md +13 -0
  8. data/alchemy_cms.gemspec +3 -3
  9. data/app/assets/javascripts/alchemy/admin.js +0 -1
  10. data/app/assets/javascripts/alchemy/alchemy.gui.js.coffee +2 -2
  11. data/app/assets/javascripts/alchemy/alchemy.link_dialog.js.coffee +7 -6
  12. data/app/assets/stylesheets/alchemy/_extends.scss +4 -4
  13. data/app/assets/stylesheets/alchemy/flatpickr.scss +182 -232
  14. data/app/assets/stylesheets/tinymce/skins/alchemy/content.min.css.scss +3 -3
  15. data/app/assets/stylesheets/tinymce/skins/alchemy/skin.min.css.scss +7 -7
  16. data/app/controllers/alchemy/admin/base_controller.rb +9 -3
  17. data/app/models/alchemy/attachment.rb +1 -1
  18. data/app/models/alchemy/element.rb +1 -1
  19. data/app/models/alchemy/node.rb +1 -1
  20. data/app/models/alchemy/page.rb +1 -1
  21. data/app/models/alchemy/picture.rb +1 -1
  22. data/app/views/alchemy/ingredients/_picture_editor.html.erb +2 -2
  23. data/config/brakeman.ignore +25 -5
  24. data/lib/alchemy/engine.rb +8 -1
  25. data/lib/alchemy/error_tracking/airbrake_handler.rb +13 -0
  26. data/lib/alchemy/error_tracking.rb +14 -0
  27. data/lib/alchemy/taggable.rb +11 -4
  28. data/lib/alchemy/upgrader.rb +6 -0
  29. data/lib/alchemy/version.rb +1 -1
  30. data/lib/alchemy_cms.rb +1 -0
  31. data/lib/generators/alchemy/install/install_generator.rb +2 -1
  32. data/lib/tasks/alchemy/upgrade.rake +6 -0
  33. data/package/admin.js +3 -1
  34. data/package/src/datepicker.js +39 -0
  35. data/package.json +2 -1
  36. metadata +44 -39
  37. 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
- if defined?(Airbrake)
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.user_class_name
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.user_class_name
60
+ stampable stamper_class_name: Alchemy.user_class.name
61
61
 
62
62
  has_many :contents, dependent: :destroy, inverse_of: :element
63
63
 
@@ -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.user_class_name
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
@@ -88,7 +88,7 @@ module Alchemy
88
88
 
89
89
  acts_as_nested_set(dependent: :destroy, scope: [:layoutpage, :language_id])
90
90
 
91
- stampable stamper_class_name: Alchemy.user_class_name
91
+ stampable stamper_class_name: Alchemy.user_class.name
92
92
 
93
93
  belongs_to :language
94
94
 
@@ -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.user_class_name
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: nil %>
58
- <%= f.hidden_field :crop_size, data: { crop_size: true }, id: nil %>
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 %>
@@ -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": 136,
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": 97,
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": 150,
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-06-29 20:56:10 +0200",
259
- "brakeman_version": "5.0.1"
278
+ "updated": "2021-10-26 21:44:59 +0200",
279
+ "brakeman_version": "5.1.1"
260
280
  }
@@ -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.user_class_name)
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,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Alchemy
4
+ module ErrorTracking
5
+ class AirbrakeHandler < BaseHandler
6
+ def self.call(exception)
7
+ return if ["development", "test"].include?(Rails.env)
8
+
9
+ notify_airbrake(exception)
10
+ end
11
+ end
12
+ end
13
+ 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
@@ -22,13 +22,20 @@ module Alchemy
22
22
  end
23
23
 
24
24
  module ClassMethods
25
- # Find all records matching all of the given tags.
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
- super(names: names, match: :all)
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
@@ -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
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alchemy
4
- VERSION = "6.0.0-b6"
4
+ VERSION = "6.0.0-rc4"
5
5
 
6
6
  def self.version
7
7
  VERSION
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-b6",
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
  },