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
@@ -67,7 +67,8 @@ shared_examples "comments" do
67
67
  select "Best rated", from: "order"
68
68
  end
69
69
 
70
- expect(page).to have_css(".comments > div:nth-child(2)", text: "Most Rated Comment")
70
+ expect(page).to have_no_css(".loading-comments", visible: :visible)
71
+ expect(page).to have_css(".comment-threads .comment-thread", text: "Most Rated Comment")
71
72
  end
72
73
 
73
74
  context "when there are comments and replies" do
@@ -79,8 +80,8 @@ shared_examples "comments" do
79
80
  expect(page).to have_no_content("Comments are disabled at this time")
80
81
  expect(page).to have_css(".comment", minimum: 1)
81
82
 
82
- within("#accordion-#{single_comment.id}") do
83
- expect(page).to have_content "1 answer"
83
+ within("#comment_#{single_comment.id}") do
84
+ expect(page).to have_content "1 reply"
84
85
  end
85
86
  end
86
87
 
@@ -132,6 +133,7 @@ shared_examples "comments" do
132
133
  visit resource_path
133
134
 
134
135
  within "#comment_#{deleted_comment.id}" do
136
+ click_on "1 reply"
135
137
  expect(page).to have_css("#comment-#{deleted_comment.id}-replies")
136
138
  expect(page).to have_content(reply.author.name)
137
139
  expect(page).to have_content(reply.body.values.first)
@@ -140,6 +142,30 @@ shared_examples "comments" do
140
142
  end
141
143
  end
142
144
 
145
+ context "when there are more comments than the default per page" do
146
+ let(:per_page) { Decidim::Comments::SortedComments::DEFAULT_COMMENTS_LIMIT }
147
+ let!(:extra_comments) { create_list(:comment, per_page - comments.size + 1, commentable:) }
148
+ let(:all_comments) { comments + extra_comments }
149
+
150
+ it "shows a load more button and loads the next page" do
151
+ visit resource_path
152
+
153
+ visible_comments = all_comments.sort_by(&:created_at).first(per_page)
154
+ hidden_comment = (all_comments.sort_by(&:created_at) - visible_comments).first
155
+
156
+ visible_comments.each do |comment|
157
+ expect(page).to have_css("#comment_#{comment.id}")
158
+ end
159
+ expect(page).to have_no_css("#comment_#{hidden_comment.id}")
160
+ expect(page).to have_button("Load more comments")
161
+
162
+ click_on "Load more comments"
163
+
164
+ expect(page).to have_css("#comment_#{hidden_comment.id}")
165
+ expect(page).to have_no_button("Load more comments")
166
+ end
167
+ end
168
+
143
169
  context "when not authenticated" do
144
170
  it "does not show form to add comments to user" do
145
171
  visit resource_path
@@ -147,6 +173,16 @@ shared_examples "comments" do
147
173
  expect(page).to have_css(".comment-thread")
148
174
  end
149
175
 
176
+ it "opens the login modal when clicking the comment button" do
177
+ visit resource_path
178
+
179
+ expect(page).to have_no_css("#loginModal-content", visible: :visible)
180
+
181
+ find(".add-comment-mobile").click
182
+
183
+ expect(page).to have_css("#loginModal-content", visible: :visible)
184
+ end
185
+
150
186
  context "when user visit a mobile browser" do
151
187
  before do
152
188
  driven_by(:iphone)
@@ -176,6 +212,22 @@ shared_examples "comments" do
176
212
  expect(page).to have_css(".add-comment form")
177
213
  end
178
214
 
215
+ it "does not show login modal when clicking the comment button" do
216
+ visit resource_path
217
+
218
+ find("a.add-comment-mobile").click
219
+
220
+ expect(page).to have_no_css("#loginModal-content", visible: :visible)
221
+ end
222
+
223
+ it "guides the user to the comment form when clicking the comment button" do
224
+ visit resource_path
225
+
226
+ find("a.add-comment-mobile").click
227
+
228
+ expect(page).to have_css("#add-comment-anchor")
229
+ end
230
+
179
231
  context "when user visit a computer browser" do
180
232
  before do
181
233
  switch_to_host(organization.host)
@@ -260,6 +312,8 @@ shared_examples "comments" do
260
312
 
261
313
  describe "when using emojis" do
262
314
  before do
