decidim-core 0.31.7 → 0.32.0.rc1

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 (488) 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 +4 -0
  6. data/app/cells/decidim/card_metadata_cell.rb +1 -1
  7. data/app/cells/decidim/comments_button_cell.rb +1 -9
  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 +2 -2
  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_participatory_spaces_cell.rb +1 -1
  15. data/app/cells/decidim/content_blocks/how_to_participate/show.erb +1 -1
  16. data/app/cells/decidim/content_blocks/html_cell.rb +1 -1
  17. data/app/cells/decidim/content_blocks/participatory_space_announcement_cell.rb +1 -3
  18. data/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb +1 -5
  19. data/app/cells/decidim/content_blocks/participatory_space_hero_settings_form/show.erb +1 -1
  20. data/app/cells/decidim/content_blocks/static_page/section_cell.rb +1 -1
  21. data/app/cells/decidim/content_blocks/static_page/section_settings_form/show.erb +1 -3
  22. data/app/cells/decidim/content_blocks/static_page/summary_cell.rb +1 -1
  23. data/app/cells/decidim/content_blocks/static_page/summary_settings_form/show.erb +1 -3
  24. data/app/cells/decidim/content_blocks/static_page/two_pane_section_cell.rb +2 -2
  25. data/app/cells/decidim/content_blocks/static_page/two_pane_section_settings_form/show.erb +2 -4
  26. data/app/cells/decidim/data_consent/category.erb +38 -25
  27. data/app/cells/decidim/footer_topics/show.erb +8 -5
  28. data/app/cells/decidim/{participatory_space_private_user_cell.rb → member_cell.rb} +1 -1
  29. data/app/cells/decidim/onboarding_action_message_cell.rb +1 -0
  30. data/app/cells/decidim/profile/details.erb +1 -1
  31. data/app/cells/decidim/profile_cell.rb +1 -0
  32. data/app/cells/decidim/profile_member_of/show.erb +13 -0
  33. data/app/cells/decidim/profile_member_of_cell.rb +35 -0
  34. data/app/cells/decidim/resource_types_filter/show.erb +2 -2
  35. data/app/cells/decidim/share_widget/qr_code_modal.erb +1 -1
  36. data/app/cells/decidim/tags_cell.rb +1 -1
  37. data/app/cells/decidim/upload_modal_cell.rb +0 -5
  38. data/app/cells/decidim/versions_list/show.erb +25 -0
  39. data/app/commands/decidim/create_follow.rb +3 -5
  40. data/app/commands/decidim/create_user_report.rb +1 -1
  41. data/app/commands/decidim/destroy_account.rb +4 -15
  42. data/app/commands/decidim/gallery_methods.rb +107 -0
  43. data/app/commands/decidim/multiple_attachments_methods.rb +27 -28
  44. data/app/commands/decidim/search.rb +5 -5
  45. data/app/controllers/concerns/decidim/ajax_permission_handler.rb +1 -1
  46. data/app/controllers/concerns/decidim/devise_controllers.rb +0 -10
  47. data/app/controllers/concerns/decidim/direct_upload.rb +3 -2
  48. data/app/controllers/concerns/decidim/ephemeral_session_checker.rb +1 -1
  49. data/app/controllers/concerns/decidim/force_authentication.rb +10 -1
  50. data/app/controllers/concerns/decidim/impersonate_users.rb +4 -0
  51. data/app/controllers/concerns/decidim/locale_switcher.rb +52 -2
  52. data/app/controllers/concerns/decidim/needs_tos_accepted.rb +1 -1
  53. data/app/controllers/concerns/decidim/participatory_space/has_members_page.rb +27 -0
  54. data/app/controllers/concerns/decidim/participatory_space_context.rb +1 -5
  55. data/app/controllers/decidim/account_controller.rb +1 -1
  56. data/app/controllers/decidim/amendments_controller.rb +5 -4
  57. data/app/controllers/decidim/components/base_controller.rb +20 -3
  58. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +1 -1
  59. data/app/controllers/decidim/devise/passwords_controller.rb +1 -1
  60. data/app/controllers/decidim/devise/registrations_controller.rb +1 -1
  61. data/app/controllers/decidim/devise/sessions_controller.rb +1 -1
  62. data/app/controllers/decidim/download_your_data_controller.rb +2 -2
  63. data/app/controllers/decidim/editor_images_controller.rb +1 -1
  64. data/app/controllers/decidim/follows_controller.rb +4 -3
  65. data/app/controllers/decidim/geolocation_controller.rb +1 -1
  66. data/app/controllers/decidim/likes_controller.rb +2 -1
  67. data/app/controllers/decidim/locales_controller.rb +3 -11
  68. data/app/controllers/decidim/messaging/conversations_controller.rb +3 -3
  69. data/app/controllers/decidim/newsletters_controller.rb +1 -1
  70. data/app/controllers/decidim/notifications_settings_controller.rb +1 -1
  71. data/app/controllers/decidim/notifications_subscriptions_controller.rb +0 -8
  72. data/app/controllers/decidim/open_data_controller.rb +1 -1
  73. data/app/controllers/decidim/report_users_controller.rb +2 -2
  74. data/app/controllers/decidim/reports_controller.rb +1 -1
  75. data/app/controllers/decidim/user_activities_controller.rb +1 -2
  76. data/app/events/decidim/amendable/amendment_base_event.rb +1 -7
  77. data/app/events/decidim/welcome_notification_event.rb +1 -1
  78. data/app/forms/decidim/upload_validation_form.rb +1 -1
  79. data/app/helpers/concerns/decidim/flash_helper_extensions.rb +1 -0
  80. data/app/helpers/decidim/active_link_to_helper.rb +136 -0
  81. data/app/helpers/decidim/amendments_helper.rb +3 -3
  82. data/app/helpers/decidim/check_boxes_tree_helper.rb +2 -2
  83. data/app/helpers/decidim/component_path_helper.rb +9 -4
  84. data/app/helpers/decidim/filters_helper.rb +0 -2
  85. data/app/helpers/decidim/menu_helper.rb +5 -3
  86. data/app/helpers/decidim/meta_tags_helper.rb +0 -2
  87. data/app/helpers/decidim/paginate_helper.rb +14 -1
  88. data/app/helpers/decidim/sanitize_helper.rb +1 -0
  89. data/app/helpers/decidim/short_link_helper.rb +5 -5
  90. data/app/helpers/decidim/translations_helper.rb +4 -4
  91. data/app/jobs/decidim/delete_inactive_participants_job.rb +2 -2
  92. data/app/jobs/decidim/process_inactive_participant_job.rb +7 -0
  93. data/app/mailers/decidim/application_mailer.rb +7 -2
  94. data/app/mailers/decidim/decidim_devise_mailer.rb +1 -0
  95. data/app/mailers/decidim/participants_account_mailer.rb +16 -0
  96. data/app/mailers/decidim/reported_mailer.rb +4 -1
  97. data/app/models/decidim/action_log.rb +1 -1
  98. data/app/models/decidim/attachment.rb +2 -20
  99. data/app/models/decidim/authorization.rb +0 -7
  100. data/app/models/decidim/authorization_transfer.rb +1 -1
  101. data/app/models/decidim/component.rb +6 -9
  102. data/app/models/decidim/content_block.rb +3 -3
  103. data/app/models/decidim/moderation.rb +1 -1
  104. data/app/models/decidim/newsletter.rb +2 -2
  105. data/app/models/decidim/participatory_space/member.rb +55 -0
  106. data/app/models/decidim/private_export.rb +0 -6
  107. data/app/models/decidim/resource_link.rb +1 -1
  108. data/app/models/decidim/short_link.rb +1 -1
  109. data/app/models/decidim/user.rb +2 -2
  110. data/app/models/decidim/user_base_entity.rb +2 -17
  111. data/app/models/decidim/user_moderation.rb +1 -1
  112. data/app/packs/src/decidim/controllers/accordion/accordion.test.js +42 -196
  113. data/app/packs/src/decidim/controllers/accordion/controller.js +17 -93
  114. data/app/packs/src/decidim/controllers/assign_role/assign_role.test.js +80 -0
  115. data/app/packs/src/decidim/controllers/assign_role/controller.js +27 -0
  116. data/app/packs/src/decidim/controllers/dropdown/controller.js +0 -6
  117. data/app/packs/src/decidim/controllers/dropdown/dropdown.test.js +0 -28
  118. data/app/packs/src/decidim/controllers/form_validator/form_validator.js +6 -6
  119. data/app/packs/src/decidim/controllers/form_validator/form_validator.test.js +1 -23
  120. data/app/packs/src/decidim/controllers/main_menu/controller.js +115 -0
  121. data/app/packs/src/decidim/controllers/main_menu/main_menu.test.js +185 -0
  122. data/app/packs/src/decidim/controllers/mention/controller.js +140 -296
  123. data/app/packs/src/decidim/controllers/mention/input_mentions.test.js +457 -120
  124. data/app/packs/src/decidim/controllers/multiple_mentions/controller.js +32 -68
  125. data/app/packs/src/decidim/controllers/multiple_mentions/input_multiple_mentions.test.js +23 -30
  126. data/app/packs/src/decidim/controllers/password_toggler/controller.js +1 -22
  127. data/app/packs/src/decidim/controllers/password_toggler/password_toggler.test.js +20 -11
  128. data/app/packs/src/decidim/datepicker/generate_datepicker.js +1 -13
  129. data/app/packs/src/decidim/direct_uploads/upload_field.js +4 -4
  130. data/app/packs/src/decidim/direct_uploads/upload_modal.js +7 -12
  131. data/app/packs/src/decidim/editor/common/suggestion.js +1 -1
  132. data/app/packs/src/decidim/editor/extensions/decidim_kit/index.js +4 -1
  133. data/app/packs/src/decidim/editor/extensions/image/index.js +8 -5
  134. data/app/packs/src/decidim/editor/extensions/link/index.js +8 -0
  135. data/app/packs/src/decidim/editor/extensions/mention/index.js +18 -5
  136. data/app/packs/src/decidim/editor/extensions/mention_resource/index.js +16 -7
  137. data/app/packs/src/decidim/editor/test/extensions/decidim_kit.test.js +13 -4
  138. data/app/packs/src/decidim/editor/test/extensions/heading.test.js +1 -1
  139. data/app/packs/src/decidim/editor/test/extensions/image.test.js +26 -28
  140. data/app/packs/src/decidim/editor/test/extensions/mention.test.js +6 -2
  141. data/app/packs/src/decidim/editor/test/extensions/video_embed.test.js +27 -15
  142. data/app/packs/src/decidim/editor/test/helpers.js +8 -10
  143. data/app/packs/src/decidim/editor/test/toolbar/full.test.js +15 -4
  144. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_block.js +8 -4
  145. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_formatting.js +5 -1
  146. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_indent.js +9 -5
  147. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_link.js +5 -1
  148. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_list.js +8 -4
  149. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_styling.js +13 -9
  150. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_content_styling.js +6 -2
  151. data/app/packs/src/decidim/geocoding/reverse_geocoding.js +5 -15
  152. data/app/packs/src/decidim/index.js +3 -5
  153. data/app/packs/src/decidim/map/controller.js +1 -10
  154. data/app/packs/src/decidim/refactor/moved/focus_guard.js +12 -12
  155. data/app/packs/src/decidim/sw/push-permissions.js +13 -48
  156. data/app/packs/src/decidim/sw/sw.js +1 -1
  157. data/app/packs/src/decidim/utilities/text.js +6 -6
  158. data/app/packs/src/decidim/vendor/tribute.js +1890 -0
  159. data/app/packs/stylesheets/decidim/_cards.scss +3 -2
  160. data/app/packs/stylesheets/decidim/_conversations.scss +0 -14
  161. data/app/packs/stylesheets/decidim/_cookies.scss +5 -13
  162. data/app/packs/stylesheets/decidim/_datepicker.scss +0 -8
  163. data/app/packs/stylesheets/decidim/_documents.scss +1 -1
  164. data/app/packs/stylesheets/decidim/_dropdown.scss +21 -31
  165. data/app/packs/stylesheets/decidim/_floating_help.scss +1 -1
  166. data/app/packs/stylesheets/decidim/_footer.scss +1 -69
  167. data/app/packs/stylesheets/decidim/_forms.scss +5 -1
  168. data/app/packs/stylesheets/decidim/_header.scss +148 -46
  169. data/app/packs/stylesheets/decidim/_language_chooser.scss +79 -0
  170. data/app/packs/stylesheets/decidim/_participatory_spaces.scss +1 -1
  171. data/app/packs/stylesheets/decidim/_tribute.scss +36 -0
  172. data/app/packs/stylesheets/decidim/application.scss +1 -2
  173. data/app/packs/stylesheets/decidim/editor.scss +33 -2
  174. data/app/packs/stylesheets/decidim/geocoding_addons.scss +2 -10
  175. data/app/presenters/decidim/admin_log/participatory_space/member_presenter.rb +40 -0
  176. data/app/presenters/decidim/admin_log/static_page_resource_presenter.rb +1 -1
  177. data/app/presenters/decidim/authorization_transfer_presenter.rb +1 -1
  178. data/app/presenters/decidim/breadcrumb_root_menu_item_presenter.rb +3 -3
  179. data/app/presenters/decidim/footer_menu_presenter.rb +4 -2
  180. data/app/presenters/decidim/log/user_presenter.rb +1 -0
  181. data/app/presenters/decidim/log/value_types/access_mode_presenter.rb +45 -0
  182. data/app/presenters/decidim/menu_item_presenter.rb +3 -9
  183. data/app/presenters/decidim/participatory_space/member_presenter.rb +48 -0
  184. data/app/presenters/decidim/resource_locator_presenter.rb +22 -3
  185. data/app/presenters/decidim/stats_presenter.rb +1 -1
  186. data/app/queries/decidim/last_activity.rb +1 -1
  187. data/app/resolvers/decidim/meta_image_url_resolver.rb +0 -7
  188. data/app/serializers/decidim/exporters/participatory_space_serializer.rb +15 -1
  189. data/app/services/decidim/email_notification_generator.rb +2 -0
  190. data/app/services/decidim/notification_generator.rb +4 -0
  191. data/app/services/decidim/notifications_subscriptions_persistor.rb +0 -6
  192. data/app/services/decidim/send_push_notification.rb +1 -5
  193. data/app/uploaders/decidim/image_uploader.rb +1 -1
  194. data/app/uploaders/decidim/organization_favicon_uploader.rb +4 -9
  195. data/app/validators/uploader_image_dimensions_validator.rb +13 -11
  196. data/app/views/decidim/gamification/badges/index.html.erb +1 -1
  197. data/app/views/decidim/homepage/show.html.erb +2 -2
  198. data/app/views/decidim/last_activities/index.html.erb +1 -1
  199. data/app/views/decidim/messaging/conversations/_error_modal.html.erb +19 -11
  200. data/app/views/decidim/messaging/conversations/_new_conversation_button.html.erb +1 -1
  201. data/app/views/decidim/messaging/conversations/_reply.html.erb +1 -1
  202. data/app/views/decidim/messaging/conversations/error.js.erb +7 -12
  203. data/app/views/decidim/messaging/conversations/new.html.erb +1 -1
  204. data/app/views/decidim/messaging/conversations/show.html.erb +2 -2
  205. data/app/views/decidim/newsletters/unsubscribe.html.erb +1 -1
  206. data/app/views/decidim/notifications_settings/show.html.erb +5 -5
  207. data/app/views/decidim/offline/show.html.erb +1 -1
  208. data/app/views/decidim/pages/index.html.erb +1 -1
  209. data/app/views/decidim/participants_account_mailer/removal_notification.html.erb +11 -0
  210. data/app/views/decidim/participatory_space/members/_member.html.erb +1 -0
  211. data/app/views/decidim/profiles/show.html.erb +1 -1
  212. data/app/views/decidim/searches/_filters.html.erb +1 -1
  213. data/app/views/decidim/shared/_resource_actions.html.erb +4 -4
  214. data/app/views/decidim/shared/_results_per_page.html.erb +1 -1
  215. data/app/views/decidim/shared/filters/_check_boxes_tree.html.erb +1 -1
  216. data/app/views/decidim/shared/filters/_dropdown_label.html.erb +4 -3
  217. data/app/views/decidim/user_activities/index.html.erb +1 -1
  218. data/app/views/devise/mailer/{invite_private_user.html.erb → invite_member.html.erb} +2 -2
  219. data/app/views/devise/mailer/{invite_private_user.text.erb → invite_member.text.erb} +2 -2
  220. data/app/views/layouts/decidim/_head.html.erb +2 -2
  221. data/app/views/layouts/decidim/_wrapper.html.erb +3 -3
  222. data/app/views/layouts/decidim/footer/_focus_mode_main.html.erb +0 -1
  223. data/app/views/layouts/decidim/footer/_main.html.erb +1 -2
  224. data/app/views/layouts/decidim/footer/_main_links.html.erb +28 -56
  225. data/app/views/layouts/decidim/header/_focus_mode_back_button.html.erb +4 -1
  226. data/app/views/layouts/decidim/header/_main.html.erb +17 -8
  227. data/app/views/layouts/decidim/header/_main_language_chooser.html.erb +24 -0
  228. data/app/views/layouts/decidim/header/_main_links_desktop.html.erb +56 -56
  229. data/app/views/layouts/decidim/header/_main_links_mobile_account.html.erb +2 -2
  230. data/app/views/layouts/decidim/header/_main_links_mobile_item_account.html.erb +3 -1
  231. data/app/views/layouts/decidim/header/_main_menu_mobile.html.erb +18 -5
  232. data/app/views/layouts/decidim/header/_main_search.html.erb +3 -3
  233. data/app/views/layouts/decidim/header/_menu.html.erb +5 -5
  234. data/app/views/layouts/decidim/header/_menu_breadcrumb_desktop.html.erb +13 -12
  235. data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile.html.erb +28 -0
  236. data/app/views/layouts/decidim/shared/_layout_center.html.erb +1 -1
  237. data/app/views/layouts/decidim/shared/_layout_item.html.erb +1 -1
  238. data/app/views/layouts/decidim/shared/_layout_two_col.html.erb +1 -1
  239. data/config/initializers/invisible_captcha.rb +1 -0
  240. data/config/locales/ar.yml +29 -12
  241. data/config/locales/bg.yml +31 -14
  242. data/config/locales/bs-BA.yml +0 -1
  243. data/config/locales/ca-IT.yml +68 -60
  244. data/config/locales/ca.yml +68 -60
  245. data/config/locales/cs.yml +56 -37
  246. data/config/locales/da.yml +0 -1
  247. data/config/locales/de.yml +58 -27
  248. data/config/locales/el.yml +26 -9
  249. data/config/locales/en.yml +64 -55
  250. data/config/locales/eo.yml +0 -1
  251. data/config/locales/es-MX.yml +67 -59
  252. data/config/locales/es-PY.yml +67 -59
  253. data/config/locales/es.yml +67 -59
  254. data/config/locales/et.yml +0 -1
  255. data/config/locales/eu.yml +104 -94
  256. data/config/locales/fa-IR.yml +0 -1
  257. data/config/locales/fi-plain.yml +63 -60
  258. data/config/locales/fi.yml +65 -62
  259. data/config/locales/fr-CA.yml +63 -39
  260. data/config/locales/fr.yml +63 -39
  261. data/config/locales/ga-IE.yml +3 -2
  262. data/config/locales/gl.yml +26 -9
  263. data/config/locales/gn-PY.yml +0 -1
  264. data/config/locales/hr.yml +0 -1
  265. data/config/locales/hu.yml +26 -12
  266. data/config/locales/id-ID.yml +25 -9
  267. data/config/locales/is-IS.yml +7 -2
  268. data/config/locales/it.yml +24 -23
  269. data/config/locales/ja.yml +65 -75
  270. data/config/locales/ka-GE.yml +0 -1
  271. data/config/locales/kaa.yml +0 -1
  272. data/config/locales/ko.yml +0 -1
  273. data/config/locales/lb.yml +27 -10
  274. data/config/locales/lt.yml +28 -12
  275. data/config/locales/lv.yml +25 -9
  276. data/config/locales/mt.yml +0 -1
  277. data/config/locales/nl.yml +27 -10
  278. data/config/locales/no.yml +27 -10
  279. data/config/locales/oc-FR.yml +0 -1
  280. data/config/locales/pl.yml +33 -18
  281. data/config/locales/pt-BR.yml +61 -26
  282. data/config/locales/pt.yml +27 -10
  283. data/config/locales/ro-RO.yml +43 -21
  284. data/config/locales/ru.yml +8 -7
  285. data/config/locales/sk.yml +25 -1409
  286. data/config/locales/sl.yml +0 -1
  287. data/config/locales/sr-CS.yml +0 -1
  288. data/config/locales/sv.yml +72 -30
  289. data/config/locales/tr-TR.yml +28 -10
  290. data/config/locales/uk.yml +6 -4
  291. data/config/locales/vi.yml +0 -1
  292. data/config/locales/zh-CN.yml +25 -9
  293. data/config/locales/zh-TW.yml +28 -10
  294. data/config/routes.rb +138 -77
  295. data/db/data/20251213075429_rename_members_in_action_log.rb +22 -0
  296. data/db/data/20260319145808_rename_send_to_members_in_newsletter.rb +27 -0
  297. data/db/migrate/20200730142511_add_file_upload_settings_to_decidim_organizations.rb +13 -15
  298. data/db/migrate/20250217192438_convert_user_groups_into_users.rb +2 -3
  299. data/db/migrate/20250523104311_move_cta_to_hero_content_block.rb +1 -1
  300. data/db/migrate/20250527122040_move_highlighted_content_banner_settings_to_content_block.rb +1 -1
  301. data/db/migrate/20250819110800_convert_private_exports_id_to_uuid.rb +2 -2
  302. data/db/migrate/20251112132305_remove_legacy_images_from_core_module.rb +27 -0
  303. data/db/migrate/20251205122428_rename_participatory_space_private_users_to_members.rb +9 -0
  304. data/db/migrate/20251216185133_rename_privatable_to_to_participatory_space_in_members.rb +10 -0
  305. data/db/migrate/20260208201405_remove_user_group_core.rb +21 -0
  306. data/db/migrate/20260208201406_remove_user_group_memberships.rb +30 -0
  307. data/db/migrate/20260208201407_remove_user_group_organizations.rb +11 -0
  308. data/db/migrate/20260217152425_remove_enable_participatory_space_filters_from_decidim_organizations.rb +7 -0
  309. data/db/migrate/20260314081619_add_index_on_decidim_members.rb +25 -0
  310. data/decidim-core.gemspec +25 -31
  311. data/lib/decidim/acts_as_tree.rb +12 -12
  312. data/lib/decidim/admin_filters_registry.rb +1 -1
  313. data/lib/decidim/amendable.rb +5 -1
  314. data/lib/decidim/api/functions/category_list.rb +1 -0
  315. data/lib/decidim/api/functions/component_finder_base.rb +1 -1
  316. data/lib/decidim/api/functions/component_list.rb +3 -1
  317. data/lib/decidim/api/functions/component_list_base.rb +1 -0
  318. data/lib/decidim/api/functions/participatory_space_finder_base.rb +1 -1
  319. data/lib/decidim/api/functions/participatory_space_list_base.rb +1 -0
  320. data/lib/decidim/api/functions/user_entity_list.rb +0 -3
  321. data/lib/decidim/api/interfaces/amendable_entity_interface.rb +1 -0
  322. data/lib/decidim/api/interfaces/amendable_interface.rb +1 -0
  323. data/lib/decidim/api/interfaces/attachable_collection_interface.rb +1 -0
  324. data/lib/decidim/api/interfaces/attachable_interface.rb +1 -0
  325. data/lib/decidim/api/interfaces/author_interface.rb +2 -1
  326. data/lib/decidim/api/interfaces/authorable_interface.rb +1 -0
  327. data/lib/decidim/api/interfaces/categories_container_interface.rb +1 -0
  328. data/lib/decidim/api/interfaces/categorizable_interface.rb +1 -0
  329. data/lib/decidim/api/interfaces/coauthorable_interface.rb +1 -0
  330. data/lib/decidim/api/interfaces/component_interface.rb +9 -8
  331. data/lib/decidim/api/interfaces/fingerprint_interface.rb +1 -0
  332. data/lib/decidim/api/interfaces/followable_interface.rb +2 -0
  333. data/lib/decidim/api/interfaces/likeable_interface.rb +2 -2
  334. data/lib/decidim/api/interfaces/localizable_interface.rb +1 -0
  335. data/lib/decidim/api/interfaces/participatory_space_interface.rb +1 -0
  336. data/lib/decidim/api/interfaces/referable_interface.rb +1 -0
  337. data/lib/decidim/api/interfaces/scopable_interface.rb +1 -0
  338. data/lib/decidim/api/interfaces/taxonomizable_interface.rb +1 -0
  339. data/lib/decidim/api/interfaces/timestamps_interface.rb +1 -0
  340. data/lib/decidim/api/interfaces/traceable_interface.rb +1 -0
  341. data/lib/decidim/api/types/attachment_collection_type.rb +5 -3
  342. data/lib/decidim/api/types/attachment_type.rb +11 -4
  343. data/lib/decidim/api/types/badge_score_type.rb +28 -0
  344. data/lib/decidim/api/types/moderation_type.rb +25 -0
  345. data/lib/decidim/api/types/participant_details_type.rb +17 -0
  346. data/lib/decidim/api/types/reportable_type.rb +18 -0
  347. data/lib/decidim/api/types/reportable_user_type.rb +17 -0
  348. data/lib/decidim/api/types/static_page_topic_type.rb +16 -0
  349. data/lib/decidim/api/types/static_page_type.rb +22 -0
  350. data/lib/decidim/api/types/taxonomy_type.rb +2 -0
  351. data/lib/decidim/api/types/user_moderation_type.rb +36 -0
  352. data/lib/decidim/api/types/user_type.rb +13 -0
  353. data/lib/decidim/asset_router/pipeline.rb +1 -1
  354. data/lib/decidim/asset_router/storage.rb +9 -9
  355. data/lib/decidim/assets/tailwind/tailwind.config.js.erb +3 -0
  356. data/lib/decidim/attachment_attributes.rb +9 -58
  357. data/lib/decidim/attribute_encryptor.rb +51 -10
  358. data/lib/decidim/attribute_object/model.rb +0 -5
  359. data/lib/decidim/block_registry.rb +1 -1
  360. data/lib/decidim/coauthorable.rb +2 -1
  361. data/lib/decidim/command.rb +2 -1
  362. data/lib/decidim/content_processor.rb +1 -1
  363. data/lib/decidim/content_renderers/base_renderer.rb +0 -112
  364. data/lib/decidim/content_renderers/blob_renderer.rb +7 -4
  365. data/lib/decidim/content_renderers/mention_resource_renderer.rb +6 -10
  366. data/lib/decidim/content_renderers/resource_renderer.rb +7 -16
  367. data/lib/decidim/content_renderers/user_renderer.rb +9 -11
  368. data/lib/decidim/core/api.rb +8 -0
  369. data/lib/decidim/core/content_blocks/registry_manager.rb +4 -10
  370. data/lib/decidim/core/engine.rb +2 -42
  371. data/lib/decidim/core/menu.rb +0 -26
  372. data/lib/decidim/core/test/factories.rb +29 -21
  373. data/lib/decidim/core/test/shared_examples/access_mode_restricted_participatory_spaces.rb +172 -0
  374. data/lib/decidim/core/test/shared_examples/access_mode_transparent_participatory_spaces.rb +241 -0
  375. data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +10 -10
  376. data/lib/decidim/core/test/shared_examples/amendable/amendment_event_examples.rb +2 -2
  377. data/lib/decidim/core/test/shared_examples/amendable/amendment_promoted_event_examples.rb +3 -3
  378. data/lib/decidim/core/test/shared_examples/comments_examples.rb +121 -143
  379. data/lib/decidim/core/test/shared_examples/fingerprint_examples.rb +2 -0
  380. data/lib/decidim/core/test/shared_examples/has_members.rb +63 -0
  381. data/lib/decidim/core/test/shared_examples/has_space_in_mcell_examples.rb +1 -2
  382. data/lib/decidim/core/test/shared_examples/manage_share_tokens_examples.rb +1 -1
  383. data/lib/decidim/core/test/shared_examples/map_examples.rb +1 -1
  384. data/lib/decidim/core/test/shared_examples/participant_details_examples.rb +16 -0
  385. data/lib/decidim/core/test/shared_examples/participatory_space_members_page_examples.rb +10 -10
  386. data/lib/decidim/core/test/shared_examples/resource_liked_event_examples.rb +3 -3
  387. data/lib/decidim/core/test/shared_examples/resource_locator_presenter_examples.rb +7 -7
  388. data/lib/decidim/core/test/shared_examples/searchable_participatory_space_examples.rb +3 -3
  389. data/lib/decidim/core/test/shared_examples/searchable_results_examples.rb +2 -2
  390. data/lib/decidim/core/test/shared_examples/simple_event.rb +1 -0
  391. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +2 -2
  392. data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +1 -1
  393. data/lib/decidim/core/test.rb +2 -1
  394. data/lib/decidim/core/version.rb +1 -1
  395. data/lib/decidim/core.rb +222 -335
  396. data/lib/decidim/download_your_data_serializers/{download_your_data_participatory_space_private_user_serializer.rb → download_your_data_member_serializer.rb} +6 -6
  397. data/lib/decidim/download_your_data_serializers.rb +2 -2
  398. data/lib/decidim/engine_router.rb +31 -6
  399. data/lib/decidim/exporters/csv.rb +1 -1
  400. data/lib/decidim/filter_form_builder.rb +1 -1
  401. data/{app/controllers/concerns → lib}/decidim/form_factory.rb +11 -1
  402. data/lib/decidim/has_settings.rb +2 -2
  403. data/lib/decidim/legacy_form_builder.rb +1 -0
  404. data/lib/decidim/locale_router_detector.rb +41 -0
  405. data/lib/decidim/maintenance/import_models/scope.rb +1 -1
  406. data/lib/decidim/maintenance/import_models.rb +0 -2
  407. data/lib/decidim/map/autocomplete.rb +3 -4
  408. data/lib/decidim/map/dynamic_map.rb +1 -3
  409. data/lib/decidim/map/frontend.rb +1 -1
  410. data/lib/decidim/map/geocoding.rb +2 -2
  411. data/lib/decidim/map/static_map.rb +10 -22
  412. data/lib/decidim/map/utility.rb +3 -6
  413. data/lib/decidim/map.rb +2 -2
  414. data/lib/decidim/menu.rb +1 -1
  415. data/lib/decidim/menu_item.rb +1 -0
  416. data/lib/decidim/menu_registry.rb +1 -1
  417. data/lib/decidim/moderation_tools.rb +1 -1
  418. data/lib/decidim/newsletter_encryptor.rb +5 -8
  419. data/lib/decidim/organization_settings.rb +2 -2
  420. data/lib/decidim/participable.rb +1 -0
  421. data/lib/decidim/participatory_space/has_members.rb +61 -0
  422. data/lib/decidim/participatory_space_manifest.rb +0 -4
  423. data/lib/decidim/participatory_space_resourceable.rb +10 -1
  424. data/lib/decidim/routes/locale_redirects.rb +47 -0
  425. data/lib/decidim/routes.rb +7 -0
  426. data/lib/decidim/search_resource_fields_mapper.rb +3 -4
  427. data/lib/decidim/searchable.rb +0 -5
  428. data/lib/decidim/seeds.rb +17 -0
  429. data/lib/decidim/shakapacker/runner.rb +4 -4
  430. data/lib/decidim/shakapacker/shakapacker.yml +28 -3
  431. data/lib/decidim/taxonomizable.rb +1 -1
  432. data/lib/decidim/translatable_attributes.rb +9 -3
  433. data/lib/decidim/view_model.rb +5 -1
  434. data/lib/devise/models/decidim_newsletterable.rb +1 -1
  435. data/lib/tasks/decidim_mailers_tasks.rake +9 -31
  436. data/lib/tasks/decidim_procfile.rake +1 -1
  437. data/lib/tasks/decidim_tasks.rake +0 -1
  438. data/lib/tasks/decidim_taxonomies.rake +1 -1
  439. data/lib/tasks/upgrade/decidim_active_storage_migration_tasks.rake +0 -1
  440. data/lib/tasks/upgrade/decidim_encryption.rake +12 -0
  441. data/lib/tasks/upgrade/decidim_migrate_wysiwyg_content.rake +0 -1
  442. data/lib/tasks/upgrade/decidim_remove_deleted_users_left_data_tasks.rake +1 -1
  443. data/lib/tasks/upgrade/{fix_deleted_private_follows.rake → fix_deleted_members_follows.rake} +5 -5
  444. data/lib/tasks/upgrade/migrations.rake +0 -1
  445. data/lib/tasks/upgrade/user_groups_migration.rake +0 -1
  446. metadata +206 -155
  447. data/app/cells/decidim/content_blocks/global_menu/show.erb +0 -11
  448. data/app/cells/decidim/content_blocks/global_menu_cell.rb +0 -35
  449. data/app/cells/decidim/content_blocks/menu_breadcrumb_last_activity/show.erb +0 -10
  450. data/app/cells/decidim/content_blocks/menu_breadcrumb_last_activity_cell.rb +0 -49
  451. data/app/cells/decidim/participatory_space_dropdown_metadata/links.erb +0 -9
  452. data/app/cells/decidim/participatory_space_dropdown_metadata/metadata.erb +0 -1
  453. data/app/cells/decidim/participatory_space_dropdown_metadata/show.erb +0 -11
  454. data/app/cells/decidim/participatory_space_dropdown_metadata_cell.rb +0 -26
  455. data/app/controllers/concerns/decidim/has_members_page.rb +0 -25
  456. data/app/controllers/decidim/private_downloads_controller.rb +0 -29
  457. data/app/jobs/decidim/newsletters_opt_in_job.rb +0 -11
  458. data/app/jobs/decidim/user_report_job.rb +0 -11
  459. data/app/mailers/decidim/delete_user_mailer.rb +0 -14
  460. data/app/models/decidim/participatory_space_private_user.rb +0 -51
  461. data/app/models/decidim/private_download.rb +0 -61
  462. data/app/packs/src/decidim/controllers/sticky_header/controller.js +0 -116
  463. data/app/packs/src/decidim/controllers/sticky_header/sticky_header.test.js +0 -320
  464. data/app/packs/src/decidim/dropdown_menu.js +0 -18
  465. data/app/packs/src/decidim/geocoding/reverse_geocoding.test.js +0 -197
  466. data/app/packs/src/decidim/identity_selector_dialog.js +0 -33
  467. data/app/packs/src/decidim/refactor/moved/focus_guard.test.js +0 -136
  468. data/app/packs/stylesheets/decidim/_editor_suggestions.scss +0 -49
  469. data/app/packs/stylesheets/decidim/_tom_select.scss +0 -23
  470. data/app/presenters/decidim/admin_log/participatory_space_private_user_presenter.rb +0 -38
  471. data/app/presenters/decidim/participatory_space_private_user_presenter.rb +0 -46
  472. data/app/services/decidim/push_subscription_endpoint_validator.rb +0 -34
  473. data/app/views/decidim/delete_user_mailer/delete.html.erb +0 -6
  474. data/app/views/decidim/participatory_space_private_users/_participatory_space_private_user.html.erb +0 -1
  475. data/app/views/layouts/decidim/footer/_main_language_chooser.html.erb +0 -26
  476. data/app/views/layouts/decidim/header/_menu_breadcrumb_items.html.erb +0 -34
  477. data/app/views/layouts/decidim/header/_menu_breadcrumb_main_dropdown_desktop.html.erb +0 -10
  478. data/app/views/layouts/decidim/header/_menu_breadcrumb_main_dropdown_mobile.html.erb +0 -17
  479. data/app/views/layouts/decidim/header/_menu_breadcrumb_main_dropdown_top_left.html.erb +0 -2
  480. data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +0 -33
  481. data/app/views/layouts/decidim/header/_mobile_language_choose.html.erb +0 -25
  482. data/lib/decidim/core/test/shared_examples/has_private_users.rb +0 -63
  483. data/lib/decidim/core/test/shared_examples/participatory_space_dropdown_metadata_cell_examples.rb +0 -81
  484. data/lib/decidim/has_private_users.rb +0 -57
  485. data/lib/decidim/maintenance/import_models/assembly_type.rb +0 -49
  486. data/lib/decidim/maintenance/import_models/participatory_process_type.rb +0 -21
  487. data/lib/decidim/query_extensions.rb +0 -64
  488. /data/app/cells/decidim/{participatory_space_private_user → member}/show.erb +0 -0
