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
@@ -5,6 +5,7 @@ module Decidim
5
5
  # This interface represents an object that have a reference field.
6
6
  module ReferableInterface
7
7
  include Decidim::Api::Types::BaseInterface
8
+
8
9
  description "An interface that can be used in display reference methods"
9
10
 
10
11
  field :reference, GraphQL::Types::String, "The reference for this record", null: true
@@ -5,6 +5,7 @@ module Decidim
5
5
  # This interface represents a scopable object.
6
6
  module ScopableInterface
7
7
  include Decidim::Api::Types::BaseInterface
8
+
8
9
  description "An interface that can be used in scopable objects."
9
10
 
10
11
  field :scope, Decidim::Core::ScopeApiType, "The object's scope", null: true
@@ -5,6 +5,7 @@ module Decidim
5
5
  # This interface represents a categorizable object.
6
6
  module TaxonomizableInterface
7
7
  include Decidim::Api::Types::BaseInterface
8
+
8
9
  description "An interface that can be used in taxonomizable objects."
9
10
 
10
11
  field :taxonomies, [Decidim::Core::TaxonomyType], "The object's taxonomies", null: true
@@ -5,6 +5,7 @@ module Decidim
5
5
  # This interface represents an object with standard create_at and updated_at timestamps.
6
6
  module TimestampsInterface
7
7
  include Decidim::Api::Types::BaseInterface
8
+
8
9
  description "An interface that can be used in objects with created_at and updated_at attributes"
9
10
 
10
11
  field :created_at, Decidim::Core::DateTimeType, description: "The date and time this object was created", null: true
@@ -5,6 +5,7 @@ module Decidim
5
5
  # This interface represents an traceable object.
6
6
  module TraceableInterface
7
7
  include Decidim::Api::Types::BaseInterface
8
+
8
9
  description "An interface that can be used in objects with traceability (versions)"
9
10
 
10
11
  field :versions, [Decidim::Core::TraceVersionType, { null: true }], "This object's versions", null: false
@@ -2,13 +2,15 @@
2
2
 
3
3
  module Decidim
4
4
  module Core
5
+ # This type represents an attachment collection
5
6
  class AttachmentCollectionType < Decidim::Api::Types::BaseObject
6
7
  description "A file attachment collection"
7
8
 
8
- field :description, Decidim::Core::TranslatedFieldType, "The description of this AttachmentCollection.", null: false
9
- field :name, Decidim::Core::TranslatedFieldType, "The name of this AttachmentCollection.", null: false
10
-
11
9
  field :attachments, [Decidim::Core::AttachmentType, { null: true }], "This object's attachments", null: false
10
+ field :description, Decidim::Core::TranslatedFieldType, "The description of this Attachment Collection", null: false
11
+ field :id, GraphQL::Types::ID, "Internal ID of this Attachment Collection", null: false
12
+ field :name, Decidim::Core::TranslatedFieldType, "The name of this Attachment Collection", null: false
13
+ field :weight, GraphQL::Types::Int, "The weight of this Attachment Collection", null: true
12
14
  end
13
15
  end
14
16
  end
@@ -2,14 +2,21 @@
2
2
 
3
3
  module Decidim
4
4
  module Core
5
+ # This type represents an attachment
5
6
  class AttachmentType < Decidim::Api::Types::BaseObject
6
7
  description "A file attachment"
8
+ implements Decidim::Core::TimestampsInterface
7
9
 
