decidim-core 0.31.2 → 0.32.1

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 (516) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -13
  3. data/app/cells/decidim/amendable/amend_button_card/show.erb +2 -2
  4. data/app/cells/decidim/amendable/amend_button_card_cell.rb +1 -1
  5. data/app/cells/decidim/author_cell.rb +0 -4
  6. data/app/cells/decidim/card_metadata_cell.rb +1 -1
  7. data/app/cells/decidim/comments_button_cell.rb +9 -1
  8. data/app/cells/decidim/content_blocks/announcement_settings_form/show.erb +5 -0
  9. data/app/cells/decidim/content_blocks/announcement_settings_form_cell.rb +17 -0
  10. data/app/cells/decidim/content_blocks/cta_settings_form/show.erb +1 -1
  11. data/app/cells/decidim/content_blocks/hero_settings_form/show.erb +1 -1
  12. data/app/cells/decidim/content_blocks/highlighted_content_banner_cell.rb +1 -1
  13. data/app/cells/decidim/content_blocks/highlighted_content_banner_settings_form/show.erb +1 -1
  14. data/app/cells/decidim/content_blocks/highlighted_elements_with_cell_for_list_cell.rb +5 -1
  15. data/app/cells/decidim/content_blocks/highlighted_participatory_spaces_cell.rb +1 -1
  16. data/app/cells/decidim/content_blocks/how_to_participate/show.erb +1 -1
  17. data/app/cells/decidim/content_blocks/html_cell.rb +1 -1
  18. data/app/cells/decidim/content_blocks/participatory_space_announcement_cell.rb +1 -3
  19. data/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb +1 -5
  20. data/app/cells/decidim/content_blocks/participatory_space_hero_settings_form/show.erb +1 -1
  21. data/app/cells/decidim/content_blocks/static_page/section_cell.rb +1 -1
  22. data/app/cells/decidim/content_blocks/static_page/section_settings_form/show.erb +3 -1
  23. data/app/cells/decidim/content_blocks/static_page/summary_cell.rb +1 -1
  24. data/app/cells/decidim/content_blocks/static_page/summary_settings_form/show.erb +3 -1
  25. data/app/cells/decidim/content_blocks/static_page/two_pane_section_cell.rb +2 -2
  26. data/app/cells/decidim/content_blocks/static_page/two_pane_section_settings_form/show.erb +4 -2
  27. data/app/cells/decidim/data_consent/category.erb +25 -38
  28. data/app/cells/decidim/footer_topics/show.erb +5 -8
  29. data/app/cells/decidim/{participatory_space_private_user → member}/show.erb +6 -6
  30. data/app/cells/decidim/{participatory_space_private_user_cell.rb → member_cell.rb} +1 -5
  31. data/app/cells/decidim/nav_links/show.erb +3 -3
  32. data/app/cells/decidim/onboarding_action_message_cell.rb +1 -0
  33. data/app/cells/decidim/profile/details.erb +1 -1
  34. data/app/cells/decidim/profile_cell.rb +1 -0
  35. data/app/cells/decidim/profile_member_of/show.erb +13 -0
  36. data/app/cells/decidim/profile_member_of_cell.rb +35 -0
  37. data/app/cells/decidim/report_button/already_reported_modal.erb +1 -1
  38. data/app/cells/decidim/report_button/flag_modal.erb +1 -1
  39. data/app/cells/decidim/report_user_button/already_reported_modal.erb +1 -1
  40. data/app/cells/decidim/report_user_button/flag_modal.erb +1 -1
  41. data/app/cells/decidim/resource_types_filter/show.erb +2 -2
  42. data/app/cells/decidim/share_text_widget/modal.erb +1 -1
  43. data/app/cells/decidim/share_widget/qr_code_modal.erb +1 -1
  44. data/app/cells/decidim/tags_cell.rb +1 -1
  45. data/app/cells/decidim/upload_modal/files.erb +5 -1
  46. data/app/cells/decidim/upload_modal_cell.rb +15 -1
  47. data/app/cells/decidim/versions_list/show.erb +25 -0
  48. data/app/commands/decidim/create_follow.rb +3 -5
  49. data/app/commands/decidim/create_user_report.rb +1 -1
  50. data/app/commands/decidim/destroy_account.rb +15 -4
  51. data/app/commands/decidim/multiple_attachments_methods.rb +42 -24
  52. data/app/commands/decidim/search.rb +5 -5
  53. data/app/controllers/concerns/decidim/ajax_permission_handler.rb +1 -1
  54. data/app/controllers/concerns/decidim/devise_controllers.rb +9 -0
  55. data/app/controllers/concerns/decidim/direct_upload.rb +3 -2
  56. data/app/controllers/concerns/decidim/ephemeral_session_checker.rb +1 -1
  57. data/app/controllers/concerns/decidim/force_authentication.rb +10 -1
  58. data/app/controllers/concerns/decidim/impersonate_users.rb +4 -0
  59. data/app/controllers/concerns/decidim/locale_switcher.rb +52 -2
  60. data/app/controllers/concerns/decidim/needs_tos_accepted.rb +1 -1
  61. data/app/controllers/concerns/decidim/participatory_space/has_members_page.rb +27 -0
  62. data/app/controllers/concerns/decidim/participatory_space_context.rb +1 -5
  63. data/app/controllers/decidim/account_controller.rb +1 -1
  64. data/app/controllers/decidim/amendments_controller.rb +5 -4
  65. data/app/controllers/decidim/components/base_controller.rb +20 -3
  66. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +1 -1
  67. data/app/controllers/decidim/devise/passwords_controller.rb +1 -1
  68. data/app/controllers/decidim/devise/registrations_controller.rb +1 -1
  69. data/app/controllers/decidim/devise/sessions_controller.rb +1 -1
  70. data/app/controllers/decidim/download_your_data_controller.rb +2 -2
  71. data/app/controllers/decidim/editor_images_controller.rb +1 -1
  72. data/app/controllers/decidim/follows_controller.rb +4 -3
  73. data/app/controllers/decidim/geolocation_controller.rb +1 -1
  74. data/app/controllers/decidim/likes_controller.rb +2 -1
  75. data/app/controllers/decidim/locales_controller.rb +3 -11
  76. data/app/controllers/decidim/messaging/conversations_controller.rb +3 -3
  77. data/app/controllers/decidim/newsletters_controller.rb +1 -1
  78. data/app/controllers/decidim/notifications_settings_controller.rb +1 -1
  79. data/app/controllers/decidim/notifications_subscriptions_controller.rb +8 -0
  80. data/app/controllers/decidim/open_data_controller.rb +1 -1
  81. data/app/controllers/decidim/private_downloads_controller.rb +29 -0
  82. data/app/controllers/decidim/report_users_controller.rb +2 -2
  83. data/app/controllers/decidim/reports_controller.rb +1 -1
  84. data/app/controllers/decidim/user_activities_controller.rb +1 -2
  85. data/app/events/decidim/amendable/amendment_base_event.rb +7 -1
  86. data/app/events/decidim/welcome_notification_event.rb +1 -1
  87. data/app/forms/decidim/upload_validation_form.rb +1 -1
  88. data/app/helpers/concerns/decidim/flash_helper_extensions.rb +1 -0
  89. data/app/helpers/decidim/active_link_to_helper.rb +136 -0
  90. data/app/helpers/decidim/amendments_helper.rb +3 -3
  91. data/app/helpers/decidim/check_boxes_tree_helper.rb +2 -2
  92. data/app/helpers/decidim/component_path_helper.rb +9 -4
  93. data/app/helpers/decidim/filters_helper.rb +0 -2
  94. data/app/helpers/decidim/mailer_helper.rb +36 -0
  95. data/app/helpers/decidim/menu_helper.rb +4 -5
  96. data/app/helpers/decidim/meta_tags_helper.rb +0 -2
  97. data/app/helpers/decidim/newsletters_helper.rb +4 -22
  98. data/app/helpers/decidim/paginate_helper.rb +14 -1
  99. data/app/helpers/decidim/sanitize_helper.rb +1 -0
  100. data/app/helpers/decidim/short_link_helper.rb +5 -5
  101. data/app/helpers/decidim/translations_helper.rb +4 -4
  102. data/app/jobs/decidim/delete_inactive_participants_job.rb +2 -2
  103. data/app/jobs/decidim/find_and_update_descendants_job.rb +8 -2
  104. data/app/jobs/decidim/process_inactive_participant_job.rb +0 -7
  105. data/app/jobs/decidim/update_search_indexes_job.rb +2 -2
  106. data/app/mailers/decidim/application_mailer.rb +11 -2
  107. data/app/mailers/decidim/decidim_devise_mailer.rb +1 -0
  108. data/app/mailers/decidim/delete_user_mailer.rb +14 -0
  109. data/app/mailers/decidim/participants_account_mailer.rb +0 -16
  110. data/app/mailers/decidim/reported_mailer.rb +4 -1
  111. data/app/models/decidim/action_log.rb +1 -1
  112. data/app/models/decidim/attachment.rb +20 -2
  113. data/app/models/decidim/authorization.rb +7 -0
  114. data/app/models/decidim/authorization_transfer.rb +1 -1
  115. data/app/models/decidim/component.rb +6 -9
  116. data/app/models/decidim/content_block.rb +3 -3
  117. data/app/models/decidim/moderation.rb +1 -1
  118. data/app/models/decidim/newsletter.rb +2 -2
  119. data/app/models/decidim/participatory_space/member.rb +55 -0
  120. data/app/models/decidim/private_download.rb +61 -0
  121. data/app/models/decidim/private_export.rb +6 -0
  122. data/app/models/decidim/resource_link.rb +1 -1
  123. data/app/models/decidim/short_link.rb +1 -1
  124. data/app/models/decidim/user.rb +2 -2
  125. data/app/models/decidim/user_base_entity.rb +17 -2
  126. data/app/models/decidim/user_moderation.rb +1 -1
  127. data/app/packs/src/decidim/a11y.js +29 -0
  128. data/app/packs/src/decidim/a11y.test.js +81 -0
  129. data/app/packs/src/decidim/confirm.js +8 -1
  130. data/app/packs/src/decidim/confirm.test.js +225 -0
  131. data/app/packs/src/decidim/controllers/accordion/accordion.test.js +272 -0
  132. data/app/packs/src/decidim/controllers/accordion/controller.js +117 -17
  133. data/app/packs/src/decidim/controllers/assign_role/assign_role.test.js +80 -0
  134. data/app/packs/src/decidim/controllers/assign_role/controller.js +27 -0
  135. data/app/packs/src/decidim/controllers/breadcrumb_truncate/breadcrumb_truncate.test.js +230 -0
  136. data/app/packs/src/decidim/controllers/breadcrumb_truncate/controller.js +172 -0
  137. data/app/packs/src/decidim/controllers/dropdown/controller.js +32 -0
  138. data/app/packs/src/decidim/controllers/dropdown/dropdown.test.js +215 -0
  139. data/app/packs/src/decidim/controllers/form_validator/form_validator.js +9 -8
  140. data/app/packs/src/decidim/controllers/form_validator/form_validator.test.js +28 -1
  141. data/app/packs/src/decidim/controllers/language_change/controller.js +1 -0
  142. data/app/packs/src/decidim/controllers/language_change/language_change.test.js +13 -0
  143. data/app/packs/src/decidim/controllers/main_menu/controller.js +152 -0
  144. data/app/packs/src/decidim/controllers/main_menu/main_menu.test.js +285 -0
  145. data/app/packs/src/decidim/controllers/mention/controller.js +296 -140
  146. data/app/packs/src/decidim/controllers/mention/input_mentions.test.js +120 -457
  147. data/app/packs/src/decidim/controllers/multiple_mentions/controller.js +68 -32
  148. data/app/packs/src/decidim/controllers/multiple_mentions/input_multiple_mentions.test.js +30 -23
  149. data/app/packs/src/decidim/controllers/password_toggler/controller.js +22 -1
  150. data/app/packs/src/decidim/controllers/password_toggler/password_toggler.test.js +11 -20
  151. data/app/packs/src/decidim/datepicker/datepicker_functions.js +26 -0
  152. data/app/packs/src/decidim/datepicker/generate_datepicker.js +3 -14
  153. data/app/packs/src/decidim/datepicker/generate_timepicker.js +3 -2
  154. data/app/packs/src/decidim/datepicker/test/datepicker_functions_adjust_picker_position.test.js +234 -0
  155. data/app/packs/src/decidim/direct_uploads/upload_field.js +4 -4
  156. data/app/packs/src/decidim/direct_uploads/upload_modal.js +12 -7
  157. data/app/packs/src/decidim/editor/common/suggestion.js +4 -2
  158. data/app/packs/src/decidim/editor/extensions/decidim_kit/index.js +4 -1
  159. data/app/packs/src/decidim/editor/extensions/image/index.js +57 -16
  160. data/app/packs/src/decidim/editor/extensions/image/node_view.js +9 -1
  161. data/app/packs/src/decidim/editor/extensions/indent/index.js +9 -0
  162. data/app/packs/src/decidim/editor/extensions/link/bubble_menu.js +34 -6
  163. data/app/packs/src/decidim/editor/extensions/link/index.js +53 -12
  164. data/app/packs/src/decidim/editor/extensions/mention/index.js +18 -5
  165. data/app/packs/src/decidim/editor/extensions/mention_resource/index.js +16 -7
  166. data/app/packs/src/decidim/editor/test/extensions/decidim_kit.test.js +13 -4
  167. data/app/packs/src/decidim/editor/test/extensions/heading.test.js +1 -1
  168. data/app/packs/src/decidim/editor/test/extensions/image.test.js +26 -28
  169. data/app/packs/src/decidim/editor/test/extensions/image_links.test.js +161 -0
  170. data/app/packs/src/decidim/editor/test/extensions/mention.test.js +6 -2
  171. data/app/packs/src/decidim/editor/test/extensions/video_embed.test.js +27 -15
  172. data/app/packs/src/decidim/editor/test/helpers.js +8 -10
  173. data/app/packs/src/decidim/editor/test/toolbar/full.test.js +15 -4
  174. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_block.js +8 -4
  175. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_formatting.js +5 -1
  176. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_indent.js +9 -5
  177. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_link.js +5 -1
  178. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_list.js +8 -4
  179. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_styling.js +13 -9
  180. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_content_styling.js +6 -2
  181. data/app/packs/src/decidim/geocoding/reverse_geocoding.js +15 -5
  182. data/app/packs/src/decidim/geocoding/reverse_geocoding.test.js +197 -0
  183. data/app/packs/src/decidim/index.js +4 -4
  184. data/app/packs/src/decidim/map/controller.js +10 -1
  185. data/app/packs/src/decidim/refactor/moved/focus_guard.js +16 -16
  186. data/app/packs/src/decidim/refactor/moved/focus_guard.test.js +136 -0
  187. data/app/packs/src/decidim/sw/push-permissions.js +48 -13
  188. data/app/packs/src/decidim/sw/sw.js +1 -1
  189. data/app/packs/src/decidim/utilities/text.js +6 -6
  190. data/app/packs/stylesheets/decidim/_cards.scss +15 -6
  191. data/app/packs/stylesheets/decidim/_conversations.scss +14 -0
  192. data/app/packs/stylesheets/decidim/_cookies.scss +13 -5
  193. data/app/packs/stylesheets/decidim/_datepicker.scss +0 -8
  194. data/app/packs/stylesheets/decidim/_documents.scss +1 -1
  195. data/app/packs/stylesheets/decidim/_dropdown.scss +22 -32
  196. data/app/packs/stylesheets/decidim/_editor_suggestions.scss +49 -0
  197. data/app/packs/stylesheets/decidim/_flash.scss +1 -1
  198. data/app/packs/stylesheets/decidim/_floating_help.scss +1 -1
  199. data/app/packs/stylesheets/decidim/_footer.scss +27 -31
  200. data/app/packs/stylesheets/decidim/_forms.scss +5 -1
  201. data/app/packs/stylesheets/decidim/_header.scss +183 -48
  202. data/app/packs/stylesheets/decidim/_language_chooser.scss +79 -0
  203. data/app/packs/stylesheets/decidim/_participatory_spaces.scss +1 -1
  204. data/app/packs/stylesheets/decidim/_rich_text.scss +17 -0
  205. data/app/packs/stylesheets/decidim/_tom_select.scss +23 -0
  206. data/app/packs/stylesheets/decidim/application.scss +3 -0
  207. data/app/packs/stylesheets/decidim/editor.scss +12 -33
  208. data/app/packs/stylesheets/decidim/geocoding_addons.scss +10 -2
  209. data/app/presenters/decidim/admin_log/participatory_space/member_presenter.rb +40 -0
  210. data/app/presenters/decidim/admin_log/static_page_resource_presenter.rb +1 -1
  211. data/app/presenters/decidim/authorization_transfer_presenter.rb +1 -1
  212. data/app/presenters/decidim/breadcrumb_root_menu_item_presenter.rb +3 -3
  213. data/app/presenters/decidim/footer_menu_presenter.rb +2 -4
  214. data/app/presenters/decidim/log/user_presenter.rb +1 -0
  215. data/app/presenters/decidim/log/value_types/access_mode_presenter.rb +45 -0
  216. data/app/presenters/decidim/menu_item_presenter.rb +15 -3
  217. data/app/presenters/decidim/participatory_space/member_presenter.rb +48 -0
  218. data/app/presenters/decidim/resource_locator_presenter.rb +22 -3
  219. data/app/presenters/decidim/stats_presenter.rb +1 -1
  220. data/app/queries/decidim/last_activity.rb +1 -1
  221. data/app/resolvers/decidim/meta_image_url_resolver.rb +7 -0
  222. data/app/serializers/decidim/exporters/participatory_space_serializer.rb +15 -1
  223. data/app/services/decidim/email_notification_generator.rb +2 -0
  224. data/app/services/decidim/notification_generator.rb +4 -0
  225. data/app/services/decidim/notifications_subscriptions_persistor.rb +6 -0
  226. data/app/services/decidim/push_subscription_endpoint_validator.rb +34 -0
  227. data/app/services/decidim/send_push_notification.rb +5 -1
  228. data/app/uploaders/decidim/image_uploader.rb +1 -1
  229. data/app/uploaders/decidim/organization_favicon_uploader.rb +4 -9
  230. data/app/validators/uploader_image_dimensions_validator.rb +13 -11
  231. data/app/views/decidim/delete_user_mailer/delete.html.erb +6 -0
  232. data/app/views/decidim/devise/invitations/edit.html.erb +3 -3
  233. data/app/views/decidim/devise/registrations/new.html.erb +1 -0
  234. data/app/views/decidim/devise/shared/_tos_fields.html.erb +3 -3
  235. data/app/views/decidim/gamification/badges/index.html.erb +1 -1
  236. data/app/views/decidim/homepage/show.html.erb +2 -2
  237. data/app/views/decidim/last_activities/index.html.erb +1 -1
  238. data/app/views/decidim/messaging/conversations/_error_modal.html.erb +11 -19
  239. data/app/views/decidim/messaging/conversations/_new_conversation_button.html.erb +1 -1
  240. data/app/views/decidim/messaging/conversations/_reply.html.erb +1 -1
  241. data/app/views/decidim/messaging/conversations/error.js.erb +12 -7
  242. data/app/views/decidim/messaging/conversations/new.html.erb +1 -1
  243. data/app/views/decidim/messaging/conversations/show.html.erb +2 -2
  244. data/app/views/decidim/newsletters/unsubscribe.html.erb +1 -1
  245. data/app/views/decidim/notification_mailer/event_received.html.erb +3 -3
  246. data/app/views/decidim/notifications_settings/show.html.erb +5 -5
  247. data/app/views/decidim/offline/show.html.erb +1 -1
  248. data/app/views/decidim/pages/_tabbed.html.erb +3 -3
  249. data/app/views/decidim/pages/index.html.erb +1 -1
  250. data/app/views/decidim/participatory_space/members/_member.html.erb +1 -0
  251. data/app/views/decidim/profiles/show.html.erb +1 -1
  252. data/app/views/decidim/searches/_filters.html.erb +1 -1
  253. data/app/views/decidim/shared/_filters.html.erb +5 -5
  254. data/app/views/decidim/shared/_resource_actions.html.erb +4 -4
  255. data/app/views/decidim/shared/_results_per_page.html.erb +1 -1
  256. data/app/views/decidim/shared/filters/_check_boxes_tree.html.erb +2 -2
  257. data/app/views/decidim/shared/filters/_collection.html.erb +1 -1
  258. data/app/views/decidim/shared/filters/_dropdown_label.html.erb +4 -3
  259. data/app/views/decidim/user_activities/index.html.erb +1 -1
  260. data/app/views/devise/mailer/{invite_private_user.html.erb → invite_member.html.erb} +2 -2
  261. data/app/views/devise/mailer/{invite_private_user.text.erb → invite_member.text.erb} +2 -2
  262. data/app/views/layouts/decidim/_head.html.erb +2 -2
  263. data/app/views/layouts/decidim/_wrapper.html.erb +3 -3
  264. data/app/views/layouts/decidim/footer/_focus_mode_main.html.erb +0 -1
  265. data/app/views/layouts/decidim/footer/_main.html.erb +1 -2
  266. data/app/views/layouts/decidim/footer/_main_links.html.erb +56 -28
  267. data/app/views/layouts/decidim/header/_focus_mode_back_button.html.erb +4 -1
  268. data/app/views/layouts/decidim/header/_main.html.erb +17 -8
  269. data/app/views/layouts/decidim/header/_main_language_chooser.html.erb +24 -0
  270. data/app/views/layouts/decidim/header/_main_links_desktop.html.erb +56 -56
  271. data/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb +2 -2
  272. data/app/views/layouts/decidim/header/_main_links_mobile_item_account.html.erb +3 -1
  273. data/app/views/layouts/decidim/header/_main_menu_mobile.html.erb +18 -5
  274. data/app/views/layouts/decidim/header/_main_search.html.erb +3 -3
  275. data/app/views/layouts/decidim/header/_menu.html.erb +5 -5
  276. data/app/views/layouts/decidim/header/_menu_breadcrumb_desktop.html.erb +40 -12
  277. data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile.html.erb +33 -0
  278. data/app/views/layouts/decidim/shared/_layout_center.html.erb +1 -1
  279. data/app/views/layouts/decidim/shared/_layout_item.html.erb +1 -1
  280. data/app/views/layouts/decidim/shared/_layout_two_col.html.erb +1 -1
  281. data/config/initializers/decidim_locale_aware_named_route_helper.rb +16 -0
  282. data/config/initializers/devise.rb +6 -0
  283. data/config/initializers/invisible_captcha.rb +1 -0
  284. data/config/locales/ar.yml +6 -38
  285. data/config/locales/bg.yml +3 -39
  286. data/config/locales/ca-IT.yml +91 -58
  287. data/config/locales/ca.yml +91 -58
  288. data/config/locales/cs.yml +54 -58
  289. data/config/locales/de.yml +45 -68
  290. data/config/locales/el.yml +3 -31
  291. data/config/locales/en.yml +88 -55
  292. data/config/locales/es-MX.yml +93 -60
  293. data/config/locales/es-PY.yml +93 -60
  294. data/config/locales/es.yml +95 -62
  295. data/config/locales/eu.yml +124 -92
  296. data/config/locales/fi-plain.yml +93 -55
  297. data/config/locales/fi.yml +96 -58
  298. data/config/locales/fr-CA.yml +70 -52
  299. data/config/locales/fr.yml +71 -54
  300. data/config/locales/ga-IE.yml +3 -1
  301. data/config/locales/gl.yml +3 -31
  302. data/config/locales/hu.yml +7 -40
  303. data/config/locales/id-ID.yml +3 -30
  304. data/config/locales/is-IS.yml +0 -6
  305. data/config/locales/it.yml +15 -33
  306. data/config/locales/ja.yml +105 -71
  307. data/config/locales/lb.yml +3 -33
  308. data/config/locales/lt.yml +4 -37
  309. data/config/locales/lv.yml +3 -30
  310. data/config/locales/nl.yml +3 -33
  311. data/config/locales/no.yml +3 -33
  312. data/config/locales/pl.yml +7 -41
  313. data/config/locales/pt-BR.yml +24 -65
  314. data/config/locales/pt.yml +3 -33
  315. data/config/locales/ro-RO.yml +12 -55
  316. data/config/locales/ru.yml +0 -16
  317. data/config/locales/sk.yml +1417 -32
  318. data/config/locales/sv.yml +44 -62
  319. data/config/locales/tr-TR.yml +20 -37
  320. data/config/locales/uk.yml +0 -9
  321. data/config/locales/zh-CN.yml +3 -30
  322. data/config/locales/zh-TW.yml +4 -35
  323. data/config/routes.rb +140 -76
  324. data/db/data/20251213075429_rename_members_in_action_log.rb +22 -0
  325. data/db/data/20260319145808_rename_send_to_members_in_newsletter.rb +27 -0
  326. data/db/migrate/20200730142511_add_file_upload_settings_to_decidim_organizations.rb +13 -15
  327. data/db/migrate/20250217192438_convert_user_groups_into_users.rb +3 -2
  328. data/db/migrate/20250523104311_move_cta_to_hero_content_block.rb +1 -1
  329. data/db/migrate/20250527122040_move_highlighted_content_banner_settings_to_content_block.rb +1 -1
  330. data/db/migrate/20250819110800_convert_private_exports_id_to_uuid.rb +2 -2
  331. data/db/migrate/20251112132305_remove_legacy_images_from_core_module.rb +27 -0
  332. data/db/migrate/20251205122428_rename_participatory_space_private_users_to_members.rb +9 -0
  333. data/db/migrate/20251216185133_rename_privatable_to_to_participatory_space_in_members.rb +10 -0
  334. data/db/migrate/20260208201405_remove_user_group_core.rb +21 -0
  335. data/db/migrate/20260208201406_remove_user_group_memberships.rb +30 -0
  336. data/db/migrate/20260208201407_remove_user_group_organizations.rb +11 -0
  337. data/db/migrate/20260217152425_remove_enable_participatory_space_filters_from_decidim_organizations.rb +7 -0
  338. data/db/migrate/20260314081619_add_index_on_decidim_members.rb +25 -0
  339. data/decidim-core.gemspec +28 -28
  340. data/lib/decidim/acts_as_tree.rb +12 -12
  341. data/lib/decidim/admin_filters_registry.rb +1 -1
  342. data/lib/decidim/amendable.rb +5 -1
  343. data/lib/decidim/api/functions/category_list.rb +1 -0
  344. data/lib/decidim/api/functions/component_finder_base.rb +1 -1
  345. data/lib/decidim/api/functions/component_list.rb +3 -1
  346. data/lib/decidim/api/functions/component_list_base.rb +1 -0
  347. data/lib/decidim/api/functions/participatory_space_finder_base.rb +1 -1
  348. data/lib/decidim/api/functions/participatory_space_list_base.rb +1 -0
  349. data/lib/decidim/api/functions/user_entity_list.rb +2 -1
  350. data/lib/decidim/api/interfaces/amendable_entity_interface.rb +1 -0
  351. data/lib/decidim/api/interfaces/amendable_interface.rb +1 -0
  352. data/lib/decidim/api/interfaces/attachable_collection_interface.rb +1 -0
  353. data/lib/decidim/api/interfaces/attachable_interface.rb +1 -0
  354. data/lib/decidim/api/interfaces/author_interface.rb +2 -1
  355. data/lib/decidim/api/interfaces/authorable_interface.rb +1 -0
  356. data/lib/decidim/api/interfaces/categories_container_interface.rb +1 -0
  357. data/lib/decidim/api/interfaces/categorizable_interface.rb +1 -0
  358. data/lib/decidim/api/interfaces/coauthorable_interface.rb +1 -0
  359. data/lib/decidim/api/interfaces/component_interface.rb +9 -8
  360. data/lib/decidim/api/interfaces/fingerprint_interface.rb +1 -0
  361. data/lib/decidim/api/interfaces/followable_interface.rb +2 -0
  362. data/lib/decidim/api/interfaces/likeable_interface.rb +2 -2
  363. data/lib/decidim/api/interfaces/localizable_interface.rb +1 -0
  364. data/lib/decidim/api/interfaces/participatory_space_interface.rb +1 -0
  365. data/lib/decidim/api/interfaces/referable_interface.rb +1 -0
  366. data/lib/decidim/api/interfaces/scopable_interface.rb +1 -0
  367. data/lib/decidim/api/interfaces/taxonomizable_interface.rb +1 -0
  368. data/lib/decidim/api/interfaces/timestamps_interface.rb +1 -0
  369. data/lib/decidim/api/interfaces/traceable_interface.rb +1 -0
  370. data/lib/decidim/api/types/attachment_collection_type.rb +5 -3
  371. data/lib/decidim/api/types/attachment_type.rb +11 -4
  372. data/lib/decidim/api/types/badge_score_type.rb +28 -0
  373. data/lib/decidim/api/types/moderation_type.rb +25 -0
  374. data/lib/decidim/api/types/participant_details_type.rb +17 -0
  375. data/lib/decidim/api/types/reportable_type.rb +18 -0
  376. data/lib/decidim/api/types/reportable_user_type.rb +17 -0
  377. data/lib/decidim/api/types/static_page_topic_type.rb +16 -0
  378. data/lib/decidim/api/types/static_page_type.rb +22 -0
  379. data/lib/decidim/api/types/taxonomy_type.rb +2 -0
  380. data/lib/decidim/api/types/user_moderation_type.rb +36 -0
  381. data/lib/decidim/api/types/user_type.rb +13 -0
  382. data/lib/decidim/asset_router/pipeline.rb +1 -1
  383. data/lib/decidim/asset_router/storage.rb +9 -9
  384. data/lib/decidim/assets/tailwind/tailwind.config.js.erb +4 -1
  385. data/lib/decidim/attachment_attributes.rb +58 -9
  386. data/lib/decidim/attribute_encryptor.rb +51 -10
  387. data/lib/decidim/attribute_object/model.rb +0 -5
  388. data/lib/decidim/block_registry.rb +1 -1
  389. data/lib/decidim/coauthorable.rb +2 -1
  390. data/lib/decidim/command.rb +2 -1
  391. data/lib/decidim/content_parsers/blob_parser.rb +3 -3
  392. data/lib/decidim/content_processor.rb +1 -1
  393. data/lib/decidim/content_renderers/base_renderer.rb +112 -0
  394. data/lib/decidim/content_renderers/blob_renderer.rb +6 -9
  395. data/lib/decidim/content_renderers/mention_resource_renderer.rb +10 -6
  396. data/lib/decidim/content_renderers/resource_renderer.rb +16 -7
  397. data/lib/decidim/content_renderers/user_renderer.rb +11 -9
  398. data/lib/decidim/core/api.rb +8 -0
  399. data/lib/decidim/core/content_blocks/registry_manager.rb +4 -10
  400. data/lib/decidim/core/engine.rb +10 -34
  401. data/lib/decidim/core/menu.rb +0 -26
  402. data/lib/decidim/core/test/factories.rb +32 -18
  403. data/lib/decidim/core/test/shared_examples/access_mode_restricted_participatory_spaces.rb +175 -0
  404. data/lib/decidim/core/test/shared_examples/access_mode_transparent_participatory_spaces.rb +244 -0
  405. data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +10 -10
  406. data/lib/decidim/core/test/shared_examples/amendable/amendment_event_examples.rb +2 -2
  407. data/lib/decidim/core/test/shared_examples/amendable/amendment_promoted_event_examples.rb +3 -3
  408. data/lib/decidim/core/test/shared_examples/comments_examples.rb +147 -117
  409. data/lib/decidim/core/test/shared_examples/fingerprint_examples.rb +2 -0
  410. data/lib/decidim/core/test/shared_examples/has_members.rb +63 -0
  411. data/lib/decidim/core/test/shared_examples/has_space_in_mcell_examples.rb +2 -1
  412. data/lib/decidim/core/test/shared_examples/manage_share_tokens_examples.rb +1 -1
  413. data/lib/decidim/core/test/shared_examples/map_examples.rb +1 -1
  414. data/lib/decidim/core/test/shared_examples/participant_details_examples.rb +16 -0
  415. data/lib/decidim/core/test/shared_examples/participatory_space_members_page_examples.rb +10 -10
  416. data/lib/decidim/core/test/shared_examples/participatory_space_members_shared_examples.rb +121 -0
  417. data/lib/decidim/core/test/shared_examples/resource_liked_event_examples.rb +3 -3
  418. data/lib/decidim/core/test/shared_examples/resource_locator_presenter_examples.rb +7 -7
  419. data/lib/decidim/core/test/shared_examples/searchable_participatory_space_examples.rb +3 -3
  420. data/lib/decidim/core/test/shared_examples/searchable_results_examples.rb +2 -2
  421. data/lib/decidim/core/test/shared_examples/simple_event.rb +1 -0
  422. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +2 -2
  423. data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +1 -1
  424. data/lib/decidim/core/test.rb +2 -1
  425. data/lib/decidim/core/version.rb +1 -1
  426. data/lib/decidim/core.rb +222 -335
  427. data/lib/decidim/download_your_data_serializers/{download_your_data_participatory_space_private_user_serializer.rb → download_your_data_member_serializer.rb} +6 -6
  428. data/lib/decidim/download_your_data_serializers.rb +2 -2
  429. data/lib/decidim/engine_router.rb +31 -6
  430. data/lib/decidim/exporters/csv.rb +1 -1
  431. data/lib/decidim/filter_form_builder.rb +1 -1
  432. data/lib/decidim/form_builder.rb +58 -36
  433. data/{app/controllers/concerns → lib}/decidim/form_factory.rb +11 -1
  434. data/lib/decidim/has_settings.rb +2 -2
  435. data/lib/decidim/legacy_form_builder.rb +1 -0
  436. data/lib/decidim/locale_router_detector.rb +41 -0
  437. data/lib/decidim/maintenance/import_models/scope.rb +1 -1
  438. data/lib/decidim/maintenance/import_models.rb +0 -2
  439. data/lib/decidim/maintenance/taxonomy_importer.rb +1 -1
  440. data/lib/decidim/map/autocomplete.rb +4 -3
  441. data/lib/decidim/map/dynamic_map.rb +3 -1
  442. data/lib/decidim/map/frontend.rb +1 -1
  443. data/lib/decidim/map/geocoding.rb +2 -2
  444. data/lib/decidim/map/static_map.rb +10 -22
  445. data/lib/decidim/map/utility.rb +3 -6
  446. data/lib/decidim/map.rb +2 -2
  447. data/lib/decidim/menu.rb +1 -1
  448. data/lib/decidim/menu_item.rb +1 -0
  449. data/lib/decidim/menu_registry.rb +1 -1
  450. data/lib/decidim/moderation_tools.rb +1 -1
  451. data/lib/decidim/newsletter_encryptor.rb +5 -8
  452. data/lib/decidim/organization_settings.rb +2 -2
  453. data/lib/decidim/participable.rb +1 -0
  454. data/lib/decidim/participatory_space/has_members.rb +61 -0
  455. data/lib/decidim/participatory_space_manifest.rb +0 -4
  456. data/lib/decidim/participatory_space_resourceable.rb +10 -1
  457. data/lib/decidim/participatory_space_user.rb +1 -1
  458. data/lib/decidim/routes/locale_redirects.rb +47 -0
  459. data/lib/decidim/routes.rb +7 -0
  460. data/lib/decidim/search_resource_fields_mapper.rb +3 -4
  461. data/lib/decidim/searchable.rb +9 -4
  462. data/lib/decidim/seeds.rb +17 -0
  463. data/lib/decidim/shakapacker/runner.rb +4 -4
  464. data/lib/decidim/shakapacker/shakapacker.yml +28 -3
  465. data/lib/decidim/taxonomizable.rb +1 -1
  466. data/lib/decidim/translatable_attributes.rb +9 -3
  467. data/lib/decidim/view_model.rb +5 -1
  468. data/lib/devise/models/decidim_newsletterable.rb +1 -1
  469. data/lib/tasks/decidim_mailers_tasks.rake +31 -9
  470. data/lib/tasks/decidim_procfile.rake +1 -1
  471. data/lib/tasks/decidim_tasks.rake +0 -1
  472. data/lib/tasks/decidim_taxonomies.rake +1 -1
  473. data/lib/tasks/upgrade/decidim_active_storage_migration_tasks.rake +0 -1
  474. data/lib/tasks/upgrade/decidim_encryption.rake +12 -0
  475. data/lib/tasks/upgrade/decidim_migrate_wysiwyg_content.rake +0 -1
  476. data/lib/tasks/upgrade/decidim_remove_deleted_users_left_data_tasks.rake +1 -1
  477. data/lib/tasks/upgrade/{fix_deleted_private_follows.rake → fix_deleted_members_follows.rake} +5 -5
  478. data/lib/tasks/upgrade/migrations.rake +0 -1
  479. data/lib/tasks/upgrade/user_groups_migration.rake +0 -1
  480. metadata +244 -132
  481. data/app/cells/decidim/content_blocks/global_menu/show.erb +0 -11
  482. data/app/cells/decidim/content_blocks/global_menu_cell.rb +0 -35
  483. data/app/cells/decidim/content_blocks/menu_breadcrumb_last_activity/show.erb +0 -10
  484. data/app/cells/decidim/content_blocks/menu_breadcrumb_last_activity_cell.rb +0 -49
  485. data/app/cells/decidim/participatory_space_dropdown_metadata/links.erb +0 -9
  486. data/app/cells/decidim/participatory_space_dropdown_metadata/metadata.erb +0 -1
  487. data/app/cells/decidim/participatory_space_dropdown_metadata/show.erb +0 -11
  488. data/app/cells/decidim/participatory_space_dropdown_metadata_cell.rb +0 -26
  489. data/app/commands/decidim/gallery_methods.rb +0 -107
  490. data/app/controllers/concerns/decidim/has_members_page.rb +0 -25
  491. data/app/jobs/decidim/newsletters_opt_in_job.rb +0 -11
  492. data/app/jobs/decidim/user_report_job.rb +0 -11
  493. data/app/models/decidim/participatory_space_private_user.rb +0 -51
  494. data/app/packs/src/decidim/controllers/sticky_header/controller.js +0 -116
  495. data/app/packs/src/decidim/controllers/sticky_header/sticky_header.test.js +0 -320
  496. data/app/packs/src/decidim/dropdown_menu.js +0 -18
  497. data/app/packs/src/decidim/identity_selector_dialog.js +0 -33
  498. data/app/packs/src/decidim/vendor/tribute.js +0 -1890
  499. data/app/packs/stylesheets/decidim/_tribute.scss +0 -36
  500. data/app/presenters/decidim/admin_log/participatory_space_private_user_presenter.rb +0 -38
  501. data/app/presenters/decidim/participatory_space_private_user_presenter.rb +0 -46
  502. data/app/views/decidim/participants_account_mailer/removal_notification.html.erb +0 -11
  503. data/app/views/decidim/participatory_space_private_users/_participatory_space_private_user.html.erb +0 -1
  504. data/app/views/layouts/decidim/footer/_main_language_chooser.html.erb +0 -26
  505. data/app/views/layouts/decidim/header/_menu_breadcrumb_items.html.erb +0 -34
  506. data/app/views/layouts/decidim/header/_menu_breadcrumb_main_dropdown_desktop.html.erb +0 -10
  507. data/app/views/layouts/decidim/header/_menu_breadcrumb_main_dropdown_mobile.html.erb +0 -17
  508. data/app/views/layouts/decidim/header/_menu_breadcrumb_main_dropdown_top_left.html.erb +0 -2
  509. data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +0 -33
  510. data/app/views/layouts/decidim/header/_mobile_language_choose.html.erb +0 -25
  511. data/lib/decidim/core/test/shared_examples/has_private_users.rb +0 -63
  512. data/lib/decidim/core/test/shared_examples/participatory_space_dropdown_metadata_cell_examples.rb +0 -81
  513. data/lib/decidim/has_private_users.rb +0 -57
  514. data/lib/decidim/maintenance/import_models/assembly_type.rb +0 -49
  515. data/lib/decidim/maintenance/import_models/participatory_process_type.rb +0 -21
  516. data/lib/decidim/query_extensions.rb +0 -64
