decidim-core 0.31.7 → 0.31.8

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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/content_blocks/participatory_space_main_data/title.erb +1 -14
  3. data/app/cells/decidim/following_cell.rb +1 -1
  4. data/app/cells/decidim/nav_links/show.erb +3 -1
  5. data/app/cells/decidim/participatory_space_private_user/show.erb +1 -1
  6. data/app/cells/decidim/share_text_widget/modal.erb +1 -0
  7. data/app/cells/decidim/share_widget/modal.erb +1 -0
  8. data/app/cells/decidim/share_widget/qr_code_modal.erb +2 -4
  9. data/app/commands/decidim/create_omniauth_registration.rb +17 -2
  10. data/app/controllers/concerns/decidim/devise_authentication_methods.rb +4 -0
  11. data/app/controllers/concerns/decidim/devise_controllers.rb +2 -0
  12. data/app/controllers/concerns/decidim/disable_redirection_to_external_host.rb +2 -0
  13. data/app/controllers/concerns/decidim/filter_resource.rb +2 -0
  14. data/app/controllers/concerns/decidim/impersonate_users.rb +2 -2
  15. data/app/controllers/concerns/decidim/locale_switcher.rb +62 -11
  16. data/app/controllers/concerns/decidim/needs_permission.rb +22 -10
  17. data/app/controllers/concerns/decidim/onboarding_action_methods.rb +2 -0
  18. data/app/controllers/concerns/decidim/paginable.rb +7 -3
  19. data/app/controllers/concerns/decidim/payload_info.rb +2 -0
  20. data/app/controllers/concerns/decidim/resource_versions_concern.rb +14 -0
  21. data/app/controllers/decidim/application_controller.rb +0 -6
  22. data/app/controllers/decidim/authorization_modals_controller.rb +2 -0
  23. data/app/controllers/decidim/components/base_controller.rb +2 -0
  24. data/app/controllers/decidim/devise/passwords_controller.rb +8 -0
  25. data/app/controllers/decidim/favicon_controller.rb +9 -0
  26. data/app/controllers/decidim/free_resource_authorization_modals_controller.rb +2 -0
  27. data/app/controllers/decidim/gamification/badges_controller.rb +2 -0
  28. data/app/controllers/decidim/homepage_controller.rb +4 -1
  29. data/app/controllers/decidim/likes_controller.rb +1 -1
  30. data/app/controllers/decidim/links_controller.rb +2 -0
  31. data/app/controllers/decidim/manifests_controller.rb +2 -0
  32. data/app/controllers/decidim/messaging/conversations_controller.rb +10 -4
  33. data/app/controllers/decidim/newsletters_controller.rb +4 -0
  34. data/app/controllers/decidim/notifications_subscriptions_controller.rb +4 -0
  35. data/app/controllers/decidim/offline_controller.rb +5 -1
  36. data/app/controllers/decidim/open_data_controller.rb +5 -1
  37. data/app/controllers/decidim/pages_controller.rb +31 -3
  38. data/app/controllers/decidim/private_downloads_controller.rb +2 -0
  39. data/app/controllers/decidim/profiles_controller.rb +10 -0
  40. data/app/controllers/decidim/qr_controller.rb +3 -1
  41. data/app/controllers/decidim/resource_autocomplete_controller.rb +2 -0
  42. data/app/controllers/decidim/searches_controller.rb +2 -0
  43. data/app/controllers/decidim/short_links_controller.rb +4 -0
  44. data/app/controllers/decidim/static_map_controller.rb +2 -0
  45. data/app/controllers/decidim/timeouts_controller.rb +4 -0
  46. data/app/controllers/decidim/tos_controller.rb +2 -0
  47. data/app/controllers/decidim/upload_validations_controller.rb +4 -2
  48. data/app/controllers/decidim/user_activities_controller.rb +2 -0
  49. data/app/forms/decidim/upload_validation_form.rb +16 -10
  50. data/app/helpers/concerns/decidim/user_role_checker.rb +35 -10
  51. data/app/helpers/decidim/sanitize_helper.rb +11 -1
  52. data/app/jobs/decidim/application_job.rb +4 -0
  53. data/app/models/decidim/authorization.rb +24 -0
  54. data/app/models/decidim/oauth_application.rb +1 -0
  55. data/app/models/decidim/user.rb +1 -0
  56. data/app/models/decidim/user_base_entity.rb +1 -1
  57. data/app/packs/src/decidim/callout.js +10 -0
  58. data/app/packs/src/decidim/callout.test.js +32 -0
  59. data/app/packs/src/decidim/controllers/accordion/accordion.test.js +64 -0
  60. data/app/packs/src/decidim/controllers/accordion/controller.js +43 -0
  61. data/app/packs/src/decidim/datepicker/datepicker_functions.js +34 -23
  62. data/app/packs/src/decidim/datepicker/generate_datepicker.js +4 -4
  63. data/app/packs/src/decidim/datepicker/test/time.test.js +39 -24
  64. data/app/packs/src/decidim/utilities/dom.js +2 -2
  65. data/app/packs/stylesheets/decidim/_content_blocks.scss +4 -10
  66. data/app/packs/stylesheets/decidim/_conversations.scss +0 -8
  67. data/app/packs/stylesheets/decidim/_modal.scss +16 -8
  68. data/app/packs/stylesheets/decidim/_modal_share.scss +0 -22
  69. data/app/packs/stylesheets/decidim/_participatory_spaces.scss +11 -1
  70. data/app/packs/stylesheets/decidim/_rich_text.scss +12 -9
  71. data/app/packs/stylesheets/decidim/_typography.scss +5 -2
  72. data/app/packs/stylesheets/decidim/legacy/email.scss +0 -5
  73. data/app/permissions/decidim/permissions.rb +20 -0
  74. data/app/presenters/decidim/admin_log/component_presenter.rb +1 -1
  75. data/app/presenters/decidim/log/base_presenter.rb +10 -1
  76. data/app/presenters/decidim/log/user_presenter.rb +2 -2
  77. data/app/serializers/decidim/exporters/open_data_blocked_user_serializer.rb +11 -2
  78. data/app/serializers/decidim/exporters/open_data_moderation_serializer.rb +25 -1
  79. data/app/services/decidim/svg_content_validator.rb +554 -0
  80. data/app/uploaders/decidim/application_uploader.rb +2 -2
  81. data/app/validators/uploader_image_content_validator.rb +278 -0
  82. data/app/views/decidim/application/_radio_accordion.html.erb +1 -5
  83. data/app/views/decidim/messaging/conversations/create.js.erb +1 -3
  84. data/app/views/decidim/shared/_login_modal.html.erb +12 -14
  85. data/app/views/layouts/decidim/_mailer_logo.html.erb +1 -1
  86. data/config/initializers/rack_attack.rb +10 -0
  87. data/config/locales/bg.yml +0 -1
  88. data/config/locales/ca-IT.yml +3 -1
  89. data/config/locales/ca.yml +3 -1
  90. data/config/locales/cs.yml +7 -1
  91. data/config/locales/de.yml +61 -3
  92. data/config/locales/en.yml +3 -1
  93. data/config/locales/es-MX.yml +3 -1
  94. data/config/locales/es-PY.yml +3 -1
  95. data/config/locales/es.yml +7 -5
  96. data/config/locales/eu.yml +155 -156
  97. data/config/locales/fi-plain.yml +1 -1
  98. data/config/locales/fi.yml +1 -1
  99. data/config/locales/fr-CA.yml +3 -1
  100. data/config/locales/fr.yml +3 -1
  101. data/config/locales/gl.yml +1441 -33
  102. data/config/locales/hu.yml +0 -1
  103. data/config/locales/ja.yml +1 -1
  104. data/config/locales/pl.yml +0 -1
  105. data/config/locales/pt-BR.yml +0 -1
  106. data/config/locales/ro-RO.yml +0 -1
  107. data/config/locales/sk.yml +2 -1
  108. data/config/locales/sv.yml +47 -10
  109. data/config/locales/tr-TR.yml +0 -2
  110. data/db/migrate/20260909000000_add_failed_attempts_and_locked_at_to_decidim_authorizations.rb +8 -0
  111. data/lib/decidim/core/test/shared_examples/participatory_space_members_page_examples.rb +77 -0
  112. data/lib/decidim/core/test/shared_examples/participatory_space_members_shared_examples.rb +85 -6
  113. data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +23 -1
  114. data/lib/decidim/core/version.rb +1 -1
  115. data/lib/decidim/core.rb +9 -0
  116. data/lib/decidim/has_upload_validations.rb +1 -0
  117. data/lib/decidim/legacy_form_builder.rb +4 -0
  118. data/lib/decidim/query_extensions.rb +2 -0
  119. metadata +10 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cdd2ee47aebc30f3404fc92bd9b5954c1dfae6cdadbbd19d28d495f7939ce3d8
