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
@@ -34,7 +34,7 @@ module Decidim
34
34
 
35
35
  on(:invalid) do
36
36
  set_flash_message :notice, :success, kind: @form.provider.capitalize
37
- render :new, status: :unprocessable_entity
37
+ render :new, status: :unprocessable_content
38
38
  end
39
39
 
40
40
  on(:add_tos_errors) do
@@ -36,7 +36,7 @@ module Decidim
36
36
  on(:invalid) do
37
37
  flash.now[:alert] = t("passwords.update.error", scope: "decidim")
38
38
  resource.errors.errors.concat(@form.errors.errors)
39
- render action: "edit", status: :unprocessable_entity
39
+ render action: "edit", status: :unprocessable_content
40
40
  end
41
41
  end
42
42
  end
@@ -40,7 +40,7 @@ module Decidim
40
40
 
41
41
  on(:invalid) do
42
42
  flash.now[:alert] = t("error", scope: "decidim.devise.registrations.create")
43
- render :new, status: :unprocessable_entity
43
+ render :new, status: :unprocessable_content
44
44
  end
45
45
  end
46
46
  end
@@ -48,7 +48,7 @@ module Decidim
48
48
 
49
49
  def redirect_to_referer_or_path
50
50
  set_flash_message(:alert, "csrf_token", scope: "devise.failure")
51
- redirect_back(fallback_location: root_path) && return
51
+ redirect_back_or_to(root_path) && return
52
52
  end
53
53
 
54
54
  def check_sign_in_enabled
@@ -37,7 +37,7 @@ module Decidim
37
37
  DownloadYourDataExportJob.perform_later(current_user)
38
38
 
39
39
  flash[:notice] = t("decidim.account.download_your_data_export.notice")
40
- redirect_back(fallback_location: download_your_data_path)
40
+ redirect_back_or_to(download_your_data_path)
41
41
  end
42
42
 
43
43
  def download_file
@@ -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
@@ -16,7 +16,7 @@ module Decidim
16
16
  end
17
17
 
18
18
  on(:invalid) do |_message|
19
- render json: { message: I18n.t("error", scope: "decidim.editor_images.create") }, status: :unprocessable_entity
19
+ render json: { message: I18n.t("error", scope: "decidim.editor_images.create") }, status: :unprocessable_content
20
20
  end
21
21
  end
22
22
  end
@@ -3,6 +3,7 @@
3
3
  module Decidim
4
4
  class FollowsController < Decidim::ApplicationController
5
5
  include FormFactory
6
+
6
7
  before_action :authenticate_user!
7
8
  helper_method :resource, :button_cell, :button_cell_mobile
8
9
 
@@ -16,7 +17,7 @@ module Decidim
16
17
  end
17
18
 
18
19
  on(:invalid) do
19
- render json: { error: I18n.t("follows.destroy.error", scope: "decidim") }, status: :unprocessable_entity
20
+ render json: { error: I18n.t("follows.destroy.error", scope: "decidim") }, status: :unprocessable_content
20
21
  end
21
22
  end
22
23
  end
@@ -31,7 +32,7 @@ module Decidim
31
32
  end
32
33
 
33
34
  on(:invalid) do
34
- render json: { error: I18n.t("follows.create.error", scope: "decidim") }, status: :unprocessable_entity
35
+ render json: { error: I18n.t("follows.create.error", scope: "decidim") }, status: :unprocessable_content
35
36
  end
36
37
  end
37
38
  end
@@ -43,7 +44,7 @@ module Decidim
43
44
  end
44
45
 
45
46
  def button_options
46
- params.require(:follow).permit(:button_classes).to_h.symbolize_keys
47
+ params.expect(follow: [:button_classes]).to_h.symbolize_keys
47
48
  end
48
49
 
49
50
  def button_cell_mobile
@@ -8,7 +8,7 @@ module Decidim
8
8
  enforce_permission_to :locate, :geolocation
9
9
 
10
10
  unless Decidim::Map.configured?
