decidim-core 0.32.0.rc1 → 0.32.0.rc3

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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/amendable/amend_button_card/show.erb +2 -2
  3. data/app/cells/decidim/card_metadata_cell.rb +1 -1
  4. data/app/cells/decidim/content_blocks/cta_settings_form/show.erb +1 -1
  5. data/app/cells/decidim/content_blocks/hero_settings_form/show.erb +1 -1
  6. data/app/cells/decidim/content_blocks/highlighted_content_banner_settings_form/show.erb +1 -1
  7. data/app/cells/decidim/content_blocks/html_cell.rb +1 -1
  8. data/app/cells/decidim/content_blocks/participatory_space_hero_settings_form/show.erb +1 -1
  9. data/app/cells/decidim/content_blocks/static_page/section_cell.rb +1 -1
  10. data/app/cells/decidim/content_blocks/static_page/section_settings_form/show.erb +3 -1
  11. data/app/cells/decidim/content_blocks/static_page/summary_cell.rb +1 -1
  12. data/app/cells/decidim/content_blocks/static_page/summary_settings_form/show.erb +3 -1
  13. data/app/cells/decidim/content_blocks/static_page/two_pane_section_cell.rb +2 -2
  14. data/app/cells/decidim/content_blocks/static_page/two_pane_section_settings_form/show.erb +4 -2
  15. data/app/cells/decidim/data_consent/category.erb +5 -5
  16. data/app/cells/decidim/resource_types_filter/show.erb +2 -2
  17. data/app/cells/decidim/upload_modal_cell.rb +5 -0
  18. data/app/controllers/concerns/decidim/devise_controllers.rb +9 -0
  19. data/app/controllers/decidim/download_your_data_controller.rb +1 -1
  20. data/app/controllers/decidim/notifications_subscriptions_controller.rb +8 -0
  21. data/app/controllers/decidim/private_downloads_controller.rb +29 -0
  22. data/app/events/decidim/amendable/amendment_base_event.rb +7 -1
  23. data/app/models/decidim/attachment.rb +20 -2
  24. data/app/models/decidim/authorization.rb +7 -0
  25. data/app/models/decidim/moderation.rb +1 -1
  26. data/app/models/decidim/participatory_space/member.rb +1 -1
  27. data/app/models/decidim/private_download.rb +61 -0
  28. data/app/models/decidim/private_export.rb +6 -0
  29. data/app/models/decidim/user_base_entity.rb +17 -2
  30. data/app/models/decidim/user_moderation.rb +1 -1
  31. data/app/packs/src/decidim/controllers/breadcrumb_truncate/breadcrumb_truncate.test.js +230 -0
  32. data/app/packs/src/decidim/controllers/breadcrumb_truncate/controller.js +172 -0
  33. data/app/packs/src/decidim/controllers/form_validator/form_validator.js +6 -6
  34. data/app/packs/src/decidim/controllers/form_validator/form_validator.test.js +23 -1
  35. data/app/packs/src/decidim/direct_uploads/upload_field.js +4 -4
  36. data/app/packs/src/decidim/direct_uploads/upload_modal.js +11 -7
  37. data/app/packs/src/decidim/index.js +2 -1
  38. data/app/packs/src/decidim/sw/push-permissions.js +48 -13
  39. data/app/packs/src/decidim/sw/sw.js +1 -1
  40. data/app/packs/src/decidim/utilities/text.js +6 -6
  41. data/app/packs/stylesheets/decidim/_floating_help.scss +1 -1
  42. data/app/packs/stylesheets/decidim/_header.scss +36 -7
  43. data/app/presenters/decidim/menu_item_presenter.rb +9 -3
  44. data/app/presenters/decidim/stats_presenter.rb +1 -1
  45. data/app/services/decidim/notifications_subscriptions_persistor.rb +6 -0
  46. data/app/services/decidim/push_subscription_endpoint_validator.rb +34 -0
  47. data/app/services/decidim/send_push_notification.rb +5 -1
  48. data/app/views/decidim/gamification/badges/index.html.erb +1 -1
  49. data/app/views/decidim/homepage/show.html.erb +1 -1
  50. data/app/views/decidim/last_activities/index.html.erb +1 -1
  51. data/app/views/decidim/newsletters/unsubscribe.html.erb +1 -1
  52. data/app/views/decidim/notifications_settings/show.html.erb +5 -5
  53. data/app/views/decidim/offline/show.html.erb +1 -1
  54. data/app/views/decidim/pages/index.html.erb +1 -1
  55. data/app/views/decidim/profiles/show.html.erb +1 -1
  56. data/app/views/decidim/shared/_resource_actions.html.erb +4 -4
  57. data/app/views/decidim/user_activities/index.html.erb +1 -1
  58. data/app/views/layouts/decidim/_wrapper.html.erb +2 -2
  59. data/app/views/layouts/decidim/header/_menu.html.erb +1 -1
  60. data/app/views/layouts/decidim/header/_menu_breadcrumb_desktop.html.erb +31 -4
  61. data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile.html.erb +17 -13
  62. data/app/views/layouts/decidim/shared/_layout_center.html.erb +1 -1
  63. data/app/views/layouts/decidim/shared/_layout_item.html.erb +1 -1
  64. data/app/views/layouts/decidim/shared/_layout_two_col.html.erb +1 -1
  65. data/config/initializers/decidim_locale_aware_named_route_helper.rb +16 -0
  66. data/config/locales/ar.yml +2 -24
  67. data/config/locales/bg.yml +4 -26
  68. data/config/locales/bs-BA.yml +1 -0
  69. data/config/locales/ca-IT.yml +30 -28
  70. data/config/locales/ca.yml +30 -28
  71. data/config/locales/cs.yml +8 -28
  72. data/config/locales/da.yml +1 -0
  73. data/config/locales/de.yml +5 -36
  74. data/config/locales/el.yml +2 -22
  75. data/config/locales/en.yml +26 -25
  76. data/config/locales/eo.yml +1 -0
  77. data/config/locales/es-MX.yml +30 -28
  78. data/config/locales/es-PY.yml +30 -28
  79. data/config/locales/es.yml +30 -28
  80. data/config/locales/et.yml +1 -0
  81. data/config/locales/eu.yml +56 -70
  82. data/config/locales/fa-IR.yml +1 -0
  83. data/config/locales/fi-plain.yml +36 -29
  84. data/config/locales/fi.yml +38 -31
  85. data/config/locales/fr-CA.yml +7 -25
  86. data/config/locales/fr.yml +7 -25
  87. data/config/locales/ga-IE.yml +1 -0
  88. data/config/locales/gl.yml +2 -23
  89. data/config/locales/gn-PY.yml +1 -0
  90. data/config/locales/hr.yml +1 -0
  91. data/config/locales/hu.yml +2 -21
  92. data/config/locales/id-ID.yml +2 -22
  93. data/config/locales/is-IS.yml +2 -7
  94. data/config/locales/it.yml +13 -19
  95. data/config/locales/ja.yml +4 -32
  96. data/config/locales/ka-GE.yml +1 -0
  97. data/config/locales/kaa.yml +1 -0
  98. data/config/locales/ko.yml +1 -0
  99. data/config/locales/lb.yml +2 -22
  100. data/config/locales/lt.yml +2 -23
  101. data/config/locales/lv.yml +2 -22
  102. data/config/locales/mt.yml +1 -0
  103. data/config/locales/nl.yml +2 -22
  104. data/config/locales/no.yml +2 -22
  105. data/config/locales/oc-FR.yml +1 -0
  106. data/config/locales/pl.yml +4 -26
  107. data/config/locales/pt-BR.yml +5 -33
  108. data/config/locales/pt.yml +2 -22
  109. data/config/locales/ro-RO.yml +2 -23
  110. data/config/locales/ru.yml +1 -8
  111. data/config/locales/sk.yml +1424 -21
  112. data/config/locales/sl.yml +1 -0
  113. data/config/locales/sr-CS.yml +1 -0
  114. data/config/locales/sv.yml +11 -34
  115. data/config/locales/tr-TR.yml +2 -23
  116. data/config/locales/uk.yml +1 -6
  117. data/config/locales/vi.yml +1 -0
  118. data/config/locales/zh-CN.yml +2 -20
  119. data/config/locales/zh-TW.yml +2 -23
  120. data/config/routes.rb +2 -0
  121. data/decidim-core.gemspec +1 -1
  122. data/lib/decidim/api/functions/user_entity_list.rb +2 -0
  123. data/lib/decidim/content_renderers/base_renderer.rb +112 -0
  124. data/lib/decidim/content_renderers/blob_renderer.rb +4 -7
  125. data/lib/decidim/content_renderers/mention_resource_renderer.rb +10 -6
  126. data/lib/decidim/content_renderers/resource_renderer.rb +16 -7
  127. data/lib/decidim/content_renderers/user_renderer.rb +11 -9
  128. data/lib/decidim/core/test/shared_examples/amendable/amendment_event_examples.rb +2 -2
  129. data/lib/decidim/core/test/shared_examples/amendable/amendment_promoted_event_examples.rb +3 -3
  130. data/lib/decidim/core/test/shared_examples/has_space_in_mcell_examples.rb +2 -1
  131. data/lib/decidim/core/test/shared_examples/resource_liked_event_examples.rb +3 -3
  132. data/lib/decidim/core/version.rb +1 -1
  133. metadata +11 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: caaaf7bbddd64f7bb5d4341c6ebeab59b35dd0f69326b136d11958165e513801