4
- data.tar.gz: 150625ae419f2acc7f6c8068ef743c7249cee604a36a14965917e940ec5b393a
3
+ metadata.gz: da2944b3eea9b97a316575553e82c7e4a14c3b2e98da84253af02ef05d4a01cc
4
+ data.tar.gz: 3e68f90d8259e679f17a9e13811dce598970c90592d9b40fbf281ea89419783c
5
5
  SHA512:
6
- metadata.gz: c8eb46226c485aa8e26c65b6a35213d73ba3928a47f4e8262816b30be044252cbc4ecc8be8bf70377e0787e5f50eb2d848fde571c26ddb0f33ee62068a3e9d0d
7
- data.tar.gz: 012df3885eb89cc74df00a64f599cae1918d4ab9d40675b1444958dbf6ba07694a3770cdc236af3628856c9e97dfc5b809fbed1ecb475fbbb93952a4067d72ee
6
+ metadata.gz: bcf39a24518f3d8e7ee79b5fa148bd884e58a7b209b87cafdc0ca447a7d9b22a207a33d535e42507fdac7cf0a8b18dc9d171a042272cf6c273939f292f4723f8
7
+ data.tar.gz: 68c57967364106483e793c7e89030bc661124ac5ce42437e47b5084c12713f26b237556559e1c71fd65c53871a282ed2c72383ffad4d2db7501249506031b8c8
@@ -23,15 +23,11 @@
23
23
  <% end %>