@@ -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 private_download_path(Decidim::PrivateDownload.for(private_export, attachment_name: :file).token)
53
+ redirect_to Rails.application.routes.url_helpers.rails_blob_url(private_export.file.blob, only_path: true)
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,8 +3,6 @@
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
-
8
6
  def create
9
7
  Decidim::NotificationsSubscriptionsPersistor.new(current_user).add_subscription(params)
10
8
  head :ok
@@ -14,11 +12,5 @@ module Decidim
14
12
  Decidim::NotificationsSubscriptionsPersistor.new(current_user).delete_subscription(params[:auth])
15
13
  head :ok
16
14
  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_entity
22
- end
23
15
  end
24
16
  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
 
@@ -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_name, :emendation_author_path
6
+ :emendation_path, :emendation_author_nickname, :emendation_author_path
7
7
 
8
8
  def amendable_title
9
9
  @amendable_title ||= translated_attribute(amendable_resource.title)
@@ -33,12 +33,6 @@ 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
-
42
36
  def emendation_author_path
43
37
  return unless emendation_resource
44
38
 
@@ -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"
@@ -55,8 +55,10 @@ module Decidim
55
55
  @footer_menu ||= ::Decidim::FooterMenuPresenter.new(
56
56
  :menu,
57
57
  self,
58
+ element_class: "font-semibold underline",
58
59
  active_class: "is-active",
59
60
  role: false,
61
+ container_options: { class: "space-y-4 break-inside-avoid" },
60
62
  label: t("layouts.decidim.footer.decidim_title")
61
63
  )
