camaleon_cms 2.9.0 → 2.9.2
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 +12 -5
- data/app/apps/plugins/front_cache/admin_controller.rb +1 -0
- data/app/apps/plugins/front_cache/front_cache_helper.rb +23 -14
- data/app/apps/plugins/visibility_post/visibility_post_helper.rb +1 -1
- data/app/apps/themes/default/views/category.html.erb +1 -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/views/category.html.erb +1 -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/controllers/camaleon_cms/admin/appearances/nav_menus_controller.rb +22 -5
- data/app/controllers/camaleon_cms/admin/appearances/widgets/assign_controller.rb +4 -2
- data/app/controllers/camaleon_cms/admin/appearances/widgets/main_controller.rb +3 -3
- data/app/controllers/camaleon_cms/admin/appearances/widgets/sidebar_controller.rb +2 -2
- data/app/controllers/camaleon_cms/admin/categories_controller.rb +9 -5
- data/app/controllers/camaleon_cms/admin/media_controller.rb +18 -5
- data/app/controllers/camaleon_cms/admin/post_tags_controller.rb +7 -4
- data/app/controllers/camaleon_cms/admin/posts/drafts_controller.rb +1 -1
- data/app/controllers/camaleon_cms/admin/posts_controller.rb +7 -4
- data/app/controllers/camaleon_cms/admin/sessions_controller.rb +2 -2
- data/app/controllers/camaleon_cms/admin/settings/custom_fields_controller.rb +33 -11
- data/app/controllers/camaleon_cms/admin/settings/post_types_controller.rb +13 -4
- data/app/controllers/camaleon_cms/admin/settings/sites_controller.rb +7 -4
- data/app/controllers/camaleon_cms/admin/settings_controller.rb +7 -4
- data/app/controllers/camaleon_cms/admin/user_roles_controller.rb +2 -2
- data/app/controllers/camaleon_cms/admin/users_controller.rb +23 -14
- data/app/controllers/camaleon_cms/admin_controller.rb +8 -0
- data/app/controllers/camaleon_cms/apps/plugins_admin_controller.rb +5 -0
- data/app/controllers/concerns/camaleon_cms/admin/custom_fields_concern.rb +29 -0
- data/app/decorators/camaleon_cms/post_decorator.rb +1 -1
- data/app/decorators/camaleon_cms/user_decorator.rb +1 -1
- data/app/helpers/camaleon_cms/admin/application_helper.rb +17 -17
- data/app/helpers/camaleon_cms/admin/post_type_helper.rb +25 -22
- data/app/helpers/camaleon_cms/comment_helper.rb +74 -40
- data/app/helpers/camaleon_cms/frontend/content_select_helper.rb +1 -1
- data/app/helpers/camaleon_cms/frontend/nav_menu_helper.rb +7 -7
- data/app/helpers/camaleon_cms/html_helper.rb +15 -1
- data/app/helpers/camaleon_cms/session_helper.rb +13 -1
- data/app/helpers/camaleon_cms/site_helper.rb +16 -3
- data/app/helpers/camaleon_cms/uploader_helper.rb +102 -51
- data/app/models/camaleon_cms/ability.rb +54 -102
- data/app/models/camaleon_cms/category.rb +2 -0
- data/app/models/camaleon_cms/custom_field.rb +14 -0
- data/app/models/camaleon_cms/custom_field_group.rb +38 -1
- data/app/models/camaleon_cms/custom_fields_relationship.rb +1 -1
- data/app/models/camaleon_cms/meta.rb +4 -0
- data/app/models/camaleon_cms/nav_menu.rb +2 -0
- data/app/models/camaleon_cms/nav_menu_item.rb +2 -0
- data/app/models/camaleon_cms/plugin.rb +2 -0
- data/app/models/camaleon_cms/post.rb +1 -1
- data/app/models/camaleon_cms/post_comment.rb +4 -0
- data/app/models/camaleon_cms/post_tag.rb +2 -0
- data/app/models/camaleon_cms/post_type.rb +3 -1
- data/app/models/camaleon_cms/site.rb +2 -0
- data/app/models/camaleon_cms/term_taxonomy.rb +1 -23
- data/app/models/camaleon_cms/theme.rb +2 -0
- data/app/models/camaleon_cms/user_role.rb +13 -0
- data/app/models/camaleon_cms/widget/main.rb +2 -0
- data/app/models/camaleon_cms/widget/sidebar.rb +2 -0
- data/app/models/camaleon_record.rb +40 -0
- data/app/models/concerns/camaleon_cms/custom_fields_read.rb +7 -7
- data/app/models/concerns/camaleon_cms/metas.rb +10 -6
- data/app/models/concerns/camaleon_cms/normalize_attrs.rb +26 -0
- data/app/models/concerns/camaleon_cms/user_methods.rb +6 -2
- data/app/models/current_request.rb +16 -0
- data/app/uploaders/camaleon_cms_aws_uploader.rb +8 -1
- data/app/validators/camaleon_cms/post_uniq_validator.rb +21 -8
- 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 +1 -1
- 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/post_tags/index.html.erb +1 -1
- data/app/views/camaleon_cms/admin/posts/_sidebar.html.erb +1 -1
- data/app/views/camaleon_cms/admin/posts/index.html.erb +3 -3
- data/app/views/camaleon_cms/admin/search.html.erb +1 -1
- data/app/views/camaleon_cms/admin/settings/custom_fields/_render.html.erb +23 -2
- 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 +6 -5
- 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/sites/index.html.erb +1 -1
- data/app/views/camaleon_cms/admin/user_roles/form.html.erb +79 -5
- data/app/views/camaleon_cms/admin/user_roles/index.html.erb +1 -1
- data/app/views/camaleon_cms/admin/users/index.html.erb +1 -1
- data/app/views/layouts/camaleon_cms/admin/_flash_messages.html.erb +2 -2
- data/config/initializers/custom_initializers.rb +2 -2
- data/config/locales/camaleon_cms/admin/ar.yml +6 -2
- data/config/locales/camaleon_cms/admin/de.yml +6 -2
- data/config/locales/camaleon_cms/admin/en.yml +6 -2
- data/config/locales/camaleon_cms/admin/es.yml +6 -2
- data/config/locales/camaleon_cms/admin/fr.yml +6 -2
- data/config/locales/camaleon_cms/admin/it.yml +6 -2
- data/config/locales/camaleon_cms/admin/nl.yml +7 -2
- data/config/locales/camaleon_cms/admin/pt-BR.yml +6 -2
- data/config/locales/camaleon_cms/admin/pt.yml +6 -2
- data/config/locales/camaleon_cms/admin/ru.yml +6 -2
- data/config/locales/camaleon_cms/admin/uk.yml +6 -2
- data/config/locales/camaleon_cms/admin/zh-CH.yml +6 -2
- 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/version.rb +1 -1
- data/lib/ext/string.rb +3 -3
- data/lib/plugin_routes.rb +6 -6
- data/lib/tasks/custom_fields_roles.rake +56 -0
- metadata +65 -8
|
@@ -30,7 +30,16 @@ module CamaleonCms
|
|
|
30
30
|
# ****** check all options for each case in Admin::CustomFieldsHelper ****
|
|
31
31
|
# SAMPLE: my_model.add_field({"name"=>"Sub Title", "slug"=>"subtitle"}, {"field_key"=>"text_box",
|
|
32
32
|
# "translate"=>true, default_value: "Get in Touch"})
|
|
33
|
+
# Adds a manual field to the group (used by admin UI)
|
|
34
|
+
# item: field attributes
|
|
35
|
+
# options: field options
|
|
33
36
|
def add_manual_field(item, options)
|
|
37
|
+
# Prevent creation of dangerous field types (select_eval) unless the actor is allowed.
|
|
38
|
+
if options[:field_key] == 'select_eval'
|
|
39
|
+
can?(:manage, :select_eval) ||
|
|
40
|
+
raise(CanCan::AccessDenied, 'Not authorized to create select_eval fields')
|
|
41
|
+
end
|
|
42
|
+
|
|
34
43
|
c = get_field(item[:slug] || item['slug'])
|
|
35
44
|
return c if c.present?
|
|
36
45
|
|
|
@@ -50,6 +59,8 @@ module CamaleonCms
|
|
|
50
59
|
|
|
51
60
|
# only used by form on admin panel (protected)
|
|
52
61
|
# return array of failed_fields and full_fields [[failed fields], [all fields]]
|
|
62
|
+
# items: hash of field items
|
|
63
|
+
# item_options: hash of options for each item
|
|
53
64
|
def add_fields(items, item_options)
|
|
54
65
|
fields.where.not(id: items.to_h.map { |_k, obj| obj['id'] }.uniq).destroy_all
|
|
55
66
|
cache_fields = []
|
|
@@ -57,12 +68,38 @@ module CamaleonCms
|
|
|
57
68
|
errors_saved = []
|
|
58
69
|
if items.present?
|
|
59
70
|
items.each do |i, item|
|
|
71
|
+
# allow string or symbol keys for incoming params
|
|
72
|
+
id_val = item['id'] || item[:id]
|
|
73
|
+
|
|
60
74
|
item[:field_order] = order_index
|
|
61
75
|
options = item_options[i] || {}
|
|
62
|
-
if
|
|
76
|
+
if id_val.present? && (field_item = fields.find_by(id: id_val)).present?
|
|
77
|
+
# If this is an existing select_eval field (or the incoming data would
|
|
78
|
+
# make it a select_eval) ensure the current actor has explicit
|
|
79
|
+
# permission. For updates we preserve the form-like behavior by
|
|
80
|
+
# collecting an error-like non-persisted field in errors_saved and
|
|
81
|
+
# skipping the update when unauthorized.
|
|
82
|
+
existing_key = (field_item.options || {})[:field_key].to_s
|
|
83
|
+
# consider field_key coming from the per-item options (options) or the item itself
|
|
84
|
+
incoming_key = (options[:field_key] || item[:field_key]).to_s
|
|
85
|
+
if (existing_key == 'select_eval' || incoming_key == 'select_eval') && !can?(:manage, :select_eval)
|
|
86
|
+
field_item.errors.add(:base, 'Not authorized to modify select_eval field')
|
|
87
|
+
errors_saved << field_item
|
|
88
|
+
next
|
|
89
|
+
end
|
|
90
|
+
|
|
63
91
|
saved = field_item.update(item)
|
|
64
92
|
cache_fields << field_item
|
|
65
93
|
else
|
|
94
|
+
# Check if the incoming options request creation of select_eval
|
|
95
|
+
incoming_key = (options[:field_key] || item[:field_key]).to_s
|
|
96
|
+
if incoming_key == 'select_eval' && !can?(:manage, :select_eval)
|
|
97
|
+
# Add an error-like non-persisted field to errors_saved to preserve behavior
|
|
98
|
+
field_item = fields.new(item)
|
|
99
|
+
field_item.errors.add(:base, 'Not authorized to create select_eval field')
|
|
100
|
+
errors_saved << field_item
|
|
101
|
+
next
|
|
102
|
+
end
|
|
66
103
|
field_item = fields.new(item)
|
|
67
104
|
cache_fields << field_item
|
|
68
105
|
saved = field_item.save
|
|
@@ -7,7 +7,7 @@ module CamaleonCms
|
|
|
7
7
|
default_scope { order("#{CamaleonCms::CustomFieldsRelationship.table_name}.term_order ASC") }
|
|
8
8
|
|
|
9
9
|
# relations
|
|
10
|
-
belongs_to :custom_field, required: false
|
|
10
|
+
belongs_to :custom_field, class_name: 'CamaleonCms::CustomField', required: false
|
|
11
11
|
|
|
12
12
|
# validates :objectid, :custom_field_id, presence: true
|
|
13
13
|
validates :custom_field_id, presence: true # error on clone model
|
|
@@ -3,6 +3,8 @@ module CamaleonCms
|
|
|
3
3
|
include CamaleonCms::Metas
|
|
4
4
|
include CamaleonCms::CommonRelationships
|
|
5
5
|
|
|
6
|
+
extend CamaleonCms::NormalizeAttrs
|
|
7
|
+
|
|
6
8
|
self.table_name = "#{PluginRoutes.static_system_info['db_prefix']}comments"
|
|
7
9
|
# attr_accessible :user_id, :post_id, :content, :author, :author_email, :author_url, :author_IP, :approved, :agent, :agent, :typee, :comment_parent, :is_anonymous
|
|
8
10
|
attr_accessor :is_anonymous
|
|
@@ -21,6 +23,8 @@ module CamaleonCms
|
|
|
21
23
|
scope :comment_parent, -> { where(comment_parent: 'is not null') }
|
|
22
24
|
scope :approveds, -> { where(approved: 'approved') }
|
|
23
25
|
|
|
26
|
+
normalize_attrs(:content)
|
|
27
|
+
|
|
24
28
|
validates :content, presence: true
|
|
25
29
|
validates_presence_of :author, :author_email, if: proc { |c| c.is_anonymous.present? }
|
|
26
30
|
after_create :update_counter
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module CamaleonCms
|
|
2
2
|
class PostType < CamaleonCms::TermTaxonomy
|
|
3
|
+
normalize_attrs(:name, :description)
|
|
4
|
+
|
|
3
5
|
alias_attribute :site_id, :parent_id
|
|
4
6
|
default_scope { where(taxonomy: :post_type) }
|
|
5
7
|
|
|
@@ -179,7 +181,7 @@ module CamaleonCms
|
|
|
179
181
|
|
|
180
182
|
# destroy all custom field groups assigned to this post type
|
|
181
183
|
def destroy_field_groups
|
|
182
|
-
if !destroyed_by_association.present? &&
|
|
184
|
+
if !destroyed_by_association.present? && %w[post page].include?(slug)
|
|
183
185
|
errors.add(:base, 'This post type can not be deleted.')
|
|
184
186
|
return false
|
|
185
187
|
end
|
|
@@ -3,11 +3,7 @@ module CamaleonCms
|
|
|
3
3
|
include CamaleonCms::Metas
|
|
4
4
|
include CamaleonCms::CustomFieldsRead
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
TRANSLATION_TAG_HIDE_REGEX = Regexp.new(TRANSLATION_TAG_HIDE_MAP.keys.map { |x| Regexp.escape(x) }.join('|')).freeze
|
|
8
|
-
TRANSLATION_TAG_RESTORE_MAP = { '--!' => '-->', '!--' => '<!--' }.freeze
|
|
9
|
-
TRANSLATION_TAG_RESTORE_REGEX =
|
|
10
|
-
Regexp.new(TRANSLATION_TAG_RESTORE_MAP.keys.map { |x| Regexp.escape(x) }.join('|')).freeze
|
|
6
|
+
extend CamaleonCms::NormalizeAttrs
|
|
11
7
|
|
|
12
8
|
def self.inherited(subclass)
|
|
13
9
|
super
|
|
@@ -22,24 +18,6 @@ module CamaleonCms
|
|
|
22
18
|
# attr_accessible :data_options
|
|
23
19
|
# attr_accessible :data_metas
|
|
24
20
|
|
|
25
|
-
# TODO: Remove the 1st branch when support will be dropped of Rails < 7.1
|
|
26
|
-
if ::Rails::VERSION::STRING < '7.1.0'
|
|
27
|
-
before_validation(on: %i[create update]) do
|
|
28
|
-
%i[name description].each do |attr|
|
|
29
|
-
next unless new_record? || attribute_changed?(attr)
|
|
30
|
-
|
|
31
|
-
self[attr] = ActionController::Base.helpers.sanitize(
|
|
32
|
-
__send__(attr)&.gsub(TRANSLATION_TAG_HIDE_REGEX, TRANSLATION_TAG_HIDE_MAP)
|
|
33
|
-
)&.gsub(TRANSLATION_TAG_RESTORE_REGEX, TRANSLATION_TAG_RESTORE_MAP)
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
else
|
|
37
|
-
normalizes :name, :description, with: lambda { |field|
|
|
38
|
-
ActionController::Base.helpers.sanitize(field.gsub(TRANSLATION_TAG_HIDE_REGEX, TRANSLATION_TAG_HIDE_MAP))
|
|
39
|
-
.gsub(TRANSLATION_TAG_RESTORE_REGEX, TRANSLATION_TAG_RESTORE_MAP)
|
|
40
|
-
}
|
|
41
|
-
end
|
|
42
|
-
|
|
43
21
|
# callbacks
|
|
44
22
|
before_validation :before_validating
|
|
45
23
|
before_destroy :destroy_dependencies
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module CamaleonCms
|
|
2
2
|
class UserRole < CamaleonCms::TermTaxonomy
|
|
3
|
+
normalize_attrs(:name, :description)
|
|
4
|
+
|
|
3
5
|
after_destroy :set_users_as_cilent
|
|
4
6
|
|
|
5
7
|
default_scope { where(taxonomy: :user_roles) }
|
|
@@ -122,6 +124,17 @@ module CamaleonCms
|
|
|
122
124
|
label: I18n.t('camaleon_cms.admin.sidebar.settings').to_s,
|
|
123
125
|
description: I18n.t('camaleon_cms.admin.users.tool_tip.settings').to_s
|
|
124
126
|
},
|
|
127
|
+
{
|
|
128
|
+
key: 'custom_fields',
|
|
129
|
+
label: I18n.t('camaleon_cms.admin.sidebar.custom_fields', default: 'Custom Fields').to_s,
|
|
130
|
+
description: I18n.t('camaleon_cms.admin.users.tool_tip.custom_fields',
|
|
131
|
+
default: 'Manage custom field groups and fields, including the select_eval type.').to_s
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
key: 'select_eval',
|
|
135
|
+
label: I18n.t('camaleon_cms.admin.custom_field.select_eval', default: 'Select Eval').to_s,
|
|
136
|
+
description: I18n.t('camaleon_cms.admin.users.tool_tip.select_eval', default: 'Allow toggling and using select_eval custom fields in the admin UI.').to_s
|
|
137
|
+
},
|
|
125
138
|
{
|
|
126
139
|
key: 'theme_settings',
|
|
127
140
|
label: I18n.t('camaleon_cms.admin.settings.theme_setting', default: 'Theme Settings').to_s,
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class CamaleonRecord < ActiveRecord::Base
|
|
4
|
+
TRANSLATION_TAG_HIDE_MAP = { '<!--' => '!--', '-->' => '--!' }.freeze
|
|
5
|
+
TRANSLATION_TAG_HIDE_REGEX = Regexp.new(TRANSLATION_TAG_HIDE_MAP.keys.map { |x| Regexp.escape(x) }.join('|')).freeze
|
|
6
|
+
TRANSLATION_TAG_RESTORE_MAP = { '--!' => '-->', '!--' => '<!--' }.freeze
|
|
7
|
+
TRANSLATION_TAG_RESTORE_REGEX =
|
|
8
|
+
Regexp.new(TRANSLATION_TAG_RESTORE_MAP.keys.map { |x| Regexp.escape(x) }.join('|')).freeze
|
|
9
|
+
|
|
4
10
|
include ActiveRecordExtras::Relation
|
|
5
11
|
|
|
6
12
|
self.abstract_class = true
|
|
@@ -43,4 +49,38 @@ class CamaleonRecord < ActiveRecord::Base
|
|
|
43
49
|
def cama_build_cache_key(key)
|
|
44
50
|
_key = "cama_cache_#{self.class.name}_#{id}_#{key}"
|
|
45
51
|
end
|
|
52
|
+
|
|
53
|
+
# Return the current user for this thread/request context.
|
|
54
|
+
# Uses ActiveSupport::CurrentAttributes (CurrentRequest.user)
|
|
55
|
+
def current_user
|
|
56
|
+
return @current_user if defined?(@current_user)
|
|
57
|
+
|
|
58
|
+
@current_user = CurrentRequest.user
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Authorization helpers that delegate to central Ability (CanCan)
|
|
62
|
+
def can?(*args)
|
|
63
|
+
# Return false if no user or site context (e.g., background jobs, console)
|
|
64
|
+
return false if current_user.nil? || current_site.nil?
|
|
65
|
+
|
|
66
|
+
ability.can?(*args)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def ability
|
|
70
|
+
# Memoize Ability per request to avoid repeated DB queries and object instantiation.
|
|
71
|
+
# In tests that modify role meta mid-request, call reset_ability to invalidate cache.
|
|
72
|
+
@ability ||= CamaleonCms::Ability.new(current_user, current_site)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Reset cached ability instance (useful in tests when role meta changes)
|
|
76
|
+
def reset_ability
|
|
77
|
+
@ability = nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# current_site memoized from the CurrentRequest.site
|
|
81
|
+
def current_site
|
|
82
|
+
return @current_site if defined?(@current_site) && @current_site.present?
|
|
83
|
+
|
|
84
|
+
@current_site = CurrentRequest.site
|
|
85
|
+
end
|
|
46
86
|
end
|
|
@@ -95,9 +95,7 @@ module CamaleonCms
|
|
|
95
95
|
f.custom_field_slug == _key && f.group_number == group_number
|
|
96
96
|
end.map(&:value)
|
|
97
97
|
else
|
|
98
|
-
custom_field_values.where(
|
|
99
|
-
custom_field_slug: _key, group_number: group_number
|
|
100
|
-
).pluck(:value)
|
|
98
|
+
custom_field_values.where(custom_field_slug: _key, group_number: group_number).pluck(:value)
|
|
101
99
|
end
|
|
102
100
|
end
|
|
103
101
|
alias get_fields get_field_values
|
|
@@ -137,7 +135,7 @@ module CamaleonCms
|
|
|
137
135
|
def get_field_values_hash(include_options = false)
|
|
138
136
|
fields = {}
|
|
139
137
|
custom_field_values.to_a.uniq.each do |field_value|
|
|
140
|
-
custom_field = field_value.
|
|
138
|
+
custom_field = field_value.custom_field
|
|
141
139
|
values = custom_field.values.where(objectid: id).pluck(:value)
|
|
142
140
|
unless include_options
|
|
143
141
|
fields[field_value.custom_field_slug] =
|
|
@@ -157,8 +155,8 @@ module CamaleonCms
|
|
|
157
155
|
# deprecated f attribute
|
|
158
156
|
def get_fields_object(_f = true)
|
|
159
157
|
fields = {}
|
|
160
|
-
custom_field_values.eager_load(:
|
|
161
|
-
custom_field = field_value.
|
|
158
|
+
custom_field_values.eager_load(:custom_field).to_a.uniq.each do |field_value|
|
|
159
|
+
custom_field = field_value.custom_field
|
|
162
160
|
# if custom_field.options[:show_frontend].to_s.to_bool
|
|
163
161
|
values = custom_field.values.where(objectid: id).pluck(:value)
|
|
164
162
|
fields[field_value.custom_field_slug] =
|
|
@@ -304,7 +302,9 @@ module CamaleonCms
|
|
|
304
302
|
private
|
|
305
303
|
|
|
306
304
|
def fix_meta_value(value)
|
|
307
|
-
|
|
305
|
+
return value.to_json if value.is_a?(ActionController::Parameters)
|
|
306
|
+
return JSON.generate(value) if value.is_a?(Array) || value.is_a?(Hash)
|
|
307
|
+
|
|
308
308
|
value
|
|
309
309
|
end
|
|
310
310
|
|
|
@@ -19,8 +19,7 @@ module CamaleonCms
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
# return value of meta with key: key,
|
|
22
|
-
# if meta not exist, return default
|
|
23
|
-
# return default if meta value == ""
|
|
22
|
+
# if meta not exist, or its value == "", return default
|
|
24
23
|
def get_meta(key, default = nil)
|
|
25
24
|
key_str = key.is_a?(Symbol) ? key.to_s : key
|
|
26
25
|
cama_fetch_cache("meta_#{key_str}") do
|
|
@@ -70,8 +69,7 @@ module CamaleonCms
|
|
|
70
69
|
|
|
71
70
|
# return configuration for current object
|
|
72
71
|
# key: attribute name
|
|
73
|
-
# default: if attribute
|
|
74
|
-
# return default if option value == ""
|
|
72
|
+
# default: if the attribute doesn't exist, or its value == "", return default
|
|
75
73
|
# return value for attribute
|
|
76
74
|
def get_option(key = nil, default = nil, meta_key = '_default')
|
|
77
75
|
values = cama_options(meta_key)
|
|
@@ -133,8 +131,14 @@ module CamaleonCms
|
|
|
133
131
|
|
|
134
132
|
# fix to parse value
|
|
135
133
|
def fix_meta_value(value)
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
changed_value = if value.is_a?(ActionController::Parameters)
|
|
135
|
+
value.to_json
|
|
136
|
+
elsif value.is_a?(Array) || value.is_a?(Hash)
|
|
137
|
+
JSON.generate(value)
|
|
138
|
+
else
|
|
139
|
+
value
|
|
140
|
+
end
|
|
141
|
+
fix_meta_var(changed_value)
|
|
138
142
|
end
|
|
139
143
|
|
|
140
144
|
# fix to detect type of the variable
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CamaleonCms
|
|
4
|
+
module NormalizeAttrs
|
|
5
|
+
def normalize_attrs(*args)
|
|
6
|
+
# TODO: Remove the 1st branch when support will be dropped of Rails < 7.1
|
|
7
|
+
if ::Rails::VERSION::STRING < '7.1.0'
|
|
8
|
+
before_validation(on: %i[create update]) do
|
|
9
|
+
args.each do |attr|
|
|
10
|
+
next unless new_record? || attribute_changed?(attr)
|
|
11
|
+
|
|
12
|
+
self[attr] = ActionController::Base.helpers.sanitize(
|
|
13
|
+
__send__(attr)&.gsub(CamaleonRecord::TRANSLATION_TAG_HIDE_REGEX, CamaleonRecord::TRANSLATION_TAG_HIDE_MAP)
|
|
14
|
+
)&.gsub(CamaleonRecord::TRANSLATION_TAG_RESTORE_REGEX, CamaleonRecord::TRANSLATION_TAG_RESTORE_MAP)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
else
|
|
18
|
+
normalizes(*args, with: lambda { |field|
|
|
19
|
+
ActionController::Base.helpers.sanitize(
|
|
20
|
+
field.gsub(CamaleonRecord::TRANSLATION_TAG_HIDE_REGEX, CamaleonRecord::TRANSLATION_TAG_HIDE_MAP)
|
|
21
|
+
).gsub(CamaleonRecord::TRANSLATION_TAG_RESTORE_REGEX, CamaleonRecord::TRANSLATION_TAG_RESTORE_MAP)
|
|
22
|
+
})
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -6,17 +6,21 @@ module CamaleonCms
|
|
|
6
6
|
include CamaleonCms::CustomFieldsRead
|
|
7
7
|
include CamaleonCms::CommonRelationships
|
|
8
8
|
|
|
9
|
+
extend CamaleonCms::NormalizeAttrs
|
|
10
|
+
|
|
9
11
|
validates_uniqueness_of :username, scope: [:site_id], case_sensitive: false,
|
|
10
12
|
message: I18n.t('camaleon_cms.admin.users.message.requires_different_username', default: 'Requires different username')
|
|
11
13
|
validates_uniqueness_of :email, scope: [:site_id], case_sensitive: false,
|
|
12
14
|
message: I18n.t('camaleon_cms.admin.users.message.requires_different_email', default: 'Requires different email')
|
|
13
15
|
|
|
16
|
+
normalize_attrs(:first_name, :last_name, :username)
|
|
17
|
+
|
|
14
18
|
# callbacks
|
|
15
19
|
before_validation :cama_before_validation
|
|
16
20
|
before_destroy :reassign_posts
|
|
17
21
|
after_destroy :reassign_comments
|
|
18
22
|
before_create { generate_token(:auth_token) }
|
|
19
|
-
#
|
|
23
|
+
# invalidate sessions when changing password
|
|
20
24
|
before_update { generate_token :auth_token if will_save_change_to_password_digest? }
|
|
21
25
|
|
|
22
26
|
# relations
|
|
@@ -117,7 +121,7 @@ module CamaleonCms
|
|
|
117
121
|
|
|
118
122
|
# reassign all posts of this user to first admin
|
|
119
123
|
# reassign all comments of this user to first admin
|
|
120
|
-
# if doesn't exist any other administrator, this will cancel the user destroy
|
|
124
|
+
# if it doesn't exist any other administrator, this will cancel the user destroy
|
|
121
125
|
def reassign_posts
|
|
122
126
|
all_posts.each do |p|
|
|
123
127
|
s = p.post_type.site
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# CurrentRequest holds per-request state (user, site) accessible to models
|
|
2
|
+
# via ActiveSupport::CurrentAttributes (thread-safe, resets after each request).
|
|
3
|
+
#
|
|
4
|
+
# Usage in controllers:
|
|
5
|
+
# CurrentRequest.user = cama_current_user
|
|
6
|
+
# CurrentRequest.site = current_site
|
|
7
|
+
#
|
|
8
|
+
# Usage in models:
|
|
9
|
+
# current_user # delegates to CurrentRequest.user via CamaleonRecord
|
|
10
|
+
# current_site # delegates to CurrentRequest.site via CamaleonRecord
|
|
11
|
+
#
|
|
12
|
+
# Note: Rails automatically resets CurrentAttributes between requests, ensuring no leakage.
|
|
13
|
+
# In specs, call CurrentRequest.reset in before/after hooks to avoid cross-test pollution.
|
|
14
|
+
class CurrentRequest < ActiveSupport::CurrentAttributes
|
|
15
|
+
attribute :user, :site
|
|
16
|
+
end
|
|
@@ -37,6 +37,8 @@ class CamaleonCmsAwsUploader < CamaleonCmsUploader
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def fetch_file(file_name)
|
|
40
|
+
return { error: 'Invalid file path' } unless valid_folder_path?(file_name)
|
|
41
|
+
|
|
40
42
|
return file_name if file_exists?(file_name)
|
|
41
43
|
|
|
42
44
|
return file_name if bucket.object(file_name).download_file(file_name) && file_exists?(file_name)
|
|
@@ -84,8 +86,9 @@ class CamaleonCmsAwsUploader < CamaleonCmsUploader
|
|
|
84
86
|
# - same_name: false => avoid to overwrite an existent file with same key and search for an available key
|
|
85
87
|
# - is_thumb: true => if this file is a thumbnail of an uploaded file
|
|
86
88
|
def add_file(uploaded_io_or_file_path, key, args = {})
|
|
89
|
+
return { error: 'Invalid file path' } unless valid_folder_path?(key)
|
|
90
|
+
|
|
87
91
|
args = { same_name: false, is_thumb: false }.merge(args)
|
|
88
|
-
res = nil
|
|
89
92
|
key = "#{@aws_settings['inner_folder']}/#{key}" if @aws_settings['inner_folder'].present? && !args[:is_thumb]
|
|
90
93
|
key = key.cama_fix_media_key
|
|
91
94
|
key = search_new_key(key) unless args[:same_name]
|
|
@@ -117,6 +120,8 @@ class CamaleonCmsAwsUploader < CamaleonCmsUploader
|
|
|
117
120
|
|
|
118
121
|
# delete a folder in AWS with :key
|
|
119
122
|
def delete_folder(key)
|
|
123
|
+
return { error: 'Invalid folder path' } unless valid_folder_path?(key)
|
|
124
|
+
|
|
120
125
|
key = "#{@aws_settings['inner_folder']}/#{key}" if @aws_settings['inner_folder'].present?
|
|
121
126
|
key = key.cama_fix_media_key
|
|
122
127
|
bucket.objects(prefix: key.slice(1..-1) << '/').delete
|
|
@@ -125,6 +130,8 @@ class CamaleonCmsAwsUploader < CamaleonCmsUploader
|
|
|
125
130
|
|
|
126
131
|
# delete a file in AWS with :key
|
|
127
132
|
def delete_file(key)
|
|
133
|
+
return { error: 'Invalid file path' } unless valid_folder_path?(key)
|
|
134
|
+
|
|
128
135
|
key = "#{@aws_settings['inner_folder']}/#{key}" if @aws_settings['inner_folder'].present?
|
|
129
136
|
key = key.cama_fix_media_key
|
|
130
137
|
begin
|
|
@@ -7,11 +7,23 @@ module CamaleonCms
|
|
|
7
7
|
ptype = record.post_type
|
|
8
8
|
return unless ptype.present? # only for posts that belongs to a post type model
|
|
9
9
|
|
|
10
|
+
post_table = CamaleonCms::Post.table_name
|
|
11
|
+
|
|
12
|
+
conditions = []
|
|
13
|
+
params = []
|
|
14
|
+
|
|
15
|
+
slug_array.each do |s|
|
|
16
|
+
conditions << "#{post_table}.slug LIKE ?"
|
|
17
|
+
params << "%-->#{s}<!--%"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
conditions << "#{post_table}.slug = ?"
|
|
21
|
+
params << record.slug
|
|
22
|
+
|
|
23
|
+
where_clause = "(#{conditions.join(' OR ')})"
|
|
24
|
+
|
|
10
25
|
posts = ptype.site.posts
|
|
11
|
-
.where(
|
|
12
|
-
"(#{slug_array.map { |s| "#{CamaleonCms::Post.table_name}.slug LIKE '%-->#{s}<!--%'" }
|
|
13
|
-
.join(' OR ')} ) OR #{CamaleonCms::Post.table_name}.slug = ?", record.slug
|
|
14
|
-
)
|
|
26
|
+
.where(where_clause, *params)
|
|
15
27
|
.where.not(id: record.id)
|
|
16
28
|
.where.not(status: %i[draft draft_child trash])
|
|
17
29
|
unless posts.empty?
|
|
@@ -28,10 +40,11 @@ module CamaleonCms
|
|
|
28
40
|
end
|
|
29
41
|
|
|
30
42
|
# avoid recursive page parent
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
return unless record.post_parent.present? && ptype.manage_hierarchy? &&
|
|
44
|
+
record.parents.cama_pluck(:id).include?(record.id)
|
|
45
|
+
|
|
46
|
+
record.errors[:base] << I18n.t('camaleon_cms.admin.post.message.recursive_hierarchy',
|
|
47
|
+
default: 'Parent Post Recursive')
|
|
35
48
|
end
|
|
36
49
|
end
|
|
37
50
|
end
|
|
@@ -46,12 +46,12 @@
|
|
|
46
46
|
</div>
|
|
47
47
|
<% if pt.manage_categories? %>
|
|
48
48
|
<div class="tab-pane class_type" id="tab-<%= pt.slug %>-categories" data-type="category" data-post_type="<%= pt.slug %>">
|
|
49
|
-
<%=
|
|
49
|
+
<%= post_type_html_inputs(pt, "categories", "categories", "checkbox", [], "categorychecklist") %>
|
|
50
50
|
</div>
|
|
51
51
|
<% end %>
|
|
52
52
|
<% if pt.manage_tags? %>
|
|
53
53
|
<div class="tab-pane class_type" id="tab-<%= pt.slug %>-tags" data-type="post_tag" data-post_type="<%= pt.slug %>">
|
|
54
|
-
<%=
|
|
54
|
+
<%= post_type_html_inputs(pt, "post_tags", "post_tags", "checkbox", [], "categorychecklist") %>
|
|
55
55
|
</div>
|
|
56
56
|
<% end %>
|
|
57
57
|
</div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<div class="alert alert-warning"><%= t('camaleon_cms.admin.widgets.warning') %></div>
|
|
1
2
|
<%= form_for @widget, as: "widget_main", url: { action: (@widget.new_record? ? "create" : "update"), controller: "camaleon_cms/admin/appearances/widgets/main", id: @widget }, html: { role: 'form', class: "validate cama_ajax_request", id: "widget_form" } do |f| %>
|
|
2
3
|
<%= render partial: 'layouts/camaleon_cms/admin/form_error', locals: {data: @widget} %>
|
|
3
4
|
<div class="form-group">
|
|
@@ -24,4 +25,3 @@
|
|
|
24
25
|
jQuery(function(){ init_form_validations($("#widget_form")); });
|
|
25
26
|
</script>
|
|
26
27
|
<% end %>
|
|
27
|
-
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
</tbody>
|
|
59
59
|
</table>
|
|
60
60
|
<%= content_tag("div", raw(t('camaleon_cms.admin.message.data_found_list')), class: "alert alert-warning") if @categories.empty? %>
|
|
61
|
-
<%=
|
|
61
|
+
<%= cama_do_pagination(@categories) %>
|
|
62
62
|
</div>
|
|
63
63
|
</div>
|
|
64
64
|
<!-- END BASIC TABLE SAMPLE -->
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<div class="panel-body">
|
|
16
16
|
<div class="messages messages-img">
|
|
17
17
|
<%= raw "<div class='alert alert-warning'>#{t('camaleon_cms.admin.comments.message.there_no_comments')}</div>" if @comments.size == 0 %>
|
|
18
|
-
<%=
|
|
18
|
+
<%= cama_comments_render_html(@comments) %>
|
|
19
19
|
</div>
|
|
20
20
|
</div>
|
|
21
|
-
</div>
|
|
21
|
+
</div>
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
</tbody>
|
|
47
47
|
</table>
|
|
48
48
|
<%= content_tag("div", raw(t('camaleon_cms.admin.message.data_found_list')), class: "alert alert-warning") if @post_tags.empty? %>
|
|
49
|
-
<%=
|
|
49
|
+
<%= cama_do_pagination(@post_tags) %>
|
|
50
50
|
</div>
|
|
51
51
|
</div>
|
|
52
52
|
<!-- END BASIC TABLE SAMPLE -->
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
</div>
|
|
102
102
|
<div class="panel-body ">
|
|
103
103
|
<div class="form-group list-categories">
|
|
104
|
-
<%=
|
|
104
|
+
<%= post_type_html_inputs(@post_type, "categories", "categories" , @post_type.get_option('has_single_category', false) ? 'radio' : "checkbox" ,params[:categories] || (@post.new_record? ? [] : @post.categories.pluck("#{CamaleonCms::TermTaxonomy.table_name}.id")), "categorychecklist", true )%>
|
|
105
105
|
</div>
|
|
106
106
|
</div>
|
|
107
107
|
</div>
|