24
24
  </div>
25
25
 
26
- <button class="button button__sm button__text-secondary mt-2" data-controls="panel-view-more-<%= seed %>" aria-expanded="false" onclick="document.querySelector('div[id^=panel-view-more]').toggleAttribute('inert')">
26
+ <button class="button button__sm button__text-secondary mt-2" data-controls="panel-view-more-<%= seed %>" aria-expanded="false">
27
27
  <span>
28
28
  <%= t("view_more", scope: "layouts.decidim.announcements") %>
29
29
  </span>
30
30
  <%= icon "arrow-down-s-line" %>
31
- <span>
32
- <%= t("view_less", scope: "layouts.decidim.announcements") %>
33
- </span>
34
- <%= icon "arrow-up-s-line" %>
35
31
  </button>
36
32
  <% else %>
37
33
  <% if rich_text_processors? %>
@@ -42,12 +38,3 @@
42
38
  <% end %>
43
39
  </div>
44
40
  <% end %>
45
- <script>
46
- const button = document.querySelector('button[data-controls^="panel-view-more"]')
47
- button.addEventListener('keydown', function(e){
48
- // press space or enter
49
- if (e.keyCode === 32 || e.keyCode === 13){
50
- document.querySelector('div[id^=panel-view-more]').toggleAttribute('inert')
51
- }
52
- })
53
- </script>
@@ -11,7 +11,7 @@ module Decidim
11
11
  end
12
12
 
13
13
  def public_followings
14
- @public_followings ||= Kaminari.paginate_array(model.public_users_followings).page(params[:page]).per(20)
14
+ @public_followings ||= model.public_users_followings.page(params[:page]).per(20)
15
15
  end
16
16
 
17
17
  def non_public_followings?
@@ -8,7 +8,9 @@
8
8
  <% model.each do |item| %>
9
9
  <li>
10
10
  <%= link_to item[:url], class: "participatory-space__nav-item" do %>
11
- <%= decidim_escape_translated(item[:name]) %>
11
+ <span class="participatory-space__nav-label">
12
+ <%= decidim_escape_translated(item[:name]) %>
13
+ </span>
12
14
  <%= icon "arrow-right-line" %>
