camaleon_cms 2.9.2 → 2.9.4
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 +14 -10
- data/app/apps/plugins/front_cache/config/initializer.rb +1 -1
- data/app/apps/plugins/front_cache/config/locales/translation.yml +0 -7
- data/app/apps/plugins/front_cache/front_cache_helper.rb +109 -37
- data/app/apps/plugins/front_cache/views/admin/settings.html.erb +0 -5
- 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 +80 -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 +146 -74
- 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 +68 -50
- data/app/decorators/camaleon_cms/post_type_decorator.rb +1 -1
- data/app/decorators/camaleon_cms/site_decorator.rb +33 -25
- 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/application_helper.rb +6 -1
- 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 +140 -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 +137 -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 +58 -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 +81 -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 +36 -42
- data/app/models/concerns/camaleon_cms/common_relationships.rb +18 -5
- data/app/models/concerns/camaleon_cms/content_shortcode_gate.rb +73 -0
- 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 +36 -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 +45 -21
- data/lib/camaleon_cms/media_security_headers.rb +27 -0
- data/lib/camaleon_cms/setup_token.rb +69 -0
- data/lib/camaleon_cms/shortcode_registry.rb +102 -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 +23 -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 +125 -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,63 @@ 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
|
-
|
|
251
|
-
}
|
|
252
|
+
def the_next_post(parent = nil)
|
|
253
|
+
# eager: false -- next/prev resolve a single sibling used only for its title/url
|
|
254
|
+
h.verify_front_visibility((parent.presence || the_post_type).posts, eager: false).where(
|
|
255
|
+
post_order_predicate_gt(object.post_order, object.created_at)
|
|
252
256
|
).where.not(id: object.id).take.try(:decorate)
|
|
253
257
|
end
|
|
254
258
|
|
|
255
|
-
# looks for the next post item related to parent element based on post_order attribute
|
|
256
|
-
# @param
|
|
259
|
+
# looks for the next post item related to the parent element based on post_order attribute
|
|
260
|
+
# @param parent: parent decorated model, like: (PostType *default), Category, PostTag, Site
|
|
257
261
|
# @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
|
-
|
|
261
|
-
|
|
262
|
+
def the_prev_post(parent = nil)
|
|
263
|
+
# eager: false -- next/prev resolve a single sibling used only for its title/url
|
|
264
|
+
h.verify_front_visibility((parent.presence || the_post_type).posts, eager: false)
|
|
265
|
+
.where(post_order_predicate_lt(object.post_order, object.created_at))
|
|
266
|
+
.where.not(id: object.id).reorder(post_order: :asc, created_at: :asc).last.try(:decorate)
|
|
262
267
|
end
|
|
263
268
|
|
|
264
269
|
# return the title with hierarchy prefixed
|
|
265
|
-
# sample: title paren 1 - title parent 2
|
|
270
|
+
# sample: title paren 1 - title parent 2 -... -...
|
|
266
271
|
# if add_parent_title: true will add parent title like: —— item 1.1.1 | item 1.1
|
|
267
272
|
def the_hierarchy_title
|
|
268
|
-
return the_title
|
|
273
|
+
return the_title if object.post_parent.blank?
|
|
269
274
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
res.html_safe
|
|
275
|
+
parts = [h.raw('—' * object.parents.count), h.sanitize(" #{the_title}")]
|
|
276
|
+
parts << h.sanitize(" | #{object.parent.decorate.the_title}") if object.show_title_with_parent
|
|
277
|
+
h.safe_join(parts)
|
|
274
278
|
end
|
|
275
279
|
|
|
276
|
-
# return all related posts of current post
|
|
280
|
+
# return all related posts of the current post
|
|
277
281
|
def the_related_posts
|
|
278
282
|
ptype = the_post_type
|
|
279
|
-
ptype.the_posts.joins(:categories).where(
|
|
283
|
+
ptype.the_posts.joins(:categories).where(
|
|
284
|
+
CamaleonCms::TermRelationship.table_name.to_s => { term_taxonomy_id: the_categories.pluck(:id) }
|
|
285
|
+
).distinct
|
|
280
286
|
end
|
|
281
287
|
|
|
282
288
|
# fix for "Using Draper::Decorator without inferred source class"
|
|
283
289
|
def self.object_class_name
|
|
284
290
|
'CamaleonCms::Post'
|
|
285
291
|
end
|
|
292
|
+
|
|
293
|
+
private
|
|
294
|
+
|
|
295
|
+
def post_order_predicate_gt(position, created_at)
|
|
296
|
+
t = CamaleonCms::Post.arel_table
|
|
297
|
+
t[:post_order].gt(position).or(t[:post_order].eq(position).and(t[:created_at].gt(created_at)))
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def post_order_predicate_lt(position, created_at)
|
|
301
|
+
t = CamaleonCms::Post.arel_table
|
|
302
|
+
t[:post_order].lt(position).or(t[:post_order].eq(position).and(t[:created_at].lt(created_at)))
|
|
303
|
+
end
|
|
286
304
|
end
|
|
287
305
|
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...
|
|
@@ -53,22 +53,26 @@ module CamaleonCms
|
|
|
53
53
|
# slug_or_id: (Array) array of post ids, return multiple posts
|
|
54
54
|
# return post model or nil
|
|
55
55
|
def the_post(slug_or_id)
|
|
56
|
+
# eager: false -- a single-record lookup must not pay the listing preloads (with_eager)
|
|
57
|
+
rel = h.verify_front_visibility(object.posts, eager: false)
|
|
56
58
|
if slug_or_id.is_a?(Integer)
|
|
57
59
|
post = begin
|
|
58
|
-
|
|
60
|
+
rel.find(slug_or_id)
|
|
59
61
|
rescue StandardError
|
|
60
62
|
nil
|
|
61
63
|
end
|
|
62
64
|
end
|
|
63
65
|
if slug_or_id.is_a?(Array)
|
|
64
66
|
post = begin
|
|
65
|
-
|
|
67
|
+
rel.find(slug_or_id)
|
|
66
68
|
rescue StandardError
|
|
67
69
|
nil
|
|
68
70
|
end
|
|
69
71
|
end
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
# use find_by_slug (multi-language aware) so posts with localized slugs
|
|
73
|
+
# (e.g. "<!--:en-->sample-post<!--:-->...") are matched instead of returning nil
|
|
74
|
+
post = rel.find_by_slug(slug_or_id) if slug_or_id.is_a?(String) # rubocop:disable Rails/DynamicFindBy
|
|
75
|
+
post&.decorate
|
|
72
76
|
end
|
|
73
77
|
|
|
74
78
|
# return a collection of categories
|
|
@@ -81,7 +85,7 @@ module CamaleonCms
|
|
|
81
85
|
def the_categories(slug_or_id = nil)
|
|
82
86
|
return the_post_type(slug_or_id).the_categories if slug_or_id.present?
|
|
83
87
|
|
|
84
|
-
object.categories
|
|
88
|
+
object.categories if slug_or_id.blank?
|
|
85
89
|
end
|
|
86
90
|
|
|
87
91
|
# return the category object with id or slug = slug_or_id from this site
|
|
@@ -96,7 +100,7 @@ module CamaleonCms
|
|
|
96
100
|
return unless slug_or_id.is_a?(String)
|
|
97
101
|
|
|
98
102
|
begin
|
|
99
|
-
the_full_categories.find_by_slug(slug_or_id).decorate
|
|
103
|
+
the_full_categories.find_by_slug(slug_or_id).decorate # rubocop:disable Rails/DynamicFindBy
|
|
100
104
|
rescue StandardError
|
|
101
105
|
nil
|
|
102
106
|
end
|
|
@@ -126,7 +130,7 @@ module CamaleonCms
|
|
|
126
130
|
return unless slug_or_id.is_a?(String)
|
|
127
131
|
|
|
128
132
|
begin
|
|
129
|
-
object.post_tags.find_by_slug(slug_or_id).decorate
|
|
133
|
+
object.post_tags.find_by_slug(slug_or_id).decorate # rubocop:disable Rails/DynamicFindBy
|
|
130
134
|
rescue StandardError
|
|
131
135
|
nil
|
|
132
136
|
end
|
|
@@ -144,7 +148,7 @@ module CamaleonCms
|
|
|
144
148
|
return unless id_or_username.is_a?(String)
|
|
145
149
|
|
|
146
150
|
begin
|
|
147
|
-
object.users.find_by_username(id_or_username).decorate
|
|
151
|
+
object.users.find_by_username(id_or_username).decorate # rubocop:disable Rails/DynamicFindBy
|
|
148
152
|
rescue StandardError
|
|
149
153
|
nil
|
|
150
154
|
end
|
|
@@ -165,14 +169,14 @@ module CamaleonCms
|
|
|
165
169
|
def the_post_type(slug_or_id)
|
|
166
170
|
if slug_or_id.is_a?(String)
|
|
167
171
|
begin
|
|
168
|
-
return object.post_types.find_by_slug(slug_or_id).decorate
|
|
172
|
+
return object.post_types.find_by_slug(slug_or_id).decorate # rubocop:disable Rails/DynamicFindBy
|
|
169
173
|
rescue StandardError
|
|
170
174
|
nil
|
|
171
175
|
end
|
|
172
176
|
end
|
|
173
177
|
if slug_or_id.is_a?(Array)
|
|
174
178
|
begin
|
|
175
|
-
return object.post_types.find_by_slug(slug_or_id).decorate
|
|
179
|
+
return object.post_types.find_by_slug(slug_or_id).decorate # rubocop:disable Rails/DynamicFindBy
|
|
176
180
|
rescue StandardError
|
|
177
181
|
nil
|
|
178
182
|
end
|
|
@@ -195,21 +199,25 @@ module CamaleonCms
|
|
|
195
199
|
lan = object.get_languages
|
|
196
200
|
return if lan.size < 2
|
|
197
201
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
202
|
+
h.content_tag(:ul, class: list_class) do
|
|
203
|
+
h.safe_join(lan.map do |lang|
|
|
204
|
+
label = if block
|
|
205
|
+
h.capture(lang, I18n.locale.to_s == lang.to_s, &block)
|
|
206
|
+
else
|
|
207
|
+
h.tag.img(src: h.asset_path("camaleon_cms/language/#{lang}.png"))
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
h.content_tag(:li, class: (current_class if I18n.locale.to_s == lang.to_s)) do
|
|
211
|
+
h.link_to(
|
|
212
|
+
label,
|
|
213
|
+
h.cama_url_to_fixed(
|
|
214
|
+
current_page ? 'url_for' : 'cama_root_url',
|
|
215
|
+
{ locale: lang, cama_set_language: lang }
|
|
216
|
+
)
|
|
217
|
+
)
|
|
218
|
+
end
|
|
219
|
+
end)
|
|
210
220
|
end
|
|
211
|
-
res << '</ul>'
|
|
212
|
-
res.join('').html_safe
|
|
213
221
|
end
|
|
214
222
|
|
|
215
223
|
# return Array of frontend languages configured for this site
|
|
@@ -245,7 +253,7 @@ module CamaleonCms
|
|
|
245
253
|
postfix = 'url'
|
|
246
254
|
postfix = 'path' if args.delete(:as_path)
|
|
247
255
|
skip_relative_url_root = args.delete(:skip_relative_url_root)
|
|
248
|
-
h.cama_current_site_host_port(args) unless args.
|
|
256
|
+
h.cama_current_site_host_port(args) unless args.key?(:host)
|
|
249
257
|
res = h.cama_url_to_fixed("cama_root_#{postfix}", args)
|
|
250
258
|
if skip_relative_url_root && PluginRoutes.static_system_info['relative_url_root'].present?
|
|
251
259
|
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
|