8
- field :description, Decidim::Core::TranslatedFieldType, "The description of this attachment.", null: false
9
- field :thumbnail, GraphQL::Types::String, "A thumbnail of this attachment, if it is an image.", method: :thumbnail_url, null: true
10
- field :title, Decidim::Core::TranslatedFieldType, "The title of this attachment.", null: false
11
- field :type, GraphQL::Types::String, "The type of this attachment", method: :file_type, null: false
10
+ field :content_type, GraphQL::Types::String, "The content type of this attachment (could be 'text/uri-list', 'image/jpeg', or any allowed content types)", null: true
11
+ field :description, Decidim::Core::TranslatedFieldType, "The description of this attachment", null: false
12
+ field :file_size, GraphQL::Types::String, "The file size of this attachment", null: true
13
+ field :id, GraphQL::Types::ID, "Internal ID of this attachment", null: false
14
+ field :link, GraphQL::Types::String, "The attached link of this attachment", null: true
15
+ field :thumbnail, GraphQL::Types::String, "A thumbnail of this attachment, if it is an image", method: :thumbnail_url, null: true
16
+ field :title, Decidim::Core::TranslatedFieldType, "The title of this attachment", null: false
17
+ field :type, GraphQL::Types::String, "The type of this attachment (could be 'link', 'jpeg', 'pdf' or any other allowed extensions)", method: :file_type, null: false
12
18
  field :url, GraphQL::Types::String, "The url of this attachment", null: false
19
+ field :weight, GraphQL::Types::Int, "The weight of this attachment", null: true
13
20
  end
14
21
  end
15
22
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Core
5
+ class BadgeScoreType < Decidim::Api::Types::BaseObject
6
+ description "An user badge score"
7
+
8
+ field :description, GraphQL::Types::String, "The description of this badge", null: false
9
+ field :image, GraphQL::Types::String, "The image of this badge", null: false
10
+ field :level, GraphQL::Types::Int, "The level of this badge", null: false
11
+ field :name, GraphQL::Types::String, "The name of this badge", null: false, method: :badge_name
12
+ field :score, GraphQL::Types::Int, "The score of this badge", null: false
13
+
14
+ delegate :level, :score, to: :status
15
+ delegate :image, :description, to: :manifest
16
+
17
+ private
18
+
19
+ def manifest
20
+ @manifest ||= status.badge
21
+ end
22
+
23
+ def status
24
+ @status ||= Decidim::Gamification.status_for(object.user, object.badge_name)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Core
5
+ # This type represents a content moderation record
6
+ class ModerationType < Decidim::Api::Types::BaseObject
7
+ description "A moderation detail"
8
+
9
+ implements Decidim::Core::TimestampsInterface
10
+
11
+ field :hidden_at, Decidim::Core::DateTimeType, "The date and time when the resource was hidden", null: true
12
+ field :id, GraphQL::Types::ID, "The ID of the moderation", null: false
13
+ field :report_count, GraphQL::Types::Int, "The number of reports of this resource", null: true
14
+ field :reported_content, GraphQL::Types::String, "The content that has been reported", null: true
15
+ field :reported_url, GraphQL::Types::String, "The URL of the resource that was reported", null: true
16
+ field :reports, [Decidim::Core::ReportableType, { null: true }], "The reports of this resource", null: true
17
+
18
+ def reported_url
19
+ return "" unless object.reportable.respond_to?(:reported_content_url)
20
+
21
+ object.reportable.reported_content_url
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Core
5
+ class ParticipantDetailsType < Decidim::Api::Types::BaseObject
6
+ description "details of a participant"
7
+
8
+ field :email, GraphQL::Types::String, "The user's email", null: false
9
+ field :name, GraphQL::Types::String, "The user's name", null: false
10
+ field :nickname, GraphQL::Types::String, "The user's nickname", null: false
11
+
12
+ def self.authorized?(object, context)
13
+ super && allowed_to?(:read, :admin_dashboard, object, context, scope: :admin)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Core
5
+ # This type represents a content report
6
+ class ReportableType < Decidim::Api::Types::BaseObject
7
+ description "A report object"
8
+
9
+ implements Decidim::Core::TimestampsInterface
10
+
11
+ field :details, GraphQL::Types::String, "The details of this report", null: false
12
+ field :id, GraphQL::Types::ID, "The ID of this reportable", null: false
13
+ field :locale, GraphQL::Types::String, "The locale of the reportable", null: false
14
+ field :reason, GraphQL::Types::String, "The reason of this report", null: false
15
+ field :user, UserType, "The author of this report", null: true
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Core
5
+ # This type represents an user report
6
+ class ReportableUserType < Decidim::Api::Types::BaseObject
7
+ description "An user report"
8
+
9
+ implements Decidim::Core::TimestampsInterface
10
+
11
+ field :details, GraphQL::Types::String, "The details of this report", null: false
12
+ field :id, GraphQL::Types::ID, "The ID of this report", null: false
13
+ field :reason, GraphQL::Types::String, "The reason of this report", null: false
14
+ field :user, UserType, "The author of this report", null: true
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Core
5
+ # This type represents a topic's page
6
+ class StaticPageTopicType < Decidim::Api::Types::BaseObject
7
+ description "The current organization static page topics"
8
+
9
+ field :description, Decidim::Core::TranslatedFieldType, "The description of this static page topic", null: false
10
+ field :id, GraphQL::Types::ID, "Internal ID of this static page topic", null: false
11
+ field :show_in_footer, GraphQL::Types::Boolean, "Whether this static page topic should be shown in the footer", null: false
12
+ field :static_pages, [Decidim::Core::StaticPageType, { null: true }], "The static pages associated to this static page topic", null: true, method: :pages
13
+ field :title, Decidim::Core::TranslatedFieldType, "The title of this static page topic", null: false
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Core
5
+ # This type represents a page
6
+ class StaticPageType < Decidim::Api::Types::BaseObject
7
+ description "The current organization static pages"
8
+
9
+ implements Decidim::Core::TimestampsInterface
10
+
11
+ field :content, Decidim::Core::TranslatedFieldType, "The content of this page", null: true
12
+ field :id, GraphQL::Types::ID, "The id of this page", null: false
13
+ field :title, Decidim::Core::TranslatedFieldType, "The title of this page", null: false
14
+ field :topic, Decidim::Core::StaticPageTopicType, "The topic of this page", null: true
15
+ field :url, GraphQL::Types::String, "The URL of this page", null: false
16
+
17
+ def url
18
+ Decidim::EngineRouter.new("decidim", { host: object.organization.host }).page_url(object)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -6,10 +6,12 @@ module Decidim
6
6
  description "A taxonomy that can be applied to other resources."