315
+ skip("This spec does not work in focus mode, since there is no language selector.") if has_selector?(".main-bar--focus-mode-back-button")
316
+
263
317
  within_language_menu do
264
318
  click_on "Castellano"
265
319
  end
@@ -310,6 +364,12 @@ shared_examples "comments" do
310
364
  let(:locale) { "Català" }
311
365
  let(:phrase) { I18n.with_locale(:ca) { I18n.t("emojis.categories.people") } }
312
366
 
367
+ around do |example|
368
+ I18n.with_locale(:ca) do
369
+ example.run
370
+ end
371
+ end
372
+
313
373
  it_behaves_like "allowing to select emojis"
314
374
  end
315
375
  end
@@ -641,96 +701,48 @@ shared_examples "comments" do
641
701
  end
642
702
  end
643
703
 
644
- context "when the user is writing a new comment while someone else comments" do
645
- let(:new_comment_body) { "Hey, I just jumped in the conversation!" }
646
- let(:new_comment) { build(:comment, commentable:, body: new_comment_body) }
647
- let(:content) { "This is a new comment" }
704
+ context "when user can show and hide replies on a thread" do
705
+ let(:thread) { comments.first }
706
+ let(:new_reply_body) { "Hey, I just jumped inside the thread!" }
707
+ let!(:new_reply) { create(:comment, commentable: thread, root_commentable: commentable, body: new_reply_body) }
648
708
 
649
- before do
650
- within "form#new_comment_for_#{commentable.commentable_type.demodulize}_#{commentable.id}" do
651
- field = find("#add-comment-#{commentable.commentable_type.demodulize}-#{commentable.id}")
652
- field.set " "
653
- field.native.send_keys content
709
+ it "displays a way to display content" do
710
+ visit resource_path
711
+ within "#comment_#{thread.id}" do
712
+ expect(page).to have_content("1 reply")
713
+ click_on "1 reply"
714
+ expect(page).to have_content(new_reply_body)
715
+ click_on "Reply", match: :first
716
+ expect(page).to have_content("Publish reply")
717
+ find("textarea[name='comment[body]']").set("Test reply comments.")
718
+ click_on "Publish reply"
719
+ expect(page).to have_content("Test reply comments.")
654
720
  end
655
- new_comment.save!
656
721
  end
657
722
 
658
- it "does not clear the current user's comment" do
659
- expect(page).to have_content(new_comment.body.values.first, wait: 20)
660
- expect(page.find("#add-comment-#{commentable.commentable_type.demodulize}-#{commentable.id}").value).to include(content)
723
+ it "displays a way to hide content" do
724
+ visit resource_path
725
+ within "#comment_#{thread.id}" do
726
+ expect(page).to have_content("1 reply")
727
+ click_on "1 reply"
728
+ expect(page).to have_content(new_reply_body)
729
+ click_on "1 reply"
730
+ expect(page).to have_no_content(new_reply_body)
731
+ end
661
732
  end
662
733
 
663
- context "when user can hide replies on a thread" do
664
- let(:thread) { comments.first }
665
- let(:new_reply_body) { "Hey, I just jumped inside the thread!" }
666
- let!(:new_reply) { create(:comment, commentable: thread, root_commentable: commentable, body: new_reply_body) }
734
+ context "when there are more replies" do
735
+ let!(:new_replies) { create_list(:comment, 2, commentable: thread, root_commentable: commentable, body: new_reply_body) }
667
736
 
668
- it "displays a way to to display content" do
669
- visit current_path
670
- within "#comment_#{thread.id}" do
671
- expect(page).to have_content("1 answer")
672
- click_on "1 answer"
673
- expect(page).to have_content(new_reply_body)
674
- click_on "Reply", match: :first
675
- expect(page).to have_content("Publish reply")
676
- find("textarea[name='comment[body]']").set("Test reply comments.")
677
- click_on "Publish reply"
678
- expect(page).to have_content("Show 2 replies")
679
- click_on "Show 2 replies"
680
- expect(page).to have_content("Test reply comments.")
681
- end
682
- end
683
-
684
- it "displays a way hide content" do
685
- visit current_path
737
+ it "displays the load replies button" do
738
+ visit resource_path
686
739
  within "#comment_#{thread.id}" do
687
- expect(page).to have_content("1 answer")
688
- click_on "1 answer"
689
- expect(page).to have_content("1 answer")
690
- click_on "1 answer"
740
+ expect(page).to have_content("3 replies")
691
741
  expect(page).to have_no_content(new_reply_body)
