camaleon_cms 2.9.2 → 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 +17 -4
- 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 +15 -10
- data/app/apps/plugins/front_cache/config/initializer.rb +1 -1
- data/app/apps/plugins/front_cache/front_cache_helper.rb +33 -9
- 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/layouts/index.html.erb +3 -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/layouts/_header.html.erb +3 -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 +8 -6
- data/app/controllers/camaleon_cms/admin/appearances/themes_controller.rb +8 -5
- data/app/controllers/camaleon_cms/admin/appearances/widgets/assign_controller.rb +7 -2
- data/app/controllers/camaleon_cms/admin/appearances/widgets/main_controller.rb +2 -1
- data/app/controllers/camaleon_cms/admin/categories_controller.rb +19 -4
- 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 +66 -14
- data/app/controllers/camaleon_cms/admin/plugins_controller.rb +1 -3
- data/app/controllers/camaleon_cms/admin/post_tags_controller.rb +10 -4
- data/app/controllers/camaleon_cms/admin/posts/drafts_controller.rb +40 -11
- data/app/controllers/camaleon_cms/admin/posts_controller.rb +55 -22
- data/app/controllers/camaleon_cms/admin/sessions_controller.rb +237 -44
- data/app/controllers/camaleon_cms/admin/settings/custom_fields_controller.rb +76 -13
- data/app/controllers/camaleon_cms/admin/settings/post_types_controller.rb +5 -2
- data/app/controllers/camaleon_cms/admin/settings/sites_controller.rb +26 -3
- data/app/controllers/camaleon_cms/admin/settings_controller.rb +5 -3
- data/app/controllers/camaleon_cms/admin/user_roles_controller.rb +7 -5
- data/app/controllers/camaleon_cms/admin/users_controller.rb +78 -11
- data/app/controllers/camaleon_cms/admin_controller.rb +136 -26
- 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 +20 -5
- 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 +66 -50
- 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 +5 -8
- 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 +34 -17
- 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 +19 -7
- 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 +143 -66
- 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 +58 -37
- data/app/helpers/camaleon_cms/plugins_helper.rb +23 -24
- data/app/helpers/camaleon_cms/session_helper.rb +188 -44
- data/app/helpers/camaleon_cms/short_code_helper.rb +181 -85
- data/app/helpers/camaleon_cms/site_helper.rb +34 -13
- data/app/helpers/camaleon_cms/theme_helper.rb +35 -19
- data/app/helpers/camaleon_cms/uploader_helper.rb +19 -473
- 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 +15 -7
- data/app/models/camaleon_cms/category.rb +6 -6
- data/app/models/camaleon_cms/custom_field.rb +15 -6
- data/app/models/camaleon_cms/custom_field_group.rb +39 -22
- 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 +5 -3
- data/app/models/camaleon_cms/nav_menu_item.rb +16 -8
- data/app/models/camaleon_cms/plugin.rb +3 -4
- 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 -5
- data/app/models/camaleon_cms/post_type.rb +21 -13
- data/app/models/camaleon_cms/site.rb +39 -29
- data/app/models/camaleon_cms/term_relationship.rb +10 -7
- data/app/models/camaleon_cms/term_taxonomy.rb +52 -4
- data/app/models/camaleon_cms/theme.rb +2 -4
- data/app/models/camaleon_cms/user.rb +17 -5
- data/app/models/camaleon_cms/user_role.rb +66 -6
- data/app/models/camaleon_cms/widget/assigned.rb +11 -6
- data/app/models/camaleon_cms/widget/main.rb +12 -8
- data/app/models/camaleon_cms/widget/sidebar.rb +3 -8
- data/app/models/camaleon_record.rb +89 -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 +111 -54
- data/app/models/concerns/camaleon_cms/metas.rb +31 -6
- 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 +8 -1
- data/app/uploaders/camaleon_cms_aws_uploader.rb +31 -10
- 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 +5 -4
- 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/categories/index.html.erb +2 -2
- 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 +2 -2
- data/app/views/camaleon_cms/admin/posts/_sidebar.html.erb +1 -1
- data/app/views/camaleon_cms/admin/posts/form.html.erb +3 -2
- data/app/views/camaleon_cms/admin/posts/index.html.erb +5 -5
- 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 +19 -4
- 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/form.html.erb +4 -3
- 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/user_roles/form.html.erb +24 -3
- data/app/views/camaleon_cms/admin/users/form.html.erb +8 -4
- data/app/views/camaleon_cms/admin/users/index.html.erb +1 -1
- 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/_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 +1 -1
- data/config/locales/camaleon_cms/admin/ar.yml +1 -0
- data/config/locales/camaleon_cms/admin/de.yml +1 -0
- data/config/locales/camaleon_cms/admin/en.yml +33 -0
- data/config/locales/camaleon_cms/admin/es.yml +1 -0
- data/config/locales/camaleon_cms/admin/fr.yml +1 -0
- data/config/locales/camaleon_cms/admin/it.yml +1 -0
- data/config/locales/camaleon_cms/admin/nl.yml +1 -0
- data/config/locales/camaleon_cms/admin/pt-BR.yml +1 -0
- data/config/locales/camaleon_cms/admin/pt.yml +1 -0
- data/config/locales/camaleon_cms/admin/ru.yml +1 -0
- data/config/locales/camaleon_cms/admin/uk.yml +1 -0
- data/config/locales/camaleon_cms/admin/zh-CH.yml +1 -0
- data/config/routes/admin.rb +33 -15
- data/config/routes/frontend.rb +21 -15
- 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 +10 -5
- 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 +15 -13
- 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 +123 -4
|
@@ -12,15 +12,18 @@ module CamaleonCms
|
|
|
12
12
|
# return the excerpt of this post
|
|
13
13
|
def the_excerpt(qty_chars = 200)
|
|
14
14
|
excerpt = object.get_meta('summary').to_s.translate(get_locale)
|
|
15
|
-
# r = {
|
|
15
|
+
# r = {
|
|
16
|
+
# content: (
|
|
17
|
+
# (excerpt if excerpt.present?) ||
|
|
18
|
+
# object.content_filtered.to_s.translate(get_locale).strip_tags.gsub(/ |\n/, " ").truncate(qty_chars)
|
|
19
|
+
# ),
|
|
20
|
+
# post: object
|
|
21
|
+
# }
|
|
16
22
|
r = {
|
|
17
|
-
content:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/ |\n/, ' '
|
|
22
|
-
).truncate(qty_chars))
|
|
23
|
-
end), post: object
|
|
23
|
+
content:
|
|
24
|
+
excerpt.presence || h.cama_strip_shortcodes(object.content_filtered.to_s.translate(get_locale)
|
|
25
|
+
.strip_tags.gsub(/ |\n/, ' ').truncate(qty_chars)),
|
|
26
|
+
post: object
|
|
24
27
|
}
|
|
25
28
|
h.hooks_run('post_the_excerpt', r)
|
|
26
29
|
r[:content]
|
|
@@ -33,17 +36,13 @@ module CamaleonCms
|
|
|
33
36
|
h.do_shortcode(r[:content], self)
|
|
34
37
|
end
|
|
35
38
|
|
|
36
|
-
#
|
|
39
|
+
# Return the thumbnail image for this post
|
|
37
40
|
# default: default image if thumbails not exist
|
|
38
41
|
# if default is empty, post_type default thumb will be returned
|
|
39
42
|
def the_thumb_url(default = nil)
|
|
40
43
|
th = object.get_meta('thumb')
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
else
|
|
44
|
-
default || object.post_type.get_option('default_thumb',
|
|
45
|
-
nil) || h.asset_url('camaleon_cms/image-not-found.png')
|
|
46
|
-
end
|
|
44
|
+
th.presence || default || object.post_type.get_option('default_thumb', nil) ||
|
|
45
|
+
h.asset_url('camaleon_cms/image-not-found.png')
|
|
47
46
|
end
|
|
48
47
|
alias the_image_url the_thumb_url
|
|
49
48
|
|
|
@@ -93,7 +92,7 @@ module CamaleonCms
|
|
|
93
92
|
args[:label_cat] = I18n.t('routes.category', default: 'category')
|
|
94
93
|
args[:category_id] = cat.id
|
|
95
94
|
args[:title] = cat.the_title(args[:locale]).parameterize
|
|
96
|
-
args[:title] = cat.the_slug
|
|
95
|
+
args[:title] = cat.the_slug if args[:title].blank?
|
|
97
96
|
else
|
|
98
97
|
p_url_format = 'post'
|
|
99
98
|
end
|
|
@@ -110,7 +109,7 @@ module CamaleonCms
|
|
|
110
109
|
args[:post_type_title] = ptype.the_title(args[:locale]).parameterize.presence || ptype.the_slug
|
|
111
110
|
args[:category_id] = cat.id
|
|
112
111
|
args[:title] = cat.the_title(args[:locale]).parameterize
|
|
113
|
-
args[:title] = cat.the_slug
|
|
112
|
+
args[:title] = cat.the_slug if args[:title].blank?
|
|
114
113
|
else
|
|
115
114
|
p_url_format = 'post'
|
|
116
115
|
end
|
|
@@ -130,12 +129,10 @@ module CamaleonCms
|
|
|
130
129
|
# sample: {es: 'https://mydomain.com/es/articulo-3.html', en: 'https://mydomain.com/en/post-3.html'}
|
|
131
130
|
def the_urls(*args)
|
|
132
131
|
args = args.extract_options!
|
|
133
|
-
|
|
134
|
-
h.current_site.the_languages.each do |l|
|
|
132
|
+
h.current_site.the_languages.each_with_object({}) do |l, hsh|
|
|
135
133
|
args[:locale] = l
|
|
136
|
-
|
|
134
|
+
hsh[l] = the_url(args.clone)
|
|
137
135
|
end
|
|
138
|
-
res
|
|
139
136
|
end
|
|
140
137
|
|
|
141
138
|
# return edit url for this post
|
|
@@ -148,10 +145,10 @@ module CamaleonCms
|
|
|
148
145
|
# return html link
|
|
149
146
|
# attrs: Hash of link tag attributes, sample: {id: "myid", class: "sss" }
|
|
150
147
|
def the_edit_link(title = nil, attrs = {})
|
|
151
|
-
return ''
|
|
148
|
+
return '' if h.cama_current_user.blank?
|
|
152
149
|
|
|
153
|
-
attrs = { target: '_blank', style: 'font-size:11px !important;cursor:pointer;' }.merge(attrs)
|
|
154
|
-
h.link_to(
|
|
150
|
+
attrs = { target: '_blank', style: 'font-size:11px !important;cursor:pointer;' }.merge!(attrs)
|
|
151
|
+
h.link_to(h.safe_join(['→ ', title || h.ct('edit', default: 'Edit')]), the_edit_url, attrs)
|
|
155
152
|
end
|
|
156
153
|
|
|
157
154
|
# show thumbnail image as html
|
|
@@ -162,7 +159,7 @@ module CamaleonCms
|
|
|
162
159
|
end
|
|
163
160
|
|
|
164
161
|
# show link and thumbnail included as html
|
|
165
|
-
# link_args: html attributes for link
|
|
162
|
+
# link_args: html attributes for the link
|
|
166
163
|
# img_args: html attributes for image
|
|
167
164
|
def the_link_thumb(link_args = {}, img_args = {})
|
|
168
165
|
h.link_to(the_thumb(img_args), the_url, link_args)
|
|
@@ -186,7 +183,15 @@ module CamaleonCms
|
|
|
186
183
|
color = 'default'
|
|
187
184
|
status = self.status
|
|
188
185
|
end
|
|
189
|
-
|
|
186
|
+
# The `else` arm above returns the raw column value, which is not validated and is writable at
|
|
187
|
+
# contributor privilege, and three admin views render this label through `raw`. Escaping the
|
|
188
|
+
# interpolated value here -- at the source, as `the_title` does -- is what makes those sinks
|
|
189
|
+
# safe. `titleize` is not a mitigation: HTML tag names and hostnames are case-insensitive.
|
|
190
|
+
# `content_tag` is deliberately not used: it emits double-quoted attributes and would change
|
|
191
|
+
# the byte output for every legitimate status, which downstream themes may match on.
|
|
192
|
+
# rubocop:disable Rails/OutputSafety -- only the escaped status is interpolated into fixed markup
|
|
193
|
+
"<span class='label label-#{color} label-form'>#{h.h(status.titleize)}</span>".html_safe
|
|
194
|
+
# rubocop:enable Rails/OutputSafety
|
|
190
195
|
end
|
|
191
196
|
|
|
192
197
|
# return the user object who created this post
|
|
@@ -209,7 +214,7 @@ module CamaleonCms
|
|
|
209
214
|
object.comments.main.approveds.eager_load(:user)
|
|
210
215
|
end
|
|
211
216
|
|
|
212
|
-
# check if the post can be visited by current
|
|
217
|
+
# check if the post can be visited by the current user
|
|
213
218
|
def can_visit?
|
|
214
219
|
r = { flag: true, post: object }
|
|
215
220
|
h.hooks_run('post_can_visit', r)
|
|
@@ -228,7 +233,7 @@ module CamaleonCms
|
|
|
228
233
|
p_type.decorate.generate_breadcrumb(add_post_type, true)
|
|
229
234
|
end
|
|
230
235
|
if object.post_parent.present? && p_type.manage_hierarchy?
|
|
231
|
-
object.parents.
|
|
236
|
+
object.parents.reverse_each do |p|
|
|
232
237
|
p = p.decorate
|
|
233
238
|
h.breadcrumb_add(p.the_title, p.published? ? p.the_url : nil)
|
|
234
239
|
end
|
|
@@ -238,50 +243,61 @@ module CamaleonCms
|
|
|
238
243
|
|
|
239
244
|
# return the post type of this post
|
|
240
245
|
def the_post_type
|
|
241
|
-
object.post_type.decorate
|
|
246
|
+
@the_post_type ||= object.post_type.decorate
|
|
242
247
|
end
|
|
243
248
|
|
|
244
|
-
# looks for the next post item related to parent element based on post_order attribute
|
|
245
|
-
# @param
|
|
249
|
+
# It looks for the next post item related to the parent element based on the post_order attribute
|
|
250
|
+
# @param parent: parent decorated model, like: (PostType *default), Category, PostTag, Site
|
|
246
251
|
# @samples: my_post.the_next_post(), my_post.the_next_post(@category), my_post.the_next_post(current_site)
|
|
247
|
-
def the_next_post(
|
|
248
|
-
(
|
|
249
|
-
|
|
250
|
-
position: object.post_order, created_at: object.created_at
|
|
251
|
-
}
|
|
252
|
+
def the_next_post(parent = nil)
|
|
253
|
+
(parent.presence || the_post_type).the_posts.where(
|
|
254
|
+
post_order_predicate_gt(object.post_order, object.created_at)
|
|
252
255
|
).where.not(id: object.id).take.try(:decorate)
|
|
253
256
|
end
|
|
254
257
|
|
|
255
|
-
# looks for the next post item related to parent element based on post_order attribute
|
|
256
|
-
# @param
|
|
258
|
+
# looks for the next post item related to the parent element based on post_order attribute
|
|
259
|
+
# @param parent: parent decorated model, like: (PostType *default), Category, PostTag, Site
|
|
257
260
|
# @samples: my_post.the_prev_post(), my_post.the_prev_post(@category), my_post.the_prev_post(current_site)
|
|
258
|
-
def the_prev_post(
|
|
259
|
-
(
|
|
260
|
-
post_order
|
|
261
|
-
|
|
261
|
+
def the_prev_post(parent = nil)
|
|
262
|
+
(parent.presence || the_post_type).the_posts
|
|
263
|
+
.where(post_order_predicate_lt(object.post_order, object.created_at))
|
|
264
|
+
.where.not(id: object.id).reorder(post_order: :asc, created_at: :asc).last.try(:decorate)
|
|
262
265
|
end
|
|
263
266
|
|
|
264
267
|
# return the title with hierarchy prefixed
|
|
265
|
-
# sample: title paren 1 - title parent 2
|
|
268
|
+
# sample: title paren 1 - title parent 2 -... -...
|
|
266
269
|
# if add_parent_title: true will add parent title like: —— item 1.1.1 | item 1.1
|
|
267
270
|
def the_hierarchy_title
|
|
268
|
-
return the_title
|
|
271
|
+
return the_title if object.post_parent.blank?
|
|
269
272
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
res.html_safe
|
|
273
|
+
parts = [h.raw('—' * object.parents.count), h.sanitize(" #{the_title}")]
|
|
274
|
+
parts << h.sanitize(" | #{object.parent.decorate.the_title}") if object.show_title_with_parent
|
|
275
|
+
h.safe_join(parts)
|
|
274
276
|
end
|
|
275
277
|
|
|
276
|
-
# return all related posts of current post
|
|
278
|
+
# return all related posts of the current post
|
|
277
279
|
def the_related_posts
|
|
278
280
|
ptype = the_post_type
|
|
279
|
-
ptype.the_posts.joins(:categories).where(
|
|
281
|
+
ptype.the_posts.joins(:categories).where(
|
|
282
|
+
CamaleonCms::TermRelationship.table_name.to_s => { term_taxonomy_id: the_categories.pluck(:id) }
|
|
283
|
+
).distinct
|
|
280
284
|
end
|
|
281
285
|
|
|
282
286
|
# fix for "Using Draper::Decorator without inferred source class"
|
|
283
287
|
def self.object_class_name
|
|
284
288
|
'CamaleonCms::Post'
|
|
285
289
|
end
|
|
290
|
+
|
|
291
|
+
private
|
|
292
|
+
|
|
293
|
+
def post_order_predicate_gt(position, created_at)
|
|
294
|
+
t = CamaleonCms::Post.arel_table
|
|
295
|
+
t[:post_order].gt(position).or(t[:post_order].eq(position).and(t[:created_at].gt(created_at)))
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def post_order_predicate_lt(position, created_at)
|
|
299
|
+
t = CamaleonCms::Post.arel_table
|
|
300
|
+
t[:post_order].lt(position).or(t[:post_order].eq(position).and(t[:created_at].lt(created_at)))
|
|
301
|
+
end
|
|
286
302
|
end
|
|
287
303
|
end
|
|
@@ -71,7 +71,7 @@ module CamaleonCms
|
|
|
71
71
|
def the_category(slug_or_id)
|
|
72
72
|
return the_categories.where(id: slug_or_id).first if slug_or_id.is_a?(Integer)
|
|
73
73
|
|
|
74
|
-
the_categories.find_by_slug(slug_or_id) if slug_or_id.is_a?(String)
|
|
74
|
+
the_categories.find_by_slug(slug_or_id) if slug_or_id.is_a?(String) # rubocop:disable Rails/DynamicFindBy
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
# return all post_tags for the post_type (active_record) filtered by permissions + hidden posts + roles + etc...
|
|
@@ -67,8 +67,10 @@ module CamaleonCms
|
|
|
67
67
|
nil
|
|
68
68
|
end
|
|
69
69
|
end
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
# use find_by_slug (multi-language aware) so posts with localized slugs
|
|
71
|
+
# (e.g. "<!--:en-->sample-post<!--:-->...") are matched instead of returning nil
|
|
72
|
+
post = the_posts.find_by_slug(slug_or_id) if slug_or_id.is_a?(String) # rubocop:disable Rails/DynamicFindBy
|
|
73
|
+
post&.decorate
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
# return a collection of categories
|
|
@@ -81,7 +83,7 @@ module CamaleonCms
|
|
|
81
83
|
def the_categories(slug_or_id = nil)
|
|
82
84
|
return the_post_type(slug_or_id).the_categories if slug_or_id.present?
|
|
83
85
|
|
|
84
|
-
object.categories
|
|
86
|
+
object.categories if slug_or_id.blank?
|
|
85
87
|
end
|
|
86
88
|
|
|
87
89
|
# return the category object with id or slug = slug_or_id from this site
|
|
@@ -96,7 +98,7 @@ module CamaleonCms
|
|
|
96
98
|
return unless slug_or_id.is_a?(String)
|
|
97
99
|
|
|
98
100
|
begin
|
|
99
|
-
the_full_categories.find_by_slug(slug_or_id).decorate
|
|
101
|
+
the_full_categories.find_by_slug(slug_or_id).decorate # rubocop:disable Rails/DynamicFindBy
|
|
100
102
|
rescue StandardError
|
|
101
103
|
nil
|
|
102
104
|
end
|
|
@@ -126,7 +128,7 @@ module CamaleonCms
|
|
|
126
128
|
return unless slug_or_id.is_a?(String)
|
|
127
129
|
|
|
128
130
|
begin
|
|
129
|
-
object.post_tags.find_by_slug(slug_or_id).decorate
|
|
131
|
+
object.post_tags.find_by_slug(slug_or_id).decorate # rubocop:disable Rails/DynamicFindBy
|
|
130
132
|
rescue StandardError
|
|
131
133
|
nil
|
|
132
134
|
end
|
|
@@ -144,7 +146,7 @@ module CamaleonCms
|
|
|
144
146
|
return unless id_or_username.is_a?(String)
|
|
145
147
|
|
|
146
148
|
begin
|
|
147
|
-
object.users.find_by_username(id_or_username).decorate
|
|
149
|
+
object.users.find_by_username(id_or_username).decorate # rubocop:disable Rails/DynamicFindBy
|
|
148
150
|
rescue StandardError
|
|
149
151
|
nil
|
|
150
152
|
end
|
|
@@ -165,14 +167,14 @@ module CamaleonCms
|
|
|
165
167
|
def the_post_type(slug_or_id)
|
|
166
168
|
if slug_or_id.is_a?(String)
|
|
167
169
|
begin
|
|
168
|
-
return object.post_types.find_by_slug(slug_or_id).decorate
|
|
170
|
+
return object.post_types.find_by_slug(slug_or_id).decorate # rubocop:disable Rails/DynamicFindBy
|
|
169
171
|
rescue StandardError
|
|
170
172
|
nil
|
|
171
173
|
end
|
|
172
174
|
end
|
|
173
175
|
if slug_or_id.is_a?(Array)
|
|
174
176
|
begin
|
|
175
|
-
return object.post_types.find_by_slug(slug_or_id).decorate
|
|
177
|
+
return object.post_types.find_by_slug(slug_or_id).decorate # rubocop:disable Rails/DynamicFindBy
|
|
176
178
|
rescue StandardError
|
|
177
179
|
nil
|
|
178
180
|
end
|
|
@@ -195,21 +197,25 @@ module CamaleonCms
|
|
|
195
197
|
lan = object.get_languages
|
|
196
198
|
return if lan.size < 2
|
|
197
199
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
200
|
+
h.content_tag(:ul, class: list_class) do
|
|
201
|
+
h.safe_join(lan.map do |lang|
|
|
202
|
+
label = if block
|
|
203
|
+
h.capture(lang, I18n.locale.to_s == lang.to_s, &block)
|
|
204
|
+
else
|
|
205
|
+
h.tag.img(src: h.asset_path("camaleon_cms/language/#{lang}.png"))
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
h.content_tag(:li, class: (current_class if I18n.locale.to_s == lang.to_s)) do
|
|
209
|
+
h.link_to(
|
|
210
|
+
label,
|
|
211
|
+
h.cama_url_to_fixed(
|
|
212
|
+
current_page ? 'url_for' : 'cama_root_url',
|
|
213
|
+
{ locale: lang, cama_set_language: lang }
|
|
214
|
+
)
|
|
215
|
+
)
|
|
216
|
+
end
|
|
217
|
+
end)
|
|
210
218
|
end
|
|
211
|
-
res << '</ul>'
|
|
212
|
-
res.join('').html_safe
|
|
213
219
|
end
|
|
214
220
|
|
|
215
221
|
# return Array of frontend languages configured for this site
|
|
@@ -245,7 +251,7 @@ module CamaleonCms
|
|
|
245
251
|
postfix = 'url'
|
|
246
252
|
postfix = 'path' if args.delete(:as_path)
|
|
247
253
|
skip_relative_url_root = args.delete(:skip_relative_url_root)
|
|
248
|
-
h.cama_current_site_host_port(args) unless args.
|
|
254
|
+
h.cama_current_site_host_port(args) unless args.key?(:host)
|
|
249
255
|
res = h.cama_url_to_fixed("cama_root_#{postfix}", args)
|
|
250
256
|
if skip_relative_url_root && PluginRoutes.static_system_info['relative_url_root'].present?
|
|
251
257
|
res = res.sub("/#{PluginRoutes.static_system_info['relative_url_root']}",
|
|
@@ -4,8 +4,12 @@ module CamaleonCms
|
|
|
4
4
|
delegate_all
|
|
5
5
|
|
|
6
6
|
# return the title for current locale
|
|
7
|
+
# The name is HTML-escaped here (like PostDecorator#the_title) because taxonomy
|
|
8
|
+
# names are plain text yet are rendered through `raw`/`html_safe` sinks such as
|
|
9
|
+
# the breadcrumb builder and the nav menu, so escaping at the source prevents
|
|
10
|
+
# stored XSS via category/tag/post_type/site names.
|
|
7
11
|
def the_title(locale = nil)
|
|
8
|
-
r = { title: object.name.translate(get_locale(locale)), object: object }
|
|
12
|
+
r = { title: h.h(object.name.to_s.translate(get_locale(locale))), object: object }
|
|
9
13
|
begin
|
|
10
14
|
h.hooks_run('taxonomy_the_title', r)
|
|
11
15
|
rescue StandardError
|
|
@@ -26,12 +30,19 @@ module CamaleonCms
|
|
|
26
30
|
h.do_shortcode(r[:content], self)
|
|
27
31
|
end
|
|
28
32
|
|
|
33
|
+
# Same shape as PostDecorator#the_status: markup built by interpolation and rendered through
|
|
34
|
+
# `raw` at admin/search.html.erb. Only I18n strings reach it today, so there is nothing to
|
|
35
|
+
# exploit here -- escaping at the source is what keeps that true if the interpolated value ever
|
|
36
|
+
# changes.
|
|
29
37
|
def the_status
|
|
30
|
-
if status.to_s.to_bool
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
color, label = if status.to_s.to_bool
|
|
39
|
+
['success', I18n.t('camaleon_cms.admin.button.actived')]
|
|
40
|
+
else
|
|
41
|
+
['default', I18n.t('camaleon_cms.admin.button.not_actived')]
|
|
42
|
+
end
|
|
43
|
+
# rubocop:disable Rails/OutputSafety -- only the escaped label is interpolated into fixed markup
|
|
44
|
+
"<span class='label label-#{color}'> #{h.h(label)} </span>".html_safe
|
|
45
|
+
# rubocop:enable Rails/OutputSafety
|
|
35
46
|
end
|
|
36
47
|
|
|
37
48
|
# return excerpt for this post type
|
|
@@ -55,7 +66,7 @@ module CamaleonCms
|
|
|
55
66
|
|
|
56
67
|
# search a post with id (integer) or slug (string)
|
|
57
68
|
def the_post(slug_or_id)
|
|
58
|
-
return nil
|
|
69
|
+
return nil if slug_or_id.blank?
|
|
59
70
|
|
|
60
71
|
if slug_or_id.is_a?(Integer)
|
|
61
72
|
begin
|
|
@@ -67,7 +78,7 @@ module CamaleonCms
|
|
|
67
78
|
return unless slug_or_id.is_a?(String)
|
|
68
79
|
|
|
69
80
|
begin
|
|
70
|
-
object.posts.find_by_slug(slug_or_id).decorate
|
|
81
|
+
object.posts.find_by_slug(slug_or_id).decorate # rubocop:disable Rails/DynamicFindBy
|
|
71
82
|
rescue StandardError
|
|
72
83
|
nil
|
|
73
84
|
end
|
|
@@ -94,10 +105,10 @@ module CamaleonCms
|
|
|
94
105
|
# return html link
|
|
95
106
|
# attrs: Hash of link tag attributes, sample: {id: "myid", class: "sss" }
|
|
96
107
|
def the_edit_link(title = nil, attrs = {})
|
|
97
|
-
return ''
|
|
108
|
+
return '' if h.cama_current_user.blank?
|
|
98
109
|
|
|
99
110
|
attrs = { target: '_blank', style: 'font-size:11px !important;cursor:pointer;' }.merge(attrs)
|
|
100
|
-
h.link_to(
|
|
111
|
+
h.link_to(h.safe_join(['→ ', title || h.ct('edit', default: 'Edit')]), the_edit_url, attrs)
|
|
101
112
|
end
|
|
102
113
|
|
|
103
114
|
# return the user owner of this item
|
|
@@ -11,11 +11,11 @@ module CamaleonCms
|
|
|
11
11
|
h.cama_admin_settings_theme_url(args)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def the_settings_link
|
|
15
|
-
return ''
|
|
14
|
+
def the_settings_link(title = nil, attrs = {})
|
|
15
|
+
return '' if h.cama_current_user.blank?
|
|
16
16
|
|
|
17
17
|
attrs = { target: '_blank', style: 'font-size:11px !important;cursor:pointer;' }.merge(attrs)
|
|
18
|
-
h.link_to(
|
|
18
|
+
h.link_to(h.safe_join(['→ ', title || h.ct('edit', default: 'Edit')]), the_settings_url, attrs)
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
end
|
|
@@ -20,7 +20,9 @@ module CamaleonCms
|
|
|
20
20
|
|
|
21
21
|
# return the avatar for this user, default: assets/admin/img/no_image.jpg
|
|
22
22
|
def the_avatar(default_avatar = nil)
|
|
23
|
-
|
|
23
|
+
return object.get_meta('avatar') if avatar_exists?
|
|
24
|
+
|
|
25
|
+
default_avatar || h.asset_url('camaleon_cms/admin/img/no_image.jpg')
|
|
24
26
|
end
|
|
25
27
|
|
|
26
28
|
# return the slogan for this user, default: Hello World
|
|
@@ -34,7 +36,7 @@ module CamaleonCms
|
|
|
34
36
|
args[:label] = I18n.t('routes.profile', default: 'profile')
|
|
35
37
|
args[:user_id] = the_id
|
|
36
38
|
args[:user_name] = the_name.parameterize
|
|
37
|
-
args[:user_name] = the_username
|
|
39
|
+
args[:user_name] = the_username if args[:user_name].blank?
|
|
38
40
|
args[:locale] = get_locale unless args.include?(:locale)
|
|
39
41
|
args[:format] = args[:format] || 'html'
|
|
40
42
|
as_path = args.delete(:as_path)
|
|
@@ -52,8 +54,26 @@ module CamaleonCms
|
|
|
52
54
|
h.current_site.posts.where(user_id: object.id)
|
|
53
55
|
end
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
# Whether this user may set another user's role. Only an admin may grant the `admin` role (the one
|
|
58
|
+
# `User#admin?` tests) or change the role of a user who is already an admin — so holding
|
|
59
|
+
# `:manage, :users` is neither a path to minting an admin (escalation) nor to stripping one (H10).
|
|
60
|
+
def role_grantor?(other_user, new_role = nil)
|
|
61
|
+
return false unless h.can?(:manage, :users) && (other_user.nil? || id != other_user.id)
|
|
62
|
+
return admin? if new_role.to_s == 'admin' || other_user&.role.to_s == 'admin'
|
|
63
|
+
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Whether this user may edit +other_user+'s login credential (password) or recovery identifiers
|
|
68
|
+
# (email, username). Only an admin may edit an admin's account: a `:manage, :users` holder who could
|
|
69
|
+
# reset an admin's password would sign in as them, and one who could repoint an admin's email would
|
|
70
|
+
# hijack a password-reset link — either is a path to superadmin that would make `role_grantor?`'s
|
|
71
|
+
# guard of the privileged set moot (H10). Editing one's own account, or any non-admin, is unrestricted
|
|
72
|
+
# here; the controller's `:manage, :users` (or self) authorization still applies first.
|
|
73
|
+
def may_edit_credentials?(other_user)
|
|
74
|
+
return true unless other_user&.admin?
|
|
75
|
+
|
|
76
|
+
admin?
|
|
57
77
|
end
|
|
58
78
|
|
|
59
79
|
def self.object_class_name
|
|
@@ -65,7 +85,8 @@ module CamaleonCms
|
|
|
65
85
|
def avatar_exists?
|
|
66
86
|
# TODO: change verification
|
|
67
87
|
# if object.get_meta('avatar').present?
|
|
68
|
-
# File.exist?(h.cama_url_to_file_path(object.get_meta('avatar'))) ||
|
|
88
|
+
# File.exist?(h.cama_url_to_file_path(object.get_meta('avatar'))) ||
|
|
89
|
+
# Faraday.head(object.get_meta('avatar')).status == 200
|
|
69
90
|
# else
|
|
70
91
|
# false
|
|
71
92
|
# end
|
|
@@ -32,16 +32,13 @@ module CamaleonCms
|
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
# return the locale for frontend translations initialized in admin controller
|
|
36
|
-
# used by models like posts, categories, ..., sample: my_post.the_url
|
|
37
|
-
# fix for https://github.com/owen2345/camaleon-cms/issues/233#issuecomment-215385432
|
|
38
|
-
def cama_get_i18n_frontend
|
|
39
|
-
@cama_i18n_frontend
|
|
40
|
-
end
|
|
41
|
-
|
|
42
35
|
# print code with auto copy
|
|
43
36
|
def cama_shortcode_print(code)
|
|
44
|
-
content_tag(
|
|
37
|
+
content_tag(
|
|
38
|
+
:input, nil, class: 'code_style', readonly: true, onmousedown: 'this.clicked = 1;',
|
|
39
|
+
onfocus: 'if (!this.clicked) this.select(); else this.clicked = 2;',
|
|
40
|
+
onclick: 'if (this.clicked == 2) this.select(); this.clicked = 0;', tabindex: '-1', value: code
|
|
41
|
+
)
|
|
45
42
|
end
|
|
46
43
|
end
|
|
47
44
|
end
|
|
@@ -4,7 +4,7 @@ module CamaleonCms
|
|
|
4
4
|
# draw the title for the admin admin panel according the breadcrumb
|
|
5
5
|
def cama_admin_title_draw
|
|
6
6
|
res = [t('camaleon_cms.admin.sidebar_top.admin_panel')]
|
|
7
|
-
breadcrumbs.reverse.slice(0, 2).
|
|
7
|
+
breadcrumbs.reverse.slice(0, 2).reverse_each { |b| res << (b.is_a?(Hash) ? b[:name] : b.name) }
|
|
8
8
|
res.join(' » ')
|
|
9
9
|
end
|
|
10
10
|
|
|
@@ -2,31 +2,19 @@ module CamaleonCms
|
|
|
2
2
|
module Admin
|
|
3
3
|
module CustomFieldsHelper
|
|
4
4
|
def cama_custom_field_elements
|
|
5
|
-
return
|
|
5
|
+
return CurrentRequest.custom_field_elements if CurrentRequest.custom_field_elements.present?
|
|
6
6
|
|
|
7
7
|
items = {}
|
|
8
8
|
items[:text_box] = {
|
|
9
9
|
key: 'text_box',
|
|
10
10
|
label: t('camaleon_cms.admin.custom_field.fields.text_box'),
|
|
11
|
-
options: {
|
|
12
|
-
required: true,
|
|
13
|
-
multiple: true,
|
|
14
|
-
translate: true,
|
|
15
|
-
default_value: '',
|
|
16
|
-
show_frontend: true
|
|
17
|
-
}
|
|
11
|
+
options: { required: true, multiple: true, translate: true, default_value: '', show_frontend: true }
|
|
18
12
|
}
|
|
19
13
|
|
|
20
14
|
items[:text_area] = {
|
|
21
15
|
key: 'text_area',
|
|
22
16
|
label: t('camaleon_cms.admin.custom_field.fields.text_area'),
|
|
23
|
-
options: {
|
|
24
|
-
required: true,
|
|
25
|
-
multiple: true,
|
|
26
|
-
translate: true,
|
|
27
|
-
default_value: '',
|
|
28
|
-
show_frontend: true
|
|
29
|
-
}
|
|
17
|
+
options: { required: true, multiple: true, translate: true, default_value: '', show_frontend: true }
|
|
30
18
|
}
|
|
31
19
|
items[:select] = {
|
|
32
20
|
key: 'select',
|
|
@@ -35,10 +23,7 @@ module CamaleonCms
|
|
|
35
23
|
required: true,
|
|
36
24
|
multiple: true,
|
|
37
25
|
translate: true,
|
|
38
|
-
multiple_options: {
|
|
39
|
-
label: t('camaleon_cms.admin.settings.options_select'),
|
|
40
|
-
default: 'radio'
|
|
41
|
-
},
|
|
26
|
+
multiple_options: { label: t('camaleon_cms.admin.settings.options_select'), default: 'radio' },
|
|
42
27
|
show_frontend: true
|
|
43
28
|
}
|
|
44
29
|
}
|
|
@@ -298,7 +283,8 @@ module CamaleonCms
|
|
|
298
283
|
}
|
|
299
284
|
|
|
300
285
|
# evaluate the content of command value on listing
|
|
301
|
-
# sample command:
|
|
286
|
+
# sample command:
|
|
287
|
+
# options_from_collection_for_select(current_site.the_posts("commerce").decorate, :id, :the_title)
|
|
302
288
|
items[:select_eval] = {
|
|
303
289
|
key: 'select_eval',
|
|
304
290
|
label: t('camaleon_cms.admin.custom_field.fields.select_eval'),
|
|
@@ -344,17 +330,32 @@ module CamaleonCms
|
|
|
344
330
|
}
|
|
345
331
|
r = { fields: items }
|
|
346
332
|
hooks_run('extra_custom_fields', r)
|
|
347
|
-
|
|
333
|
+
CurrentRequest.custom_field_elements = r[:fields]
|
|
348
334
|
end
|
|
349
335
|
|
|
350
336
|
# add your model class into custom fields editor
|
|
351
337
|
# Note: to use custom fields on your model, you need the following:
|
|
352
|
-
# - add: belongs_to :site (in your model)
|
|
338
|
+
# - add: belongs_to :site (in your model)
|
|
339
|
+
# //don't forget multi site support, i.e.: you need site_id attribute in your table
|
|
353
340
|
# - add: include CamaleonCms::CustomFieldsRead (in your model)
|
|
354
341
|
# ==> With this, you can manage your model like a plugin. Check api -> custom fields section into docs)
|
|
355
342
|
# model_class: class name (Product)
|
|
356
343
|
def cf_add_model(model_class)
|
|
357
|
-
|
|
344
|
+
CurrentRequest.extra_models_for_fields ||= []
|
|
345
|
+
CurrentRequest.extra_models_for_fields << model_class
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# Models offered in the field-group placement dropdown: those registered via cf_add_model plus any
|
|
349
|
+
# a custom_field_custom_models hook appends. Seeded from the legacy @_extra_models_for_fields ivar
|
|
350
|
+
# so a controller still assigning it keeps working. The dropdown used to read that ivar while
|
|
351
|
+
# cf_add_model wrote CurrentRequest, so registered models never appeared. Regression M18.
|
|
352
|
+
# The seed and the hook payload are copies: hook appends must reach only this read, not
|
|
353
|
+
# accumulate in the request store or leak into the controller ivar.
|
|
354
|
+
def cf_extra_models_for_fields
|
|
355
|
+
CurrentRequest.extra_models_for_fields ||= (instance_variable_get(:@_extra_models_for_fields) || []).dup
|
|
356
|
+
f_args = { models: CurrentRequest.extra_models_for_fields.dup }
|
|
357
|
+
hooks_run('custom_field_custom_models', f_args)
|
|
358
|
+
f_args[:models]
|
|
358
359
|
end
|
|
359
360
|
end
|
|
360
361
|
end
|