7
7
 
8
8
  field :children, [Decidim::Core::TaxonomyType], "The children of this taxonomy.", null: false
9
+ field :children_count, GraphQL::Types::Int, "The number of children of this taxonomy."
9
10
  field :id, GraphQL::Types::ID, "The id of this taxonomy.", null: false
10
11
  field :is_root, Boolean, "Whether this taxonomy is a root taxonomy (root taxonomies have no parents).", null: false, method: :root?
11
12
  field :name, Decidim::Core::TranslatedFieldType, "The name of this taxonomy.", null: false
12
13
  field :parent, Decidim::Core::TaxonomyType, "The parent of this taxonomy.", null: true
14
+ field :taxonomizations_count, GraphQL::Types::Int, "The number of taxonomizations of this taxonomy."
13
15
  end
14
16
  end
15
17
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Core
5
+ # This type represents a user moderation
6
+ class UserModerationType < Decidim::Api::Types::BaseObject
7
+ description "A moderated user detail"
8
+
9
+ implements Decidim::Core::TimestampsInterface
10
+
11
+ field :about, GraphQL::Types::String, "The about data of this user", null: true
12
+ field :block_reasons, GraphQL::Types::String, "The reasons why the user was blocked", null: true
13
+ field :blocked_at, Decidim::Core::DateTimeType, "The date at which the user was blocked", null: true
14
+ field :blocking_user, UserType, "The user who blocked the user", null: true
15
+ field :id, GraphQL::Types::ID, "The ID of the moderation", null: false
16
+ field :reports, [Decidim::Core::ReportableUserType, { null: true }], "The reports for this user", null: true
17
+ field :user_id, GraphQL::Types::ID, "The ID of this user'", null: false, method: :decidim_user_id
18
+
19
+ def about
20
+ object.user.presenter.about
21
+ end
22
+
23
+ def block_reasons
24
+ object.blocking.justification
25
+ end
26
+
27
+ def blocked_at
28
+ object.user.blocked_at
29
+ end
30
+
31
+ def blocking_user
32
+ object.blocking.blocking_user
33
+ end
34
+ end
35
+ end
36
+ end
@@ -7,18 +7,25 @@ module Decidim
7
7
  description "A user"