62
64
  end
@@ -68,11 +70,11 @@ module Decidim
68
70
  # The queries already include the order by weight
69
71
  Decidim::ParticipatoryProcesses::OrganizationParticipatoryProcesses.new(current_organization) |
70
72
  Decidim::ParticipatoryProcesses::PromotedParticipatoryProcesses.new
71
- ).select(&:published?).map { |process| remove_private_space_if_not_private_user(process) }&.compact&.first
73
+ ).select(&:published?).map { |process| remove_restricted_space_if_not_member(process) }&.compact&.first
72
74
  end
73
75
 
74
- def remove_private_space_if_not_private_user(process)
75
- return nil if process.private_space == true && !process.can_participate?(current_user)
76
+ def remove_restricted_space_if_not_member(process)
77
+ return nil if process.restricted? && !process.can_participate?(current_user)
76
78
 
77
79
  process
78
80
  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])
@@ -16,9 +16,22 @@ module Decidim
16
16
  content_tag :div, class: "flex flex-col-reverse md:flex-row items-center justify-between gap-1 py-8 md:py-16 md:flex-wrap", data: { pagination: "" } do
17
17
  template = ""
18
18
  template += render(partial: "decidim/shared/results_per_page", locals: { per_page: }, formats: [:html]) if collection.total_pages.positive?