@@ -2,7 +2,7 @@
2
2
  <div data-dialog-container>
3
3
  <div data-dialog-title>
4
4
  <%= icon "qr-code-line" %>
5
- <h2 tabindex="-1"><%= t("decidim.share_widget.qr_code") %></h2>
5
+ <h2 id="dialog-title-qr-code-dialog" tabindex="-1"><%= t("decidim.share_widget.qr_code") %></h2>
6
6
  </div>
7
7
  <div class="content">
8
8
  <div>
@@ -25,7 +25,7 @@ module Decidim
25
25
  @taxonomies ||= model.taxonomies.map do |taxonomy|
26
26
  {
27
27
  name: decidim_sanitize_translated(taxonomy.name),
28
- url: resource_locator(model).index(filter: { "with_any_taxonomies[#{taxonomy.root_taxonomy.id}]" => [taxonomy.id.to_s] })
28
+ url: resource_locator(model).index(filter: { "with_any_taxonomies" => { taxonomy.root_taxonomy.id => [taxonomy.id.to_s] } })
29
29
  }
30
30
  end
31
31
  end
@@ -42,7 +42,11 @@
42
42
  <% end %>
43
43
  <% end %>
44
44
  <% if attachment_blob.present? %>
45
- <%= form.hidden_field attribute, value: attachment_blob.signed_id, id: "hidden_#{attribute}_#{attachment_blob.id}" %>
45
+ <% if is_persisted_attachment %>
46
+ <%= form.hidden_field attribute, value: attachment.id, id: "hidden_#{attribute}_#{attachment.id}" %>
47
+ <% else %>
48
+ <%= form.hidden_field attribute, value: attachment_blob.signed_id, id: "hidden_#{attribute}_#{attachment_blob.id}" %>
49
+ <% end %>
46
50
  <% end %>