11
- return render(json: { message: I18n.t("not_configured", scope: "decidim.application.geocoding"), found: false }, status: :unprocessable_entity)
11
+ return render(json: { message: I18n.t("not_configured", scope: "decidim.application.geocoding"), found: false }, status: :unprocessable_content)
12
12
  end
13
13
 
14
14
  geocoder = Decidim::Map.utility(:geocoding, organization: current_organization)
@@ -5,6 +5,7 @@ module Decidim
5
5
  class LikesController < Decidim::Components::BaseController
6
6
  # we need to +include+ to be able to call :like_button from the view
7
7
  include Decidim::LikeableHelper
8
+
8
9
  helper_method :like_button
9
10
  # we need to declare with +helper+ to be able to call :render_like_identity from the views
10
11
  helper Decidim::LikeableHelper
@@ -22,7 +23,7 @@ module Decidim
22
23
  end
23
24
 
24
25
  on(:invalid) do
25
- render json: { error: I18n.t("resource_likes.create.error", scope: "decidim") }, status: :unprocessable_entity
26
+ render json: { error: I18n.t("resource_likes.create.error", scope: "decidim") }, status: :unprocessable_content
26
27
  end
27
28
  end
28
29
  end
@@ -7,20 +7,12 @@ module Decidim
7
7
 
8
8
  def create
9
9
  enforce_permission_to :create, :locales
10
- current_user.update!(locale: params["locale"]) if current_user && params["locale"] && available_locales.include?(params["locale"])
11
-
12
- redirect_to referer_with_new_locale
13
- end
14
10
 
15
- private
11
+ desired_locale = params["locale"] if params["locale"] && available_locales.include?(params["locale"])
16
12
 
17
- def referer_with_new_locale
18
- uri = URI(request.referer || "/")
19
- query = uri.query.to_s.gsub(/locale=[a-zA-Z-]{2,5}/, "")
20
- params = URI.decode_www_form(query) << ["locale", current_locale]
21
- uri.query = URI.encode_www_form(params)
13
+ current_user.update!(locale: params["locale"]) if current_user && params["locale"] && available_locales.include?(params["locale"])
22
14
 
23
- uri.to_s
15
+ redirect_to canonical_url(request.referer || "/", desired_locale || default_locale)
24
16
  end
25
17
  end
26
18
  end
@@ -30,7 +30,7 @@ module Decidim
30
30
  conversation = conversation_between(current_user, @form.recipient)
31
31
  end
32
32
 
33
- return redirect_back(fallback_location: profile_path(current_user.nickname)) if @form.recipient.empty?
33
+ return redirect_back_or_to(profile_path(current_user.nickname)) if @form.recipient.empty?
34
34
 
35
35
  return redirect_to conversation_path(conversation) if conversation
36
36
 
@@ -53,7 +53,7 @@ module Decidim
53
53
  render action: :error, locals: {
54
54
  error: I18n.t("messaging.conversations.create.error", scope: "decidim"),
55
55
  messages:
56
- }, status: :unprocessable_entity
56
+ }, status: :unprocessable_content
57
57
  end
58
58
  end
59
59
  end
@@ -89,7 +89,7 @@ module Decidim
89
89
  render action: :error, locals: {
90
90
  error: I18n.t("messaging.conversations.update.error", scope: "decidim"),
91
91
  messages:
92
- }, status: :unprocessable_entity
92
+ }, status: :unprocessable_content
93
93
  end
94
94
  end
95
95
  end
@@ -34,7 +34,7 @@ module Decidim
34
34
 
35
35
  on(:invalid) do
36
36
  flash.now[:alert] = t("newsletters.unsubscribe.error", scope: "decidim")
37
- render action: :unsubscribe, status: :unprocessable_entity
37
+ render action: :unsubscribe, status: :unprocessable_content
38
38
  end
39
39
  end
40
40
  else
@@ -22,7 +22,7 @@ module Decidim
22
22
 
23
23
  on(:invalid) do
24
24
  flash.now[:alert] = t("notifications_settings.update.error", scope: "decidim")
25
- render action: :show, status: :unprocessable_entity
25
+ render action: :show, status: :unprocessable_content
26
26
  end
27
27
  end