4
- data.tar.gz: e18600f3eec00c3fbf76b58e90a34bf4888a114f7dc5a9d35896540d30a7a20f
3
+ metadata.gz: 5c8c0eaf7af52859f34c0b152525144104d544b91f8a5ba49173b2f25530709c
4
+ data.tar.gz: c1d8019a4006489b276e3d2ca8c5c6f194890035369ab69a7c7e358376f16fae
5
5
  SHA512:
6
- metadata.gz: 847ec9bd0ae30f358fd5330e3bf61cd34adedca669986b5082e391473e3f66df4e7eab20bac8ad4478827fd66b2d3e94e46559ef4138cf289d5a71caf60e904b
7
- data.tar.gz: b832cfbd8827d809a1792ff0f7a6688f2282e3f2bfc8975bf821175465333ade87ef0e2fd92bf9ac3512f54e40d31872d2f35a28424b8549de717e2f645141b3
6
+ metadata.gz: 88f9cdca14f469d2fe61ca88c3ba56f8e44586a951be4de8a3faa3f9de1d75b982f8b0db9023052470118f8f47c4d327eecf4687a568f636a18a6c85cfacd874
7
+ data.tar.gz: de42f147191cad92bd9b25c908a4526aaa317313e44603828b59ec0f40e9360f1a9cc8e046b64ed226b9c1585cdca4b213f271380e003d43936b813ebef6160f
@@ -1,5 +1,5 @@
1
- <li role="menuitem" class="dropdown__item">
2
- <%= action_authorized_link_to :amend, new_amend_path, resource: model, data: { "redirect_url" => new_amend_path }, id: "amend-button", class: "dropdown__button" do %>
1
+ <li role="presentation" class="dropdown__item">
2
+ <%= action_authorized_link_to :amend, new_amend_path, resource: model, data: { "redirect_url" => new_amend_path }, id: "amend-button", class: "dropdown__button", role: "menuitem" do %>
3
3
  <span><%= t("button", scope: "decidim.amendments.amendable", model_name: nil) %></span>