19
- template += paginate collection, window: 2, outer_window: 1, theme: "decidim", params: paginate_params
19
+ template += paginate collection, window: 2, outer_window: 1, theme: "decidim", params: pagination_params(paginate_params)
20
20
  template.html_safe
21
21
  end
22
22
  end
23
+
24
+ private
25
+
26
+ def pagination_params(paginate_params)
27
+ request_params = params.to_unsafe_h.except("locale", :locale)
28
+ request_params["q"] = request_params["q"].except("locale", :locale) if request_params["q"].is_a?(Hash)
29
+ request_params[:locale] = nil if admin_controller_with_locale_prefix?
30
+ request_params.merge(paginate_params)
31
+ end
32
+
33
+ def admin_controller_with_locale_prefix?
34
+ request.path_parameters[:locale].present? && controller_path.to_s.include?("/admin/")
35
+ end
23
36
  end
24
37
  end
@@ -131,6 +131,7 @@ module Decidim
131
131
  # @param method [Symbol] Method name
132
132
  #
133
133
  # @return ActiveSupport::SafeBuffer
134
+ # @param [Object, nil] presenter_class
134
135
  def render_sanitized_content(resource, method, presenter_class: nil)
135
136
  content = present(resource, presenter_class:).send(method, links: true, strip_tags: !try(:safe_content?))