47
51
  </div>
48
52
  <% end %>
@@ -128,7 +128,16 @@ module Decidim
128
128
  @attachments = begin
129
129
  attachments = options[:attachments] || form.object.send(attribute)
130
130
  attachments = Array(attachments).compact_blank
131
- attachments.map { |attachment| attachment.is_a?(String) ? ActiveStorage::Blob.find_signed(attachment) : attachment }
131
+ attachments.map do |attachment|
132
+ case attachment
133
+ when String
134
+ ActiveStorage::Blob.find_signed(attachment)
135
+ when Integer
136
+ Decidim::Attachment.find_by(id: attachment)
137
+ else
138
+ attachment
139
+ end
140
+ end.compact
132
141
  end
133
142
  end
134
143
 
@@ -168,6 +177,11 @@ module Decidim
168
177
 
169
178
  def file_attachment_path(attachment)
170
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
+
171
185
  return Rails.application.routes.url_helpers.rails_blob_url(attachment, only_path: true) if attachment.is_a? ActiveStorage::Blob
172
186
 
173
187
  if attachment.try(:attached?)
@@ -1,3 +1,28 @@
1
1
  <% reverse_ordered_versions.each_with_index do |version, index| %>
2
2
  <%= cell("decidim/versions_list_item", version, index:, versioned_resource:, version_path:, i18n_scope:, total:) %>