4
4
  <%= icon "pencil-line" %>
5
5
  <% end %>
@@ -29,7 +29,7 @@ module Decidim
29
29
  return unless show_space?
30
30
 
31
31
  {
32
- text: decidim_escape_translated(participatory_space.title),
32
+ text: translated_attribute(participatory_space.title),
33
33
  icon: resource_type_icon_key(participatory_space.class),
34
34
  url: Decidim::ResourceLocatorPresenter.new(participatory_space).path
35
35
  }
@@ -4,6 +4,6 @@
4
4
  <%= settings_fields.translated :text_field, :description, label: t("decidim.content_blocks.cta_settings_form.description") %>
5
5
  <% end %>
6
6
 
7
- <% form.fields_for :images, form.object.images do |images_fields| %>
7
+ <% form.fields_for :images, content_block.images_container do |images_fields| %>
8
8
  <%= images_fields.upload :background_image, label: t("decidim.content_blocks.cta_settings_form.background_image") %>
9
9
  <% end %>
@@ -14,7 +14,7 @@
14
14
  </div>
15
15
  <% end %>
16
16
 
17
- <% form.fields_for :images, form.object.images do |images_fields| %>
17
+ <% form.fields_for :images, content_block.images_container do |images_fields| %>
18
18
  <div class="row column">
19
19
  <%= images_fields.upload :background_image, label: t(".background_image"), button_class: "button button__sm button__transparent-secondary" %>