136
137
 
@@ -10,11 +10,11 @@ module Decidim
10
10
  # also resolves the current mounted route name to make it possible to refer
11
11
  # to the same context when redirecting the short URL to correct full URL.
12
12
  #
13
- # @option kwargs [Boolean] :route_name the route name to which the short
14
- # link should link to
15
- # @option kwargs [Float] :params the URL query parameters that should be
16
- # included in the URL where the short link redirects to
17
- # @return [String] The short URL
13
+ # Accepts keyword arguments such as:
14
+ # - `route_name`: the route name to link to
15
+ # - `params`: query parameters for the redirect
16
+ #
17
+ # @return [String] The short URL.
18
18
  def short_url(**)
19
19
  target = respond_to?(:current_component) && current_component
20
20
  target ||= respond_to?(:current_participatory_space) && current_participatory_space
@@ -30,8 +30,8 @@ module Decidim
30
30
  #
31
31
  # Returns a Hash with the locales as keys and the empty strings as values.
32
32
  def empty_translatable(locales = Decidim.available_locales)
33
- locales.each_with_object({}) do |locale, result|
34
- result[locale.to_s] = ""
33
+ locales.to_h do |locale|
34
+ [locale.to_s, ""]
35
35
  end
36
36
  end
37
37
 
@@ -49,8 +49,8 @@ module Decidim
49
49
  def ensure_translatable(value, locales = Decidim.available_locales)