8
8
 
9
9
  implements Decidim::Core::AuthorInterface
10
+ implements Decidim::Core::FollowableInterface
11
+ implements Decidim::Core::TimestampsInterface
10
12
 
13
+ field :about, GraphQL::Types::String, "The user's about data", null: true
11
14
  field :avatar_url, GraphQL::Types::String, "The user's avatar url", null: false
12
15
  field :badge, GraphQL::Types::String, "A badge for the user", null: false
16
+ field :badges, [Decidim::Core::BadgeScoreType, { null: true }], "The user's badges", null: true
13
17
  field :deleted, GraphQL::Types::Boolean, "Whether the user's account has been deleted or not", null: false
14
18
  field :direct_messages_enabled, GraphQL::Types::String,
15
19
  null: false,
16
20
  description: ["If the user making the request is logged in, it will return whether this recipient accepts a conversation or not.",
17
21
  " It will return false for non-logged requests."].join
22
+ field :followers_count, GraphQL::Types::Int, "The number of users following this user", null: true
23
+ field :following_count, GraphQL::Types::Int, "The number of users this user is following", null: true
18
24
  field :id, GraphQL::Types::ID, "The user's id", null: false
19
25
  field :name, GraphQL::Types::String, "The user's name", null: false
20
26
  field :nickname, GraphQL::Types::String, "The user's nickname", null: false
21
27
  field :organization_name, Decidim::Core::TranslatedFieldType, "The user's organization name", null: false
28
+ field :personal_url, GraphQL::Types::String, "The user's personal url", null: true
22
29
  field :profile_path, GraphQL::Types::String, "The user's profile url", null: false
23
30
 
24
31
  def nickname
@@ -49,6 +56,12 @@ module Decidim
49
56
  object.presenter.badge
50
57
  end
51
58
 
59
+ def badges
60
+ return [] unless object.organization.badges_enabled?
61
+
62
+ Decidim::Gamification::BadgeScore.where(user_id: object.id)
63
+ end
64
+
52
65
  def self.authorized?(object, context)
53
66
  super && object.confirmed? && !object.blocked? && !object.deleted?
54
67
  end
@@ -22,7 +22,7 @@ module Decidim
22
22
 
23
23
  # Generates the correct URL to the asset with the provided options.
24
24
  #
25
- # @param options [Hash] The options for the URL that are the normal route
25
+ # Accepts the options for the URL that are the normal route
26
26
  # options Rails route helpers accept
27
27
  # @return [String] The full URL to the asset or when host cannot be
28
28
  # resolved, the asset path.
@@ -26,7 +26,7 @@ module Decidim
26
26
  class Storage
27
27
  # Initializes the router.
28
28
  #
29
- # @param [ActiveStorage::Attached, ActiveStorage::Blob] The asset to route
29
+ # @param asset [ActiveStorage::Attached, ActiveStorage::Blob] The asset to route
30
30
  # to
31
31
  def initialize(asset)
32
32
  @asset = asset
@@ -41,7 +41,7 @@ module Decidim
41
41
 
42
42
  # Generates the correct URL to the asset with the provided options.
43
43
  #
44
- # @param options The options for the URL that are the normal route options
44
+ # Accepts any options for the URL that are the normal route options
45
45
  # Rails route helpers accept
46
46
  # @return [String] The URL of the asset
47
47
  def url(**options)
@@ -115,8 +115,8 @@ module Decidim
115
115
  # already when the logic below is unnecessary. This logic is needed e.g.
116
116
  # for serializers where the request context is not available.