20
20
  </div>
@@ -20,7 +20,7 @@
20
20
  </div>
21
21
  <% end %>
22
22
 
23
- <% form.fields_for :images, form.object.images do |images_fields| %>
23
+ <% form.fields_for :images, content_block.images_container do |images_fields| %>
24
24
  <div class="row column">
25
25
  <%= images_fields.upload :background_image, label: t(".background_image"), button_class: "button button__sm button__transparent-secondary" %>
26
26
  </div>
@@ -8,7 +8,7 @@ module Decidim
8
8
  end
9
9
 
10
10
  def html_content
11
- translated_attribute(model.settings.html_content).html_safe
11
+ decidim_sanitize_editor_admin(translated_attribute(model.settings.html_content))
12
12
  end
13
13
  end
14
14
  end
@@ -8,7 +8,7 @@
8
8
  </div>
9
9
  <% end %>
10
10
 
11
- <% form.fields_for :images, form.object.images do |images_fields| %>
11
+ <% form.fields_for :images, content_block.images_container do |images_fields| %>
12
12
  <div class="row column">
13
13
  <%= images_fields.upload :background_image, label: t("decidim.content_blocks.cta_settings_form.background_image"), button_class: "button button__sm button__transparent-secondary" %>
14
14
  </div>
@@ -5,7 +5,7 @@ module Decidim
5
5
  module StaticPage
6
6
  class SectionCell < Decidim::ViewModel
7
7
  def content
8
- translated_attribute(model.settings.content).html_safe
8
+ decidim_sanitize_editor_admin(translated_attribute(model.settings.content))
9
9
  end
10
10
  end
11
11
  end
@@ -1,3 +1,5 @@
1
1
  <% form.fields_for :settings, form.object.settings do |settings_fields| %>
2
- <%= settings_fields.translated :editor, :content, label: %>
2
+ <div class="row column">
3
+ <%= settings_fields.translated :editor, :content, label: %>
4
+ </div>
3
5
  <% end %>
@@ -5,7 +5,7 @@ module Decidim
5
5
  module StaticPage
6
6
  class SummaryCell < Decidim::ViewModel
7
7
  def content
8
- translated_attribute(model.settings.summary).html_safe
8
+ decidim_sanitize_editor_admin(translated_attribute(model.settings.summary))
9
9
  end
10
10
  end
11
11
  end
@@ -1,3 +1,5 @@
1
1
  <% form.fields_for :settings, form.object.settings do |settings_fields| %>
2
- <%= settings_fields.translated :editor, :summary, label: %>
2
+ <div class="row column">
3
+ <%= settings_fields.translated :editor, :summary, label: %>
4
+ </div>
3
5
  <% end %>
@@ -5,11 +5,11 @@ module Decidim
5
5
  module StaticPage
6
6
  class TwoPaneSectionCell < Decidim::ViewModel
7
7
  def left_column
8
- translated_attribute(model.settings.left_column).html_safe
8
+ decidim_sanitize_editor_admin(translated_attribute(model.settings.left_column))
9
9
  end
10
10
 
11
11
  def right_column
12
- translated_attribute(model.settings.right_column).html_safe
12
+ decidim_sanitize_editor_admin(translated_attribute(model.settings.right_column))
13
13
  end
14
14
  end
15
15
  end
@@ -1,4 +1,6 @@
1
1
  <% form.fields_for :settings, form.object.settings do |settings_fields| %>
2
- <%= settings_fields.translated :editor, :left_column, label: label_left_column %>
3
- <%= settings_fields.translated :editor, :right_column, label: label_right_column %>
2
+ <div class="row column">
3
+ <%= settings_fields.translated :editor, :left_column, label: label_left_column %>
4
+ <%= settings_fields.translated :editor, :right_column, label: label_right_column %>
5
+ </div>
4
6
  <% end %>
@@ -13,12 +13,12 @@
13
13
  <%= icon "close-line", class: "cookies__category-toggle-icon" %>
14
14
  </label>
15
15
 
16
- <div id="accordion-trigger-<%= category[:slug] %>" role="group" data-controls="accordion-panel-<%= category[:slug] %>" aria-labelledby="accordion-title-<%= category[:slug] %>">
17
- <h3 id="accordion-title-<%= category[:slug] %>" class="cookies__category-trigger-title">
18
- <%= category[:title] %>
19
- </h3>
16
+ <h3 id="accordion-title-<%= category[:slug] %>" class="cookies__category-trigger-title">
17
+ <%= category[:title] %>
18
+ </h3>
20
19
 