13
15
  <% end %>
14
16
  </li>
@@ -15,7 +15,7 @@
15
15
  <% end %>
16
16
 
17
17
  <div class="mt-3">
18
- <span class="text-gray-2 capitalize font-semibold">
18
+ <span class="text-gray-2 font-semibold">
19
19
  <%= role_translated %>
20
20
  </span>
21
21
  </div>
@@ -1,5 +1,6 @@
1
1
  <%= decidim_modal id: "socialShare", class: "share-modal" do %>
2
2
  <div data-dialog-container>
3
+ <%= icon "share-line" %>
3
4
  <h2 id="dialog-title-socialShare" tabindex="-1" data-dialog-title><%= t("share", scope: "decidim.shared.share_modal") %></h2>
4
5
 
5
6
  <div>
@@ -1,5 +1,6 @@
1
1
  <%= decidim_modal id: "socialShare", class: "share-modal" do %>
2
2
  <div data-dialog-container>
3
+ <%= icon "share-line" %>
3
4
  <h2 id="dialog-title-social-share-modal" tabindex="-1" data-dialog-title><%= t("share", scope: "decidim.shared.share_modal") %></h2>
4
5
 
5
6
  <div>
@@ -1,9 +1,7 @@
1
1
  <%= decidim_modal id: "QRCodeDialog", class: "qr-modal" do %>
2
2
  <div data-dialog-container>
3
- <div data-dialog-title>
4
- <%= icon "qr-code-line" %>
5
- <h2 id="dialog-title-qr-code-dialog" tabindex="-1"><%= t("decidim.share_widget.qr_code") %></h2>
6
- </div>
3
+ <%= icon "qr-code-line" %>
4
+ <h2 id="dialog-title-qr-code-dialog" tabindex="-1" data-dialog-title><%= t("decidim.share_widget.qr_code") %></h2>
7
5
  <div class="content">
8
6
  <div>
9
7
  <% if current_organization.logo.attached? %>
@@ -30,9 +30,9 @@ module Decidim
30
30
  end
31
31
  return broadcast(:invalid) if form.invalid?
32
32
 
33
+ initialize_user
33
34
  transaction do
34
- create_or_find_user
35
- @identity = create_identity
35
+ @identity = existing_identity || create_identity
36
36
  end
37
37
  trigger_omniauth_event
38
38
 
@@ -50,6 +50,21 @@ module Decidim
50
50
 