117
117
  #
118
- # @param record The record for which to check the organization
119
- # @param opts Options for building the URL
118
+ # @param record [Object] The record for which to check the organization
119
+ # @param opts [Hash] Options for building the URL
120
120
  # @return [void]
121
121
  def ensure_current_host(record, **opts)
122
122
  return if asset_url_available?
@@ -141,7 +141,7 @@ module Decidim
141
141
 
142
142
  # Determines the organization for the passed record.
143
143
  #
144
- # @param record The record for which to fetch the organization
144
+ # @param record [Object] The record for which to fetch the organization
145
145
  # @return [Decidim::Organization, nil] The organization for the record or
146
146
  # `nil` if the organization cannot be determined
147
147
  def organization_for(record)
@@ -154,8 +154,7 @@ module Decidim
154
154
 
155
155
  # Returns the URL for the given blob object.
156
156
  #
157
- # @param blob The blob object
158
- # @param options Options for building the URL
157
+ # @param options [Hash] Options for building the URL
159
158
  # @return [String, nil] The URL to the blob object or `nil` if the blob is
160
159
  # not defined.
161
160
  def blob_url(**options)
@@ -207,7 +206,8 @@ module Decidim
207
206
  # because once the image is stored at the storage service, it already has
208
207
  # the correct file extension.
209
208
  #
210
- # @param options The options for building the URL
209
+ # Accepts any options for the URL that are the normal route options
210
+ # Rails route helpers accept
211
211
  # @return [String, nil] The converted representation URL or `nil` if the
212
212
  # asset is not defined.
213
213
  def rails_representation_url(**)
@@ -235,7 +235,7 @@ module Decidim
235
235
  # variant has to be served through the service's own representation URL
236
236
  # causing it to be processed and stored at the storage service.
237
237
  #
238
- # @param options The options for building the URL
238
+ # @param options [Hash] The options for building the URL
239
239
  # @return [String, nil] The variant URL at the storage service or `nil` if
240
240
  # the variant has not been processed yet and does not yet exist at the
241
241
  # storage service or `nil` when the asset is not defined
@@ -68,7 +68,7 @@ module.exports = {
68
68
  sans: ["Source Sans Pro", "ui-sans-serif", "system-ui", "sans-serif"]
69
69
  },