21
- <span>
20
+ <div id="accordion-trigger-<%= category[:slug] %>" role="group" data-controls="accordion-panel-<%= category[:slug] %>" aria-labelledby="accordion-title-<%= category[:slug] %>">
21
+ <span aria-hidden="true">
22
22
  <%= icon "arrow-down-s-line", class: "cookies__category-trigger-arrow" %>
23
23
  <%= icon "arrow-up-s-line", class: "cookies__category-trigger-arrow" %>
24
24
  </span>
@@ -10,8 +10,8 @@
10
10
  </button>
11
11
  <ul id="dropdown-menu-resource">
12
12
  <% resource_types.each do |resource_type| %>
13
- <li role="menuitem">
14
- <%= link_to filter_url(resource_type[0]), class: "filter#{" is-active" if filter_param == resource_type[0]}" do %>
13
+ <li role="presentation">
14
+ <%= link_to filter_url(resource_type[0]), class: "filter#{" is-active" if filter_param == resource_type[0]}", role: "menuitem" do %>
15
15
  <span class="sr-only"><%= resource_type[1] %></span>
16
16
  <%= text_with_resource_icon(*resource_type) %>
17
17
  <% end %>
@@ -177,6 +177,11 @@ module Decidim
177
177
 
178
178
  def file_attachment_path(attachment)
179
179
  return unless attachment
180
+
181
+ if attachment.respond_to?(:record) && attachment.record.is_a?(Decidim::Authorization) && attachment.name.to_s == "verification_attachment"
182
+ return decidim.private_download_path(Decidim::PrivateDownload.for(attachment.record, attachment_name: attachment.name).token)
183
+ end
184
+
180
185
  return Rails.application.routes.url_helpers.rails_blob_url(attachment, only_path: true) if attachment.is_a? ActiveStorage::Blob
181
186
 
182
187
  if attachment.try(:attached?)
@@ -41,6 +41,10 @@ module Decidim
41
41
 
42
42
  layout "layouts/decidim/application"
43
43
 
44
+ # Ensure locale is set before Devise's own prepended callbacks and reset
45
+ # after the request finishes.
46
+ prepend_around_action :set_current_locale
47
+
44
48
  # Saves the location before loading each page so we can return to the
45
49
  # right page.
46
50
  before_action :store_current_location
@@ -58,6 +62,11 @@ module Decidim
58
62
 
59
63
  store_location_for(:user, redirect_url)
60
64
  end
65
+
66
+ def set_current_locale(&)
67
+ locale = Decidim::LocaleRouterDetector.new(request, params).locale
68
+ I18n.with_locale(locale, &)
69
+ end
61
70
  end
62
71
  end
63
72
  end
@@ -50,7 +50,7 @@ module Decidim
50
50
  flash[:error] = t("decidim.account.download_your_data_export.export_expired")
51
51
  redirect_to download_your_data_path
52
52
  elsif private_export.file.attached?
53
- redirect_to Rails.application.routes.url_helpers.rails_blob_url(private_export.file.blob, only_path: true)
53
+ redirect_to private_download_path(Decidim::PrivateDownload.for(private_export, attachment_name: :file).token)
54
54
  else
55
55
  flash[:error] = t("decidim.account.download_your_data_export.file_no_exists")
56
56
  redirect_to download_your_data_path
@@ -3,6 +3,8 @@
3
3
  module Decidim
4
4
  # The controller to handle the subscriptions to push notifications
5
5
  class NotificationsSubscriptionsController < Decidim::ApplicationController
6
+ rescue_from Decidim::NotificationsSubscriptionsPersistor::UnsupportedPushSubscriptionEndpointError, with: :unsupported_browser
7
+
6
8
  def create
7
9
  Decidim::NotificationsSubscriptionsPersistor.new(current_user).add_subscription(params)
8
10
  head :ok
@@ -12,5 +14,11 @@ module Decidim
12
14
  Decidim::NotificationsSubscriptionsPersistor.new(current_user).delete_subscription(params[:auth])
13
15
  head :ok
14
16
  end
17
+
18
+ private
19
+
20
+ def unsupported_browser
21
+ render json: { error: I18n.t("notifications_settings.show.push_notifications_unsupported_browser", scope: "decidim") }, status: :unprocessable_content
22
+ end
15
23
  end