51
51
  REGEXP_SANITIZER = /[<>?%&\^*#@()\[\]=+:;"{}\\|]/
52
52
 
53
+ def initialize_user
54
+ create_or_find_user
55
+ rescue ActiveRecord::RecordNotUnique
56
+ @create_retries ||= 0
57
+
58
+ # This may happen if the callback endpoint is called several times in a
59
+ # row which some Omniauth providers may allow (e.g. through a double
60
+ # click). This should ensure that the user will not get an error even if
61
+ # the authentication service sent the callback request several times.
62
+ raise if @create_retries >= 2
63
+
64
+ @create_retries += 1
65
+ retry
66
+ end
67
+
53
68
  def create_or_find_user
54
69
  @user = User.find_or_initialize_by(
55
70
  email: verified_email,
@@ -9,6 +9,8 @@ module Decidim
9
9
  include Decidim::OnboardingActionMethods
10
10
 
11
11
  included do
12
+ protected
13
+
12
14
  def after_sign_in_path_for(user)
13
15
  if user.present? && user.blocked?
14
16
  check_user_block_status(user)
@@ -21,6 +23,8 @@ module Decidim
21
23
  end
22
24
  end
23
25
 
26
+ private
27
+
24
28
  # Calling the `stored_location_for` method removes the key, so in order
25
29
  # to check if there is any pending redirect after login I need to call
26
30
  # this method and use the value to set a pending redirect. This is the
@@ -49,6 +49,8 @@ module Decidim
49
49
  # right page.
50
50
  before_action :store_current_location
51
51
 
52
+ protected
53
+
52
54
  def permission_class_chain
53
55
  PermissionsRegistry.chain_for(DeviseControllers)
54
56
  end
@@ -7,6 +7,8 @@ module Decidim
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
+ private
11
+
10
12
  def redirect_back(fallback_location:, allow_other_host: true, **args) # rubocop:disable Lint/UnusedMethodArgument
11
13
  super(fallback_location:, allow_other_host: Decidim.allow_open_redirects, **args)
12
14
  end
@@ -11,6 +11,8 @@ module Decidim
11
11
  # this way we can use Rails' form helpers and have automatically checked checkboxes and
12
12
  # radio buttons in the view, for example.
13
13
  class Filter
14
+ private
15
+
14
16
  def initialize(filter)
15
17
  @filter = filter
16
18
  end
@@ -26,6 +26,8 @@ module Decidim
26
26
  @current_user ||= managed_user || real_user
27
27
  end
28
28
 
29
+ private
30
+
29
31
  # Clear the `@real_user` instance variable because otherwise that would be
30
32
  # the return value for any `current_user` calls after the user has already
31
33
  # signed out.
@@ -47,8 +49,6 @@ module Decidim
47
49
  ((impersonation_session_ends_at - Time.current) / 60).round
48
50
  end
49
51
 
50
- private
51
-
52
52
  def current_user_impersonated?
53
53
  current_user && impersonation_log.present?
54
54
  end
@@ -9,7 +9,7 @@ module Decidim
9
9
 
10
10
  included do
11
11
  around_action :switch_locale
12
- helper_method :current_locale, :available_locales, :default_locale
12
+ helper_method :current_locale, :available_locales, :default_locale, :canonical_url
13
13
 
14
14
  # Sets the locale for the current session.
15
15
  # Saves current locale in a session variable in case some links are locale-orphaned
@@ -24,16 +24,6 @@ module Decidim
24
24
  I18n.with_locale(locale, &)
25
25
  end
26
26
 
27
- # Adds the current locale to all the URLs generated by url_for so users
28
- # experience a consistent behaviour if they copy or share links.
29
- #
30
- # Returns a Hash.
31
- def default_url_options
32
- return {} if current_locale == default_locale.to_s
33
-
34
- { locale: current_locale }
35
- end
36
-
37
27
  # The current locale for the user. Available as a helper for the views.
38
28
  #
39
29
  # Returns a String.
@@ -99,6 +89,67 @@ module Decidim
99
89
  end
100
90
  lang == "*" ? nil : lang
101
91
  end
92
+
93
+ def canonical_url(desired_url, target_locale = default_locale)
94
+ uri = URI(desired_url)
95
+ desired_locale = available_locales.include?(target_locale) ? target_locale : default_locale
96
+
97
+ path_segments = uri.path.split("/").compact_blank
98
+ locale_segment = path_segments.first
99
+
100
+ query = uri.query.to_s.gsub(/locale=[a-zA-Z-]{2,5}/, "")
101
+
102
+ if available_locales.include?(locale_segment)
103
+ path_segments[0] = desired_locale
104
+
105
+ uri.path = "/#{path_segments.join("/")}"
106
+
107
+ if query.present?
108
+ params = URI.decode_www_form(query)
109
+ uri.query = URI.encode_www_form(params)
110
+ else
111
+ uri.query = nil
112
+ end
113
+ elsif uri.host.blank? || uri.host == request.host
114
+ uri.path = if uri.path == "/"
115
+ "/#{desired_locale}"
116
+ else
117
+ "/#{desired_locale}#{uri.path}"
118
+ end
119
+
120
+ if query.present?
121
+ params = URI.decode_www_form(query)
122
+ uri.query = URI.encode_www_form(params)
123
+ else
124
+ uri.query = nil
125
+ end
126
+ else
127
+ params = URI.decode_www_form(query) << ["locale", desired_locale]
128
+ uri.query = URI.encode_www_form(params)
129
+ end
130
+
131
+ uri.to_s
132
+ end
133
+
134
+ private
135
+
136
+ # Adds the current locale to all the URLs generated by url_for so users
137
+ # experience a consistent behaviour if they copy or share links.
138
+ #
139
+ # Returns a Hash.
140
+ def default_url_options
141
+ return {} if current_locale == default_locale.to_s
142
+
143
+ { locale: current_locale }
144
+ end
145
+
146
+ def locale_in_script_name?
147
+ script_name = request&.script_name.to_s
148
+ return false if script_name.blank?
149
+
150
+ locale_segment = script_name.split("/").compact_blank.first
151
+ available_locales.include?(locale_segment)
152
+ end
102
153
  # rubocop: enable Metrics/CyclomaticComplexity
103
154
  # rubocop: enable Metrics/PerceivedComplexity
104
155
  end
@@ -41,19 +41,11 @@ module Decidim
41
41
  component_settings: try(:component_settings),
42
42
  current_organization: try(:current_organization),
43
43
  current_component: try(:current_component),
44
- share_token: try(:store_share_token)
44
+ share_token: store_share_token
45
45
  }
46
46
  end
47
47
 
48
- def enforce_permission_to(action, subject, extra_context = {})
49
- if Rails.env.development?
50
- Rails.logger.debug "==========="
51
- Rails.logger.debug [permission_scope, action, subject, permission_class_chain].map(&:inspect).join("\n")
52
- Rails.logger.debug "==========="
53
- end
54
-
55
- raise Decidim::ActionForbidden unless allowed_to?(action, subject, extra_context)
56
- end
48
+ public
57
49
 
58
50
  # rubocop:disable Metrics/ParameterLists
59
51
  def allowed_to?(action, subject, extra_context = {}, chain = permission_class_chain, user = current_user, scope = nil)
@@ -76,6 +68,18 @@ module Decidim
76
68
  allowed_to?(action, subject, extra_context, chain, user, :admin)
77
69
  end
78
70
 
71
+ protected
72
+
73
+ def enforce_permission_to(action, subject, extra_context = {})
74
+ if Rails.env.development?
75
+ Rails.logger.debug "==========="
76
+ Rails.logger.debug [permission_scope, action, subject, permission_class_chain].map(&:inspect).join("\n")
77
+ Rails.logger.debug "==========="
78
+ end
79
+
80
+ raise Decidim::ActionForbidden unless allowed_to?(action, subject, extra_context)
81
+ end
82
+
79
83
  def permission_class_chain
80
84
  raise "Please, make this method return an array of permission classes"
81
85
  end
@@ -83,6 +87,14 @@ module Decidim
83
87
  def permission_scope
84
88
  raise "Please, make this method return a symbol"
85
89
  end
90
+
91
+ private
92
+
93
+ def store_share_token
94
+ session[:share_token] = params[:share_token] if params.has_key?(:share_token)
95
+
96
+ session[:share_token].presence
97
+ end
86
98
  end
87
99
  end
88
100
  end
@@ -21,6 +21,8 @@ module Decidim
21
21
  OnboardingManager.new(user).pending_action?
22
22
  end
23
23
 
24
+ private
25
+
24
26
  def store_onboarding_cookie_data!(user)
25
27
  data = onboarding_cookie_data
26
28
  return if data.nil?
@@ -13,9 +13,7 @@ module Decidim
13
13
  helper_method :per_page, :page_offset
14
14
  helper Decidim::PaginateHelper
15
15
 
16
- def paginate(resources)
17
- resources.page(params[:page]).per(per_page)
18
- end
16
+ protected
19
17
 
20
18
  def per_page
21
19
  if OPTIONS.include?(params[:per_page])
@@ -31,6 +29,12 @@ module Decidim
31
29
  def page_offset
32
30
  [params[:page].to_i - 1, 0].max * per_page
33
31
  end
32
+
33
+ private
34
+
35
+ def paginate(resources)
36
+ resources.page(params[:page]).per(per_page)
37
+ end
34
38
  end
35
39
  end
36
40
  end
@@ -8,6 +8,8 @@ module Decidim
8
8
  include Decidim::TranslatableAttributes
9
9
 
10
10
  included do
11
+ private
12
+
11
13
  def append_info_to_payload(payload)
12
14
  super
13
15
  payload[:user_id] = try(:current_user).try(:id)
@@ -11,11 +11,25 @@ module Decidim
11
11
  helper_method :current_version, :versioned_resource
12
12
 
13
13
  def show
14
+ enforce_permission_to(*versioned_resource_permission)
15
+
14
16
  raise ActionController::RoutingError, "Not found" unless current_version
15
17
  end
16
18
 
17
19
  private
18
20
 
21
+ # The versions must honour the same `:read` permission as their resource,
22
+ # so a resource that is hidden, private, deleted or unpublished (and
23
+ # therefore cannot be read on its own) cannot be reached through its
24
+ # versions either.
25
+ def versioned_resource_permission
26
+ resource = versioned_resource
27
+ raise ActionController::RoutingError, "Not found" unless resource
28
+
29
+ subject = resource.model_name.element.to_sym
30
+ [:read, subject, { subject => resource }]
31
+ end
32
+
19
33
  # Overwrite this method in your controller to define how to find the
20
34
  # versioned resource.
21
35
  def versioned_resource
@@ -59,12 +59,6 @@ module Decidim
59
59
 
60
60
  skip_before_action :disable_http_caching, unless: :user_signed_in?
61
61
 
62
- def store_share_token
63
- session[:share_token] = params[:share_token] if params.has_key?(:share_token)
64
-
65
- session[:share_token].presence
66
- end
67
-
68
62
  private
69
63
 
70
64
  def allow_browser(**); end
@@ -6,6 +6,8 @@ module Decidim
6
6
  layout false
7
7
 
8
8
  def show
9
+ enforce_permission_to :read, :authorization
10
+
9
11
  store_onboarding_cookie_data!(current_user)
10
12
  end
11
13
 
@@ -66,6 +66,8 @@ module Decidim
66
66
  raise ActionController::RoutingError, "Not Found" unless current_user_can_visit_space?
67
67
  end
68
68
 
69
+ protected
70
+
69
71
  def set_component_breadcrumb_item
70
72
  context_breadcrumb_items << {
71
73
  label: current_component.name,
@@ -14,6 +14,8 @@ module Decidim
14
14
  before_action :check_sign_in_enabled
15
15
 
16
16
  def change_password
17
+ enforce_permission_to(:update, :user, current_user:)
18
+
17
19
  self.resource = current_user
18
20
  @send_path = apply_password_path
19
21
 
@@ -22,6 +24,8 @@ module Decidim
22
24
  end
23
25
 
24
26
  def apply_password
27
+ enforce_permission_to(:update, :user, current_user:)
28
+
25
29
  self.resource = current_user
26
30
  @send_path = apply_password_path
27
31
 
@@ -43,6 +47,10 @@ module Decidim
43
47
 
44
48
  private
45
49
 
50
+ def user_has_no_permission_path
51
+ new_user_session_path
52
+ end
53
+
46
54
  def check_sign_in_enabled
47
55
  redirect_to new_user_session_path unless current_organization.sign_in_enabled?
48
56
  end
@@ -12,6 +12,7 @@ module Decidim
12
12
  class FaviconController < ::DecidimController
13
13
  include ActionController::DataStreaming # For Rails 7, check out `ActiveStorage::Streaming`.
14
14
  include NeedsOrganization
15
+ include NeedsPermission
15
16
 
16
17
  skip_before_action :verify_authenticity_token, :verify_organization
17
18
  skip_after_action :verify_same_origin_request
@@ -52,5 +53,13 @@ module Decidim
52
53
 
53
54
  @favicon_blob ||= current_organization.favicon_ico&.blob
54
55
  end
56
+
57
+ def permission_class_chain
58
+ [Decidim::Permissions]
59
+ end
60
+
61
+ def permission_scope
62
+ :public
63
+ end
55
64
  end
56
65
  end
@@ -6,6 +6,8 @@ module Decidim
6
6
  layout false
7
7
 
8
8
  def show
9
+ enforce_permission_to :read, :authorization
10
+
9
11
  render template: "decidim/authorization_modals/show"
10
12
  end
11
13
 
@@ -6,6 +6,8 @@ module Decidim
6
6
  include HasSpecificBreadcrumb
7
7
 
8
8
  def index
9
+ enforce_permission_to :read, :badges
10
+
9
11
  @badges = Decidim::Gamification.badges.sort_by(&:name)
10
12
  end
11
13
 
@@ -3,6 +3,9 @@
3
3
  module Decidim
4
4
  class HomepageController < Decidim::ApplicationController
5
5
  skip_before_action :store_current_location
6
- def show; end
6
+
7
+ def show
8
+ enforce_permission_to :read, :homepage
9
+ end
7
10
  end
8
11
  end
@@ -8,7 +8,7 @@ module Decidim
8
8
  helper_method :like_button
9
9
  # we need to declare with +helper+ to be able to call :render_like_identity from the views
10
10
  helper Decidim::LikeableHelper
11
- helper_method :resource
11
+ helper_method :resource, :current_component
12
12
 
13
13
  before_action :authenticate_user!
14
14
 
@@ -15,6 +15,8 @@ module Decidim
15
15
  rescue_from URI::InvalidURIError, with: :modal
16
16
 
17
17
  def new
18
+ enforce_permission_to :read, :link
19
+
18
20
  headers["X-Robots-Tag"] = "none"
19
21
  headers["Link"] = %(<#{url_for}>; rel="canonical")
20
22
  end
@@ -4,6 +4,8 @@ module Decidim
4
4
  # A controller to serve the manifest file for PWA
5
5
  class ManifestsController < Decidim::ApplicationController
6
6
  def show
7
+ enforce_permission_to :read, :manifest
8
+
7
9
  organization_presenter = OrganizationPresenter.new(current_organization)
8
10
  render layout: false, locals: { organization_params: organization_presenter }, content_type: "application/manifest+json"
9
11
  end
@@ -43,10 +43,7 @@ module Decidim
43
43
 
44
44
  StartConversation.call(@form) do
45
45
  on(:ok) do |conversation|
46
- render action: :create, locals: {
47
- conversation:,
48
- form: MessageForm.new
49
- }
46
+ render action: :create, locals: { conversation: }
50
47
  end
51
48
 
52
49
  on(:invalid) do |messages|
@@ -96,6 +93,15 @@ module Decidim
96
93
 
97
94
  def check_multiple
98
95
  @form = form(ConversationForm).from_params(params, sender: current_user)
96
+
97
+ conversation = conversation_between_multiple(@form.recipient.to_a.prepend(current_user))
98
+
99
+ if conversation
100
+ enforce_permission_to :read, :conversation, conversation:
101
+ else
102
+ enforce_permission_to :create, :conversation, conversation: new_conversation(@form.recipient)
103
+ end
104
+
99
105
  redirect_link = current_or_new_conversation_path_with_multiple(@form.recipient, nickname: params[:nickname])
100
106
  redirect_to redirect_link
101
107
  end
@@ -11,6 +11,8 @@ module Decidim
11
11
  helper_method :newsletter
12
12
 
13
13
  def show
14
+ enforce_permission_to :read, :newsletter
15
+
14
16
  @user = current_user
15
17
  @organization = current_organization
16
18
 
@@ -20,6 +22,8 @@ module Decidim
20
22
  end
21
23
 
22
24
  def unsubscribe
25
+ enforce_permission_to :unsubscribe, :newsletter
26
+
23
27
  encryptor = Decidim::NewsletterEncryptor
24
28
 
25
29
  decrypted_string = encryptor.sent_at_decrypted(params[:u])
@@ -6,11 +6,15 @@ module Decidim
6
6
  rescue_from Decidim::NotificationsSubscriptionsPersistor::UnsupportedPushSubscriptionEndpointError, with: :unsupported_browser
7
7
 
8
8
  def create
9
+ enforce_permission_to(:update, :user, current_user:)
10
+
9
11
  Decidim::NotificationsSubscriptionsPersistor.new(current_user).add_subscription(params)
10
12
  head :ok
11
13
  end
12
14
 
13
15
  def destroy
16
+ enforce_permission_to(:update, :user, current_user:)
17
+
14
18
  Decidim::NotificationsSubscriptionsPersistor.new(current_user).delete_subscription(params[:auth])
15
19
  head :ok
16
20
  end
@@ -4,7 +4,11 @@ module Decidim
4
4
  class OfflineController < Decidim::ApplicationController
5
5
  include HasSpecificBreadcrumb
6
6
 
7
- def show; end
7
+ def show
8
+ enforce_permission_to :read, :offline
9
+ end
10
+
11
+ private
8
12
 
9
13
  def breadcrumb_item
10
14
  {