70
70
  fontSize: {
71
- xs: ["13px", "16px"],
71
+ xs: ["12px", "16px"],
72
72
  sm: ["14px", "18px"],
73
73
  md: ["16px", "20px"],
74
74
  lg: ["18px", "23px"],
@@ -81,6 +81,9 @@ module.exports = {
81
81
  extend: {
82
82
  transitionProperty: {
83
83
  'top': 'top',
84
+ },
85
+ screens: {
86
+ 'xs': '375px'
84
87
  }
85
88
  }
86
89
  },
@@ -15,24 +15,39 @@ module Decidim
15
15
  #
16
16
  # name - The attribute's name
17
17
  #
18
- #
19
18
  # Example:
20
19
  #
21
- # attachment_attribute :photos
20
+ # attachments_attribute :photos
22
21
  # # This will create two attributes of the following types:
23
22
  # # attribute :photos, Array[Integer]
24
23
  # # attribute :add_photos, Array
25
- # # In addition, it will generate the getter method for the attribute
26
- # # returning an array of the Decidim::Attachment records.
24
+ # # In addition, it will generate:
25
+ # # - A setter that handles String (JSON/CSV), Integer, or Array inputs.
26
+ # # - A getter that falls back to add_photos when the attribute is blank.
27
+ # # - Private helpers for parsing and extracting IDs.
27
28
  #
28
29
  # Returns nothing.
29
- def attachments_attribute(name)
30
+ def attachments_attribute(name) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
30
31
  attribute name, Array[Integer]
31
32
  attribute :"add_#{name}", Array
32
33
 
33
- # Define the getter method that fetches the attachment records based on
34
- # their types. For Strings and Integers, assumes they are IDs and will
35
- # fetch the attachment record matching that ID.
34
+ # Setter: coerces String (JSON or comma-separated IDs) and bare Integer
35
+ # values into the expected Array[Integer] format before delegating to super.
36
+ define_method :"#{name}=" do |value|
37
+ case value
38
+ when String
39
+ parsed = send(:"parse_string_#{name}", value)
40
+ parsed.any? ? super(parsed) : super(value)
41
+ when Integer
42
+ super([value])
43
+ else
44
+ super(value)
45
+ end
46
+ end
47
+
48
+ # Getter: resolves stored integer IDs to Decidim::Attachment records,
49
+ # caching the result on the instance. Falls back to extracting IDs from
50
+ # add_<name> when the attribute itself is blank, then resolves those too.
36
51
  variable_name = "@#{name}_records"
37
52
  define_method name do
38
53
  return instance_variable_get(variable_name) if instance_variable_defined?(variable_name)
@@ -40,9 +55,15 @@ module Decidim
40
55
  original = @attributes[name.to_s].value_before_type_cast
41
56
  return original if original && !original.is_a?(Array)
42
57
 
58
+ ids = if super().blank? && send(:"add_#{name}").present?
59
+ send(:"extract_ids_from_add_#{name}")
60
+ else
61
+ super()
62
+ end
63
+
43
64
  instance_variable_set(
44
65
  variable_name,
45
- super().map do |attachment|
66
+ ids.map do |attachment|
46
67
  if attachment.is_a?(Integer)
47
68
  Decidim::Attachment.find_by(id: attachment)
48
69
  else
@@ -51,6 +72,34 @@ module Decidim
51
72
  end.compact
52
73
  )
53
74
  end
75
+
76
+ # Private helpers -------------------------------------------------------
77
+
78
+ define_method :"extract_ids_from_add_#{name}" do
79
+ send(:"add_#{name}")
80
+ .select { |item| item.is_a?(Hash) && (item[:id].present? || item["id"].present?) }
81
+ .map { |item| (item[:id] || item["id"]).to_i }
82
+ end
83
+
84
+ define_method :"parse_string_#{name}" do |value|
85
+ return [] if value.blank?
86
+
87
+ send(:"parse_#{name}_ids", value)
88
+ end
89
+
90
+ define_method :"parse_#{name}_ids" do |value|
91
+ ids = begin
92
+ Array(JSON.parse(value))
93
+ rescue JSON::ParserError
94
+ value.split(",").map(&:strip)
95
+ end
96
+
97
+ ids.map(&:to_i).reject(&:zero?)
98
+ end
99
+
100
+ private :"extract_ids_from_add_#{name}"
101
+ private :"parse_string_#{name}"
102
+ private :"parse_#{name}_ids"
54
103
  end
55
104
  end
56
105
  end
@@ -2,11 +2,23 @@
2
2
 
3
3
  module Decidim
4
4
  class AttributeEncryptor
5
- def self.encrypt(string)
6
- cryptor.encrypt_and_sign(string) if string.present?
5
+ attr_reader :secret, :hash_digest_class, :secret_key_base, :key_len, :is_retry
6
+
7
+ def initialize(secret: "attribute", **options)
8
+ @secret = secret
9
+ @hash_digest_class = options.fetch(:hash_digest_class, Rails.application.config.active_support.hash_digest_class)
10
+ @secret_key_base = options.fetch(:secret_key_base, Rails.application.secret_key_base)
11
+ @key_len = options.fetch(:key_len, ActiveSupport::MessageEncryptor.key_len)
12
+ @is_retry = options.fetch(:is_retry, false)
7
13
  end
8
14
 
9
- def self.decrypt(string_encrypted)
15
+ def encrypt(string)
16
+ return if string.blank?
17
+
18
+ encryptor.encrypt_and_sign(string)
19
+ end
20
+
21
+ def decrypt(string_encrypted)
10
22
  return if string_encrypted.blank?
11
23
 
12
24
  # `ActiveSupport::MessageEncryptor` expects all values passed to the
@@ -15,16 +27,45 @@ module Decidim
15
27
  # If something else is passed, just return the value as is.
16
28
  return string_encrypted unless string_encrypted.is_a?(String)
17
29
 
18
- cryptor.decrypt_and_verify(string_encrypted)
30
+ encryptor.decrypt_and_verify(string_encrypted)
31
+ rescue ActiveSupport::MessageEncryptor::InvalidMessage => e
32
+ # Since we have migrated from SHA1 to SHA256, we need to ensure that any encrypted string not migrated is still being decrypted successfully.
33
+ # There are some resources that are still using SHA1, so we need to retry with the legacy encryptor.
34
+ # Some of those resources are:
35
+ # - Newsletter unsubscribe links (being sent to users via email)
36
+ raise e if is_retry
37
+
38
+ legacy_encryptor.decrypt(string_encrypted)
39
+ end
40
+
41
+ def self.encrypt(string)
42
+ cryptor.encrypt(string)
43
+ end
44
+
45
+ def self.decrypt(string_encrypted)
46
+ cryptor.decrypt(string_encrypted)
19
47
  end
20
48
 
21
49
  def self.cryptor
22
- @cryptor ||= begin
23
- key = ActiveSupport::KeyGenerator.new("attribute", hash_digest_class: OpenSSL::Digest::SHA1).generate_key(
24
- Rails.application.secret_key_base, ActiveSupport::MessageEncryptor.key_len
25
- )
26
- ActiveSupport::MessageEncryptor.new(key)
27
- end
50
+ @cryptor ||= new(secret: "attribute")
51
+ end
52
+
53
+ private
54
+
55
+ def legacy_encryptor
56
+ @legacy_encryptor ||= self.class.new(secret:, hash_digest_class: OpenSSL::Digest::SHA1, is_retry: true)
57
+ end
58
+
59
+ def encryptor
60
+ @encryptor ||= ActiveSupport::MessageEncryptor.new(key)
61
+ end
62
+
63
+ def key
64
+ @key ||= key_generator.generate_key(secret_key_base, key_len)
65
+ end
66
+
67
+ def key_generator
68
+ @key_generator ||= ActiveSupport::KeyGenerator.new(secret, hash_digest_class:)
28
69
  end
29
70
  end
30
71
  end
@@ -107,11 +107,6 @@ module Decidim
107
107
  # through symbols by calling `obj.attributes[:key]` or
108
108
  # `obj.attributes.slice(:key1, :key2)`. In the legacy Virtus models, this
109
109
  # returned a hash with symbol keys.
110
- #
111
- # Deprecated:
112
- # Attributes access through symbols is deprecated and may be removed in
113
- # future versions. Please refactor all your attributes calls to access the
114
- # attributes through string keys.
115
110
  def attributes
116
111
  super.with_indifferent_access
117
112
  end
@@ -8,7 +8,7 @@ module Decidim
8
8
  class BlockRegistry
9
9
  # Provides access to the registered blocks with their names.
10
10
  #
11
- # @return [Hash<Symbol => Proc>] A hash of the currently registered blocks
11
+ # @return [Hash{Symbol => Proc}] A hash of the currently registered blocks
12
12
  # with their keys as the hash keys and the blocks as the hash values.
13
13
  def registrations
14
14
  @registrations ||= {}
@@ -138,7 +138,8 @@ module Decidim
138
138
  # Adds a new coauthor to the list of coauthors. The coauthorship is created with
139
139
  # current object as coauthorable and `user` param as author.
140
140
  #
141
- # @param author: The new coauthor.
141
+ # @param author [Decidim::User] The new coauthor.
142
+ # @param extra_attributes [Hash{Symbol => Object}]
142
143
  # @extra_attrs: Extra
143
144
  def add_coauthor(author, extra_attributes = {})
144
145
  return if coauthorships.exists?(decidim_author_id: author.id, decidim_author_type: author.class.base_class.name)