3
3
  <% end %>
4
+
5
+ <% if versioned_resource.class.include?(Decidim::Fingerprintable) %>
6
+ <% fingerprint_id = dom_id(versioned_resource, :fingerprint_dialog) %>
7
+ <section class="mt-4 ml-2">
8
+ <%= content_tag :button, t("decidim.fingerprint.check"), class: "button button__lg button__text-secondary font-normal text-sm underline", data: { dialog_open: fingerprint_id } %>
9
+ </section>
10
+ <%= decidim_modal id: fingerprint_id, class: "fingerprint-modal" do %>
11
+ <div data-dialog-container>
12
+ <%= icon "fingerprint-line" %>
13
+ <h2 id="dialog-title-<%= fingerprint_id %>" tabindex="-1" data-dialog-title><%= t "decidim.fingerprint.title" %></h2>
14
+ <div class="fingerprint-modal__container">
15
+ <p id="dialog-desc-<%= fingerprint_id %>"><%= t "decidim.fingerprint.explanation" %></p>
16
+ <div>
17
+ <span class="fingerprint-modal__span"><%= t "decidim.fingerprint.value" %>:</span>
18
+ <code class="fingerprint-modal__code"><%= decidim_html_escape versioned_resource.fingerprint.value %></code>
19
+ </div>
20
+ <div>
21
+ <span class="fingerprint-modal__span"><%= t "decidim.fingerprint.source" %>:</span>
22
+ <code class="fingerprint-modal__code"><%= decidim_html_escape versioned_resource.fingerprint.source %></code>
23
+ </div>
24
+ <p><%= t("decidim.fingerprint.replicate_help", online_calculator_link: link_to(t("decidim.fingerprint.online_calculator_name"), "https://www.md5calc.com/sha256", target: "_blank", rel: "noopener")).html_safe %></p>
25
+ </div>
26
+ </div>
27
+ <% end %>
28
+ <% end %>
@@ -20,6 +20,7 @@ module Decidim
20
20
  # Returns nothing.
