decidim-core 0.28.3 → 0.28.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/activity_cell.rb +1 -4
- data/app/cells/decidim/author/show.erb +5 -4
- data/app/cells/decidim/author_cell.rb +26 -0
- data/app/cells/decidim/card_s/show.erb +5 -3
- data/app/cells/decidim/content_blocks/stats_cell.rb +1 -1
- data/app/cells/decidim/diff_cell.rb +4 -0
- data/app/cells/decidim/endorsement_buttons_cell.rb +1 -1
- data/app/cells/decidim/nav_links/show.erb +3 -3
- data/app/cells/decidim/newsletter_templates/image_text_cta_cell.rb +1 -1
- data/app/cells/decidim/resource_types_filter/show.erb +11 -12
- data/app/cells/decidim/translation_bar/show.erb +3 -3
- data/app/cells/decidim/translation_bar_cell.rb +1 -1
- data/app/commands/decidim/amendable/create_draft.rb +1 -0
- data/app/commands/decidim/destroy_account.rb +3 -0
- data/app/controllers/concerns/decidim/devise_authentication_methods.rb +1 -1
- data/app/controllers/concerns/decidim/direct_upload.rb +82 -0
- data/app/controllers/decidim/doorkeeper/credentials_controller.rb +1 -1
- data/app/controllers/decidim/links_controller.rb +1 -1
- data/app/controllers/decidim/profiles_controller.rb +4 -0
- data/app/forms/decidim/upload_validation_form.rb +1 -1
- data/app/helpers/concerns/decidim/user_role_checker.rb +46 -0
- data/app/helpers/decidim/cta_button_helper.rb +1 -1
- data/app/helpers/decidim/layout_helper.rb +28 -0
- data/app/helpers/decidim/map_helper.rb +6 -1
- data/app/helpers/decidim/menu_helper.rb +1 -1
- data/app/helpers/decidim/sanitize_helper.rb +11 -2
- data/app/helpers/decidim/scopes_helper.rb +5 -2
- data/app/models/decidim/action_log.rb +11 -1
- data/app/models/decidim/attachment.rb +1 -1
- data/app/packs/src/decidim/a11y.js +11 -15
- data/app/packs/src/decidim/append_redirect_url_to_modals.js +24 -14
- data/app/packs/src/decidim/direct_uploads/upload_field.js +21 -8
- data/app/packs/src/decidim/direct_uploads/upload_modal.js +3 -0
- data/app/packs/src/decidim/index.js +3 -0
- data/app/packs/src/decidim/remote_tooltips.js +38 -0
- data/app/packs/src/decidim/toggle.js +1 -1
- data/app/packs/src/decidim/tooltips.js +42 -22
- data/app/packs/stylesheets/decidim/_buttons.scss +1 -1
- data/app/packs/stylesheets/decidim/_modal_update.scss +4 -0
- data/app/packs/stylesheets/decidim/_profile.scss +1 -1
- data/app/packs/stylesheets/decidim/_progress-bar.scss +1 -1
- data/app/packs/stylesheets/decidim/legacy/conference-diploma.scss +2 -1
- data/app/presenters/decidim/attachment_presenter.rb +1 -1
- data/app/presenters/decidim/menu_item_presenter.rb +1 -1
- data/app/queries/decidim/last_activity.rb +16 -5
- data/app/services/decidim/base_diff_renderer.rb +26 -2
- data/app/services/decidim/email_notification_generator.rb +14 -5
- data/app/views/decidim/devise/omniauth_registrations/new.html.erb +1 -1
- data/app/views/decidim/offline/show.html.erb +1 -1
- data/app/views/decidim/pages/_tabbed.html.erb +5 -5
- data/app/views/decidim/shared/_filters.html.erb +5 -5
- data/app/views/decidim/shared/_orders.html.erb +3 -2
- data/app/views/decidim/shared/filters/_check_boxes_tree.html.erb +1 -1
- data/app/views/decidim/shared/filters/_collection.html.erb +1 -1
- data/app/views/layouts/decidim/_head.html.erb +1 -1
- data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +1 -1
- data/app/views/layouts/decidim/shared/_layout_user_profile.html.erb +2 -2
- data/config/locales/ar.yml +12 -1
- data/config/locales/bg.yml +0 -1
- data/config/locales/bn-BD.yml +1 -0
- data/config/locales/bs-BA.yml +98 -0
- data/config/locales/ca.yml +14 -10
- data/config/locales/cs.yml +6 -1
- data/config/locales/de.yml +18 -14
- data/config/locales/el.yml +3 -1
- data/config/locales/en.yml +5 -1
- data/config/locales/es-MX.yml +6 -2
- data/config/locales/es-PY.yml +6 -2
- data/config/locales/es.yml +12 -8
- data/config/locales/eu.yml +202 -185
- data/config/locales/fi-plain.yml +5 -1
- data/config/locales/fi.yml +40 -36
- data/config/locales/fr-CA.yml +6 -2
- data/config/locales/fr.yml +5 -1
- data/config/locales/ga-IE.yml +5 -0
- data/config/locales/gl.yml +4 -1
- data/config/locales/hu.yml +1 -2
- data/config/locales/id-ID.yml +4 -0
- data/config/locales/is-IS.yml +4 -1
- data/config/locales/it.yml +40 -0
- data/config/locales/ja.yml +18 -16
- data/config/locales/lb.yml +5 -0
- data/config/locales/lt.yml +1 -2
- data/config/locales/lv.yml +4 -0
- data/config/locales/nl.yml +6 -1
- data/config/locales/no.yml +5 -0
- data/config/locales/pl.yml +1 -2
- data/config/locales/pt-BR.yml +199 -1
- data/config/locales/pt.yml +11 -0
- data/config/locales/ro-RO.yml +302 -180
- data/config/locales/ru.yml +4 -0
- data/config/locales/sk.yml +5 -1
- data/config/locales/sv.yml +452 -81
- data/config/locales/tr-TR.yml +6 -1
- data/config/locales/uk.yml +4 -1
- data/config/locales/zh-CN.yml +5 -0
- data/config/locales/zh-TW.yml +4 -1
- data/config/routes.rb +1 -0
- data/decidim-core.gemspec +4 -1
- data/lib/decidim/api/functions/component_list.rb +1 -1
- data/lib/decidim/api/functions/participatory_space_finder_base.rb +11 -1
- data/lib/decidim/api/interfaces/participatory_space_interface.rb +1 -1
- data/lib/decidim/api/types/component_type.rb +7 -0
- data/lib/decidim/api/types/user_group_type.rb +4 -0
- data/lib/decidim/api/types/user_type.rb +4 -0
- data/lib/decidim/attributes/rich_text.rb +38 -0
- data/lib/decidim/attributes/time_with_zone.rb +11 -1
- data/lib/decidim/attributes.rb +2 -0
- data/lib/decidim/content_parsers/blob_parser.rb +93 -0
- data/lib/decidim/content_parsers.rb +1 -0
- data/lib/decidim/content_renderers/blob_renderer.rb +90 -0
- data/lib/decidim/content_renderers.rb +1 -0
- data/lib/decidim/core/engine.rb +35 -1
- data/lib/decidim/core/test/factories.rb +28 -0
- data/lib/decidim/core/test/shared_examples/authorable_interface_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +25 -2
- data/lib/decidim/core/test/shared_examples/system_endorse_resource_examples.rb +112 -14
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/core.rb +11 -0
- data/lib/decidim/diffy_extension.rb +18 -0
- data/lib/decidim/form_builder.rb +1 -1
- data/lib/decidim/map/autocomplete.rb +1 -0
- data/lib/decidim/organization_settings.rb +4 -1
- data/lib/decidim/participatory_space_user.rb +4 -0
- data/lib/decidim/query_extensions.rb +0 -26
- data/lib/decidim/settings_manifest.rb +2 -0
- data/lib/decidim/translatable_attributes.rb +6 -1
- data/lib/decidim/view_model.rb +1 -1
- data/lib/tasks/upgrade/decidim_attachments.rake +14 -0
- data/lib/tasks/upgrade/decidim_fix_categorization.rake +34 -8
- metadata +30 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30504edbc5451f226b04213804ae8b02392132d8f66f9d5ebe9ea58ad264031e
|
4
|
+
data.tar.gz: 0ff217364122ef3812f7aa950e4908364126ceca46f135d0d5dc049b1ee19537
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 897aec8c06d1dd2110a5bd880e07061cab5e12495b707ed175afa81468c5ac162cf3d7a6643879eab83a82a9ca76232ff82dcb0d9b29ccf277d328fec6539a35
|
7
|
+
data.tar.gz: 88e9607861160a270e3604733a323fc2b1d359779c335ff8ccce97c9e587062c9c916d07682ad0ddda2b50abe2f718d3ce4baeb5bf77cbf3aab77ea231160014
|
@@ -106,10 +106,7 @@ module Decidim
|
|
106
106
|
hash << id_prefix
|
107
107
|
hash << I18n.locale.to_s
|
108
108
|
hash << model.class.name.underscore
|
109
|
-
hash << model.cache_key_with_version
|
110
|
-
if (author_cell = author)
|
111
|
-
hash.push(Digest::MD5.hexdigest(author_cell.send(:cache_hash)))
|
112
|
-
end
|
109
|
+
hash << model.cache_key_with_version if model.respond_to?(:cache_key_with_version)
|
113
110
|
|
114
111
|
hash.join(Decidim.cache_key_separator)
|
115
112
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
<%# If the options hash has the demo key it means we are in the decidim-design engine, so it is not a real-world scenario with actual users %>
|
2
|
+
<% tooltip = options.has_key?(:demo) ? { tooltip: render(:profile_minicard).html_safe } : nil %>
|
3
|
+
<%= content_tag(:span, class: :author, data: ) do %>
|
4
|
+
<%= content_tag :span, class: "author__container#{" is-compact" if layout == :compact}", data: tooltip do %>
|
4
5
|
<% if layout == :compact %>
|
5
6
|
<%= render :avatar %>
|
6
7
|
|
@@ -24,4 +25,4 @@
|
|
24
25
|
<%= render action %>
|
25
26
|
<% end %>
|
26
27
|
<% end %>
|
27
|
-
|
28
|
+
<% end %>
|
@@ -49,8 +49,26 @@ module Decidim
|
|
49
49
|
@context_actions_options ||= options[:context_actions].map(&:to_sym)
|
50
50
|
end
|
51
51
|
|
52
|
+
def profile_minicard
|
53
|
+
render
|
54
|
+
end
|
55
|
+
|
52
56
|
private
|
53
57
|
|
58
|
+
# If the options hash has the demo key it means we are in the decidim-design engine,
|
59
|
+
# so it is not a real-world scenario with actual users
|
60
|
+
def data
|
61
|
+
@data ||= begin
|
62
|
+
internal_data = { author: true }
|
63
|
+
if has_tooltip? && !options.has_key?(:demo)
|
64
|
+
internal_data["remote_tooltip"] = true
|
65
|
+
internal_data["tooltip-url"] = decidim.profile_tooltip_path(raw_model.nickname)
|
66
|
+
end
|
67
|
+
|
68
|
+
internal_data
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
54
72
|
def layout
|
55
73
|
@layout ||= LAYOUTS.include?(options[:layout]) ? options[:layout] : :default
|
56
74
|
end
|
@@ -162,5 +180,13 @@ module Decidim
|
|
162
180
|
def resource_name
|
163
181
|
@resource_name ||= from_context.class.name.demodulize.underscore
|
164
182
|
end
|
183
|
+
|
184
|
+
def has_tooltip?
|
185
|
+
return false if model.deleted?
|
186
|
+
return false if model.respond_to?(:blocked?) && model.blocked?
|
187
|
+
return true if options.has_key?(:tooltip)
|
188
|
+
|
189
|
+
model.has_tooltip?
|
190
|
+
end
|
165
191
|
end
|
166
192
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
-
<%=
|
1
|
+
<%= content_tag :div, id: dom_id(resource), class: "card__search" do %>
|
2
2
|
<%= content_tag title_tag, class: "h4 card__search-title" do %>
|
3
|
-
<%=
|
3
|
+
<%= link_to resource_path, class: "card__search" do %>
|
4
|
+
<%= title %>
|
5
|
+
<% end %>
|
4
6
|
<% end %>
|
5
7
|
<% if metadata_cell.present? %>
|
6
8
|
<div class="card__search-metadata">
|
7
|
-
|
9
|
+
<%= cell metadata_cell, resource, links: false %>
|
8
10
|
</div>
|
9
11
|
<% end %>
|
10
12
|
<% end %>
|
@@ -71,6 +71,10 @@ module Decidim
|
|
71
71
|
|
72
72
|
# DiffRenderer class for the current_version's item; falls back to `BaseDiffRenderer`.
|
73
73
|
def diff_renderer_class
|
74
|
+
renderer_class = "#{current_version.item_type}DiffRenderer".safe_constantize
|
75
|
+
|
76
|
+
return renderer_class if renderer_class
|
77
|
+
|
74
78
|
if current_version.item_type.deconstantize == "Decidim"
|
75
79
|
"#{current_version.item_type.pluralize}::DiffRenderer".constantize
|
76
80
|
else
|
@@ -77,7 +77,7 @@ module Decidim
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def user_has_verified_groups?
|
80
|
-
current_user && Decidim::UserGroups::ManageableUserGroups.for(current_user).verified.any?
|
80
|
+
current_user && current_organization.user_groups_enabled? && Decidim::UserGroups::ManageableUserGroups.for(current_user).verified.any?
|
81
81
|
end
|
82
82
|
|
83
83
|
def endorse_translated
|
@@ -1,12 +1,12 @@
|
|
1
1
|
<div class="participatory-space__nav-container">
|
2
|
-
<button id="dropdown-trigger-participatory-space" data-component="dropdown" data-target="dropdown-menu-participatory-space" data-auto-close="true" data-scroll-to-menu="true">
|
2
|
+
<button id="dropdown-trigger-participatory-space" data-component="dropdown" data-target="dropdown-menu-participatory-space" data-auto-close="true" data-scroll-to-menu="true" data-open-md="true">
|
3
3
|
<span><%= t("decidim.searches.filters.jump_to") %></span>
|
4
4
|
<%= icon "arrow-down-s-line" %>
|
5
5
|
<%= icon "arrow-up-s-line" %>
|
6
6
|
</button>
|
7
|
-
<ul id="dropdown-menu-participatory-space" class="participatory-space__nav"
|
7
|
+
<ul id="dropdown-menu-participatory-space" class="participatory-space__nav">
|
8
8
|
<% model.each do |item| %>
|
9
|
-
<li>
|
9
|
+
<li role="menuitem">
|
10
10
|
<%= link_to item[:url], class: "participatory-space__nav-item" do %>
|
11
11
|
<%= item[:name] %>
|
12
12
|
<%= icon "arrow-right-line" %>
|
@@ -50,7 +50,7 @@ module Decidim
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def main_image_url
|
53
|
-
newsletter.template.images_container.attached_uploader(:main_image).url
|
53
|
+
newsletter.template.images_container.attached_uploader(:main_image).url
|
54
54
|
end
|
55
55
|
|
56
56
|
def organization_primary_color
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<div id="<%= id %>" class="filter-container">
|
2
|
-
<button id="dropdown-trigger-resource" data-component="dropdown" data-target="dropdown-menu-resource" data-
|
2
|
+
<button id="dropdown-trigger-resource" data-component="dropdown" data-target="dropdown-menu-resource" data-open-md="true">
|
3
3
|
<% resource_types.each do |resource_type| %>
|
4
4
|
<span data-value="<%= resource_type[0] %>" class="<%= "is-active" if filter_param == resource_type[0] %>">
|
5
5
|
<%= text_with_resource_icon(*resource_type) %>
|
@@ -8,15 +8,14 @@
|
|
8
8
|
<%= icon "arrow-down-s-line" %>
|
9
9
|
<%= icon "arrow-up-s-line" %>
|
10
10
|
</button>
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
<% end %>
|
11
|
+
<ul id="dropdown-menu-resource">
|
12
|
+
<% resource_types.each do |resource_type| %>
|
13
|
+
<li role="menuitem">
|
14
|
+
<%= link_to decidim.last_activities_path(filter: { with_resource_type: resource_type[0] } ), class: "filter#{" is-active" if filter_param == resource_type[0]}" do %>
|
15
|
+
<span class="sr-only"><%= resource_type[1] %></span>
|
16
|
+
<%= text_with_resource_icon(*resource_type) %>
|
17
|
+
<% end %>
|
18
|
+
</li>
|
19
|
+
<% end %>
|
20
|
+
</ul>
|
22
21
|
</div>
|
@@ -1,6 +1,6 @@
|
|
1
|
-
<div
|
2
|
-
<div class="
|
1
|
+
<div>
|
2
|
+
<div class="pt-4 pb-4 text-center bg-background">
|
3
3
|
<%= link %>
|
4
|
-
<span class="translation-button-help"><%= help_text %></span>
|
4
|
+
<span class="translation-button-help ml-4"><%= help_text %></span>
|
5
5
|
</div>
|
6
6
|
</div>
|
@@ -53,6 +53,7 @@ module Decidim
|
|
53
53
|
emendation.body = { I18n.locale => form.emendation_params.with_indifferent_access[:body] }
|
54
54
|
emendation.component = amendable.component
|
55
55
|
emendation.add_author(current_user, user_group)
|
56
|
+
emendation.category = amendable.category if amendable.respond_to?(:category)
|
56
57
|
emendation.save!
|
57
58
|
emendation
|
58
59
|
end
|
@@ -35,6 +35,9 @@ module Decidim
|
|
35
35
|
@user.name = ""
|
36
36
|
@user.nickname = ""
|
37
37
|
@user.email = ""
|
38
|
+
@user.personal_url = ""
|
39
|
+
@user.about = ""
|
40
|
+
@user.notifications_sending_frequency = "none"
|
38
41
|
@user.delete_reason = @form.delete_reason
|
39
42
|
@user.admin = false if @user.admin?
|
40
43
|
@user.deleted_at = Time.current
|
@@ -12,7 +12,7 @@ module Decidim
|
|
12
12
|
if user.present? && user.blocked?
|
13
13
|
check_user_block_status(user)
|
14
14
|
elsif user.needs_password_update?
|
15
|
-
change_password_path
|
15
|
+
decidim.change_password_path
|
16
16
|
elsif first_login_and_not_authorized?(user) && !user.admin? && !pending_redirect?(user)
|
17
17
|
decidim_verifications.first_login_authorizations_path
|
18
18
|
else
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module DirectUpload
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
include Decidim::NeedsOrganization
|
9
|
+
skip_before_action :verify_organization
|
10
|
+
|
11
|
+
before_action :check_organization!,
|
12
|
+
:check_authenticated!,
|
13
|
+
:check_user_belongs_to_organization,
|
14
|
+
:validate_direct_upload
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def validate_direct_upload
|
20
|
+
# We skip the validation if we are in system panel. `current_admin` refers to the main system admin user.
|
21
|
+
return if current_admin.present?
|
22
|
+
|
23
|
+
head :unprocessable_entity unless [
|
24
|
+
maximum_allowed_size.try(:to_i) >= blob_args[:byte_size].try(:to_i),
|
25
|
+
content_types.any? { |pattern| pattern.match?(blob_args[:content_type]) },
|
26
|
+
content_types.any? { |pattern| pattern.match?(MiniMime.lookup_by_extension(extension)&.content_type) },
|
27
|
+
allowed_extensions.any? { |pattern| pattern.match?(extension) }
|
28
|
+
].all?
|
29
|
+
rescue NoMethodError
|
30
|
+
head :unprocessable_entity
|
31
|
+
end
|
32
|
+
|
33
|
+
def extension
|
34
|
+
File.extname(blob_args[:filename]).delete(".")
|
35
|
+
end
|
36
|
+
|
37
|
+
def maximum_allowed_size
|
38
|
+
current_organization.settings.upload_maximum_file_size
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_organization!
|
42
|
+
head :unauthorized if current_organization.blank? && current_admin.blank?
|
43
|
+
end
|
44
|
+
|
45
|
+
def check_authenticated!
|
46
|
+
head :unauthorized if current_user.blank? && current_admin.blank?
|
47
|
+
end
|
48
|
+
|
49
|
+
def check_user_belongs_to_organization
|
50
|
+
return if current_admin.present?
|
51
|
+
|
52
|
+
head :unauthorized unless current_organization == current_user.organization
|
53
|
+
end
|
54
|
+
|
55
|
+
def allowed_extensions
|
56
|
+
if user_has_elevated_role?
|
57
|
+
current_organization.settings.upload_allowed_file_extensions_admin
|
58
|
+
else
|
59
|
+
current_organization.settings.upload_allowed_file_extensions
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def content_types
|
64
|
+
if user_has_elevated_role?
|
65
|
+
current_organization.settings.upload_allowed_content_types_admin
|
66
|
+
else
|
67
|
+
current_organization.settings.upload_allowed_content_types
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def user_has_elevated_role?
|
74
|
+
[
|
75
|
+
current_user&.admin?,
|
76
|
+
defined?(Decidim::Assemblies::AssembliesWithUserRole) && Decidim::Assemblies::AssembliesWithUserRole.for(current_user).any?,
|
77
|
+
defined?(Decidim::Conferences::ConferencesWithUserRole) && Decidim::Conferences::ConferencesWithUserRole.for(current_user).any?,
|
78
|
+
defined?(Decidim::ParticipatoryProcessesWithUserRole) && Decidim::ParticipatoryProcessesWithUserRole.for(current_user).any?
|
79
|
+
].any?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -28,7 +28,7 @@ module Decidim
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def avatar_url
|
31
|
-
avatar_url = current_resource_owner.attached_uploader(:avatar).url
|
31
|
+
avatar_url = current_resource_owner.attached_uploader(:avatar).url
|
32
32
|
return unless avatar_url
|
33
33
|
|
34
34
|
unless %r{^https?://}.match? avatar_url
|
@@ -41,7 +41,7 @@ module Decidim
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def escape_url(external_url)
|
44
|
-
before_fragment, fragment = external_url.split("#", 2)
|
44
|
+
before_fragment, fragment = URI.decode_www_form_component(external_url).split("#", 2)
|
45
45
|
escaped_before_fragment = URI::Parser.new.escape(before_fragment)
|
46
46
|
|
47
47
|
if fragment
|
@@ -27,6 +27,10 @@ module Decidim
|
|
27
27
|
redirect_to profile_activity_path(nickname: params[:nickname])
|
28
28
|
end
|
29
29
|
|
30
|
+
def tooltip
|
31
|
+
render json: { data: cell("decidim/author", profile_holder.presenter).profile_minicard }
|
32
|
+
end
|
33
|
+
|
30
34
|
def following
|
31
35
|
@content_cell = "decidim/following"
|
32
36
|
@title_key = "following"
|
@@ -10,7 +10,7 @@ module Decidim
|
|
10
10
|
# Property is named as attribute in upload modal and passthru validator, but
|
11
11
|
# it cannot be named as attribute here.
|
12
12
|
attribute :property, String
|
13
|
-
attribute :blob,
|
13
|
+
attribute :blob, Decidim::Attributes::Blob
|
14
14
|
attribute :form_class, String
|
15
15
|
|
16
16
|
validates :resource_class, presence: true
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module UserRoleChecker
|
5
|
+
# Shared behaviour for signed_in admins
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def user_has_any_role?(user, participatory_space = nil, broad_check: false)
|
11
|
+
return false unless user
|
12
|
+
|
13
|
+
[
|
14
|
+
user.admin,
|
15
|
+
user.roles.any?,
|
16
|
+
participatory_process_user_role?(user, participatory_space, broad_check:),
|
17
|
+
assembly_user_role?(user, participatory_space, broad_check:),
|
18
|
+
conference_user_role?(user, participatory_space, broad_check:)
|
19
|
+
].any?
|
20
|
+
end
|
21
|
+
|
22
|
+
def participatory_process_user_role?(user, participatory_process = nil, broad_check: false)
|
23
|
+
return false unless Decidim.module_installed?(:participatory_processes)
|
24
|
+
return Decidim::ParticipatoryProcessUserRole.exists?(user:) if broad_check
|
25
|
+
return false unless participatory_process.is_a?(Decidim::ParticipatoryProcess)
|
26
|
+
|
27
|
+
Decidim::ParticipatoryProcessUserRole.exists?(user:, participatory_process:)
|
28
|
+
end
|
29
|
+
|
30
|
+
def assembly_user_role?(user, assembly = nil, broad_check: false)
|
31
|
+
return false unless Decidim.module_installed?(:assemblies)
|
32
|
+
return Decidim::AssemblyUserRole.exists?(user:) if broad_check
|
33
|
+
return false unless assembly.is_a?(Decidim::Assembly)
|
34
|
+
|
35
|
+
Decidim::AssemblyUserRole.exists?(user:, assembly:)
|
36
|
+
end
|
37
|
+
|
38
|
+
def conference_user_role?(user, conference = nil, broad_check: false)
|
39
|
+
return false unless Decidim.module_installed?(:conferences)
|
40
|
+
return Decidim::ConferenceUserRole.exists?(user:) if broad_check
|
41
|
+
return false unless conference.is_a?(Decidim::Conference)
|
42
|
+
|
43
|
+
Decidim::ConferenceUserRole.exists?(user:, conference:)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -16,7 +16,7 @@ module Decidim
|
|
16
16
|
# Finds the CTA button path to reuse it in other places.
|
17
17
|
def cta_button_path
|
18
18
|
if current_organization.cta_button_path.present?
|
19
|
-
current_organization.cta_button_path
|
19
|
+
"/#{current_organization.cta_button_path}"
|
20
20
|
elsif Decidim::ParticipatoryProcess.where(organization: current_organization).published.any?
|
21
21
|
decidim_participatory_processes.participatory_processes_path
|
22
22
|
elsif current_user
|
@@ -169,6 +169,20 @@ module Decidim
|
|
169
169
|
end
|
170
170
|
end
|
171
171
|
|
172
|
+
def current_url(params = request.parameters)
|
173
|
+
return url_for(params) if respond_to?(:current_participatory_space) || respond_to?(:current_component)
|
174
|
+
|
175
|
+
each_decidim_engine do |helpers|
|
176
|
+
return helpers.url_for(params)
|
177
|
+
rescue ActionController::UrlGenerationError
|
178
|
+
# Continue to next engine in case the URL is not available.
|
179
|
+
end
|
180
|
+
|
181
|
+
main_app.url_for(params)
|
182
|
+
rescue ActionController::UrlGenerationError
|
183
|
+
"#{request.base_url}#{"?#{params.to_query}" unless params.empty?}"
|
184
|
+
end
|
185
|
+
|
172
186
|
private
|
173
187
|
|
174
188
|
def empty_organization_description?
|
@@ -177,6 +191,20 @@ module Decidim
|
|
177
191
|
organization_description.blank? || organization_description == "<p></p>"
|
178
192
|
end
|
179
193
|
|
194
|
+
def each_decidim_engine
|
195
|
+
Rails.application.railties.each do |engine|
|
196
|
+
next unless engine.is_a?(Rails::Engine)
|
197
|
+
next unless engine.isolated?
|
198
|
+
next unless engine.engine_name.start_with?("decidim_")
|
199
|
+
next unless respond_to?(engine.engine_name)
|
200
|
+
|
201
|
+
yield public_send(engine.engine_name)
|
202
|
+
end
|
203
|
+
return unless respond_to?(:decidim)
|
204
|
+
|
205
|
+
yield decidim
|
206
|
+
end
|
207
|
+
|
180
208
|
def tag_builder
|
181
209
|
@tag_builder ||= ActionView::Helpers::TagHelper::TagBuilder.new(self)
|
182
210
|
end
|
@@ -35,7 +35,12 @@ module Decidim
|
|
35
35
|
data: { "external-link": "text-only" }
|
36
36
|
}.merge(map_html_options)
|
37
37
|
return link_to(map_url, html_options) do
|
38
|
-
|
38
|
+
# We also add the latitude and the longitude to prevent the Workbox cache to be overly aggressive when updating a map
|
39
|
+
image_tag decidim.static_map_path(
|
40
|
+
sgid: resource.to_sgid.to_s,
|
41
|
+
latitude: resource.latitude,
|
42
|
+
longitude: resource.longitude
|
43
|
+
), alt: "#{map_service_brand} - #{address_text}"
|
39
44
|
end
|
40
45
|
end
|
41
46
|
end
|
@@ -49,7 +49,7 @@ module Decidim
|
|
49
49
|
self,
|
50
50
|
element_class: "font-semibold underline",
|
51
51
|
active_class: "is-active",
|
52
|
-
container_options: { class: "space-y-4 break-inside-avoid" },
|
52
|
+
container_options: { class: "space-y-4 break-inside-avoid", role: :menu },
|
53
53
|
label: t("layouts.decidim.footer.decidim_title")
|
54
54
|
)
|
55
55
|
end
|
@@ -37,13 +37,22 @@ module Decidim
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
# Converts the blob and blob variant references to blob URLs.
|
41
|
+
def decidim_rich_text(html, options = {})
|
42
|
+
renderer = Decidim::ContentProcessor.renderer_klass(:blob).constantize.new(html)
|
43
|
+
renderer.render(options)
|
44
|
+
end
|
45
|
+
|
40
46
|
def decidim_sanitize_editor(html, options = {})
|
41
47
|
content_tag(:div, decidim_sanitize(html, options), class: %w(rich-text-display))
|
42
48
|
end
|
43
49
|
|
44
50
|
def decidim_sanitize_editor_admin(html, options = {})
|
45
51
|
html = Decidim::IframeDisabler.new(html, options).perform
|
46
|
-
decidim_sanitize_editor(
|
52
|
+
decidim_sanitize_editor(
|
53
|
+
decidim_rich_text(html),
|
54
|
+
{ scrubber: Decidim::AdminInputScrubber.new }.merge(options)
|
55
|
+
)
|
47
56
|
end
|
48
57
|
|
49
58
|
def decidim_html_escape(text)
|
@@ -51,7 +60,7 @@ module Decidim
|
|
51
60
|
end
|
52
61
|
|
53
62
|
def decidim_url_escape(text)
|
54
|
-
decidim_html_escape(text).sub(
|
63
|
+
decidim_html_escape(text).sub(/^\s*javascript:/, "")
|
55
64
|
end
|
56
65
|
|
57
66
|
def decidim_sanitize_translated(text)
|
@@ -53,11 +53,14 @@ module Decidim
|
|
53
53
|
# options - An optional Hash with options:
|
54
54
|
#
|
55
55
|
# Returns nothing.
|
56
|
-
def scopes_select_field(form, name, root: false, options: {})
|
56
|
+
def scopes_select_field(form, name, root: false, options: {}, html_options: {})
|
57
|
+
options = options.merge(include_blank: I18n.t("decidim.scopes.prompt")) unless options.has_key?(:include_blank)
|
58
|
+
|
57
59
|
form.select(
|
58
60
|
name,
|
59
61
|
ordered_scopes_descendants_for_select(root),
|
60
|
-
options
|
62
|
+
options,
|
63
|
+
html_options
|
61
64
|
)
|
62
65
|
end
|
63
66
|
|
@@ -138,6 +138,7 @@ module Decidim
|
|
138
138
|
Decidim::Proposals::Proposal
|
139
139
|
Decidim::Surveys::Survey
|
140
140
|
Decidim::Assembly
|
141
|
+
Decidim::Conference
|
141
142
|
Decidim::Initiative
|
142
143
|
Decidim::ParticipatoryProcess
|
143
144
|
).select do |klass|
|
@@ -154,7 +155,16 @@ module Decidim
|
|
154
155
|
end
|
155
156
|
|
156
157
|
def self.publicable_public_resource_types
|
157
|
-
@publicable_public_resource_types ||= public_resource_types
|
158
|
+
@publicable_public_resource_types ||= public_resource_types
|
159
|
+
.select { |klass| klass.constantize.column_names.include?("published_at") } - publicable_exceptions
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.publicable_exceptions
|
163
|
+
@publicable_exceptions = %w(
|
164
|
+
Decidim::Blogs::Post
|
165
|
+
).select do |klass|
|
166
|
+
klass.safe_constantize.present?
|
167
|
+
end
|
158
168
|
end
|
159
169
|
|
160
170
|
def self.ransackable_scopes(auth_object = nil)
|
@@ -59,7 +59,6 @@ const createDropdown = (component) => {
|
|
59
59
|
const dropdownOptions = {};
|
60
60
|
dropdownOptions.dropdown = component.dataset.target;
|
61
61
|
dropdownOptions.hover = component.dataset.hover === "true";
|
62
|
-
dropdownOptions.isOpen = component.dataset.open === "true";
|
63
62
|
dropdownOptions.autoClose = component.dataset.autoClose === "true";
|
64
63
|
|
65
64
|
// This snippet allows to disable the dropdown based on the current viewport
|
@@ -78,6 +77,17 @@ const createDropdown = (component) => {
|
|
78
77
|
return
|
79
78
|
}
|
80
79
|
|
80
|
+
dropdownOptions.isOpen = component.dataset.open === "true";
|
81
|
+
|
82
|
+
const isOpen = Object.keys(screens).some((key) => {
|
83
|
+
if (!isScreenSize(key)) {
|
84
|
+
return false;
|
85
|
+
}
|
86
|
+
return Boolean(component.dataset[`open-${key}`.replace(/-([a-z])/g, (str) => str[1].toUpperCase())]);
|
87
|
+
});
|
88
|
+
|
89
|
+
dropdownOptions.isOpen = dropdownOptions.isOpen || isOpen;
|
90
|
+
|
81
91
|
if (!component.id) {
|
82
92
|
// when component has no id, we enforce to have it one
|
83
93
|
component.id = `dropdown-${Math.random().toString(36).substring(7)}`
|
@@ -104,20 +114,6 @@ const createDropdown = (component) => {
|
|
104
114
|
});
|
105
115
|
}
|
106
116
|
|
107
|
-
// Disable focus on children elements so we can pass the AXE accessibility tests
|
108
|
-
const dropdownMenu = document.getElementById(dropdownOptions.dropdown);
|
109
|
-
if (dropdownMenu.getAttribute("aria-hidden") === "true") {
|
110
|
-
dropdownMenu.
|
111
|
-
querySelectorAll("a, input, button").
|
112
|
-
forEach((element) => { element.tabIndex = -1 })
|
113
|
-
}
|
114
|
-
|
115
|
-
component.addEventListener("click", () => {
|
116
|
-
dropdownMenu.
|
117
|
-
querySelectorAll("a, input, button").
|
118
|
-
forEach((element) => { element.tabIndex = 0 })
|
119
|
-
})
|
120
|
-
|
121
117
|
Dropdowns.render(component.id, dropdownOptions);
|
122
118
|
}
|
123
119
|
|