50
50
  return empty_translatable(locales) unless value.is_a?(Hash)
51
51
 
52
- locales.each_with_object({}) do |locale, result|
53
- result[locale.to_s] = value[locale.to_s] || value[locale] || ""
52
+ locales.to_h do |locale|
53
+ [locale.to_s, value[locale.to_s] || value[locale] || ""]
54
54
  end
55
55
  end
56
56
 
@@ -14,9 +14,9 @@ module Decidim
14
14
 
15
15
  private
16
16
 
17
- def enqueue_jobs(users, action, *args)
17
+ def enqueue_jobs(users, action, *)
18
18
  users.find_each do |user|
19
- ProcessInactiveParticipantJob.perform_later(user.id, action, *args)
19
+ ProcessInactiveParticipantJob.perform_later(user.id, action, *)
20
20
  end
21
21
  end
22
22
 
@@ -31,6 +31,13 @@ module Decidim
31
31
  end
32
32
 
33
33
  def process_remove_user(user)
34
+ email = user.email
35
+ name = user.name
36
+ locale = user.locale
37
+ organization = user.organization
38
+
39
+ ParticipantsAccountMailer.removal_notification(email, name, locale, organization).deliver_later
40
+
34
41
  Decidim::DestroyAccount.call(
35
42
  Decidim::DeleteAccountForm.from_params(
36
43
  delete_reason: I18n.t("decidim.account.destroy.inactive_account_removal_reason", inactivity_period: Decidim.delete_inactive_users_after_days)