21
21
  def call
22
22
  return broadcast(:invalid) if form.invalid?
23
+ return broadcast(:invalid) unless current_user.is_a?(Decidim::User)
23
24
 
24
25
  create_follow!
25
26
  increment_score
@@ -32,13 +33,10 @@ module Decidim
32
33
  attr_reader :follow, :form
33
34
 
34
35
  def create_follow!
35
- @follow = Follow.find_by(
36
+ @follow = Follow.where(
36
37
  followable: form.followable,
37
38
  user: current_user
38
- ) || Follow.create!(
39
- followable: form.followable,
40
- user: current_user
41
- )
39
+ ).first_or_create!
42
40
  end
43
41
 
44
42
  def increment_score
@@ -58,7 +58,7 @@ module Decidim
58
58
  current_user.organization.admins.each do |admin|
59
59
  next unless admin.email_on_moderations
60
60
 
61
- Decidim::UserReportJob.perform_later(admin, report)
61
+ UserReportMailer.notify(admin, report).deliver_later
62
62
  end
63
63
  end
64
64
 
@@ -15,7 +15,7 @@ module Decidim
15
15
  def call
16
16
  return broadcast(:invalid) unless @form.valid?
17
17
 
18
- Decidim::User.transaction do
18
+ with_events(with_transaction: true) do
19
19
  destroy_user_account!