742
+ click_on "3 replies"
743
+ expect(page).to have_content(new_reply_body)
692
744
  end
693
745
  end
694
-
695
- context "when are more replies" do
696
- let!(:new_replies) { create_list(:comment, 2, commentable: thread, root_commentable: commentable, body: new_reply_body) }
697
-
698
- it "displays the show button" do
699
- visit current_path
700
- within "#comment_#{thread.id}" do
701
- expect(page).to have_content("3 answers")
702
- expect(page).to have_no_content(new_reply_body)
703
- click_on "3 answers"
704
- expect(page).to have_content(new_reply_body)
705
- end
706
- end
707
- end
708
- end
709
-
710
- context "when inside a thread reply form" do
711
- let(:thread) { comments.first }
712
- let(:new_reply_body) { "Hey, I just jumped inside the thread!" }
713
- let(:new_reply) { build(:comment, commentable: thread, root_commentable: commentable, body: new_reply_body) }
714
- let(:reply_content) { "This is a new reply" }
715
-
716
- before do
717
- within "div#comment_#{thread.id}" do
718
- find("span", text: "Reply").click
719
- end
720
-
721
- within "form#new_comment_for_#{thread.commentable_type.demodulize}_#{thread.id}" do
722
- field = find("#add-comment-#{thread.commentable_type.demodulize}-#{thread.id}")
723
- field.set " "
724
- field.native.send_keys reply_content
725
- end
726
- new_reply.save!
727
- end
728
-
729
- it "does not clear the current user's comment" do
730
- expect(page).to have_content(new_reply.body.values.first, wait: 20)
731
- expect(page.find("#add-comment-#{commentable.commentable_type.demodulize}-#{commentable.id}").value).to include(content)
732
- expect(page.find("#add-comment-#{thread.commentable_type.demodulize}-#{thread.id}").value).to include(reply_content)
733
- end
734
746
  end
735
747
  end
736
748
 
@@ -895,8 +907,8 @@ shared_examples "comments" do
895
907
  visit current_path
896
908
 
897
909
  within "#comments #comment_#{parent.id}" do
898
- expect(page).to have_css("#comment-#{parent.id}-replies")
899
- expect(page.find("#comment-#{parent.id}-replies").text).to be_blank
910
+ expect(page).to have_no_css(".show-replies-button")
911
+ expect(page).to have_no_css("#comment-#{parent.id}-replies")
900
912
  end
901
913
  end
902
914
 
@@ -960,6 +972,10 @@ shared_examples "comments" do
960
972
  skip "Commentable comments has no votes" unless commentable.comments_have_votes?
961
973
 
962
974
  visit current_path
975
+
976
+ within "#comment_#{comments[0].id}" do
977
+ click_on "1 reply"
978
+ end
963
979
  expect(page).to have_css("#comment_#{comments[0].id} > [data-comment-footer] > .comment__footer-grid .comment__votes .js-comment__votes--up", text: /0/, visible: :all)
964
980
  page.find("#comment_#{comments[0].id} > [data-comment-footer] > .comment__footer-grid .comment__votes .js-comment__votes--up").click
965
981
  expect(page).to have_css("#comment_#{comments[0].id} > [data-comment-footer] > .comment__footer-grid .comment__votes .js-comment__votes--up", text: /1/, visible: :all)
@@ -1000,16 +1016,16 @@ shared_examples "comments" do
1000
1016
  let(:content) { "A valid user mention: @#{mentioned_user.nickname}" }
1001
1017
 
1002
1018
  context "when text finish with a mention" do
1003
- it "shows the tribute container" do
1004
- expect(page).to have_css(".tribute-container", text: mentioned_user.name, wait: 10)
1019
+ it "shows the suggestions menu" do
1020
+ expect(page).to have_css(".editor-suggestions-item", text: "@#{mentioned_user.nickname} (#{mentioned_user.name})", wait: 10)
1005
1021
  end
1006
1022
  end
1007
1023
 
1008
1024
  context "when text contains a mention" do
1009
1025
  let(:content) { "A valid user mention: @#{mentioned_user.nickname}." }
1010
1026
 
1011
- it "shows the tribute container" do
1012
- expect(page).to have_no_css(".tribute-container", text: mentioned_user.name)
1027
+ it "hides the suggestions menu" do
1028
+ expect(page).to have_no_css(".editor-suggestions-item", text: "@#{mentioned_user.nickname} (#{mentioned_user.name})")
1013
1029
  end