28
28
  end
@@ -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
@@ -15,7 +15,7 @@ module Decidim
15
15
  else
16
16
  schedule_open_data_generation(resource)
17
17
  flash[:alert] = t("decidim.open_data.not_available_yet")
18
- redirect_back fallback_location: open_data_path
18
+ redirect_back_or_to(open_data_path)
19
19
  end
20
20
  end
21
21
 
@@ -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
@@ -18,13 +18,13 @@ module Decidim
18
18
  if @form.block?
19
19
  redirect_to decidim_admin.new_user_block_path(user_id: reportable.id, hide: form.hide?)
20
20
  else
21
- redirect_back fallback_location: root_path
21
+ redirect_back_or_to(root_path)
22
22
  end
23
23
  end
24
24
 
25
25
  on(:invalid) do
26
26
  flash[:alert] = I18n.t("decidim.reports.create.error")
27
- redirect_back fallback_location: root_path
27
+ redirect_back_or_to(root_path)
28
28
  end
29
29
  end
30
30
  end
@@ -26,7 +26,7 @@ module Decidim
26
26
 
27
27
  on(:invalid) do
28
28
  flash[:alert] = I18n.t("decidim.reports.create.error")
29
- redirect_back fallback_location: root_path
29
+ redirect_back_or_to(root_path)
30
30
  end
31
31
  end
32
32
  end
@@ -56,8 +56,7 @@ module Decidim
56
56
 
57
57
  def resource_types
58
58
  @resource_types = begin