20
20
  destroy_user_identities
21
21
  destroy_follows
@@ -28,7 +28,7 @@ module Decidim
28
28
  destroy_user_badges
29
29
  destroy_user_likes
30
30
  destroy_user_reports
31
- destroy_participatory_space_private_user
31
+ destroy_member
32
32
  delegate_destroy_to_participatory_spaces
33
33
  end
34
34
 
@@ -101,8 +101,8 @@ module Decidim
101
101
  Decidim::Follow.where(user: current_user).find_each(&:destroy)
102
102
  end
103
103
 
104
- def destroy_participatory_space_private_user
105
- Decidim::ParticipatorySpacePrivateUser.where(user: current_user).find_each(&:destroy)
104
+ def destroy_member
105
+ Decidim::ParticipatorySpace::Member.where(user: current_user).find_each(&:destroy)
106
106
  end
107
107
 
108
108
  def delegate_destroy_to_participatory_spaces
@@ -110,5 +110,16 @@ module Decidim
110
110
  space_manifest.invoke_on_destroy_account(current_user)
111
111
  end
112
112
  end
113
+
114
+ # We use memoization in this particular email, as we want to have the data available before the actual anonymization
115
+ def event_arguments
116
+ @event_arguments ||= {
117
+ user_id: current_user.id,
118
+ user_email: current_user.email,
119
+ user_name: current_user.name,
120
+ locale: current_user.locale,
121
+ organization: current_user.organization
122
+ }
123
+ end
113
124
  end
114
125
  end
@@ -5,16 +5,16 @@ module Decidim
5
5
  private
6
6
 
7
7
  def build_attachments
8
- @documents = []
9
- @form.add_documents.compact_blank.each do |attachment|
8
+ @attachments = []
9
+ @form.add_attachments.compact_blank.each do |attachment|
10
10
  if attachment.is_a?(Hash) && attachment.has_key?(:id)
11
11
  update_attachment_title_for(attachment)
12
12
  next
13
13
  end
14
14
 