1014
1030
  end
1015
1031
  end
@@ -1018,8 +1034,8 @@ shared_examples "comments" do
1018
1034
  let!(:mentioned_user) { create(:user, organization:) }
1019
1035
  let(:content) { "A unconfirmed user mention: @#{mentioned_user.nickname}" }
1020
1036
 
1021
- it "do not show the tribute container" do
1022
- expect(page).to have_no_css(".tribute-container", text: mentioned_user.name)
1037
+ it "does not show the suggestions menu" do
1038
+ expect(page).to have_no_css(".editor-suggestions-item", text: "@#{mentioned_user.nickname} (#{mentioned_user.name})")
1023
1039
  end
1024
1040
  end
1025
1041
  end
@@ -1043,7 +1059,7 @@ shared_examples "comments" do
1043
1059
 
1044
1060
  it "replaces the mention with a link to the user's profile" do
1045
1061
  expect(page).to have_comment_from(user, "A valid user mention: @#{mentioned_user.nickname}", wait: 20)
1046
- expect(page).to have_link "@#{mentioned_user.nickname}", href: "http://#{mentioned_user.organization.host}:#{Capybara.server_port}/profiles/#{mentioned_user.nickname}"
1062
+ expect(page).to have_link "@#{mentioned_user.nickname}", href: "http://#{mentioned_user.organization.host}:#{Capybara.server_port}/en/profiles/#{mentioned_user.nickname}"
1047
1063
  end
1048
1064
  end
1049
1065
 
@@ -1195,6 +1211,7 @@ shared_examples "comments with two columns" do
1195
1211
  let!(:user) { create(:user, :confirmed, organization:) }
1196
1212
 
1197
1213
  before do
1214
+ switch_to_host(organization.host)
1198
1215
  login_as user, scope: :user
1199
1216
  end
1200
1217
 
@@ -1209,7 +1226,7 @@ shared_examples "comments with two columns" do
1209
1226
  expect(page).to have_css(".comment", count: comments.length)
1210
1227
 
1211
1228
  within(".comments-two-columns") do
1212
- check_comments_order(".comments-section__in-favor", comments_in_favor)
1229
+ check_comments_order(".comments-section__in-favor", comments_in_favor.reverse)
1213
1230
  check_comments_order(".comments-section__against", comments_against)
1214
1231
  end
1215
1232
  end
@@ -1230,6 +1247,7 @@ shared_examples "comments with two columns" do
1230
1247
 
1231
1248
  context "when commentable is closed" do
1232
1249
  let!(:commentable) { closed_commentable }
1250
+ let!(:comments) { [] }
1233
1251
  let!(:highest_voted_comment_in_favor) { create(:comment, :in_favor, commentable:, created_at: 2.days.ago, up_votes_count: 15) }
1234
1252
  let!(:high_voted_comment_in_favor) { create(:comment, :in_favor, commentable:, created_at: 4.days.ago, up_votes_count: 10) }
1235
1253
  let!(:older_comment_in_favor) { create(:comment, :in_favor, commentable:, created_at: 3.days.ago, up_votes_count: 5) }
@@ -1238,27 +1256,26 @@ shared_examples "comments with two columns" do
1238
1256
  let!(:high_voted_comment_against) { create(:comment, :against, commentable:, created_at: 5.days.ago, up_votes_count: 8) }
1239
1257
  let!(:older_comment_against) { create(:comment, :against, commentable:, created_at: 3.days.ago, up_votes_count: 4) }
1240
1258
 
1241
- it "shows comments with top comments at the beginning and interleaved order after" do
1259
+ it "shows comments sorted by the selected filter in mobile view" do
1242
1260
  resize_window_to_mobile
1243
1261
  visit resource_path
1262
+ sleep 1
1244
1263
 
1245
1264
  within(".comment-threads") do