16
24
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ class PrivateDownloadsController < Decidim::ApplicationController
5
+ before_action :authenticate_user!
6
+
7
+ def show
8
+ return head :not_found unless private_download.attached?
9
+ return head :not_found unless private_download.authorized_for?(current_user)
10
+
11
+ disposition = private_download.attachment.content_type.start_with?("image/") ? :inline : :attachment
12
+
13
+ send_data(
14
+ private_download.attachment.download,
15
+ filename: private_download.attachment.filename.to_s,
16
+ type: private_download.attachment.content_type,
17
+ disposition:
18
+ )
19
+ rescue Decidim::PrivateDownload::InvalidTokenError
20
+ head :not_found
21
+ end
22
+
23
+ private
24
+
25
+ def private_download
26
+ @private_download ||= Decidim::PrivateDownload.from_token(params[:id])
27
+ end
28
+ end
29
+ end
@@ -3,7 +3,7 @@
3
3
  module Decidim::Amendable
4
4
  class AmendmentBaseEvent < Decidim::Events::SimpleEvent
5
5
  i18n_attributes :amendable_path, :amendable_type, :amendable_title,
6
- :emendation_path, :emendation_author_nickname, :emendation_author_path
6
+ :emendation_path, :emendation_author_nickname, :emendation_author_name, :emendation_author_path
7
7
 
8
8
  def amendable_title
9
9
  @amendable_title ||= translated_attribute(amendable_resource.title)
@@ -33,6 +33,12 @@ module Decidim::Amendable
33
33
  @emendation_author_nickname ||= emendation_author.nickname
34
34
  end
35
35
 
36
+ def emendation_author_name
37
+ return unless emendation_resource
38
+
39
+ @emendation_author_name ||= emendation_author.name
40
+ end
41
+
36
42
  def emendation_author_path
37
43
  return unless emendation_resource
38
44
 
@@ -88,7 +88,7 @@ module Decidim
88
88
  # Returns String.
89
89
  def file_type
90
90
  if file?
91
- url&.split(".")&.last&.split("&")&.first&.downcase
91
+ file.filename.extension&.downcase
92
92
  elsif link?
93
93
  "link"
94
94
  end
@@ -100,7 +100,13 @@ module Decidim
100
100
  def url
101
101
  @url ||=
102
102
  if file?
103
- attached_uploader(:file).url
103
+ if private_download_required?
104
+ Decidim::Core::Engine.routes.url_helpers.private_download_path(
105
+ Decidim::PrivateDownload.for(self, attachment_name: :file).token
106
+ )
107
+ else
108
+ attached_uploader(:file).url
109
+ end
104
110
  elsif link?
105
111
  link
106
112
  end
@@ -144,5 +150,17 @@ module Decidim
144
150
 
145
151
  attached_to.can_participate?(user)
146
152
  end
153
+
154
+ def private_download_authorized?(user, requested_attachment_name)
155
+ return false unless requested_attachment_name.to_s == "file"
156
+
157
+ can_participate?(user)
158
+ end
159
+
160
+ def private_download_required?
161
+ return attached_to.restricted? if attached_to.respond_to?(:restricted?)
162
+
163
+ attached_to.respond_to?(:component) && attached_to.component&.restricted_space?
164
+ end
147
165
  end
148
166
  end
@@ -91,6 +91,13 @@ module Decidim
91
91
  Decidim::AuthorizationTransfer.perform!(self, handler)
92
92
  end
93
93
 
94
+ def private_download_authorized?(user, requested_attachment_name)
95
+ return false unless requested_attachment_name.to_s == "verification_attachment"
96
+ return true if user&.admin? && user.organization == organization
97
+
98
+ user == self.user
99
+ end
100
+
94
101
  private
95
102
 
96
103
  def active_handler?
@@ -32,7 +32,7 @@ module Decidim
32
32
  end
33
33
 
34
34
  def self.ransackable_attributes(_auth_object = nil)
35
- %w(reported_id_string reported_content created_at)
35
+ %w(reported_id_string reported_content created_at report_count)
36
36
  end
37
37
 
38
38
  def self.ransackable_associations(_auth_object = nil)
@@ -42,7 +42,7 @@ module Decidim
42
42
  def self.ransackable_attributes(auth_object = nil)