15
- @documents << Attachment.new(
15
+ @attachments << Attachment.new(
16
16
  title: title_for(attachment),
17
- attached_to: @attached_to || documents_attached_to,
17
+ attached_to: @attached_to || attachments_attached_to,
18
18
  file: signed_id_for(attachment),
19
19
  content_type: content_type_for(attachment)
20
20
  )
@@ -26,11 +26,11 @@ module Decidim
26
26
  end
27
27
 
28
28
  def attachments_invalid?
29
- @documents.each do |document|
30
- next if document.valid? || !document.errors.has_key?(:file)
29
+ @attachments.each do |attachment|
30
+ next if attachment.valid? || !attachment.errors.has_key?(:file)
31
31
 
32
- document.errors[:file].each do |error|
33
- @form.errors.add(:add_documents, error)
32
+ attachment.errors[:file].each do |error|
33
+ @form.errors.add(:add_attachments, error)
34
34
  end
35
35
 
36
36
  return true
@@ -41,36 +41,38 @@ module Decidim
41
41
 
42
42
  def create_attachments(first_weight: 0)
43
43
  weight = first_weight
44
- # Add the weights first to the old document
45
- @form.documents.each do |document|
46
- document.update!(weight:)
44
+ # Add the weights first to the old attachments
45
+ attachment_ids = keep_ids
46
+ Decidim::Attachment.where(id: attachment_ids).each do |attachment|
47
+ attachment.update!(weight:)
47
48
  weight += 1
48
49
  end
49
- @documents.map! do |document|
50
- document.weight = weight
51
- document.attached_to = documents_attached_to
52
- document.save!
50
+ @attachments.map! do |attachment|
51
+ attachment.weight = weight
52
+ attachment.attached_to = attachments_attached_to
53
+ attachment.save!
53
54
  weight += 1
54
- @form.documents << document
55
+ @form.attachments << attachment
55
56
  end
56
57
  end
57
58
 
58
- def document_cleanup!(include_all_attachments: false)
59
- documents = include_all_attachments ? documents_attached_to.attachments.with_attached_file : documents_attached_to.documents
59
+ def attachment_cleanup!(include_all_attachments: false)
60
+ attachments = include_all_attachments ? attachments_attached_to.attachments.with_attached_file : attachments_attached_to.attachments
60
61
 
61
- documents.each do |document|
62
- document.destroy! if @form.documents.map(&:id).exclude? document.id
62
+ attachments.each do |attachment|
63
+ attachment.destroy! unless keep_ids.include?(attachment.id)
63
64
  end
64
65
 
65
- documents_attached_to.reload
66
- documents_attached_to.instance_variable_set(:@documents, nil)
66
+ attachments_attached_to.reload
67
+ attachments_attached_to.instance_variable_set(:@attachments, nil)
68
+ attachments_attached_to.instance_variable_set(:@photos, nil)
67
69
  end
68
70
 
69
71
  def process_attachments?
70
- @form.add_documents.any?
72
+ @form.add_attachments.any?
71
73
  end
72
74
 
73
- def documents_attached_to
75
+ def attachments_attached_to
74
76
  return @attached_to if @attached_to.present?
75
77
  return form.current_organization if form.respond_to?(:current_organization)
76
78
 
@@ -98,5 +100,21 @@ module Decidim
98
100
  def blob(signed_id)
99
101
  ActiveStorage::Blob.find_signed(signed_id)
100
102
  end
103
+
104
+ def keep_ids
105
+ attachments_array = Array(@form.attachments)
106
+ attachments_array.map do |doc|
107
+ case doc
108
+ when Decidim::Attachment
109
+ doc.id
110
+ when Integer
111
+ doc
112
+ when String
113
+ doc.match?(/\A\d+\z/) ? doc.to_i : nil
114
+ when Hash
115
+ (doc[:id] || doc["id"]).to_i
116
+ end
117
+ end.compact
118
+ end
101
119
  end
102
120
  end
@@ -7,10 +7,10 @@ module Decidim
7
7
 
8
8
  # Public: Initializes the command.
9
9
  #
10
- # @param term: The term to search for.
11
- # @param organization: The Organization to which the results are constrained.
12
- # @param filters: (optional) A Hash of SearchableResource attributes to filter for.
13
- # @param page_params: (optional) A Hash with `page` and `per_page` options to paginate.
10
+ # @param term [String] - The term to search for.
11
+ # @param organization [Decidim::Organization] - The Organization to which the results are constrained.
12
+ # @param filters [Hash] - (optional) A Hash of SearchableResource attributes to filter for.
13
+ # @param page_params [Hash] - (optional) A Hash with `page` and `per_page` options to paginate.
14
14
  def initialize(term, organization, filters = {}, page_params = {})
15
15
  @term = term
16
16
  @organization = organization
@@ -91,7 +91,7 @@ module Decidim
91
91
  query = query.where(decidim_participatory_space: spaces)
92
92
  end
93
93
 
94
- query = query.order("datetime DESC")
94
+ query = query.order(datetime: :desc)
95
95
  query = query.global_search(I18n.transliterate(term)) if term.present?
96
96
  query
97
97
  end
@@ -15,7 +15,7 @@ module Decidim
15
15
  def ajax_user_has_no_permission
16
16
  return user_has_no_permission unless request.xhr?
17
17
 
18
- render json: { message: I18n.t("actions.unauthorized", scope: "decidim.core") }, status: :unprocessable_entity
18
+ render json: { message: I18n.t("actions.unauthorized", scope: "decidim.core") }, status: :unprocessable_content
19
19
  end
20
20
  end
21
21
  end
@@ -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
@@ -6,6 +6,7 @@ module Decidim
6
6
 
7
7
  included do
8
8
  include Decidim::NeedsOrganization
9
+
9
10
  skip_before_action :verify_organization
10
11
 
11
12
  before_action :check_organization!,
@@ -18,14 +19,14 @@ module Decidim
18
19
  # We skip the validation if we are in system panel. `current_admin` refers to the main system admin user.
19
20
  return if current_admin.present?
20
21
 
21
- head :unprocessable_entity unless [
22
+ head :unprocessable_content unless [
22
23
  maximum_allowed_size.try(:to_i) >= blob_args[:byte_size].try(:to_i),
23
24
  content_types.any? { |pattern| pattern.match?(blob_args[:content_type]) },
24
25
  content_types.any? { |pattern| pattern.match?(MiniMime.lookup_by_extension(extension)&.content_type) },
25
26
  allowed_extensions.any? { |pattern| pattern.match?(extension) }
26
27
  ].all?
27
28
  rescue NoMethodError
28
- head :unprocessable_entity
29
+ head :unprocessable_content
29
30
  end
30
31
 
31
32
  def extension
@@ -78,7 +78,7 @@ module Decidim
78
78
  end
79
79
  paths_list.prepend(
80
80
  pending_authorizations_path,
81
- decidim.page_path(terms_of_service_page)
81
+ decidim.page_path(terms_of_service_page, locale: current_locale)
82
82
  )
83
83
 
84
84
  paths_list.find { |el| /\A#{URI.parse(el).path}/.match?(request.path) }
@@ -38,12 +38,21 @@ module Decidim
38
38
  default_unauthorized_paths + Decidim::StaticPage.where(
39
39
  organization: current_organization,
40
40
  allow_public_access: true
41
- ).pluck(Arel.sql("CONCAT('/pages/', slug)"))
41
+ ).pluck(
42
+ Arel::Nodes::Concat.new(
43
+ Arel::Nodes.build_quoted("/#{current_locale}/pages/"),
44
+ Arel::Table.new(Decidim::StaticPage.table_name)[:slug]
45
+ )
46
+ )
42
47
  end
43
48
 
44
49
  def default_unauthorized_paths
45
50
  # /locale is for changing the locale and /manifest.webmanifest to request PWA manifest
46
51
  %w(/locale /manifest.webmanifest)
47
52
  end
53
+
54
+ def current_locale
55
+ @current_locale ||= I18n.locale.to_s
56
+ end
48
57
  end
49
58
  end
@@ -71,6 +71,10 @@ module Decidim
71
71
  # Prevent redirect on non-HTML responses, because we want redirect AFTER impersonation.js inits a reload.
72
72
  return if request && request.negotiate_mime([Mime[:html]]).blank?
73
73
  return unless can_impersonate_users?
74
+
75
+ # Keep the expiration check in sync with the active impersonation log so
76
+ # the redirect happens in the same request when the session just expired.
77
+ impersonation_log&.ensure_not_expired!
74
78
  return unless expired_log
75
79
 
76
80
  expired_log.update!(ended_at: Time.current)
@@ -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
@@ -21,6 +21,7 @@ module Decidim
21
21
  else
22
22
  locale = default_locale
23
23
  end
24
+
24
25
  I18n.with_locale(locale, &)
25
26
  end
26
27
 
@@ -29,7 +30,7 @@ module Decidim
29
30
  #
30
31
  # Returns a Hash.
31
32
  def default_url_options
32
- return {} if current_locale == default_locale.to_s
33
+ return {} if locale_in_script_name?
33
34
 
34
35
  { locale: current_locale }
35
36
  end
@@ -99,6 +100,55 @@ module Decidim
99
100
  end
100
101
  lang == "*" ? nil : lang
101
102
  end
103
+
104
+ def canonical_url(desired_url, target_locale = default_locale)
105
+ uri = URI(desired_url)
106
+ desired_locale = available_locales.include?(target_locale) ? target_locale : default_locale
107
+
108
+ path_segments = uri.path.split("/").compact_blank
109
+ locale_segment = path_segments.first
110
+
111
+ query = uri.query.to_s.gsub(/locale=[a-zA-Z-]{2,5}/, "")
112
+
113
+ if available_locales.include?(locale_segment)
114
+ path_segments[0] = desired_locale
115
+
116
+ uri.path = "/#{path_segments.join("/")}"
117
+
118
+ if query.present?
119
+ params = URI.decode_www_form(query)
120
+ uri.query = URI.encode_www_form(params)
121
+ else
122
+ uri.query = nil
123
+ end
124
+ elsif uri.host.blank? || uri.host == request.host
125
+ uri.path = if uri.path == "/"
126
+ "/#{desired_locale}"
127
+ else
128
+ "/#{desired_locale}#{uri.path}"
129
+ end
130
+
131
+ if query.present?
132
+ params = URI.decode_www_form(query)
133
+ uri.query = URI.encode_www_form(params)
134
+ else
135
+ uri.query = nil
136
+ end
137
+ else
138
+ params = URI.decode_www_form(query) << ["locale", desired_locale]
139
+ uri.query = URI.encode_www_form(params)
140
+ end
141
+
142
+ uri.to_s
143
+ end
144
+
145
+ def locale_in_script_name?
146
+ script_name = request&.script_name.to_s
147
+ return false if script_name.blank?
148
+
149
+ locale_segment = script_name.split("/").compact_blank.first
150
+ available_locales.include?(locale_segment)
151
+ end
102
152
  # rubocop: enable Metrics/CyclomaticComplexity
103
153
  # rubocop: enable Metrics/PerceivedComplexity
104
154
  end
@@ -43,7 +43,7 @@ module Decidim
43
43
  end
44
44
 
45
45
  def tos_path
46
- decidim.page_path terms_of_service_page
46
+ decidim.page_path terms_of_service_page, locale: current_locale
47
47
  end
48
48
 
49
49
  def redirect_to_tos
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ module ParticipatorySpace
7
+ module HasMembersPage
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ helper_method :collection
12
+
13
+ private
14
+
15
+ def can_visit_index?
16
+ current_user_can_visit_space? && current_participatory_space.members_public_page?
17
+ end
18
+
19
+ def members
20
+ @members ||= current_participatory_space.members.published
21
+ end
22
+
23
+ alias_method :collection, :members
24
+ end
25
+ end
26
+ end
27
+ end
@@ -36,8 +36,6 @@ module Decidim
36
36
  # title of the space (mandatory).
37
37
  # * url - The url of the resource (optional).
38
38
  # * active - Whether the item is active (optional).
39
- # * dropdown_cell - When this value is present is used to generate a dropdown
40
- # associated to the item (optional).
41
39
  # * resource - The resource of the item. This value is passed to the
42
40
  # dropdown cell, so it is mandatory if the dropdown cell is
43
41
  # present.
@@ -48,7 +46,6 @@ module Decidim
48
46
  label: current_participatory_space.title,
49
47
  url: Decidim::ResourceLocatorPresenter.new(current_participatory_space).path,
50
48
  active: true,
51
- dropdown_cell: current_participatory_space_manifest.breadcrumb_cell,
52
49
  resource: current_participatory_space
53
50
  }
54
51
  end
@@ -79,8 +76,7 @@ module Decidim
79
76
 
80
77
  # Method for current user can visit the space (assembly or process)
81
78
  def current_user_can_visit_space?
82
- return true unless current_participatory_space.try(:private_space?) &&
83
- !current_participatory_space.try(:is_transparent?)
79
+ return true unless current_participatory_space.respond_to?(:restricted?) && current_participatory_space.restricted?
84
80
  return false unless current_user
85
81
  return true if current_user.admin?
86
82
  return true if user_has_any_role?(current_user, current_participatory_space, broad_check: true)
@@ -31,7 +31,7 @@ module Decidim
31
31
  on(:invalid) do |password|
32
32
  fetch_entered_password(password)
33
33
  flash[:alert] = t("account.update.error", scope: "decidim")
34
- render action: :show, status: :unprocessable_entity
34
+ render action: :show, status: :unprocessable_content
35
35
  end
36
36
  end
37
37
  end
@@ -5,6 +5,7 @@ module Decidim
5
5
  include Decidim::ApplicationHelper
6
6
  include FormFactory
7
7
  include HasSpecificBreadcrumb
8
+
8
9
  helper Decidim::ResourceReferenceHelper
9
10
 
10
11
  before_action :authenticate_user!
@@ -38,7 +39,7 @@ module Decidim
38
39
 
39
40
  on(:invalid) do
40
41
  flash.now[:alert] = t("created.error", scope: "decidim.amendments")
41
- render :new, status: :unprocessable_entity
42
+ render :new, status: :unprocessable_content
42
43
  end
43
44
  end
44
45
  end
@@ -62,7 +63,7 @@ module Decidim
62
63
 
63
64
  on(:invalid) do
64
65
  flash.now[:alert] = t("error", scope: "decidim.amendments.update_draft")
65
- render :edit_draft, status: :unprocessable_entity
66
+ render :edit_draft, status: :unprocessable_content
66
67
  end
67
68
  end
68
69
  end
@@ -100,7 +101,7 @@ module Decidim
100
101
 
101
102
  on(:invalid) do
102
103
  flash.now[:alert] = t("error", scope: "decidim.amendments.publish_draft")
103
- render :edit_draft, status: :unprocessable_entity
104
+ render :edit_draft, status: :unprocessable_content
104
105
  end
105
106
  end
106
107
  end
@@ -160,7 +161,7 @@ module Decidim
160
161
 
161
162
  on(:invalid) do
162
163
  flash.now[:alert] = t("accepted.error", scope: "decidim.amendments")
163
- render :review, status: :unprocessable_entity
164
+ render :review, status: :unprocessable_content
164
165
  end
165
166
  end
166
167
  end
@@ -10,6 +10,7 @@ module Decidim
10
10
  include Decidim::NeedsPermission
11
11
 
12
12
  include ParticipatorySpaceContext
13
+
13
14
  before_action :authorize_participatory_space
14
15
 
15
16
  helper Decidim::FiltersHelper
@@ -35,7 +36,7 @@ module Decidim
35
36
 
36
37
  before_action :redirect_unless_feature_private
37
38
 
38
- before_action :set_component_breadcrumb_item
39
+ before_action :set_breadcrumb_items
39
40
 
40
41
  def current_participatory_space
41
42
  request.env["decidim.current_participatory_space"]
@@ -66,14 +67,30 @@ module Decidim
66
67
  raise ActionController::RoutingError, "Not Found" unless current_user_can_visit_space?
67
68
  end
68
69
 
69
- def set_component_breadcrumb_item
70
- context_breadcrumb_items << {
70
+ def set_breadcrumb_items
71
+ context_breadcrumb_items << add_current_component
72
+ context_breadcrumb_items << add_parent_breadcrumb_item
73
+ context_breadcrumb_items << add_breadcrumb_item
74
+ end
75
+
76
+ private
77
+
78
+ def add_current_component
79
+ {
71
80
  label: current_component.name,
72
81
  url: Decidim::EngineRouter.main_proxy(current_component).root_path,
73
82
  active: false,
74
83
  resource: current_component
75
84
  }
76
85
  end
86
+
87
+ def add_parent_breadcrumb_item
88
+ {}
89
+ end
90
+
91
+ def add_breadcrumb_item
92
+ {}
93
+ end
77
94
  end
78
95
  end
79
96
  end