1246
- interleaved_comments = [
1247
- highest_voted_comment_in_favor,
1265
+ expected_order = [
1248
1266
  highest_voted_comment_against,
1249
- high_voted_comment_in_favor,
1250
- high_voted_comment_against,
1267
+ highest_voted_comment_in_favor,
1268
+ older_comment_against,
1251
1269
  older_comment_in_favor,
1252
- older_comment_against
1270
+ high_voted_comment_in_favor,
1271
+ high_voted_comment_against
1253
1272
  ]
1254
1273
 
1255
1274
  all_comments = all(".comment-thread")
1256
1275
 
1257
- interleaved_comments.each_with_index do |comment, index|
1276
+ expected_order.each_with_index do |comment, index|
1258
1277
  expect(all_comments[index]).to have_content(comment.body["en"])
1259
1278
  end
1260
-
1261
- expect(page).to have_css(".most-upvoted-label", text: "Most upvoted", count: 2)
1262
1279
  end
1263
1280
 
1264
1281
  resize_window_to_desktop
@@ -1285,31 +1302,36 @@ shared_examples "comments with two columns" do
1285
1302
  end
1286
1303
 
1287
1304
  context "when commentable is not closed" do
1305
+ let!(:comments) { [] }
1288
1306
  let!(:oldest_in_favor_comment) { create(:comment, :in_favor, commentable:, created_at: 3.days.ago) }
1289
1307
  let!(:older_in_favor_comment) { create(:comment, :in_favor, commentable:, created_at: 2.days.ago) }
1290
1308
  let!(:oldest_against_comment) { create(:comment, :against, commentable:, created_at: 4.days.ago) }
1291
1309
  let!(:newer_against_comment) { create(:comment, :against, commentable:, created_at: 1.day.ago) }
1292
1310
 
1293
- it "shows the comments in two columns sorted by creation date in ascending order" do
1311
+ it "shows the comments in two columns sorted by creation date in descending order" do
1312
+ resize_window_to_desktop
1294
1313
  visit resource_path
1295
1314
 
1296
1315
  within(".comments-two-columns") do
1297
- check_comments_order(".comments-section__in-favor", [oldest_in_favor_comment, older_in_favor_comment])
1298
- check_comments_order(".comments-section__against", [oldest_against_comment, newer_against_comment])
1316
+ check_comments_order(".comments-section__in-favor", [older_in_favor_comment, oldest_in_favor_comment])
1317
+ check_comments_order(".comments-section__against", [newer_against_comment, oldest_against_comment])
1299
1318
  end
1300
1319
  end
1301
1320
 
1302
- it "allows the user to add a new comment at the end of the respective column" do
1321
+ it "allows the user to add a new comment at the top of the respective column" do
1322
+ resize_window_to_desktop
1303
1323
  visit resource_path
1304
1324
 
1305
1325
  add_new_comment("In favor", "This is a new comment in favor")
1306
1326
 
1307
1327
  within(".comments-section__in-favor") do
1308
1328
  expect(page).to have_content("This is a new comment in favor")
1329
+ expect(first(".comment-thread")).to have_content("This is a new comment in favor")
1309
1330
  end
1310
1331
  end
1311
1332
 
1312
1333
  it "disables the publish button until 'in favor' or 'against' is selected" do
1334
+ resize_window_to_desktop
1313
1335
  visit resource_path
1314
1336
 
1315
1337
  expect(page).to have_button("Publish comment", disabled: true)
@@ -1327,14 +1349,21 @@ shared_examples "comments with two columns" do
1327
1349
  it "shows comments sorted by creation date when viewed on a small screen" do
1328
1350
  resize_window_to_mobile
1329
1351
  visit resource_path
1352
+ sleep 1
1330
1353
 
1331
1354
  within(".comment-threads") do
1332
- comments = all(".comment-thread")
1355
+ expect(page).to have_css(".comment-thread", minimum: 4)
1333
1356
 
1334
- expect(comments[0]).to have_content(oldest_in_favor_comment.body["en"])
1335
- expect(comments[1]).to have_content(oldest_against_comment.body["en"])
1336
- expect(comments[2]).to have_content(older_in_favor_comment.body["en"])
1337
- expect(comments[3]).to have_content(newer_against_comment.body["en"])
1357
+ expected_order = [
1358
+ newer_against_comment,
1359
+ older_in_favor_comment,
1360
+ oldest_in_favor_comment,
1361
+ oldest_against_comment
1362
+ ]
1363
+
1364
+ expected_order.each_with_index do |comment, index|
1365
+ expect(all(".comment-thread")[index]).to have_content(comment.body["en"])
1366
+ end
1338
1367
  end
1339
1368
 
1340
1369
  resize_window_to_desktop
@@ -1356,25 +1385,26 @@ shared_examples "comments with two columns" do
1356
1385
  let!(:latest_comment_against) { create(:comment, :against, commentable:, created_at: 1.day.ago, up_votes_count: 1) }
1357
1386
 
1358
1387
  before do
1388
+ resize_window_to_desktop
1359
1389
  visit resource_path
1360
1390
  end
1361
1391
 
1362
- it "shows the top voted comments at the top of each column, followed by comments in ascending chronological order" do
1392
+ it "shows the top voted comments at the top of each column, followed by comments in descending chronological order" do
1363
1393
  within(".comments-two-columns") do
1364
1394
  check_comments_order(".comments-section__in-favor", [
1365
1395
  highest_voted_comment_in_favor,
1366
- high_voted_comment_in_favor,
1367
- older_comment_in_favor,
1396
+ latest_comment_in_favor,
1368
1397
  recent_comment_in_favor,
1369
- latest_comment_in_favor
1398
+ older_comment_in_favor,
1399
+ high_voted_comment_in_favor
1370
1400
  ])
1371
1401
 
1372
1402
  check_comments_order(".comments-section__against", [
1373
1403
  highest_voted_comment_against,
1374
- high_voted_comment_against,
1375
- older_comment_against,
1404
+ latest_comment_against,
1376
1405
  recent_comment_against,
1377
- latest_comment_against
1406
+ older_comment_against,
1407
+ high_voted_comment_against
1378
1408
  ])
1379
1409
  end
1380
1410
  end
@@ -5,6 +5,7 @@ shared_examples "fingerprint" do
5
5
 
6
6
  it "shows a fingerprint" do
7
7
  visit(resource_locator(fingerprintable).path)
8
+ click_on("see other versions")
8
9
  click_on("Check fingerprint")
9
10
 
10
11
  within ".fingerprint-modal" do
@@ -19,6 +20,7 @@ shared_examples "consistent fingerprint" do
19
20
 
20
21
  it "shows the fingerprint source with correct spacing" do
21
22
  visit(resource_locator(fingerprintable).path)
23
+ click_on("see other versions")
22
24
  click_on("Check fingerprint")
23
25
 
24
26
  within ".fingerprint-modal" do
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples_for "has members" do
6
+ let(:factory_name) { described_class.name.demodulize.underscore.to_sym }
7
+
8
+ let!(:open_space) do
9
+ create(factory_name, access_mode: "open", published_at: Time.current)
10
+ end
11
+
12
+ let!(:restricted_space) do
13
+ create(factory_name, access_mode: "restricted", published_at: Time.current)
14
+ end
15
+
16
+ def create_space_member(space, user = create(:user, organization: space.organization))
17
+ Decidim::ParticipatorySpace::Member.create(participatory_space: space, user:)
18
+ end
19
+
20
+ describe ".public_spaces" do
21
+ let(:scope) { described_class.send(:public_spaces) }
22
+
23
+ it { expect(scope).to eq([open_space]) }
24
+ end
25
+
26
+ describe ".visible_for" do
27
+ let(:scope) { described_class.send(:visible_for, user) }
28
+
29
+ before { create_space_member(restricted_space) }
30
+
31
+ context "without user" do
32
+ let(:user) { nil }
33
+
34
+ it { expect(scope).to contain_exactly(open_space) }
35
+ end
36
+
37
+ context "with non-member" do
38
+ let(:user) { create(:user) }
39
+
40
+ it { expect(scope).to contain_exactly(open_space) }
41
+ end
42
+
43
+ context "with member" do
44
+ let(:user) { restricted_space.users.first }
45
+
46
+ it { expect(scope).to contain_exactly(open_space, restricted_space) }
47
+ end
48
+
49
+ context "when the space is both public and has members" do
50
+ # Visible spaces for non-member.
51
+ let(:user) { create(:user) }
52
+
53
+ before do
54
+ # Public space has multiple members.
55
+ create_space_member(open_space)
56
+ create_space_member(open_space)
57
+ end
58
+
59
+ # Expect no duplicate results.
60
+ it { expect(scope).to contain_exactly(open_space) }
61
+ end
62
+ end
63
+ end
@@ -8,7 +8,8 @@ shared_examples_for "has space in m-cell" do
8
8
  let(:show_space) { true }
9
9
 
10
10
  it "renders the space where the model belongs to" do
11
- expect(cell_html).to have_content(decidim_escape_translated(model.component.participatory_space.title))
11
+ expect(cell_html).to have_content(translated_attribute(model.component.participatory_space.title))
12
+ expect(cell_html.to_s).to include(decidim_escape_translated(model.component.participatory_space.title).gsub(""", "\""))
12
13
  end
13
14
  end
14
15
  end
@@ -181,7 +181,7 @@ shared_examples "manage resource share tokens" do
181
181
  accept_confirm { click_on "Delete" }
182
182
  end
183
183
 
184
- expect(page).to have_admin_callout("Access link successfully destroyed")
184
+ expect(page).to have_callout("Access link successfully destroyed")
185
185
  expect(page).to have_css("tbody tr", count: 2)
186
186
  end
187
187
  end
@@ -205,7 +205,7 @@ shared_examples "a record with front-end geocoding address field" do |geocoded_m
205
205
  # the dummy test geocoding API defined at
206
206
  # `decidim-dev/lib/decidim/dev/test/map_server.rb`. Search for
207
207
  # `serve_autocomplete`.
208
- expect(page).to have_content("successfully")
208
+ expect(page).to have_callout(geocoded_success_message)
209
209
  final = if geocoded_record
210
210
  geocoded_model.find(geocoded_record.id)
211
211
  else
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples "loggable participant details" do
4
+ it "returns the participant private details" do
5
+ expect(response["participantDetails"]).to include("email" => participant.email)
6
+ expect(response["participantDetails"]).to include("nickname" => participant.nickname)
7
+ expect(response["participantDetails"]).to include("name" => participant.name)
8
+ end
9
+
10
+ it "logs the action in action log" do
11
+ expect { response }.to change(Decidim::ActionLog, :count).by(1)
12
+ action_log = Decidim::ActionLog.last
13
+ expect(action_log.user).to eq(current_user)
14
+ expect(action_log.resource).to eq(participant)
15
+ end
16
+ end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  shared_examples "participatory space members page examples" do
4
- let(:user1) { create(:user, organization: privatable_to.organization) }
5
- let(:user2) { create(:user, organization: privatable_to.organization) }
6
- let(:user3) { create(:user, organization: privatable_to.organization) }
4
+ let(:user1) { create(:user, organization: participatory_space.organization) }
5
+ let(:user2) { create(:user, organization: participatory_space.organization) }
6
+ let(:user3) { create(:user, organization: participatory_space.organization) }
7
7
 
8
8
  before do
9
9
  request.env["decidim.current_organization"] = organization
@@ -12,19 +12,19 @@ shared_examples "participatory space members page examples" do
12
12
  describe "GET index" do
13
13
  context "when participatory space has no members" do
14
14
  it "redirects to 404" do
15
- expect { get :index, params: { slug_param => slug } }
15
+ expect { get :index, params: { slug_param => slug, :locale => I18n.locale } }
16
16
  .to raise_error(ActionController::RoutingError)
17
17
  end
18
18
  end
19
19
 
20
20
  context "when participatory space has members" do
21
- let!(:member1) { create(:participatory_space_private_user, privatable_to:, user: user1, published: true) }
22
- let!(:member2) { create(:participatory_space_private_user, privatable_to:, user: user2, published: true) }
23
- let!(:non_published) { create(:participatory_space_private_user, privatable_to:, user: user3, published: false) }
21
+ let!(:member1) { create(:member, participatory_space:, user: user1, published: true) }
22
+ let!(:member2) { create(:member, participatory_space:, user: user2, published: true) }
23
+ let!(:non_published) { create(:member, participatory_space:, user: user3, published: false) }
24
24
 
25
25
  context "when user has permissions" do
26
26
  it "displays list of members" do
27
- get :index, params: { slug_param => slug }
27
+ get :index, params: { slug_param => slug, :locale => I18n.locale }
28
28
 
29
29
  expect(controller.helpers.collection).to contain_exactly(member1, member2)
30
30
  end
@@ -36,9 +36,9 @@ shared_examples "participatory space members page examples" do
36
36
  end
37
37
 
38
38
  it "redirects to participatory space path" do
39
- get :index, params: { slug_param => slug }
39
+ get :index, params: { slug_param => slug, :locale => I18n.locale }
40
40
 
41
- expect(response).to redirect_to(privatable_to)
41
+ expect(response).to redirect_to(destination_path)
42
42
  end
43
43
  end
44
44
  end