camaleon_cms 2.9.1 → 2.9.3
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.
- checksums.yaml +4 -4
- data/README.md +29 -9
- data/Rakefile +3 -16
- data/app/apps/plugins/attack/admin_controller.rb +9 -6
- data/app/apps/plugins/attack/attack_helper.rb +35 -25
- data/app/apps/plugins/authoring_post/authoring_post_helper.rb +23 -16
- data/app/apps/plugins/front_cache/admin_controller.rb +16 -10
- data/app/apps/plugins/front_cache/config/initializer.rb +1 -1
- data/app/apps/plugins/front_cache/front_cache_helper.rb +57 -24
- data/app/apps/plugins/visibility_post/config/config.json +1 -0
- data/app/apps/plugins/visibility_post/config/routes_front.txt +1 -0
- data/app/apps/plugins/visibility_post/front_controller.rb +23 -0
- data/app/apps/plugins/visibility_post/visibility_post_helper.rb +141 -70
- data/app/apps/themes/camaleon_first/main_helper.rb +18 -12
- data/app/apps/themes/default/assets/css/style.css.scss +24 -0
- data/app/apps/themes/default/assets/genericons/genericons.css +3 -8
- data/app/apps/themes/default/default_helper.rb +2 -1
- data/app/apps/themes/default/views/category.html.erb +1 -1
- data/app/apps/themes/default/views/layouts/index.html.erb +3 -1
- data/app/apps/themes/default/views/post_tag.html.erb +1 -1
- data/app/apps/themes/default/views/post_type.html.erb +1 -1
- data/app/apps/themes/default/views/search.html.erb +1 -1
- data/app/apps/themes/new/assets/css/styles.css.scss +24 -0
- data/app/apps/themes/new/custom_helper.rb +5 -9
- data/app/apps/themes/new/views/category.html.erb +1 -1
- data/app/apps/themes/new/views/layouts/_header.html.erb +3 -1
- data/app/apps/themes/new/views/post_tag.html.erb +1 -1
- data/app/apps/themes/new/views/post_type.html.erb +1 -1
- data/app/apps/themes/new/views/search.html.erb +1 -1
- data/app/assets/javascripts/camaleon_cms/admin/_data.js +16 -0
- data/app/assets/javascripts/camaleon_cms/admin/_post.js +5 -2
- data/app/assets/javascripts/camaleon_cms/admin/nav_menu.js +14 -3
- data/app/assets/javascripts/camaleon_cms/admin/uploader/_media_manager.js +5 -0
- data/app/controllers/camaleon_cms/admin/appearances/nav_menus_controller.rb +29 -10
- data/app/controllers/camaleon_cms/admin/appearances/themes_controller.rb +8 -5
- data/app/controllers/camaleon_cms/admin/appearances/widgets/assign_controller.rb +9 -2
- data/app/controllers/camaleon_cms/admin/appearances/widgets/main_controller.rb +4 -3
- data/app/controllers/camaleon_cms/admin/appearances/widgets/sidebar_controller.rb +2 -2
- data/app/controllers/camaleon_cms/admin/categories_controller.rb +27 -8
- data/app/controllers/camaleon_cms/admin/comments_controller.rb +0 -1
- data/app/controllers/camaleon_cms/admin/installers_controller.rb +32 -1
- data/app/controllers/camaleon_cms/admin/media_controller.rb +84 -19
- data/app/controllers/camaleon_cms/admin/plugins_controller.rb +1 -3
- data/app/controllers/camaleon_cms/admin/post_tags_controller.rb +15 -6
- data/app/controllers/camaleon_cms/admin/posts/drafts_controller.rb +40 -11
- data/app/controllers/camaleon_cms/admin/posts_controller.rb +58 -22
- data/app/controllers/camaleon_cms/admin/sessions_controller.rb +238 -45
- data/app/controllers/camaleon_cms/admin/settings/custom_fields_controller.rb +103 -18
- data/app/controllers/camaleon_cms/admin/settings/post_types_controller.rb +17 -5
- data/app/controllers/camaleon_cms/admin/settings/sites_controller.rb +33 -7
- data/app/controllers/camaleon_cms/admin/settings_controller.rb +11 -6
- data/app/controllers/camaleon_cms/admin/user_roles_controller.rb +9 -7
- data/app/controllers/camaleon_cms/admin/users_controller.rb +89 -18
- data/app/controllers/camaleon_cms/admin_controller.rb +144 -26
- data/app/controllers/camaleon_cms/apps/plugins_admin_controller.rb +5 -0
- data/app/controllers/camaleon_cms/camaleon_controller.rb +37 -92
- data/app/controllers/camaleon_cms/frontend_controller.rb +140 -70
- data/app/controllers/concerns/camaleon_cms/admin/custom_fields_concern.rb +44 -0
- data/app/controllers/concerns/camaleon_cms/frontend_concern.rb +46 -17
- data/app/controllers/concerns/camaleon_cms/frontend_visited_state_concern.rb +72 -0
- data/app/controllers/concerns/camaleon_cms/hook_lifecycle_concern.rb +104 -0
- data/app/controllers/concerns/camaleon_cms/request_context_concern.rb +113 -0
- data/app/controllers/concerns/camaleon_cms/runtime_admin_menu_concern.rb +237 -0
- data/app/controllers/concerns/camaleon_cms/runtime_captcha_image_concern.rb +13 -0
- data/app/controllers/concerns/camaleon_cms/runtime_html_content_concern.rb +143 -0
- data/app/controllers/concerns/camaleon_cms/runtime_shortcode_theme_concern.rb +246 -0
- data/app/controllers/concerns/camaleon_cms/runtime_state_concern.rb +13 -0
- data/app/controllers/concerns/camaleon_cms/runtime_uploader_concern.rb +54 -0
- data/app/controllers/concerns/camaleon_cms/session_captcha_runtime_concern.rb +19 -0
- data/app/controllers/concerns/camaleon_cms/session_runtime_concern.rb +40 -0
- data/app/decorators/camaleon_cms/application_decorator.rb +11 -8
- data/app/decorators/camaleon_cms/category_decorator.rb +3 -2
- data/app/decorators/camaleon_cms/post_comment_decorator.rb +13 -5
- data/app/decorators/camaleon_cms/post_decorator.rb +67 -51
- data/app/decorators/camaleon_cms/post_type_decorator.rb +1 -1
- data/app/decorators/camaleon_cms/site_decorator.rb +29 -23
- data/app/decorators/camaleon_cms/term_taxonomy_decorator.rb +21 -10
- data/app/decorators/camaleon_cms/theme_decorator.rb +3 -3
- data/app/decorators/camaleon_cms/user_decorator.rb +26 -5
- data/app/helpers/camaleon_cms/admin/application_helper.rb +21 -24
- data/app/helpers/camaleon_cms/admin/breadcrumb_helper.rb +1 -1
- data/app/helpers/camaleon_cms/admin/custom_fields_helper.rb +24 -23
- data/app/helpers/camaleon_cms/admin/menus_helper.rb +249 -139
- data/app/helpers/camaleon_cms/admin/post_type_helper.rb +51 -31
- data/app/helpers/camaleon_cms/camaleon_helper.rb +31 -39
- data/app/helpers/camaleon_cms/captcha_helper.rb +73 -53
- data/app/helpers/camaleon_cms/comment_helper.rb +87 -41
- data/app/helpers/camaleon_cms/content_helper.rb +13 -6
- data/app/helpers/camaleon_cms/email_helper.rb +7 -3
- data/app/helpers/camaleon_cms/frontend/content_select_helper.rb +34 -20
- data/app/helpers/camaleon_cms/frontend/nav_menu_helper.rb +144 -67
- data/app/helpers/camaleon_cms/frontend/seo_helper.rb +39 -28
- data/app/helpers/camaleon_cms/frontend/site_helper.rb +32 -12
- data/app/helpers/camaleon_cms/hooks_helper.rb +14 -4
- data/app/helpers/camaleon_cms/html_helper.rb +73 -38
- data/app/helpers/camaleon_cms/plugins_helper.rb +23 -24
- data/app/helpers/camaleon_cms/session_helper.rb +195 -39
- data/app/helpers/camaleon_cms/short_code_helper.rb +181 -85
- data/app/helpers/camaleon_cms/site_helper.rb +43 -9
- data/app/helpers/camaleon_cms/theme_helper.rb +35 -19
- data/app/helpers/camaleon_cms/uploader_helper.rb +19 -422
- data/app/helpers/camaleon_cms/user_roles_helper.rb +5 -4
- data/app/mailers/camaleon_cms/html_mailer.rb +4 -4
- data/app/models/camaleon_cms/ability.rb +65 -105
- data/app/models/camaleon_cms/category.rb +7 -5
- data/app/models/camaleon_cms/custom_field.rb +29 -6
- data/app/models/camaleon_cms/custom_field_group.rb +75 -21
- data/app/models/camaleon_cms/custom_fields_relationship.rb +133 -2
- data/app/models/camaleon_cms/media.rb +8 -2
- data/app/models/camaleon_cms/meta.rb +2 -2
- data/app/models/camaleon_cms/nav_menu.rb +6 -2
- data/app/models/camaleon_cms/nav_menu_item.rb +18 -8
- data/app/models/camaleon_cms/plugin.rb +4 -3
- data/app/models/camaleon_cms/post.rb +113 -27
- data/app/models/camaleon_cms/post_comment.rb +10 -6
- data/app/models/camaleon_cms/post_default.rb +42 -12
- data/app/models/camaleon_cms/post_relationship.rb +6 -4
- data/app/models/camaleon_cms/post_tag.rb +4 -3
- data/app/models/camaleon_cms/post_type.rb +22 -12
- data/app/models/camaleon_cms/site.rb +40 -28
- data/app/models/camaleon_cms/term_relationship.rb +10 -7
- data/app/models/camaleon_cms/term_taxonomy.rb +51 -5
- data/app/models/camaleon_cms/theme.rb +3 -3
- data/app/models/camaleon_cms/user.rb +17 -5
- data/app/models/camaleon_cms/user_role.rb +77 -4
- data/app/models/camaleon_cms/widget/assigned.rb +11 -6
- data/app/models/camaleon_cms/widget/main.rb +13 -7
- data/app/models/camaleon_cms/widget/sidebar.rb +3 -6
- data/app/models/camaleon_record.rb +123 -5
- data/app/models/concerns/camaleon_cms/categories_tags_for_posts.rb +20 -38
- data/app/models/concerns/camaleon_cms/common_relationships.rb +18 -5
- data/app/models/concerns/camaleon_cms/custom_fields_read.rb +115 -58
- data/app/models/concerns/camaleon_cms/metas.rb +32 -7
- data/app/models/concerns/camaleon_cms/normalize_attrs.rb +2 -8
- data/app/models/concerns/camaleon_cms/site_default_settings.rb +120 -16
- data/app/models/concerns/camaleon_cms/user_methods.rb +44 -19
- data/app/models/current_request.rb +23 -0
- data/app/uploaders/camaleon_cms_aws_uploader.rb +39 -11
- data/app/uploaders/camaleon_cms_local_uploader.rb +76 -19
- data/app/uploaders/camaleon_cms_uploader.rb +23 -10
- data/app/validators/camaleon_cms/post_uniq_validator.rb +21 -8
- data/app/validators/camaleon_cms/uniq_validator.rb +1 -1
- data/app/validators/camaleon_cms/user_url_validator.rb +215 -36
- data/app/views/camaleon_cms/admin/appearances/nav_menus/_left_menu_items.html.erb +2 -2
- data/app/views/camaleon_cms/admin/appearances/widgets/main/form.html.erb +1 -1
- data/app/views/camaleon_cms/admin/categories/index.html.erb +3 -3
- data/app/views/camaleon_cms/admin/comments/index.html.erb +2 -2
- data/app/views/camaleon_cms/admin/comments/list.html.erb +1 -1
- data/app/views/camaleon_cms/admin/installers/form.html.erb +5 -0
- data/app/views/camaleon_cms/admin/installers/welcome.html.erb +30 -6
- data/app/views/camaleon_cms/admin/plugins/_plugins_list.html.erb +2 -2
- data/app/views/camaleon_cms/admin/post_tags/index.html.erb +3 -3
- data/app/views/camaleon_cms/admin/posts/_sidebar.html.erb +2 -2
- data/app/views/camaleon_cms/admin/posts/form.html.erb +3 -2
- data/app/views/camaleon_cms/admin/posts/index.html.erb +6 -6
- data/app/views/camaleon_cms/admin/search.html.erb +1 -1
- data/app/views/camaleon_cms/admin/sessions/back_to_parent.html.erb +39 -0
- data/app/views/camaleon_cms/admin/sessions/logout_confirm.html.erb +27 -0
- data/app/views/camaleon_cms/admin/settings/_email_settings.html.erb +4 -1
- data/app/views/camaleon_cms/admin/settings/custom_fields/_get_items.html.erb +1 -1
- data/app/views/camaleon_cms/admin/settings/custom_fields/_render.html.erb +42 -6
- data/app/views/camaleon_cms/admin/settings/custom_fields/_render_category_simple.html.erb +1 -1
- data/app/views/camaleon_cms/admin/settings/custom_fields/fields/_select_eval.html.erb +1 -1
- data/app/views/camaleon_cms/admin/settings/custom_fields/form.html.erb +5 -4
- data/app/views/camaleon_cms/admin/settings/custom_fields/index.html.erb +1 -1
- data/app/views/camaleon_cms/admin/settings/post_types/index.html.erb +1 -1
- data/app/views/camaleon_cms/admin/settings/shortcodes.html.erb +4 -4
- data/app/views/camaleon_cms/admin/settings/site.html.erb +1 -1
- data/app/views/camaleon_cms/admin/settings/sites/form.html.erb +1 -1
- data/app/views/camaleon_cms/admin/settings/sites/index.html.erb +1 -1
- data/app/views/camaleon_cms/admin/user_roles/form.html.erb +102 -7
- data/app/views/camaleon_cms/admin/user_roles/index.html.erb +1 -1
- data/app/views/camaleon_cms/admin/users/form.html.erb +8 -4
- data/app/views/camaleon_cms/admin/users/index.html.erb +2 -2
- data/app/views/camaleon_cms/default_theme/partials/_render_custom_field.html.erb +8 -2
- data/app/views/camaleon_cms/default_theme/sitemap.html.erb +1 -1
- data/app/views/camaleon_cms/default_theme/sitemap.xml.builder +1 -1
- data/app/views/layouts/camaleon_cms/admin/_flash_messages.html.erb +2 -2
- data/app/views/layouts/camaleon_cms/admin/_header.html.erb +1 -1
- data/config/initializers/action_view.rb +42 -5
- data/config/initializers/active_record_extension.rb +13 -27
- data/config/initializers/assets.rb +52 -23
- data/config/initializers/custom_initializers.rb +3 -3
- data/config/locales/camaleon_cms/admin/ar.yml +7 -2
- data/config/locales/camaleon_cms/admin/de.yml +7 -2
- data/config/locales/camaleon_cms/admin/en.yml +39 -2
- data/config/locales/camaleon_cms/admin/es.yml +7 -2
- data/config/locales/camaleon_cms/admin/fr.yml +7 -2
- data/config/locales/camaleon_cms/admin/it.yml +7 -2
- data/config/locales/camaleon_cms/admin/nl.yml +8 -2
- data/config/locales/camaleon_cms/admin/pt-BR.yml +7 -2
- data/config/locales/camaleon_cms/admin/pt.yml +7 -2
- data/config/locales/camaleon_cms/admin/ru.yml +7 -2
- data/config/locales/camaleon_cms/admin/uk.yml +7 -2
- data/config/locales/camaleon_cms/admin/zh-CH.yml +7 -2
- data/config/routes/admin.rb +33 -15
- data/config/routes/frontend.rb +21 -15
- data/db/migrate/20150611161134_post_table_into_utf8.rb +14 -14
- data/db/migrate/20150926095310_rename_column_posts.rb +3 -3
- data/db/migrate/20151212095328_add_confirm_token_to_users.rb +3 -3
- data/db/migrate/20160504155652_add_feature_to_posts.rb +1 -1
- data/db/migrate/20160504155653_move_first_name_of_users.rb +2 -2
- data/db/migrate/20160609121449_add_group_to_custom_field_values.rb +1 -1
- data/db/migrate/20161215202255_drop_user_relationship_table.rb +1 -1
- data/db/migrate/20180124132318_create_media.rb +1 -1
- data/db/migrate/20180704211100_adjust_field_length.rb +1 -1
- data/lib/camaleon_cms/assets_precompile.rb +86 -0
- data/lib/camaleon_cms/captcha_image_generation.rb +65 -0
- data/lib/camaleon_cms/content_security.rb +158 -0
- data/lib/camaleon_cms/engine.rb +47 -9
- data/lib/camaleon_cms/media_security_headers.rb +27 -0
- data/lib/camaleon_cms/setup_token.rb +69 -0
- data/lib/camaleon_cms/svg_content_checker.rb +123 -0
- data/lib/camaleon_cms/task_reporter.rb +14 -0
- data/lib/camaleon_cms/unsafe_markup.rb +207 -0
- data/lib/camaleon_cms/uploader_content_security.rb +248 -0
- data/lib/camaleon_cms/uploader_image_processing.rb +166 -0
- data/lib/camaleon_cms/uploader_path_security.rb +146 -0
- data/lib/camaleon_cms/uploader_pipeline.rb +350 -0
- data/lib/camaleon_cms/uploader_support.rb +86 -0
- data/lib/camaleon_cms/version.rb +1 -1
- data/lib/camaleon_cms.rb +11 -0
- data/lib/ext/hash.rb +28 -2
- data/lib/ext/string.rb +13 -8
- data/lib/ext/translator.rb +10 -2
- data/lib/generators/camaleon_cms/gem_plugin_template/app/controllers/plugins/my_plugin/admin_controller.rb +5 -1
- data/lib/generators/camaleon_cms/install_generator.rb +7 -4
- data/lib/generators/camaleon_cms/install_template/plugin_routes.rb +5 -12
- data/lib/generators/camaleon_cms/theme_generator.rb +5 -10
- data/lib/generators/camaleon_cms/theme_template/views/layouts/index.html.erb +3 -1
- data/lib/plugin_routes.rb +412 -368
- data/lib/tasks/camaleon_cms/camaleon_tasks.rake +2 -1
- data/lib/tasks/cross_site_field_groups.rake +74 -0
- data/lib/tasks/custom_fields_roles.rake +58 -0
- data/lib/tasks/orphaned_comments.rake +42 -0
- data/lib/tasks/private_upload_acls.rake +31 -0
- data/lib/tasks/site_custom_field_groups.rake +36 -0
- data/lib/tasks/unsafe_stored_content.rake +42 -0
- data/lib/tasks/unsafe_stored_uploads.rake +70 -0
- data/lib/tasks/user_field_groups.rake +27 -0
- metadata +185 -7
|
@@ -1,436 +1,33 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module CamaleonCms
|
|
4
|
+
# Uploader entry point for views, ActiveJobs, and any standalone object that includes
|
|
5
|
+
# it (see config/initializers/custom_initializers.rb). The implementation lives in the
|
|
6
|
+
# shared modules below, which CamaleonCms::RuntimeUploaderConcern includes as well, so
|
|
7
|
+
# the two entry points cannot drift.
|
|
4
8
|
module UploaderHelper
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
onstalled onstorage onsuspend ontimeupdate ontoggle onunloadonsubmit onvolumechange onwaiting onwheel
|
|
11
|
-
].map { |pattern| /#{pattern}\w*\s*=/i }.freeze
|
|
12
|
-
|
|
13
|
-
SUSPICIOUS_PATTERNS = (UNSAFE_EVENT_PATTERNS + [
|
|
14
|
-
/<script[\s>]/i, # Script tags
|
|
15
|
-
/javascript:/i, # JavaScript in href/src attributes
|
|
16
|
-
/<iframe[\s>]/i, # Iframes
|
|
17
|
-
/<object[\s>]/i, # Object tags
|
|
18
|
-
/<embed[\s>]/i, # Embed tags
|
|
19
|
-
/<base[\s>]/i, # Base tags (can be used to manipulate URLs)
|
|
20
|
-
/data:/i # data: URLs (which can include scripts)
|
|
21
|
-
]).freeze
|
|
22
|
-
|
|
9
|
+
include UploaderContentSecurity
|
|
10
|
+
include UploaderPathSecurity
|
|
11
|
+
include UploaderPipeline
|
|
12
|
+
include UploaderImageProcessing
|
|
13
|
+
include UploaderSupport
|
|
23
14
|
include ActionView::Helpers::NumberHelper
|
|
24
15
|
include CamaleonCms::CamaleonHelper
|
|
25
16
|
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# dimension: dimension for the image (sample: 30x30 | x30 | 30x | 300x300?)
|
|
33
|
-
# formats: extensions permitted, sample: jpg,png,... or generic: images | videos | audios | documents (default *)
|
|
34
|
-
# remove_source: Boolean (delete source file after saved if this is true, default false)
|
|
35
|
-
# same_name: Boolean (save the file with the same name if defined true, else search for a non used name)
|
|
36
|
-
# versions: (String) Create additional multiple versions of the image uploaded,
|
|
37
|
-
# sample: '300x300,505x350' ==> Will create two extra images with these dimensions
|
|
38
|
-
# sample "test.png", versions: '200x200,450x450' will generate: thumb/test-png_200x200.png, test-png_450x450.png
|
|
39
|
-
# thumb_size: String (redefine the dimensions of the thumbnail, sample: '100x100' ==> only for images)
|
|
40
|
-
# temporal_time: if great than 0 seconds, then this file will expire (removed) in that time (default: 0)
|
|
41
|
-
# To manage jobs, please check https://edgeguides.rubyonrails.org/active_job_basics.html
|
|
42
|
-
# Note: if you are using temporal_time, you will need to copy the file to another directory later
|
|
43
|
-
# sample: upload_file(params[:my_file], {formats: "images", folder: "temporal"})
|
|
44
|
-
# sample: upload_file(params[:my_file], {formats: "jpg,png,gif,mp3,mp4", temporal_time: 10.minutes, maximum: 10.megabytes})
|
|
45
|
-
def upload_file(uploaded_io, settings = {})
|
|
46
|
-
cached_name = uploaded_io.is_a?(ActionDispatch::Http::UploadedFile) ? uploaded_io.original_filename : nil
|
|
47
|
-
return { error: 'File is empty', file: nil, size: nil } unless uploaded_io.present?
|
|
48
|
-
|
|
49
|
-
if uploaded_io.is_a?(String) && uploaded_io.match(%r{^https?://}).present? # download url file
|
|
50
|
-
tmp = cama_tmp_upload(uploaded_io)
|
|
51
|
-
return tmp if tmp[:error].present?
|
|
52
|
-
|
|
53
|
-
settings[:remove_source] = true
|
|
54
|
-
uploaded_io = tmp[:file_path]
|
|
55
|
-
end
|
|
56
|
-
uploaded_io = File.open(uploaded_io) if uploaded_io.is_a?(String)
|
|
57
|
-
if settings[:dimension].present?
|
|
58
|
-
uploaded_io = File.open(cama_resize_upload(uploaded_io.path, settings[:dimension]))
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
return { error: 'Potentially malicious content found!' } if file_content_unsafe?(uploaded_io)
|
|
62
|
-
|
|
63
|
-
settings = settings.to_sym
|
|
64
|
-
settings[:uploaded_io] = uploaded_io
|
|
65
|
-
settings = {
|
|
66
|
-
folder: '',
|
|
67
|
-
maximum: current_site.get_option('filesystem_max_size', 100).to_f.megabytes,
|
|
68
|
-
formats: '*',
|
|
69
|
-
generate_thumb: true,
|
|
70
|
-
temporal_time: 0,
|
|
71
|
-
filename: begin
|
|
72
|
-
cached_name || uploaded_io.original_filename
|
|
73
|
-
rescue StandardError
|
|
74
|
-
uploaded_io.path.split('/').last
|
|
75
|
-
end.cama_fix_filename,
|
|
76
|
-
file_size: File.size(uploaded_io.to_io),
|
|
77
|
-
remove_source: false,
|
|
78
|
-
same_name: false,
|
|
79
|
-
versions: '',
|
|
80
|
-
thumb_size: nil
|
|
81
|
-
}.merge!(settings)
|
|
82
|
-
hooks_run('before_upload', settings)
|
|
83
|
-
res = { error: nil }
|
|
84
|
-
|
|
85
|
-
# guard against path traversal
|
|
86
|
-
return { error: 'Invalid file path' } unless cama_uploader.valid_folder_path?(settings[:folder])
|
|
87
|
-
|
|
88
|
-
# formats validations
|
|
89
|
-
return { error: "#{ct('file_format_error')} (#{settings[:formats]})" } unless cama_uploader.class.validate_file_format(
|
|
90
|
-
uploaded_io.path, settings[:formats]
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
# file size validations
|
|
94
|
-
if settings[:maximum] < settings[:file_size]
|
|
95
|
-
res[:error] =
|
|
96
|
-
"#{ct('file_size_exceeded', default: 'File size exceeded')} (#{number_to_human_size(settings[:maximum])})"
|
|
97
|
-
return res
|
|
98
|
-
end
|
|
99
|
-
# save file
|
|
100
|
-
key = File.join(settings[:folder], settings[:filename]).to_s.cama_fix_slash
|
|
101
|
-
res = cama_uploader.add_file(settings[:uploaded_io], key, { same_name: settings[:same_name] })
|
|
102
|
-
|
|
103
|
-
# generate image versions
|
|
104
|
-
if res['file_type'] == 'image'
|
|
105
|
-
settings[:versions].to_s.gsub(' ', '').split(',').each do |v|
|
|
106
|
-
version_path = cama_resize_upload(settings[:uploaded_io].path, v, { replace: false })
|
|
107
|
-
cama_uploader.add_file(version_path, cama_uploader.version_path(res['key'], v), is_thumb: true,
|
|
108
|
-
same_name: true)
|
|
109
|
-
FileUtils.rm_f(version_path)
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# generate thumb
|
|
114
|
-
if settings[:generate_thumb] && res['thumb'].present?
|
|
115
|
-
cama_uploader_generate_thumbnail(uploaded_io.path, res['key'], settings[:thumb_size],
|
|
116
|
-
settings[:remove_source])
|
|
117
|
-
end
|
|
118
|
-
FileUtils.rm_f(uploaded_io.path) if settings[:remove_source] && File.exist?(uploaded_io.path)
|
|
119
|
-
|
|
120
|
-
hooks_run('after_upload', settings)
|
|
121
|
-
|
|
122
|
-
# temporal file upload (always put as local for temporal files)
|
|
123
|
-
if settings[:temporal_time] > 0
|
|
124
|
-
CamaleonCmsUploader.delete_block.call(settings, cama_uploader, key)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
res
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
# generate thumbnail of a existent image
|
|
131
|
-
# key: key of the current file
|
|
132
|
-
# the thumbnail will be saved in my_images/my_img.png => my_images/thumb/my_img.png
|
|
133
|
-
def cama_uploader_generate_thumbnail(uploaded_io, key, thumb_size = nil, remove_source = false)
|
|
134
|
-
w = cama_uploader.thumb[:w]
|
|
135
|
-
h = cama_uploader.thumb[:h]
|
|
136
|
-
w, h = thumb_size.split('x') if thumb_size.present?
|
|
137
|
-
uploaded_io = File.open(uploaded_io) if uploaded_io.is_a?(String)
|
|
138
|
-
path_thumb = cama_resize_and_crop(uploaded_io.path, w, h)
|
|
139
|
-
thumb = cama_uploader.add_file(path_thumb, cama_uploader.version_path(key).sub('.svg', '.jpg'), is_thumb: true,
|
|
140
|
-
same_name: true)
|
|
141
|
-
FileUtils.rm_f(path_thumb) if remove_source
|
|
142
|
-
thumb
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
# helper to find an available filename for file_path in that directory
|
|
146
|
-
# sample: uploader_verify_name("/var/www/my_image.jpg")
|
|
147
|
-
# return "/var/www/my_image_1.jpg" => if "/var/www/my_image.jpg" exist
|
|
148
|
-
# return "/var/www/my_image.jpg" => if "/var/www/my_image.jpg" doesn't exist
|
|
149
|
-
def uploader_verify_name(file_path)
|
|
150
|
-
dir = File.dirname(file_path)
|
|
151
|
-
filename = File.basename(file_path).to_s.cama_fix_filename
|
|
152
|
-
files = Dir.entries(dir)
|
|
153
|
-
if files.include?(filename)
|
|
154
|
-
i = 1
|
|
155
|
-
_filename = filename
|
|
156
|
-
while files.include?(_filename)
|
|
157
|
-
_filename = "#{File.basename(filename, File.extname(filename))}_#{i}#{File.extname(filename)}"
|
|
158
|
-
i += 1
|
|
159
|
-
end
|
|
160
|
-
filename = _filename
|
|
161
|
-
end
|
|
162
|
-
"#{File.dirname(file_path)}/#{filename}"
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
# convert downloaded file path into public url
|
|
166
|
-
def cama_file_path_to_url(file_path)
|
|
167
|
-
file_path.sub(Rails.public_path.to_s, begin
|
|
168
|
-
root_url
|
|
169
|
-
rescue StandardError
|
|
170
|
-
cama_root_url
|
|
171
|
-
end)
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
# convert public url to file path
|
|
175
|
-
def cama_url_to_file_path(url)
|
|
176
|
-
File.join(Rails.public_path, URI(url.to_s).path)
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
# crop and image and saved as imagename_crop.ext
|
|
180
|
-
# file: file path
|
|
181
|
-
# w: new width
|
|
182
|
-
# h: new height
|
|
183
|
-
# w_offset: left offset
|
|
184
|
-
# w_offset: top offset
|
|
185
|
-
# resize: true/false
|
|
186
|
-
# (true => resize the image to this dimension)
|
|
187
|
-
# (false => crop the image with this dimension)
|
|
188
|
-
# replace: Boolean (replace current image or create another file)
|
|
189
|
-
def cama_crop_image(file_path, w = nil, h = nil, w_offset = 0, h_offset = 0, resize = false, replace = true)
|
|
190
|
-
force = ''
|
|
191
|
-
force = '!' if w.present? && h.present? && !w.include?('?') && !h.include?('?')
|
|
192
|
-
img = MiniMagick::Image.open(file_path)
|
|
193
|
-
w = img[:width].to_f > w.sub('?', '').to_i ? w.sub('?', '') : img[:width] if w.present? && w.to_s.include?('?')
|
|
194
|
-
h = img[:height].to_f > h.sub('?', '').to_i ? h.sub('?', '') : img[:height] if h.present? && h.to_s.include?('?')
|
|
195
|
-
data = { img: img, w: w, h: h, w_offset: w_offset, h_offset: h_offset, resize: resize, replace: replace }
|
|
196
|
-
hooks_run('before_crop_image', data)
|
|
197
|
-
data[:img].combine_options do |i|
|
|
198
|
-
i.resize("#{w if w.present?}x#{h if h.present?}#{force}") if data[:resize]
|
|
199
|
-
i.crop "#{w if w.present?}x#{h if h.present?}+#{w_offset}+#{h_offset}#{force}" unless data[:resize]
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
res = file_path
|
|
203
|
-
unless data[:replace]
|
|
204
|
-
ext = File.extname(file_path)
|
|
205
|
-
res = file_path.gsub(ext, "_crop#{ext}")
|
|
206
|
-
end
|
|
207
|
-
data[:img].write res
|
|
208
|
-
res
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
# resize and crop a file
|
|
212
|
-
# SVGs are converted to JPEGs for editing
|
|
213
|
-
# Params:
|
|
214
|
-
# file: (String) File path
|
|
215
|
-
# w: (Integer) width
|
|
216
|
-
# h: (Integer) height
|
|
217
|
-
# settings:
|
|
218
|
-
# gravity: (Sym, default :north_east) Crop position: :north_west, :north, :north_east, :east, :south_east, :south, :south_west, :west, :center
|
|
219
|
-
# overwrite: (Boolean, default true) true for overwrite current image with resized resolutions, false: create other file called with prefix "crop_"
|
|
220
|
-
# output_name: (String, default prefixd name with crop_), permit to define the output name of the thumbnail if overwrite = true
|
|
221
|
-
# Return: (String) file path where saved this cropped
|
|
222
|
-
# sample: cama_resize_and_crop(my_file, 200, 200, {gravity: :north_east, overwrite: false})
|
|
223
|
-
def cama_resize_and_crop(file, w, h, settings = {})
|
|
224
|
-
settings = { gravity: :north_east, overwrite: true, output_name: +'' }.merge!(settings)
|
|
225
|
-
img = MiniMagick::Image.open(file)
|
|
226
|
-
if file.end_with? '.svg'
|
|
227
|
-
img.format 'jpg'
|
|
228
|
-
file.sub! '.svg', '.jpg'
|
|
229
|
-
settings[:output_name]&.sub!('.svg', '.jpg')
|
|
230
|
-
end
|
|
231
|
-
w = img[:width].to_f > w.sub('?', '').to_i ? w.sub('?', '') : img[:width] if w.present? && w.to_s.include?('?')
|
|
232
|
-
h = img[:height].to_f > h.sub('?', '').to_i ? h.sub('?', '') : img[:height] if h.present? && h.to_s.include?('?')
|
|
233
|
-
w_original = img[:width].to_f
|
|
234
|
-
h_original = img[:height].to_f
|
|
235
|
-
w = w.to_i if w.present?
|
|
236
|
-
h = h.to_i if h.present?
|
|
237
|
-
|
|
238
|
-
# check proportions
|
|
239
|
-
if w_original * h < h_original * w
|
|
240
|
-
op_resize = "#{w.to_i}x"
|
|
241
|
-
w_result = w
|
|
242
|
-
h_result = (h_original * w / w_original)
|
|
243
|
-
else
|
|
244
|
-
op_resize = "x#{h.to_i}"
|
|
245
|
-
w_result = (w_original * h / h_original)
|
|
246
|
-
h_result = h
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
w_offset, h_offset = cama_crop_offsets_by_gravity(settings[:gravity], [w_result, h_result], [w, h])
|
|
250
|
-
data = { img: img, w: w, h: h, w_offset: w_offset, h_offset: h_offset, op_resize: op_resize, settings: settings }
|
|
251
|
-
hooks_run('before_resize_crop', data)
|
|
252
|
-
data[:img].combine_options do |i|
|
|
253
|
-
i.resize(data[:op_resize])
|
|
254
|
-
i.gravity(settings[:gravity])
|
|
255
|
-
i.crop "#{data[:w].to_i}x#{data[:h].to_i}+#{data[:w_offset]}+#{data[:h_offset]}!"
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
if settings[:overwrite]
|
|
259
|
-
data[:img].write(file.sub('.svg', '.jpg'))
|
|
260
|
-
elsif settings[:output_name].present?
|
|
261
|
-
data[:img].write(file = File.join(File.dirname(file), settings[:output_name]).to_s)
|
|
262
|
-
else
|
|
263
|
-
data[:img].write(file = uploader_verify_name(File.join(File.dirname(file),
|
|
264
|
-
"crop_#{File.basename(file.sub('.svg', '.jpg'))}")))
|
|
265
|
-
end
|
|
266
|
-
file
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
# upload tmp file
|
|
270
|
-
# support for url and local path
|
|
271
|
-
# sample:
|
|
272
|
-
# cama_tmp_upload('https://camaleon.website/media/132/logo2.png') ==> /var/rails/my_project/public/tmp/1/logo2.png
|
|
273
|
-
# cama_tmp_upload('/var/www/media/132/logo 2.png') ==> /var/rails/my_project/public/tmp/1/logo-2.png
|
|
274
|
-
# accept args:
|
|
275
|
-
# name: to indicate the name to use, sample: cama_tmp_upload('/var/www/media/132/logo 2.png', {name: 'owen.png', formats: 'images'})
|
|
276
|
-
# formats: extensions permitted, sample: jpg,png,... or generic: images | videos | audios | documents (default *)
|
|
277
|
-
# dimension: 20x30
|
|
278
|
-
# return: {file_path, error}
|
|
279
|
-
def cama_tmp_upload(uploaded_io, args = {})
|
|
280
|
-
tmp_path = args[:path] || File.join(Rails.public_path, 'tmp', current_site.id.to_s).to_s
|
|
281
|
-
FileUtils.mkdir_p(tmp_path) unless Dir.exist?(tmp_path)
|
|
282
|
-
saved = false
|
|
283
|
-
if uploaded_io.is_a?(String) && uploaded_io.start_with?('data:') # create tmp file using base64 format
|
|
284
|
-
_tmp_name = args[:name]
|
|
285
|
-
return { error: cama_t('camaleon_cms.admin.media.name_required').to_s } unless params[:name].present?
|
|
286
|
-
return { error: "#{ct('file_format_error')} (#{args[:formats]})" } unless cama_uploader.class.validate_file_format(
|
|
287
|
-
_tmp_name, args[:formats]
|
|
288
|
-
)
|
|
289
|
-
|
|
290
|
-
path = uploader_verify_name(File.join(tmp_path, _tmp_name))
|
|
291
|
-
File.open(path, 'wb') { |f| f.write(Base64.decode64(uploaded_io.split(';base64,').last)) }
|
|
292
|
-
uploaded_io = File.open(path)
|
|
293
|
-
saved = true
|
|
294
|
-
elsif uploaded_io.is_a?(String) && (uploaded_io.start_with?('http://') || uploaded_io.start_with?('https://'))
|
|
295
|
-
return { error: "#{ct('file_format_error')} (#{args[:formats]})" } unless cama_uploader.class.validate_file_format(
|
|
296
|
-
uploaded_io, args[:formats]
|
|
297
|
-
)
|
|
298
|
-
|
|
299
|
-
if uploaded_io.include?(current_site.the_url(locale: nil))
|
|
300
|
-
uploaded_io = File.join(Rails.public_path, uploaded_io.sub(current_site.the_url(locale: nil), '')).to_s
|
|
301
|
-
end
|
|
302
|
-
_tmp_name = uploaded_io.split('/').last.split('?').first
|
|
303
|
-
args[:name] = args[:name] || _tmp_name
|
|
304
|
-
uploaded_io = URI(uploaded_io).open
|
|
305
|
-
end
|
|
306
|
-
uploaded_io = File.open(uploaded_io) if uploaded_io.is_a?(String)
|
|
307
|
-
return { error: "#{ct('file_format_error')} (#{args[:formats]})" } unless cama_uploader.class.validate_file_format(
|
|
308
|
-
_tmp_name || uploaded_io.path, args[:formats]
|
|
309
|
-
)
|
|
310
|
-
|
|
311
|
-
if args[:maximum].present? && args[:maximum] < begin
|
|
312
|
-
uploaded_io.size
|
|
313
|
-
rescue StandardError
|
|
314
|
-
File.size(uploaded_io)
|
|
315
|
-
end
|
|
316
|
-
return { error: "#{ct('file_size_exceeded',
|
|
317
|
-
default: 'File size exceeded')} (#{number_to_human_size(args[:maximum])})" }
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
name = args[:name] || uploaded_io&.original_filename || uploaded_io.path.split('/').last
|
|
321
|
-
name = "#{File.basename(name, File.extname(name)).parameterize}#{File.extname(name)}"
|
|
322
|
-
path ||= uploader_verify_name(File.join(tmp_path, name))
|
|
323
|
-
File.open(path, 'wb') { |f| f.write(uploaded_io.read) } unless saved
|
|
324
|
-
path = cama_resize_upload(path, args[:dimension]) if args[:dimension].present?
|
|
325
|
-
{ file_path: path, error: nil }
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
# resize image if the format is correct
|
|
329
|
-
# return resized file path
|
|
330
|
-
def cama_resize_upload(image_path, dimension, args = {})
|
|
331
|
-
if cama_uploader.class.validate_file_format(image_path, 'image') && dimension.present?
|
|
332
|
-
r = { file: image_path, w: dimension.split('x')[0], h: dimension.split('x')[1], w_offset: 0, h_offset: 0,
|
|
333
|
-
resize: !dimension.split('x')[2] || dimension.split('x')[2] == 'resize',
|
|
334
|
-
replace: true, gravity: :north_east }.merge!(args)
|
|
335
|
-
hooks_run('on_uploader_resize', r)
|
|
336
|
-
image_path = if r[:w].present? && r[:h].present?
|
|
337
|
-
cama_resize_and_crop(r[:file], r[:w], r[:h], { overwrite: r[:replace], gravity: r[:gravity] })
|
|
338
|
-
else
|
|
339
|
-
cama_crop_image(r[:file], r[:w], r[:h], r[:w_offset], r[:h_offset], r[:resize], r[:replace])
|
|
340
|
-
end
|
|
341
|
-
end
|
|
342
|
-
image_path
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
# return the current uploader
|
|
346
|
-
def cama_uploader
|
|
347
|
-
@cama_uploader ||= lambda {
|
|
348
|
-
thumb = current_site.get_option('filesystem_thumb_size', '100x100').split('x')
|
|
349
|
-
args = {
|
|
350
|
-
server: current_site.get_option('filesystem_type', 'local').downcase,
|
|
351
|
-
thumb: { w: thumb[0], h: thumb[1] },
|
|
352
|
-
aws_settings: {
|
|
353
|
-
region: current_site.get_option('filesystem_region', 'us-west-2'),
|
|
354
|
-
access_key: current_site.get_option('filesystem_s3_access_key'),
|
|
355
|
-
secret_key: current_site.get_option('filesystem_s3_secret_key'),
|
|
356
|
-
bucket: current_site.get_option('filesystem_s3_bucket_name'),
|
|
357
|
-
cloud_front: current_site.get_option('filesystem_s3_cloudfront'),
|
|
358
|
-
aws_file_upload_settings: lambda { |settings|
|
|
359
|
-
settings
|
|
360
|
-
}, # permit to add your custom attributes for file_upload https://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#upload_file-instance_method
|
|
361
|
-
aws_file_read_settings: lambda { |data, _s3_file|
|
|
362
|
-
data
|
|
363
|
-
} # permit to read custom attributes from aws file and add to file parsed object
|
|
364
|
-
},
|
|
365
|
-
custom_uploader: nil # possibility to use custom file uploader
|
|
366
|
-
}
|
|
367
|
-
hooks_run('on_uploader', args)
|
|
368
|
-
return args[:custom_uploader] if args[:custom_uploader].present?
|
|
369
|
-
|
|
370
|
-
case args[:server]
|
|
371
|
-
when 's3', 'aws'
|
|
372
|
-
CamaleonCmsAwsUploader.new(
|
|
373
|
-
{ current_site: current_site, thumb: args[:thumb], aws_settings: args[:aws_settings] }, self
|
|
374
|
-
)
|
|
375
|
-
else
|
|
376
|
-
CamaleonCmsLocalUploader.new({ current_site: current_site, thumb: args[:thumb] }, self)
|
|
377
|
-
end
|
|
378
|
-
}.call
|
|
17
|
+
# Message seam overrides (see CamaleonCms::UploaderPipeline). This entry point runs
|
|
18
|
+
# where `ct` and `cama_t` exist, so upload errors keep going through them: `ct` fires
|
|
19
|
+
# the `on_translation` hook, letting plugins override the text. The pipeline defaults
|
|
20
|
+
# go straight to I18n, which is all a controller can do.
|
|
21
|
+
def cama_uploader_ct(key, args = {})
|
|
22
|
+
ct(key, args)
|
|
379
23
|
end
|
|
380
24
|
|
|
381
|
-
def
|
|
382
|
-
|
|
383
|
-
end
|
|
384
|
-
|
|
385
|
-
def slugify_folder(val)
|
|
386
|
-
split_folder = val.split('/')
|
|
387
|
-
split_folder[-1] = slugify(split_folder.last)
|
|
388
|
-
split_folder.join('/')
|
|
389
|
-
end
|
|
390
|
-
|
|
391
|
-
private
|
|
392
|
-
|
|
393
|
-
def file_content_unsafe?(uploaded_io)
|
|
394
|
-
file = uploaded_io.is_a?(ActionDispatch::Http::UploadedFile) ? uploaded_io.tempfile : uploaded_io
|
|
395
|
-
file_content_unsafe = nil
|
|
396
|
-
|
|
397
|
-
file.set_encoding(Encoding::BINARY) if file.respond_to?(:binmode) && file.respond_to?(:set_encoding)
|
|
398
|
-
|
|
399
|
-
file_content = file.read
|
|
400
|
-
SUSPICIOUS_PATTERNS.each do |pattern|
|
|
401
|
-
if file_content =~ pattern
|
|
402
|
-
Rails.logger.info { "Potentially malicious content found: #{pattern.inspect}" }
|
|
403
|
-
break file_content_unsafe = pattern.inspect
|
|
404
|
-
end
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
file_content_unsafe
|
|
408
|
-
end
|
|
409
|
-
|
|
410
|
-
# helper for resize and crop method
|
|
411
|
-
def cama_crop_offsets_by_gravity(gravity, original_dimensions, cropped_dimensions)
|
|
412
|
-
original_width, original_height = original_dimensions
|
|
413
|
-
cropped_width, cropped_height = cropped_dimensions
|
|
414
|
-
|
|
415
|
-
vertical_offset = case gravity
|
|
416
|
-
when :north_west, :north, :north_east then 0
|
|
417
|
-
when :center, :east, :west then [((original_height - cropped_height) / 2.0).to_i, 0].max
|
|
418
|
-
when :south_west, :south, :south_east then (original_height - cropped_height).to_i
|
|
419
|
-
end
|
|
420
|
-
|
|
421
|
-
horizontal_offset = case gravity
|
|
422
|
-
when :north_west, :west, :south_west then 0
|
|
423
|
-
when :center, :north, :south then [((original_width - cropped_width) / 2.0).to_i, 0].max
|
|
424
|
-
when :north_east, :east, :south_east then (original_width - cropped_width).to_i
|
|
425
|
-
end
|
|
426
|
-
|
|
427
|
-
[horizontal_offset, vertical_offset]
|
|
25
|
+
def cama_uploader_t(key, args = {})
|
|
26
|
+
cama_t(key, args)
|
|
428
27
|
end
|
|
429
28
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
def cama_parse_for_thumb_name(file_path)
|
|
433
|
-
"#{@fog_connection_hook_res[:thumb_folder_name]}/#{File.basename(file_path).parameterize}#{File.extname(file_path)}"
|
|
29
|
+
def cama_uploader_human_size(bytes)
|
|
30
|
+
number_to_human_size(bytes)
|
|
434
31
|
end
|
|
435
32
|
end
|
|
436
33
|
end
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
module CamaleonCms
|
|
2
2
|
module UserRolesHelper
|
|
3
3
|
def cama_get_roles_values
|
|
4
|
-
@_cache_cama_get_roles_values ||= lambda
|
|
4
|
+
@_cache_cama_get_roles_values ||= lambda do
|
|
5
5
|
roles_list = CamaleonCms::UserRole::ROLES
|
|
6
|
-
# permit
|
|
7
|
-
# sample:
|
|
6
|
+
# permit adding custom roles to be listed in editing roles form
|
|
7
|
+
# sample:
|
|
8
|
+
# args[:roles_list][:manager] << {key: 'my_role_key', label: "my_custom_permission", description: "lorem ipsum"}
|
|
8
9
|
# authorize! :manage, :my_role_key
|
|
9
10
|
args = { roles_list: roles_list }
|
|
10
11
|
hooks_run('available_user_roles_list', args)
|
|
11
12
|
args[:roles_list]
|
|
12
|
-
|
|
13
|
+
end.call
|
|
13
14
|
end
|
|
14
15
|
end
|
|
15
16
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module CamaleonCms
|
|
2
|
-
class HtmlMailer < ActionMailer::Base
|
|
2
|
+
class HtmlMailer < ActionMailer::Base # rubocop:disable Rails/ApplicationMailer
|
|
3
3
|
include CamaleonCms::SiteHelper
|
|
4
4
|
include CamaleonCms::HooksHelper
|
|
5
5
|
include CamaleonCms::PluginsHelper
|
|
@@ -23,7 +23,7 @@ module CamaleonCms
|
|
|
23
23
|
layout_name: 'camaleon_cms/mailer',
|
|
24
24
|
format: 'html'
|
|
25
25
|
}.merge(data)
|
|
26
|
-
data[:cc_to] = [data[:cc_to]] if data[:cc_to].is_a?(String) ||
|
|
26
|
+
data[:cc_to] = [data[:cc_to]] if data[:cc_to].is_a?(String) || data[:cc_to].blank?
|
|
27
27
|
|
|
28
28
|
mail_data = { to: email, subject: subject }
|
|
29
29
|
if @current_site.get_option('mailer_enabled') == 1
|
|
@@ -72,7 +72,7 @@ module CamaleonCms
|
|
|
72
72
|
end
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
layout = data[:layout_name].
|
|
75
|
+
layout = data[:layout_name].presence || false
|
|
76
76
|
if data[:template_name].present? # render email with template
|
|
77
77
|
if data[:format] == 'html'
|
|
78
78
|
mail(mail_data) do |format|
|
|
@@ -92,7 +92,7 @@ module CamaleonCms
|
|
|
92
92
|
mail(mail_data) { |format| format.html { render inline: @html, layout: layout } } if data[:format] == 'html'
|
|
93
93
|
mail(mail_data) { |format| format.text { render inline: @html, layout: layout } } if data[:format] == 'txt'
|
|
94
94
|
end
|
|
95
|
-
mail(mail_data)
|
|
95
|
+
mail(mail_data) if data[:format].blank?
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
private
|