43
43
  return [] unless auth_object&.admin?
44
44
 
45
- %w(name nickname email invitation_accepted_at last_sign_in_at invitation_sent_at role)
45
+ %w(name nickname email invitation_accepted_at last_sign_in_at invitation_sent_at role published)
46
46
  end
47
47
 
48
48
  def self.ransackable_associations(_auth_object = nil)
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ class PrivateDownload
5
+ class InvalidTokenError < StandardError; end
6
+
7
+ VERIFIER_PURPOSE = :private_download
8
+
9
+ def self.for(record, attachment_name:)
10
+ new(record:, attachment_name:)
11
+ end
12
+
13
+ def self.from_token(token)
14
+ payload = verifier.verify(token, purpose: VERIFIER_PURPOSE).with_indifferent_access
15
+ record = GlobalID::Locator.locate(payload[:gid])
16
+
17
+ raise InvalidTokenError if record.blank?
18
+
19
+ new(record:, attachment_name: payload[:attachment_name])
20
+ rescue ActiveSupport::MessageVerifier::InvalidSignature, TypeError
21
+ raise InvalidTokenError
22
+ end
23
+
24
+ def self.verifier
25
+ @verifier ||= ActiveSupport::MessageVerifier.new(Rails.application.secret_key_base, serializer: JSON)
26
+ end
27
+
28
+ def initialize(record:, attachment_name:)
29
+ @record = record
30
+ @attachment_name = attachment_name.to_s
31
+ end
32
+
33
+ def token
34
+ self.class.verifier.generate(
35
+ {
36
+ gid: record.to_global_id.to_s,
37
+ attachment_name:
38
+ },
39
+ purpose: VERIFIER_PURPOSE
40
+ )
41
+ end
42
+
43
+ def attachment
44
+ record.public_send(attachment_name)
45
+ end
46
+
47
+ def attached?
48
+ attachment.respond_to?(:attached?) && attachment.attached?
49
+ end
50
+
51
+ def authorized_for?(user)
52
+ return false unless record.respond_to?(:private_download_authorized?)
53
+
54
+ record.private_download_authorized?(user, attachment_name)
55
+ end
56
+
57
+ private
58
+
59
+ attr_reader :record, :attachment_name
60
+ end
61
+ end
@@ -24,5 +24,11 @@ module Decidim
24
24
  self.content_type = file.content_type
25
25
  self.file_size = file.byte_size
26
26
  end
27
+
28
+ def private_download_authorized?(user, requested_attachment_name)
29
+ return false unless requested_attachment_name.to_s == "file"
30
+
31
+ attached_to == user
32
+ end
27
33
  end
28
34
  end
@@ -69,12 +69,27 @@ module Decidim
69
69
  Decidim::UserBaseEntity.joins(:follows).where(decidim_follows: { user: self }).blocked.exists?
70
70
  end
71
71
 
72
+ ransacker :role do
73
+ Arel.sql(%{CASE WHEN "decidim_users"."admin" = true THEN 'admin' ELSE cast("decidim_users"."roles" as text) END})
74
+ end
75
+
76
+ ransacker :user_moderation_report_count do
77
+ query = <<~SQL.squish
78
+ (
79
+ SELECT COALESCE(MAX(decidim_user_moderations.report_count), 0)
80
+ FROM decidim_user_moderations
81
+ WHERE decidim_user_moderations.decidim_user_id = decidim_users.id
82
+ )
83
+ SQL
84
+ Arel.sql(query)
85
+ end
86
+
72
87
  def self.ransackable_attributes(auth_object = nil)
73
- base = %w(name email nickname last_sign_in_at)
88
+ base = %w(name email nickname last_sign_in_at created_at)
74
89
 
75
90
  return base unless auth_object&.admin?
76
91
 
77
- base + %w(invitation_sent_at invitation_accepted_at officialized_at)
92
+ base + %w(invitation_sent_at invitation_accepted_at officialized_at role user_moderation_report_count)
78
93
  end
79
94
 
80
95
  def self.ransackable_associations(_auth_object = nil)
@@ -19,7 +19,7 @@ module Decidim
19
19
  end
20
20
 
21
21
  def self.ransackable_attributes(_auth_object = nil)
22
- []
22
+ %w(created_at report_count)
23
23
  end
24
24
 
25
25
  def self.ransackable_associations(_auth_object = nil)