59
- array = %w(Decidim::Proposals::CollaborativeDraft
60
- Decidim::Comments::Comment
59
+ array = %w(Decidim::Comments::Comment
61
60
  Decidim::Debates::Debate
62
61
  Decidim::Initiative
63
62
  Decidim::Meetings::Meeting
@@ -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
 
@@ -45,7 +45,7 @@ module Decidim
45
45
  template
46
46
  .gsub("{{name}}", user.presenter.name)
47
47
  .gsub("{{organization}}", organization_name(organization))
48
- .gsub("{{help_url}}", url_helpers.pages_url(host: organization.host))
48
+ .gsub("{{help_url}}", url_helpers.pages_url(host: organization.host, locale: I18n.locale))
49
49
  .gsub("{{badges_url}}", url_helpers.gamification_badges_url(host: organization.host))
50
50
  .html_safe
51
51
  end
@@ -54,7 +54,7 @@ module Decidim
54
54
 
55
55
  def form_object_class
56
56
  @form_object_class ||= begin
57
- form_class.constantize if form_class.present?
57
+ form_class.presence&.constantize
58
58
  rescue NameError
59
59
  nil
60
60
  end
@@ -57,6 +57,7 @@ module Decidim
57
57
  # @param closable [Boolean] - Whether the close icon is added.
58
58
  #
59
59
  # @return [String] the HTML with the alert box
60
+ # @param [Hash{Symbol => Object}] opts
60
61
  def alert_box(value, alert_class, closable, opts = {})
61
62
  options = {
62
63
  class: "flash #{alert_class}",
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # Overrides {ActiveLinkTo#is_active_link?} to handle locale-prefixed URLs.
5
+ #
6
+ # Decidim adds the locale as a URL path segment (e.g. `/en/processes`), so
7
+ # the URL passed to the helper and `request.original_fullpath` both carry a
8
+ # locale prefix. This module normalizes the URL argument to always carry the
9
+ # current locale prefix before delegating to the gem, so active-state
10
+ # detection works correctly regardless of whether the caller already included
11
+ # the locale in the URL or not.
12
+ #
13
+ # When the locale is part of the Rails script name rather than the path
14
+ # (i.e. the application is mounted at a locale-prefixed mount point), no
15
+ # normalization is performed and the original gem behaviour is preserved.
16
+ #
17
+ # Include this module *after* {ActiveLinkTo} so that this override takes
18
+ # precedence.
19
+ module ActiveLinkToHelper
20
+ # Overrides {ActiveLinkTo#is_active_link?} to normalise locale-prefixed
21
+ # URLs before comparison.
22
+ #
23
+ # @param url [String] the URL to check
24
+ # @param condition [Boolean, Symbol, Regexp, Array, Hash, nil] the active
25
+ # condition, same as accepted by the `active_link_to` gem
26
+ #
27
+ # @return [Boolean] whether the link is considered active
28
+ def is_active_link?(url, condition = nil) # rubocop:disable Naming/PredicatePrefix
29
+ super(locale_prefixed_url(url), condition)
30
+ end
31
+
32
+ private
33
+
34
+ # Normalizes a URL so its path carries the current locale prefix, but only
35
+ # when the current request path itself has a locale prefix. This preserves
36
+ # correct behaviour in engines mounted without a locale segment (e.g. the
37
+ # admin engine at +/admin+) where neither the request path nor the
38
+ # generated paths contain a locale segment.
39
+ #
40
+ # When normalization does apply, any existing locale prefix is stripped
41
+ # first to avoid double-prefixing.
42
+ #
43
+ # Returns the URL unchanged for non-String values, when no locale segments
44
+ # are configured, when the locale lives in the script name, or when the
45
+ # current request path has no locale prefix.
46
+ #
47
+ # @param url [String] the URL to normalize
48
+ #
49
+ # @return [String] the normalized URL
50
+ def locale_prefixed_url(url)
51
+ locale_pattern = locale_prefix_pattern
52
+ return url unless normalizable_url?(url, locale_pattern)
53
+
54
+ current = try(:current_locale) || I18n.locale.to_s
55
+ return url if current.blank?
56
+
57
+ rewrite_url_with_locale(url, locale_pattern, current)
58
+ end
59
+
60
+ # Determines whether a URL string should be normalized with a locale prefix.
61
+ #
62
+ # Returns +false+ when any of the following conditions are true:
63
+ # - +url+ is not a +String+
64
+ # - the locale lives in the script name (via +locale_in_script_name?+)
65
+ # - +locale_pattern+ is +nil+ (no locales are configured)
66
+ # - the current request path does not begin with a locale segment
67
+ #
68
+ # @param url [String] the URL candidate for normalization
69
+ # @param locale_pattern [Regexp, nil] the pattern built by {#locale_prefix_pattern},
70
+ # or +nil+ when no locales are available
71
+ #
72
+ # @return [Boolean] +true+ when the URL should be rewritten with a locale prefix
73
+ def normalizable_url?(url, locale_pattern)
74
+ return false unless url.is_a?(String)
75
+ return false if try(:locale_in_script_name?)
76
+ return false if locale_pattern.nil?
77
+
78
+ current_path = try(:request)&.original_fullpath.to_s
79
+ current_path.match?(locale_pattern)
80
+ end
81
+
82
+ # Builds a +Regexp+ that matches any available locale code at the start of a
83
+ # URL path segment (e.g. +/en+, +/zh-TW+).
84
+ #
85
+ # Locales are sorted longest-first so that longer codes such as +zh-TW+ are
86
+ # tried before shorter ones like +zh+, preventing partial matches.
87
+ #
88
+ # @return [Regexp, nil] the locale-matching pattern, or +nil+ when no locales
89
+ # are configured
90
+ def locale_prefix_pattern
91
+ locales = available_locale_segments
92
+ return if locales.empty?
93
+
94
+ %r{\A/(#{Regexp.union(locales)})(?=/|\z)}
95
+ end
96
+
97
+ # Rewrites the path component of +url+ so it begins with the +current+ locale
98
+ # prefix. Any preexisting locale prefix is stripped first to prevent
99
+ # double-prefixing (e.g. +/en/en/foo+ would never be produced).
100
+ #
101
+ # Returns +url+ unchanged when the URI cannot be parsed.
102
+ #
103
+ # @param url [String] the URL whose path should be rewritten
104
+ # @param locale_pattern [Regexp] the pattern used to strip an existing locale prefix
105
+ # @param current [String] the locale code to prepend (e.g. +"en"+ or +"zh-TW"+)
106
+ #
107
+ # @return [String] the URL with its path rewritten to carry +current+ as the
108
+ # leading segment, or the original +url+ if parsing fails
109
+ def rewrite_url_with_locale(url, locale_pattern, current)
110
+ uri = Addressable::URI.parse(url)
111
+ return url if uri.nil?
112
+
113
+ stripped_path = uri.path.to_s.sub(locale_pattern, "")
114
+ stripped_path = "/" if stripped_path.empty?
115
+
116
+ uri.path = "/#{current}#{stripped_path}"
117
+ uri.to_s
118
+ rescue Addressable::URI::InvalidURIError
119
+ url
120
+ end
121
+
122
+ # Returns the list of available locale codes sorted longest-first.
123
+ #
124
+ # Sorting longest-first ensures that longer locale codes (e.g. +zh-TW+) are
125
+ # matched before shorter ones (e.g. +zh+) when building a {#locale_prefix_pattern}.
126
+ #
127
+ # Falls back to {Decidim.available_locales} when +available_locales+ is not
128
+ # defined on the including context (e.g. outside a controller).
129
+ #
130
+ # @return [Array<String>] locale code strings sorted by descending length
131
+ def available_locale_segments
132
+ locales = try(:available_locales) || Decidim.available_locales
133
+ locales.map(&:to_s).sort_by(&:length).reverse
134
+ end
135
+ end
136
+ end
@@ -17,9 +17,9 @@ module Decidim
17
17
  end
18
18
 
19
19
  # Checks if the user can participate in a participatory space
20
- # based on its settings related with Decidim::HasPrivateUsers.
21
- def can_participate_in_private_space?
22
- return true unless current_participatory_space.class.included_modules.include?(HasPrivateUsers)
20
+ # based on its settings related with Decidim::ParticipatorySpace::HasMembers.
21
+ def can_participate_in_restricted_space?
22
+ return true unless current_participatory_space.class.included_modules.include?(Decidim::ParticipatorySpace::HasMembers)
23
23
 
24
24
  current_participatory_space.can_participate?(current_user)
25
25
  end
@@ -18,12 +18,12 @@ module Decidim
18
18
  label_options: {
19
19
  "data-children-checkbox": parent_id,
20
20
  value:,
21
- for: "#{options[:namespace]}_#{options[:id]}"
21
+ for: options[:id]
22
22
  }
23
23
  }
24
24
  options.merge!(checkbox_options)
25
25
  # as taxonomies work with a nested array of values, we need to manually check if the value is checked
26
- matches = options[:id]&.match(/^with_any_taxonomies_([0-9]+)__taxonomy-([0-9_]+)/)
26
+ matches = options[:id]&.match(/^with_any_taxonomies_taxonomy-([0-9]+)_([0-9_]+)/)
27
27
  if matches.present? && object.respond_to?(:with_any_taxonomies) && object.with_any_taxonomies&.dig(matches[1]).is_a?(Array)
28
28
  options[:checked] = object.with_any_taxonomies[matches[1]].include?(value.to_s)
29
29
  end
@@ -8,8 +8,11 @@ module Decidim
8
8
  # component - the Component we want to find the root path for.
9
9
  #
10
10
  # Returns a relative url.
11
- def main_component_path(component)
11
+ def main_component_path(component, desired_params = {})
12
12
  current_params = try(:params) || {}
13
+ current_params = current_params.merge(locale: I18n.locale)
14
+ .merge(desired_params)
15
+
13
16
  EngineRouter.main_proxy(component).root_path(locale: current_params[:locale])
14
17
  end
15
18
 
@@ -18,8 +21,11 @@ module Decidim
18
21
  # component - the Component we want to find the root path for.
19
22
  #
20
23
  # Returns an absolute url.
21
- def main_component_url(component)
24
+ def main_component_url(component, desired_params = {})
22
25
  current_params = try(:params) || {}
26
+ current_params = current_params.merge(locale: I18n.locale)
27
+ .merge(desired_params)
28
+
23
29
  EngineRouter.main_proxy(component).root_url(locale: current_params[:locale])
24
30
  end
25
31
 
@@ -29,8 +35,7 @@ module Decidim
29
35
  #
30
36
  # Returns a relative url.
31
37
  def manage_component_path(component)
32
- current_params = try(:params) || {}
33
- EngineRouter.admin_proxy(component).root_path(locale: current_params[:locale])
38
+ EngineRouter.admin_proxy(component).root_path
34
39
  end
35
40
 
36
41
  # Returns whether the component can be managed or not by checking if it has
@@ -44,8 +44,6 @@ module Decidim
44
44
  I18n.t("decidim/meetings/meeting.other", scope: "activerecord.models")
45
45
  when "debates"
46
46
  I18n.t("decidim/debates/debate.other", scope: "activerecord.models")
47
- when "sortitions"
48
- I18n.t("decidim/sortitions/sortition.other", scope: "activerecord.models")
49
47
  when "surveys"
50
48
  I18n.t("decidim/surveys/survey.other", scope: "activerecord.models")
51
49
  when "projects"
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # Helper that provides methods to render order selector and links
5
+ module MailerHelper
6
+ # Transforms relative image URLs in HTML content to absolute URLs using the provided host.
7
+ # This is used in emails (newsletters and notifications) to ensure images display correctly
8
+ # in email clients.
9
+ #
10
+ # @param content [String] - HTML content with img tags
11
+ # @param host [String] - the Decidim::Organization host to use for the root URL
12
+ #
13
+ # @return [String] - the content with transformed image URLs
14
+ def decidim_transform_image_urls(content, host)
15
+ return content if host.blank? || content.blank?
16
+
17
+ root_url = if Decidim.storage_cdn_host.present?
18
+ Decidim.storage_cdn_host.chomp("/")
19
+ else
20
+ Decidim::EngineRouter.new("decidim", {}).root_url(host:).chomp("/")
21
+ end
22
+
23
+ content.gsub(/src\s*=\s*(['"])([^'"]*)\1/) do
24
+ quote = Regexp.last_match(1)
25
+ src_value = Regexp.last_match(2)
26
+
27
+ if src_value.blank? || src_value.start_with?("http://", "https://", "data:", "//", "cid:")
28
+ %(src=#{quote}#{src_value}#{quote})
29
+ else
30
+ normalized_src = src_value.start_with?("/") ? src_value : "/#{src_value}"
31
+ %(src=#{quote}#{root_url}#{normalized_src}#{quote})
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -55,9 +55,8 @@ module Decidim
55
55
  @footer_menu ||= ::Decidim::FooterMenuPresenter.new(
56
56
  :menu,
57
57
  self,
58
- element_class: "font-semibold underline",
59
58
  active_class: "is-active",
60
- container_options: { class: "space-y-4 break-inside-avoid", role: :menu },
59
+ role: false,
61
60
  label: t("layouts.decidim.footer.decidim_title")
62
61
  )
63
62
  end
@@ -69,11 +68,11 @@ module Decidim
69
68
  # The queries already include the order by weight
70
69
  Decidim::ParticipatoryProcesses::OrganizationParticipatoryProcesses.new(current_organization) |
71
70
  Decidim::ParticipatoryProcesses::PromotedParticipatoryProcesses.new
72
- ).select(&:published?).map { |process| remove_private_space_if_not_private_user(process) }&.compact&.first
71
+ ).select(&:published?).map { |process| remove_restricted_space_if_not_member(process) }&.compact&.first
73
72
  end
74
73
 
75
- def remove_private_space_if_not_private_user(process)
76
- return nil if process.private_space == true && !process.can_participate?(current_user)
74
+ def remove_restricted_space_if_not_member(process)
75
+ return nil if process.restricted? && !process.can_participate?(current_user)
77
76
 
78
77
  process
79
78
  end
@@ -8,8 +8,6 @@ module Decidim
8
8
  # the other methods to see how they work.
9
9
  #
10
10
  # @param [Hash] tags - A Hash containing the meta tag name as keys and its content as values.
11
- # @param [Object, nil] resource - The resource object that may contain the image.
12
- #
13
11
  # @return [nil]
14
12
  def add_decidim_meta_tags(tags)
15
13
  add_decidim_page_title(tags[:title])