decidim-core 0.29.2 → 0.30.0.rc2

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 (484) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/amendable/amend_button_card/show.erb +6 -4
  3. data/app/cells/decidim/amendable/amend_button_card_cell.rb +8 -0
  4. data/app/cells/decidim/amendable/amendments/show.erb +1 -1
  5. data/app/cells/decidim/amendable/promote_button_card/show.erb +2 -0
  6. data/app/cells/decidim/author_cell.rb +1 -1
  7. data/app/cells/decidim/card_l/extra_data.erb +1 -0
  8. data/app/cells/decidim/card_metadata_cell.rb +9 -16
  9. data/app/cells/decidim/comments_button_cell.rb +14 -2
  10. data/app/cells/decidim/content_blocks/highlighted_elements_cell.rb +2 -0
  11. data/app/cells/decidim/content_blocks/highlighted_elements_with_cell_for_list_cell.rb +1 -1
  12. data/app/cells/decidim/endorsement_block/show.erb +0 -1
  13. data/app/cells/decidim/endorsement_block_cell.rb +6 -0
  14. data/app/cells/decidim/endorsement_buttons/button_content.erb +1 -1
  15. data/app/cells/decidim/endorsement_buttons/select_identity_button.erb +1 -1
  16. data/app/cells/decidim/endorsement_buttons/show.erb +7 -7
  17. data/app/cells/decidim/endorsement_buttons/verification_modal.erb +4 -2
  18. data/app/cells/decidim/endorsers_list/empty.erb +3 -0
  19. data/app/cells/decidim/endorsers_list/full.erb +17 -5
  20. data/app/cells/decidim/endorsers_list/show.erb +19 -10
  21. data/app/cells/decidim/endorsers_list_cell.rb +19 -6
  22. data/app/cells/decidim/follow_button/show.erb +1 -2
  23. data/app/cells/decidim/follow_button_cell.rb +5 -0
  24. data/app/cells/decidim/map/show.erb +3 -0
  25. data/app/cells/decidim/map/template.erb +14 -0
  26. data/app/cells/decidim/map_cell.rb +39 -0
  27. data/app/cells/decidim/notification_actions/buttons_cell.rb +1 -1
  28. data/app/cells/decidim/onboarding_action_message/show.erb +15 -0
  29. data/app/cells/decidim/onboarding_action_message_cell.rb +81 -0
  30. data/app/cells/decidim/participatory_space_private_user/show.erb +23 -0
  31. data/app/cells/decidim/participatory_space_private_user_cell.rb +21 -0
  32. data/app/cells/decidim/progress_bar/show.erb +2 -2
  33. data/app/cells/decidim/report_button_cell.rb +1 -0
  34. data/app/cells/decidim/resource_history/show.erb +20 -0
  35. data/app/cells/decidim/resource_history_cell.rb +66 -0
  36. data/app/cells/decidim/share_button_cell.rb +0 -4
  37. data/app/cells/decidim/share_widget/modal.erb +26 -0
  38. data/app/cells/decidim/share_widget/show.erb +2 -0
  39. data/app/cells/decidim/share_widget_cell.rb +20 -0
  40. data/app/cells/decidim/tags/show.erb +7 -4
  41. data/app/cells/decidim/tags_cell.rb +11 -72
  42. data/app/commands/decidim/amendable/create_draft.rb +2 -2
  43. data/app/commands/decidim/create_ephemeral_user.rb +52 -0
  44. data/app/commands/decidim/create_omniauth_registration.rb +13 -3
  45. data/app/commands/decidim/create_report.rb +1 -5
  46. data/app/commands/decidim/create_user_group.rb +6 -2
  47. data/app/commands/decidim/destroy_ephemeral_user.rb +47 -0
  48. data/app/commands/decidim/update_account.rb +11 -3
  49. data/app/commands/decidim/update_notifications_settings.rb +1 -0
  50. data/app/commands/decidim/update_resources_taxonomies.rb +67 -0
  51. data/app/commands/decidim/update_user_group.rb +7 -1
  52. data/app/constraints/decidim/current_component.rb +1 -1
  53. data/app/controllers/concerns/decidim/ajax_permission_handler.rb +21 -0
  54. data/app/controllers/concerns/decidim/devise_authentication_methods.rb +3 -6
  55. data/app/controllers/concerns/decidim/devise_controllers.rb +2 -0
  56. data/app/controllers/concerns/decidim/disable_redirection_to_external_host.rb +1 -1
  57. data/app/controllers/concerns/decidim/ephemeral_session_checker.rb +87 -0
  58. data/app/controllers/concerns/decidim/filter_resource.rb +4 -2
  59. data/app/controllers/concerns/decidim/has_members_page.rb +25 -0
  60. data/app/controllers/concerns/decidim/headers/browser_feature_permissions.rb +50 -0
  61. data/app/controllers/concerns/decidim/locale_switcher.rb +2 -2
  62. data/app/controllers/concerns/decidim/needs_password_change.rb +0 -1
  63. data/app/controllers/concerns/decidim/needs_permission.rb +2 -1
  64. data/app/controllers/concerns/decidim/needs_tos_accepted.rb +4 -5
  65. data/app/controllers/concerns/decidim/onboarding_action_methods.rb +52 -0
  66. data/app/controllers/decidim/application_controller.rb +10 -0
  67. data/app/controllers/decidim/authorization_modals_controller.rb +8 -2
  68. data/app/controllers/decidim/components/base_controller.rb +3 -7
  69. data/app/controllers/decidim/devise/confirmations_controller.rb +4 -0
  70. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +8 -1
  71. data/app/controllers/decidim/devise/registrations_controller.rb +1 -1
  72. data/app/controllers/decidim/devise/sessions_controller.rb +2 -0
  73. data/app/controllers/decidim/download_your_data_controller.rb +33 -2
  74. data/app/controllers/decidim/editor_images_controller.rb +1 -11
  75. data/app/controllers/decidim/follows_controller.rb +1 -1
  76. data/app/controllers/decidim/geolocation_controller.rb +19 -0
  77. data/app/controllers/decidim/homepage_controller.rb +0 -1
  78. data/app/controllers/decidim/open_data_controller.rb +33 -8
  79. data/app/controllers/decidim/user_conversations_controller.rb +1 -11
  80. data/app/events/decidim/soft_delete_resource_event.rb +15 -0
  81. data/app/forms/decidim/amendable/form.rb +4 -2
  82. data/app/forms/decidim/ephemeral_user_form.rb +22 -0
  83. data/app/forms/decidim/notifications_settings_form.rb +1 -0
  84. data/app/forms/decidim/omniauth_registration_form.rb +14 -1
  85. data/app/helpers/concerns/decidim/flash_helper_extensions.rb +17 -2
  86. data/app/helpers/decidim/action_authorization_helper.rb +75 -14
  87. data/app/helpers/decidim/amendments_helper.rb +0 -9
  88. data/app/helpers/decidim/application_helper.rb +6 -2
  89. data/app/helpers/decidim/breadcrumb_helper.rb +6 -0
  90. data/app/helpers/decidim/cache_helper.rb +1 -1
  91. data/app/helpers/decidim/check_boxes_tree_helper.rb +25 -53
  92. data/app/helpers/decidim/decidim_form_helper.rb +0 -44
  93. data/app/helpers/decidim/endorsable_helper.rb +0 -10
  94. data/app/helpers/decidim/layout_helper.rb +6 -0
  95. data/app/helpers/decidim/messaging/conversation_helper.rb +2 -3
  96. data/app/helpers/decidim/meta_tags_helper.rb +32 -23
  97. data/app/helpers/decidim/modal_helper.rb +23 -0
  98. data/app/helpers/decidim/omniauth_helper.rb +5 -5
  99. data/app/helpers/decidim/onboarding_action_helper.rb +13 -0
  100. data/app/helpers/decidim/orders_helper.rb +2 -1
  101. data/app/helpers/decidim/participatory_space_helpers.rb +1 -1
  102. data/app/helpers/decidim/passwords_helper.rb +2 -2
  103. data/app/helpers/decidim/taxonomies_helper.rb +40 -0
  104. data/app/jobs/decidim/download_your_data_export_job.rb +2 -19
  105. data/app/jobs/decidim/event_publisher_job.rb +18 -9
  106. data/app/jobs/decidim/export_job.rb +5 -1
  107. data/app/jobs/decidim/export_participatory_space_job.rb +4 -1
  108. data/app/jobs/decidim/hide_child_resources_job.rb +24 -0
  109. data/app/jobs/decidim/open_data_job.rb +4 -4
  110. data/app/mailers/decidim/export_mailer.rb +7 -12
  111. data/app/models/decidim/action_log.rb +11 -0
  112. data/app/models/decidim/category.rb +4 -0
  113. data/app/models/decidim/component.rb +25 -3
  114. data/app/models/decidim/metric.rb +2 -1
  115. data/app/models/decidim/moderation.rb +16 -0
  116. data/app/models/decidim/newsletter.rb +12 -8
  117. data/app/models/decidim/organization.rb +7 -3
  118. data/app/models/decidim/participatory_space_private_user.rb +20 -0
  119. data/app/models/decidim/private_export.rb +24 -0
  120. data/app/models/decidim/push_notification_message.rb +1 -1
  121. data/app/models/decidim/report.rb +1 -1
  122. data/app/models/decidim/scope.rb +4 -0
  123. data/app/models/decidim/share_token.rb +36 -10
  124. data/app/models/decidim/taxonomization.rb +23 -0
  125. data/app/models/decidim/taxonomy.rb +139 -0
  126. data/app/models/decidim/taxonomy_filter.rb +130 -0
  127. data/app/models/decidim/taxonomy_filter_item.rb +33 -0
  128. data/app/models/decidim/user.rb +9 -23
  129. data/app/models/decidim/user_base_entity.rb +12 -0
  130. data/app/models/decidim/user_moderation.rb +9 -0
  131. data/app/models/decidim/user_report.rb +4 -0
  132. data/app/packs/entrypoints/decidim_core.js +1 -0
  133. data/app/packs/entrypoints/decidim_geocoding.js +2 -0
  134. data/app/packs/images/decidim/brands/facebook.svg +10 -0
  135. data/app/packs/images/decidim/brands/google.svg +7 -1
  136. data/app/packs/images/decidim/brands/twitter-x.svg +3 -0
  137. data/app/packs/src/decidim/check_boxes_tree.js +0 -1
  138. data/app/packs/src/decidim/clipboard.js +18 -9
  139. data/app/packs/src/decidim/confirm.js +79 -59
  140. data/app/packs/src/decidim/decidim_application.js +1 -0
  141. data/app/packs/src/decidim/form_remote.js +1 -1
  142. data/app/packs/src/decidim/geocoding/reverse_geocoding.js +60 -0
  143. data/app/packs/src/decidim/impersonation.js +1 -1
  144. data/app/packs/src/decidim/index.js +11 -1
  145. data/app/packs/src/decidim/map/provider/here.js +1 -1
  146. data/app/packs/src/decidim/onboarding_pending_action.js +24 -0
  147. data/app/packs/src/decidim/session_timeouter.js +1 -1
  148. data/app/packs/src/decidim/sticky_footer.js +29 -0
  149. data/app/packs/src/decidim/sticky_header.js +6 -31
  150. data/app/packs/src/decidim/user_registrations.js +13 -0
  151. data/app/packs/src/decidim/utilities/dom.js +148 -0
  152. data/app/packs/stylesheets/decidim/_accordion.scss +30 -0
  153. data/app/packs/stylesheets/decidim/_buttons.scss +19 -0
  154. data/app/packs/stylesheets/decidim/_dropdown.scss +1 -1
  155. data/app/packs/stylesheets/decidim/_endorsers_list.scss +26 -20
  156. data/app/packs/stylesheets/decidim/_forms.scss +2 -2
  157. data/app/packs/stylesheets/decidim/_hashtags.scss +5 -0
  158. data/app/packs/stylesheets/decidim/_header.scss +5 -3
  159. data/app/packs/stylesheets/decidim/_layout.scss +32 -2
  160. data/app/packs/stylesheets/decidim/_login.scss +53 -6
  161. data/app/packs/stylesheets/decidim/_modal.scss +42 -0
  162. data/app/packs/stylesheets/decidim/_modal_tos_refuse.scss +4 -0
  163. data/app/packs/stylesheets/decidim/_participatory_spaces.scss +46 -0
  164. data/app/packs/stylesheets/decidim/_profile.scss +1 -1
  165. data/app/packs/stylesheets/decidim/_success_image.scss +64 -0
  166. data/app/packs/stylesheets/decidim/_tribute.scss +36 -0
  167. data/app/packs/stylesheets/decidim/application.scss +2 -0
  168. data/app/packs/stylesheets/decidim/geocoding_addons.scss +5 -0
  169. data/app/packs/stylesheets/decidim/map.scss +7 -10
  170. data/app/packs/stylesheets/decidim/resource_history.scss +31 -0
  171. data/app/permissions/decidim/permissions.rb +8 -2
  172. data/app/presenters/decidim/admin_log/base_user_presenter.rb +67 -0
  173. data/app/presenters/decidim/admin_log/component_presenter.rb +32 -3
  174. data/app/presenters/decidim/admin_log/moderation_presenter.rb +30 -3
  175. data/app/presenters/decidim/admin_log/share_token_presenter.rb +39 -0
  176. data/app/presenters/decidim/admin_log/taxonomy_filter_presenter.rb +57 -0
  177. data/app/presenters/decidim/admin_log/taxonomy_presenter.rb +48 -0
  178. data/app/presenters/decidim/admin_log/user_group_presenter.rb +6 -6
  179. data/app/presenters/decidim/admin_log/user_presenter.rb +4 -18
  180. data/app/presenters/decidim/log/value_types/date_presenter.rb +1 -0
  181. data/app/presenters/decidim/log/value_types/taxonomy_presenter.rb +29 -0
  182. data/app/presenters/decidim/participatory_space_private_user_presenter.rb +50 -0
  183. data/app/presenters/decidim/taxonomy_filter_presenter.rb +19 -0
  184. data/app/presenters/decidim/taxonomy_presenter.rb +14 -0
  185. data/app/queries/decidim/metrics/blocked_users_metric_manage.rb +2 -2
  186. data/app/queries/decidim/metrics/users_metric_manage.rb +2 -2
  187. data/app/queries/decidim/public_activities.rb +1 -12
  188. data/app/queries/decidim/stats_users_count.rb +2 -2
  189. data/app/resolvers/decidim/meta_image_url_resolver.rb +128 -0
  190. data/app/serializers/decidim/exporters/open_data_blocked_user_serializer.rb +25 -0
  191. data/app/serializers/decidim/exporters/open_data_metric_serializer.rb +22 -0
  192. data/app/serializers/decidim/exporters/open_data_moderation_serializer.rb +30 -0
  193. data/app/serializers/decidim/exporters/open_data_taxonomy_serializer.rb +30 -0
  194. data/app/serializers/decidim/exporters/open_data_user_group_serializer.rb +38 -0
  195. data/app/serializers/decidim/exporters/open_data_user_serializer.rb +39 -0
  196. data/app/serializers/decidim/exporters/participatory_space_serializer.rb +104 -0
  197. data/app/serializers/decidim/exporters/serializer.rb +25 -0
  198. data/app/serializers/decidim/schema_org_breadcrumb_list_serializer.rb +52 -0
  199. data/app/services/decidim/action_authorizer.rb +32 -3
  200. data/app/services/decidim/base_diff_renderer.rb +1 -1
  201. data/app/services/decidim/download_your_data_exporter.rb +58 -24
  202. data/app/services/decidim/onboarding_manager.rb +272 -0
  203. data/app/services/decidim/open_data_exporter.rb +139 -13
  204. data/app/services/decidim/traceability.rb +13 -0
  205. data/app/uploaders/decidim/application_uploader.rb +1 -1
  206. data/app/validators/etiquette_validator.rb +9 -2
  207. data/app/validators/passthru_validator.rb +1 -1
  208. data/app/validators/translated_etiquette_validator.rb +32 -0
  209. data/app/views/decidim/account/_password_fields.html.erb +2 -2
  210. data/app/views/decidim/application/_accordion_section.html.erb +14 -0
  211. data/app/views/decidim/application/_collection.html.erb +30 -18
  212. data/app/views/decidim/devise/omniauth_registrations/new.html.erb +5 -1
  213. data/app/views/decidim/devise/omniauth_registrations/new_tos_fields.html.erb +29 -0
  214. data/app/views/decidim/devise/registrations/new.html.erb +10 -22
  215. data/app/views/decidim/devise/sessions/new.html.erb +24 -29
  216. data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +2 -4
  217. data/app/views/decidim/devise/shared/_tos_fields.html.erb +16 -0
  218. data/app/views/decidim/download_your_data/_export.html.erb +15 -0
  219. data/app/views/decidim/download_your_data/show.html.erb +51 -5
  220. data/app/views/decidim/endorsements/update_buttons_and_counters.js.erb +16 -19
  221. data/app/views/decidim/export_mailer/download_your_data_export.html.erb +2 -2
  222. data/app/views/decidim/export_mailer/export.html.erb +5 -1
  223. data/app/views/decidim/notifications_settings/show.html.erb +22 -0
  224. data/app/views/decidim/open_data/_how_to_open_accordion_section.html.erb +15 -0
  225. data/app/views/decidim/open_data/index.html.erb +108 -0
  226. data/app/views/decidim/pages/show.html.erb +2 -1
  227. data/app/views/decidim/participatory_space_private_users/_participatory_space_private_user.html.erb +1 -0
  228. data/app/views/decidim/shared/_login_modal.html.erb +26 -20
  229. data/app/views/decidim/shared/_orders.html.erb +2 -2
  230. data/app/views/decidim/shared/_resource_actions.html.erb +21 -0
  231. data/app/views/decidim/shared/filters/_check_boxes_tree.html.erb +1 -2
  232. data/app/views/decidim/shared/filters/_collection.html.erb +1 -1
  233. data/app/views/decidim/shared/filters/_dropdown_label.html.erb +7 -4
  234. data/app/views/layouts/decidim/_application.html.erb +0 -1
  235. data/app/views/layouts/decidim/_js_configuration.html.erb +1 -0
  236. data/app/views/layouts/decidim/_logo.html.erb +1 -1
  237. data/app/views/layouts/decidim/_logo_mobile.html.erb +1 -1
  238. data/app/views/layouts/decidim/_meta_tags_config.html.erb +6 -11
  239. data/app/views/layouts/decidim/_schema_org_breadcrumb_list.html.erb +3 -0
  240. data/app/views/layouts/decidim/_wrapper.html.erb +15 -9
  241. data/app/views/layouts/decidim/footer/_main_links.html.erb +1 -1
  242. data/app/views/layouts/decidim/header/_close_ephemeral_session.html.erb +25 -0
  243. data/app/views/layouts/decidim/header/_main.html.erb +14 -10
  244. data/app/views/layouts/decidim/header/_menu_breadcrumb_items.html.erb +2 -0
  245. data/app/views/layouts/decidim/shared/_layout_item.html.erb +1 -1
  246. data/config/assets.rb +2 -1
  247. data/config/locales/ar.yml +27 -59
  248. data/config/locales/bg.yml +3 -64
  249. data/config/locales/ca.yml +370 -61
  250. data/config/locales/cs.yml +371 -54
  251. data/config/locales/de.yml +365 -54
  252. data/config/locales/el.yml +1 -48
  253. data/config/locales/en.yml +363 -54
  254. data/config/locales/eo.yml +0 -2
  255. data/config/locales/es-MX.yml +363 -57
  256. data/config/locales/es-PY.yml +363 -57
  257. data/config/locales/es.yml +367 -58
  258. data/config/locales/eu.yml +373 -65
  259. data/config/locales/fi-plain.yml +365 -57
  260. data/config/locales/fi.yml +370 -59
  261. data/config/locales/fr-CA.yml +178 -54
  262. data/config/locales/fr.yml +179 -52
  263. data/config/locales/ga-IE.yml +0 -21
  264. data/config/locales/gl.yml +1 -34
  265. data/config/locales/hu.yml +1 -53
  266. data/config/locales/id-ID.yml +1 -34
  267. data/config/locales/is-IS.yml +0 -16
  268. data/config/locales/it.yml +5 -60
  269. data/config/locales/ja.yml +215 -56
  270. data/config/locales/lb.yml +1 -52
  271. data/config/locales/lt.yml +1 -59
  272. data/config/locales/lv.yml +1 -40
  273. data/config/locales/nl.yml +1 -53
  274. data/config/locales/no.yml +2 -52
  275. data/config/locales/pl.yml +4 -66
  276. data/config/locales/pt-BR.yml +11 -52
  277. data/config/locales/pt.yml +2 -52
  278. data/config/locales/ro-RO.yml +219 -117
  279. data/config/locales/ru.yml +0 -20
  280. data/config/locales/sk.yml +1 -41
  281. data/config/locales/sv.yml +138 -59
  282. data/config/locales/tr-TR.yml +1 -50
  283. data/config/locales/uk.yml +0 -18
  284. data/config/locales/zh-CN.yml +1 -50
  285. data/config/locales/zh-TW.yml +1 -54
  286. data/config/routes.rb +4 -10
  287. data/db/migrate/20181025082245_add_timestamps_to_components.rb +2 -0
  288. data/db/migrate/20240628111905_add_visible_to_components.rb +7 -0
  289. data/db/migrate/20240704115429_create_decidim_taxonomies.rb +23 -0
  290. data/db/migrate/20240717093514_add_registered_only_to_decidim_share_tokens.rb +7 -0
  291. data/db/migrate/20240722215500_change_object_changes_on_versions.rb +39 -0
  292. data/db/migrate/20240806065417_create_decidim_taxonomy_filters.rb +23 -0
  293. data/db/migrate/20240822161348_add_deleted_at_to_decidim_components.rb +8 -0
  294. data/db/migrate/20240906162524_add_part_of_to_taxonomies.rb +26 -0
  295. data/db/migrate/20241001135825_add_role_to_participatory_space_private_users.rb +7 -0
  296. data/db/migrate/20241001140408_add_published_to_participatory_space_private_users.rb +7 -0
  297. data/db/migrate/20241022002600_create_private_exports.rb +18 -0
  298. data/db/migrate/20241028114430_add_component_counter_to_taxonomy_filters.rb +7 -0
  299. data/db/migrate/20241111104357_add_names_and_space_boolean_to_taxonomy_filters.rb +9 -0
  300. data/db/migrate/20241127093708_add_taxonomy_to_metrics.rb +7 -0
  301. data/db/migrate/20241204121445_add_participatory_space_manifests_from_taxonomy_filters.rb +9 -0
  302. data/decidim-core.gemspec +14 -17
  303. data/lib/decidim/action_authorization.rb +3 -2
  304. data/lib/decidim/amendable.rb +1 -1
  305. data/lib/decidim/api/input_filters/category_input_filter.rb +5 -3
  306. data/lib/decidim/api/input_filters/component_input_filter.rb +33 -20
  307. data/lib/decidim/api/input_filters/user_entity_input_filter.rb +53 -44
  308. data/lib/decidim/api/input_sorts/component_input_sort.rb +15 -13
  309. data/lib/decidim/api/input_sorts/user_entity_input_sort.rb +4 -4
  310. data/lib/decidim/api/interfaces/author_interface.rb +3 -2
  311. data/lib/decidim/api/interfaces/coauthorable_interface.rb +5 -5
  312. data/lib/decidim/api/interfaces/endorsable_interface.rb +2 -2
  313. data/lib/decidim/api/interfaces/participatory_space_interface.rb +5 -10
  314. data/lib/decidim/api/interfaces/taxonomizable_interface.rb +13 -0
  315. data/lib/decidim/api/types/amendment_type.rb +5 -7
  316. data/lib/decidim/api/types/area_api_type.rb +3 -3
  317. data/lib/decidim/api/types/attachment_type.rb +3 -3
  318. data/lib/decidim/api/types/category_type.rb +2 -2
  319. data/lib/decidim/api/types/decidim_type.rb +5 -1
  320. data/lib/decidim/api/types/fingerprint_type.rb +1 -1
  321. data/lib/decidim/api/types/localized_string_type.rb +1 -1
  322. data/lib/decidim/api/types/metric_history_type.rb +2 -0
  323. data/lib/decidim/api/types/metric_type.rb +1 -1
  324. data/lib/decidim/api/types/organization_type.rb +5 -0
  325. data/lib/decidim/api/types/participatory_space_link_type.rb +2 -2
  326. data/lib/decidim/api/types/participatory_space_manifest_type.rb +1 -1
  327. data/lib/decidim/api/types/quantifiable_translated_field_type.rb +1 -1
  328. data/lib/decidim/api/types/scope_api_type.rb +2 -3
  329. data/lib/decidim/api/types/session_type.rb +1 -2
  330. data/lib/decidim/api/types/taxonomy_type.rb +15 -0
  331. data/lib/decidim/api/types/trace_version_type.rb +2 -2
  332. data/lib/decidim/api/types/translated_field_type.rb +3 -5
  333. data/lib/decidim/api/types/user_group_type.rb +7 -20
  334. data/lib/decidim/api/types/user_type.rb +7 -20
  335. data/lib/decidim/asset_router/storage.rb +4 -4
  336. data/lib/decidim/assets/tailwind/tailwind.config.js.erb +2 -1
  337. data/lib/decidim/attachment_attributes.rb +1 -1
  338. data/lib/decidim/attribute_encryptor.rb +1 -1
  339. data/lib/decidim/attribute_object/nested_validator.rb +1 -1
  340. data/lib/decidim/attributes/integer_with_units.rb +27 -0
  341. data/lib/decidim/attributes.rb +2 -0
  342. data/lib/decidim/authorization_form_builder.rb +0 -7
  343. data/lib/decidim/coauthorable.rb +1 -1
  344. data/lib/decidim/command.rb +3 -3
  345. data/lib/decidim/commands/destroy_resource.rb +5 -1
  346. data/lib/decidim/commands/resource_handler.rb +2 -2
  347. data/lib/decidim/commands/restore_resource.rb +45 -0
  348. data/lib/decidim/commands/soft_delete_resource.rb +63 -0
  349. data/lib/decidim/component_manifest.rb +7 -0
  350. data/lib/decidim/core/api.rb +2 -0
  351. data/lib/decidim/core/engine.rb +21 -7
  352. data/lib/decidim/core/menu.rb +0 -5
  353. data/lib/decidim/core/seeds.rb +42 -2
  354. data/lib/decidim/core/test/factories.rb +105 -2
  355. data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +85 -0
  356. data/lib/decidim/core/test/shared_examples/comments_examples.rb +393 -38
  357. data/lib/decidim/core/test/shared_examples/components_controller_hide_shared_examples.rb +11 -0
  358. data/lib/decidim/core/test/shared_examples/components_controller_reorder_shared_examples.rb +21 -0
  359. data/lib/decidim/core/test/shared_examples/download_open_data_shared_context.rb +36 -0
  360. data/lib/decidim/core/test/shared_examples/download_open_data_shared_examples.rb +45 -0
  361. data/lib/decidim/core/test/shared_examples/download_your_data_shared_examples.rb +17 -0
  362. data/lib/decidim/core/test/shared_examples/etiquette_validator_examples.rb +25 -0
  363. data/lib/decidim/core/test/shared_examples/follows_examples.rb +43 -0
  364. data/lib/decidim/core/test/shared_examples/has_taxonomies.rb +94 -0
  365. data/lib/decidim/core/test/shared_examples/manage_share_tokens_examples.rb +237 -0
  366. data/lib/decidim/core/test/shared_examples/map_examples.rb +2 -0
  367. data/lib/decidim/core/test/shared_examples/open_data_exporter_examples.rb +102 -0
  368. data/lib/decidim/core/test/shared_examples/participatory_space_members_page_examples.rb +46 -0
  369. data/lib/decidim/core/test/shared_examples/participatory_space_search_examples.rb +98 -0
  370. data/lib/decidim/core/test/shared_examples/permissions.rb +7 -7
  371. data/lib/decidim/core/test/shared_examples/preview_with_share_token_examples.rb +94 -0
  372. data/lib/decidim/core/test/shared_examples/reports_examples.rb +60 -5
  373. data/lib/decidim/core/test/shared_examples/resource_endorsed_event_examples.rb +2 -2
  374. data/lib/decidim/core/test/shared_examples/resource_search_examples.rb +75 -69
  375. data/lib/decidim/core/test/shared_examples/searchable_resources_shared_context.rb +1 -1
  376. data/lib/decidim/core/test/shared_examples/simple_event.rb +33 -19
  377. data/lib/decidim/core/test/shared_examples/social_share_examples.rb +46 -0
  378. data/lib/decidim/core/test/shared_examples/softdeleteable_components_examples.rb +173 -0
  379. data/lib/decidim/core/test/shared_examples/system_endorse_resource_examples.rb +54 -8
  380. data/lib/decidim/core/test/shared_examples/taxonomizable_interface_examples.rb +20 -0
  381. data/lib/decidim/core/test/shared_examples/taxonomizable_resource_examples.rb +37 -0
  382. data/lib/decidim/core/test/shared_examples/taxonomy_settings.rb +49 -0
  383. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +1 -1
  384. data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +2 -2
  385. data/lib/decidim/core/test/shared_examples/with_endorsable_permissions_examples.rb +1 -1
  386. data/lib/decidim/core/test.rb +9 -5
  387. data/lib/decidim/core/version.rb +1 -1
  388. data/lib/decidim/core.rb +58 -0
  389. data/lib/decidim/download_your_data_serializers/download_your_data_identity_serializer.rb +0 -4
  390. data/lib/decidim/download_your_data_serializers/download_your_data_participatory_space_private_user_serializer.rb +3 -1
  391. data/lib/decidim/download_your_data_serializers/download_your_data_report_serializer.rb +2 -1
  392. data/lib/decidim/download_your_data_serializers/download_your_data_user_serializer.rb +6 -7
  393. data/lib/decidim/download_your_data_serializers.rb +19 -0
  394. data/lib/decidim/exporters/csv.rb +6 -0
  395. data/lib/decidim/exporters/export_manifest.rb +14 -0
  396. data/lib/decidim/exporters/pdf.rb +26 -22
  397. data/lib/decidim/filter_form_builder.rb +12 -15
  398. data/lib/decidim/form_builder.rb +6 -129
  399. data/lib/decidim/has_category.rb +5 -1
  400. data/lib/decidim/has_private_users.rb +4 -0
  401. data/lib/decidim/has_taxonomy_settings.rb +47 -0
  402. data/lib/decidim/has_upload_validations.rb +1 -1
  403. data/lib/decidim/legacy_form_builder.rb +118 -0
  404. data/lib/decidim/maintenance/import_models/application_record.rb +93 -0
  405. data/lib/decidim/maintenance/import_models/area.rb +82 -0
  406. data/lib/decidim/maintenance/import_models/area_type.rb +12 -0
  407. data/lib/decidim/maintenance/import_models/assembly_type.rb +49 -0
  408. data/lib/decidim/maintenance/import_models/categorization.rb +14 -0
  409. data/lib/decidim/maintenance/import_models/category.rb +139 -0
  410. data/lib/decidim/maintenance/import_models/participatory_process_type.rb +21 -0
  411. data/lib/decidim/maintenance/import_models/scope.rb +163 -0
  412. data/lib/decidim/maintenance/import_models.rb +19 -0
  413. data/lib/decidim/maintenance/taxonomy_importer.rb +142 -0
  414. data/lib/decidim/maintenance/taxonomy_plan.rb +78 -0
  415. data/lib/decidim/maintenance.rb +12 -0
  416. data/lib/decidim/map/autocomplete.rb +52 -8
  417. data/lib/decidim/map/dynamic_map.rb +1 -1
  418. data/lib/decidim/map/provider/dynamic_map/here.rb +1 -40
  419. data/lib/decidim/map/provider/geocoding/here.rb +9 -3
  420. data/lib/decidim/map.rb +3 -6
  421. data/lib/decidim/moderation_tools.rb +29 -5
  422. data/lib/decidim/newsletter_encryptor.rb +1 -1
  423. data/lib/decidim/paddable.rb +1 -1
  424. data/lib/decidim/participable.rb +10 -10
  425. data/lib/decidim/participatory_space_user.rb +10 -0
  426. data/lib/decidim/private_download_helper.rb +15 -0
  427. data/lib/decidim/record_encryptor.rb +51 -46
  428. data/lib/decidim/resourceable.rb +16 -0
  429. data/lib/decidim/seeds.rb +18 -20
  430. data/lib/decidim/settings_manifest.rb +34 -1
  431. data/lib/decidim/soft_deletable.rb +17 -0
  432. data/lib/decidim/taxonomizable.rb +72 -0
  433. data/lib/decidim/view_model.rb +0 -1
  434. data/lib/tasks/decidim_download_your_data_tasks.rake +2 -4
  435. data/lib/tasks/decidim_procfile.rake +6 -0
  436. data/lib/tasks/decidim_tasks.rake +1 -0
  437. data/lib/tasks/decidim_taxonomies.rake +160 -0
  438. data/lib/tasks/upgrade/{decidim_fix_categorization.rake → clean.rake} +25 -18
  439. data/lib/tasks/upgrade/clean_hidden_resources.rake +33 -0
  440. data/lib/tasks/upgrade/decidim_active_storage_migration_tasks.rake +1 -1
  441. data/lib/tasks/upgrade/migrations.rake +94 -0
  442. metadata +198 -103
  443. data/app/cells/decidim/amendable/amenders_list/show.erb +0 -0
  444. data/app/cells/decidim/content_blocks/base/content.erb +0 -0
  445. data/app/cells/decidim/endorsers_list/full_endorsers_list.erb +0 -3
  446. data/app/cells/decidim/endorsers_list_button/content.erb +0 -1
  447. data/app/cells/decidim/endorsers_list_button_cell.rb +0 -15
  448. data/app/cells/decidim/scopes_picker/scope_picker_prompt.erb +0 -3
  449. data/app/cells/decidim/scopes_picker/scope_picker_values.erb +0 -5
  450. data/app/cells/decidim/scopes_picker/show.erb +0 -14
  451. data/app/cells/decidim/scopes_picker_cell.rb +0 -92
  452. data/app/commands/decidim/update_user_interests.rb +0 -41
  453. data/app/controllers/decidim/scopes_controller.rb +0 -84
  454. data/app/controllers/decidim/user_interests_controller.rb +0 -30
  455. data/app/forms/decidim/user_interest_scope_form.rb +0 -25
  456. data/app/forms/decidim/user_interests_form.rb +0 -17
  457. data/app/helpers/decidim/categories_helper.rb +0 -26
  458. data/app/helpers/decidim/scopes_helper.rb +0 -105
  459. data/app/packs/images/decidim/vendor/leaflet/layers-2x.png +0 -0
  460. data/app/packs/images/decidim/vendor/leaflet/layers.png +0 -0
  461. data/app/packs/images/decidim/vendor/leaflet/marker-icon-2x.png +0 -0
  462. data/app/packs/images/decidim/vendor/leaflet/marker-icon.png +0 -0
  463. data/app/packs/images/decidim/vendor/leaflet/marker-shadow.png +0 -0
  464. data/app/packs/src/decidim/vendor/leaflet-tilelayer-here.js +0 -212
  465. data/app/packs/stylesheets/decidim/legacy/MarkerCluster.Default.scss +0 -67
  466. data/app/packs/stylesheets/decidim/legacy/MarkerCluster.scss +0 -18
  467. data/app/packs/stylesheets/decidim/legacy/leaflet.scss +0 -705
  468. data/app/validators/scope_belongs_to_component_validator.rb +0 -16
  469. data/app/views/decidim/account/_user_groups.html.erb +0 -0
  470. data/app/views/decidim/scopes/_scopes_picker_input.html.erb +0 -19
  471. data/app/views/decidim/scopes/picker.html.erb +0 -53
  472. data/app/views/decidim/shared/_comments.html.erb +0 -0
  473. data/app/views/decidim/shared/_share_modal.html.erb +0 -26
  474. data/app/views/decidim/shared/_tags.html.erb +0 -1
  475. data/app/views/decidim/user_interests/_areas.html.erb +0 -14
  476. data/app/views/decidim/user_interests/_scopes.html.erb +0 -22
  477. data/app/views/decidim/user_interests/show.html.erb +0 -22
  478. data/config/initializers/foundation_rails_helper.rb +0 -4
  479. data/lib/decidim/core/test/shared_examples/has_category.rb +0 -38
  480. data/lib/decidim/core/test/shared_examples/has_scope.rb +0 -11
  481. data/lib/decidim/core/test/shared_examples/manage_component_share_tokens.rb +0 -83
  482. data/lib/decidim/core/test/shared_examples/preview_component_with_share_token_examples.rb +0 -49
  483. data/lib/decidim/core/test/shared_examples/scope_helper_examples.rb +0 -93
  484. data/lib/decidim/seven_zip_wrapper.rb +0 -29
@@ -14,12 +14,12 @@ module Decidim
14
14
  return @query if @query
15
15
 
16
16
  @query = Decidim::User.blocked.where(organization: @organization)
17
- @query = @query.where("blocked_at <= ?", end_time)
17
+ @query = @query.where(blocked_at: ..end_time)
18
18
  @query
19
19
  end
20
20
 
21
21
  def quantity
22
- @quantity ||= @query.where("blocked_at >= ?", start_time).count
22
+ @quantity ||= @query.where(blocked_at: start_time..).count
23
23
  end
24
24
  end
25
25
  end
@@ -15,11 +15,11 @@ module Decidim
15
15
  .where("deleted_at IS NULL OR deleted_at > ?", end_time)
16
16
  .where("blocked_at IS NULL OR blocked_at > ?", end_time)
17
17
  .confirmed
18
- .where("created_at <= ?", end_time)
18
+ .where(created_at: ..end_time)
19
19
  end
20
20
 
21
21
  def quantity
22
- @quantity ||= query.where("created_at >= ?", start_time).count
22
+ @quantity ||= query.where(created_at: start_time..).count
23
23
  end
24
24
  end
25
25
  end
@@ -20,8 +20,6 @@ module Decidim
20
20
  # :follows - a collection of `Decidim::Follow` resources. It will return any
21
21
  # activity affecting any of these resources, performed by any of them or
22
22
  # contained in any of them as spaces.
23
- # :scopes - a collection of `Decidim::Scope`. It will return any activity that
24
- # took place in any of those scopes.
25
23
  class PublicActivities < LastActivity
26
24
  def initialize(organization, options = {})
27
25
  @organization = organization
@@ -29,7 +27,6 @@ module Decidim
29
27
  @user = options[:user]
30
28
  @current_user = options[:current_user]
31
29
  @follows = options[:follows]
32
- @scopes = options[:scopes]
33
30
  end
34
31
 
35
32
  def query
@@ -45,7 +42,7 @@ module Decidim
45
42
 
46
43
  private
47
44
 
48
- attr_reader :resource_name, :user, :follows, :scopes
45
+ attr_reader :resource_name, :user, :follows
49
46
 
50
47
  def filter_follows(query)
51
48
  conditions = []
@@ -61,8 +58,6 @@ module Decidim
61
58
  conditions += followed_spaces_conditions(follows)
62
59
  end
63
60
 
64
- conditions += interesting_scopes_conditions(scopes)
65
-
66
61
  return query if conditions.empty?
67
62
 
68
63
  chained_conditions = conditions.inject do |previous_condition, condition|
@@ -90,12 +85,6 @@ module Decidim
90
85
  end
91
86
  end
92
87
 
93
- def interesting_scopes_conditions(interesting_scopes)
94
- return [] if interesting_scopes.blank?
95
-
96
- [Decidim::ActionLog.arel_table[:decidim_scope_id].in(interesting_scopes.map(&:id))]
97
- end
98
-
99
88
  def participatory_space_classes
100
89
  Decidim.participatory_space_manifests.map(&:model_class_name)
101
90
  end
@@ -16,8 +16,8 @@ module Decidim
16
16
 
17
17
  def query
18
18
  users = Decidim::User.where(organization: @organization).not_deleted.not_blocked.confirmed
19
- users = users.where("created_at >= ?", @start_at) if @start_at.present?
20
- users = users.where("created_at <= ?", @end_at) if @end_at.present?
19
+ users = users.where(created_at: @start_at..) if @start_at.present?
20
+ users = users.where(created_at: ..@end_at) if @end_at.present?
21
21
  users.count
22
22
  end
23
23
  end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # Resolves the most appropriate image URL for meta tags from a given resource within an organization.
5
+ # Searches in the following order: attachment images, images in resource description, participatory space images, and default content block images.
6
+ # Ensures the selected image is resized to 1200x630 pixels.
7
+ class MetaImageUrlResolver
8
+ include TranslatableAttributes
9
+
10
+ IMAGE_FIELDS = [:hero_image, :banner_image, :avatar].freeze
11
+ DESCRIPTION_FIELDS = [:body, :description, :short_description, :content, :additional_info].freeze
12
+ CONTENT_BLOCK_TYPES = {
13
+ { manifest_name: :hero, scope_name: :homepage } => [:background_image]
14
+ }.freeze
15
+
16
+ def initialize(resource, organization)
17
+ @resource = resource
18
+ @organization = organization
19
+ end
20
+
21
+ attr_reader :resource, :organization
22
+
23
+ # Resolves the image blob to be used for meta tags.
24
+ #
25
+ # @return [String, nil] - The resolved image blob or nil if no image is found.
26
+ def resolve
27
+ return unless blob
28
+
29
+ resized_variant = blob.variant(resize_to_limit: [1200, 630]).processed
30
+ Rails.application.routes.url_helpers.rails_representation_url(resized_variant, only_path: true)
31
+ end
32
+
33
+ # Determines the image blob to be used for meta tags by following a hierarchy.
34
+ #
35
+ # @return [ActiveStorage::Blob, nil] - The image blob or nil if no image is found.
36
+ def blob
37
+ @blob ||= blob_from_image_fields || blob_from_attachments || blob_from_description || blob_from_participatory_space || blob_from_content_blocks
38
+ end
39
+
40
+ private
41
+
42
+ # Fetches the image blob from the resource's attached image fields.
43
+ #
44
+ # @return [ActiveStorage::Blob, nil] - The image blob or nil if not found.
45
+ def blob_from_image_fields
46
+ IMAGE_FIELDS.each do |image_name|
47
+ next unless resource.respond_to?(image_name) && resource.respond_to?(:attached_uploader)
48
+
49
+ blob = blob_from_attached_file(resource.send(image_name))
50
+ return blob if blob.present?
51
+ end
52
+
53
+ nil
54
+ end
55
+
56
+ # Fetches the first attachment image blob.
57
+ #
58
+ # @return [ActiveStorage::Blob, nil] - The image blob or nil if not found.
59
+ def blob_from_attachments
60
+ attachment = resource.try(:attachments)&.find { |a| a.content_type.in?(%w(image/jpeg image/png image/webp)) }
61
+ blob_from_attached_file(attachment&.file)
62
+ end
63
+
64
+ # Extracts the first image blob from the resource description.
65
+ #
66
+ # @return [ActiveStorage::Blob, nil] - The image blob or nil if not found.
67
+ def blob_from_description
68
+ DESCRIPTION_FIELDS.each do |field|
69
+ html = resource.try(field)
70
+ next unless html
71
+
72
+ html = translated_attribute(html).strip if html.is_a?(Hash)
73
+ next if html.blank?
74
+
75
+ image_element = Nokogiri::HTML(html).css("img").first
76
+ next unless image_element
77
+
78
+ image_url = image_element["src"]
79
+ next if image_url.blank?
80
+
81
+ blob = find_blob_by_key(image_url.split("/").second_to_last)
82
+ return blob if blob.present?
83
+ end
84
+
85
+ nil
86
+ end
87
+
88
+ # Fetches the image blob from the participatory space.
89
+ #
90
+ # @return [ActiveStorage::Blob, nil] - The image blob or nil if not found.
91
+ def blob_from_participatory_space
92
+ participatory_space = resource.try(:participatory_space)
93
+ return unless participatory_space
94
+
95
+ MetaImageUrlResolver.new(participatory_space, organization).blob
96
+ end
97
+
98
+ # Fetches the default homepage image blob.
99
+ #
100
+ # @return [ActiveStorage::Blob, nil] - The image blob or nil if not found.
101
+ def blob_from_content_blocks
102
+ CONTENT_BLOCK_TYPES.each do |type, image_names|
103
+ Decidim::ContentBlock.where(type.merge(organization:)).find_each do |content_block|
104
+ next unless content_block.respond_to?(:images_container)
105
+
106
+ image_names.each do |image_name|
107
+ next unless content_block.images_container.respond_to?(image_name)
108
+
109
+ blob = blob_from_attached_file(content_block.images_container.send(image_name))
110
+ return blob if blob.present?
111
+ end
112
+ end
113
+ end
114
+
115
+ nil
116
+ end
117
+
118
+ def find_blob_by_key(blob_key)
119
+ ActiveStorage::Blob.find_signed(blob_key) if blob_key.present?
120
+ end
121
+
122
+ def blob_from_attached_file(file)
123
+ return unless file.respond_to?(:attached?) && file.attached?
124
+
125
+ file.blob
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Exporters
5
+ class OpenDataBlockedUserSerializer < Decidim::Exporters::Serializer
6
+ # Public: Initializes the serializer with a resource
7
+ def initialize(resource)
8
+ @resource = resource
9
+ end
10
+
11
+ # Public: Exports a hash with the serialized data for this resource.
12
+ def serialize
13
+ {
14
+ user_id: resource.user.id,
15
+ blocked_at: resource.user.blocked_at,
16
+ about: resource.user.about,
17
+ reasons: resource.reports.map(&:reason),
18
+ details: resource.reports.map(&:details),
19
+ block_reasons: resource.blocking.justification,
20
+ blocking_user: resource.blocking.blocking_user.presenter.name
21
+ }
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Exporters
5
+ class OpenDataMetricSerializer < Decidim::Exporters::Serializer
6
+ # Public: Initializes the serializer with a resource
7
+ def initialize(resource)
8
+ @resource = resource
9
+ end
10
+
11
+ # Public: Exports a hash with the serialized data for this resource.
12
+ def serialize
13
+ {
14
+ day: resource.day,
15
+ metric_type: resource.metric_type,
16
+ cumulative: resource.cumulative,
17
+ quantity: resource.quantity
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Exporters
5
+ class OpenDataModerationSerializer < Decidim::Exporters::Serializer
6
+ # Public: Initializes the serializer with a resource
7
+ def initialize(resource)
8
+ @resource = resource
9
+ end
10
+
11
+ # Public: Exports a hash with the serialized data for this resource.
12
+ def serialize
13
+ {
14
+ id: resource.id,
15
+ hidden_at: resource.hidden_at,
16
+ report_count: resource.report_count,
17
+ reported_url: resource.reportable.reported_content_url,
18
+ reportable_type: resource.decidim_reportable_type,
19
+ reportable_id: resource.decidim_reportable_id,
20
+ reported_content: resource.reported_content,
21
+ reports: {
22
+ reasons: resource.reports.map(&:reason),
23
+ locale: resource.reports.map(&:locale),
24
+ details: resource.reports.map(&:details)
25
+ }
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Exporters
5
+ class OpenDataTaxonomySerializer < Decidim::Exporters::Serializer
6
+ # Public: Initializes the serializer with a resource
7
+ def initialize(resource)
8
+ @resource = resource
9
+ end
10
+
11
+ # Public: Exports a hash with the serialized data for this resource.
12
+ def serialize
13
+ {
14
+ id: resource.id,
15
+ name: resource.name,
16
+ parent_id: resource.parent_id,
17
+ weight: resource.weight,
18
+ children_count: resource.children_count,
19
+ taxonomizations_count: resource.taxonomizations_count,
20
+ created_at: resource.created_at,
21
+ updated_at: resource.updated_at,
22
+ filters_count: resource.filters_count,
23
+ filter_items_count: resource.filter_items_count,
24
+ part_of: resource.part_of,
25
+ is_root: resource.root?
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Exporters
5
+ class OpenDataUserGroupSerializer < Decidim::Exporters::Serializer
6
+ # Public: Initializes the serializer with a resource
7
+ def initialize(resource)
8
+ @resource = resource
9
+ end
10
+
11
+ # Public: Exports a hash with the serialized data for this resource.
12
+ def serialize
13
+ {
14
+ id: resource.id,
15
+ name: presented.name,
16
+ nickname: presented.nickname,
17
+ avatar_url: presented.avatar_url(:thumb),
18
+ profile_url: presented.profile_url,
19
+ deleted: presented.deleted?,
20
+ badge: presented.badge,
21
+ members_count: resource.accepted_memberships.count,
22
+ members: {
23
+ id: resource.accepted_users.collect(&:id),
24
+ name: resource.accepted_users.collect(&:name)
25
+ }
26
+ }
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :resource
32
+
33
+ def presented
34
+ @presented ||= resource.presenter
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Exporters
5
+ class OpenDataUserSerializer < Decidim::Exporters::Serializer
6
+ # Public: Initializes the serializer with a resource
7
+ def initialize(resource)
8
+ @resource = resource
9
+ end
10
+
11
+ # Public: Exports a hash with the serialized data for this resource.
12
+ def serialize
13
+ {
14
+ id: resource.id,
15
+ name: presented.name,
16
+ nickname: presented.nickname,
17
+ about: presented.about,
18
+ avatar_url: presented.avatar_url(:thumb),
19
+ profile_url: presented.profile_url,
20
+ direct_messages_enabled: (resource.direct_message_types != "followed-only"),
21
+ deleted: presented.deleted?,
22
+ badge: presented.badge,
23
+ groups: {
24
+ id: resource.accepted_user_groups.collect(&:id),
25
+ name: resource.accepted_user_groups.collect(&:name)
26
+ }
27
+ }
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :resource
33
+
34
+ def presented
35
+ @presented ||= resource.presenter
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Exporters
5
+ # This class serves as the base class for the serializers that export
6
+ # participatory spaces.
7
+ class ParticipatorySpaceSerializer < Decidim::Exporters::Serializer
8
+ include Decidim::ApplicationHelper
9
+ include Decidim::ResourceHelper
10
+ include Decidim::TranslationsHelper
11
+
12
+ # Public: Initializes the serializer with a resource
13
+ def initialize(resource)
14
+ @resource = resource
15
+ end
16
+
17
+ # Public: Exports a hash with the serialized data for this resource.
18
+ def serialize
19
+ {
20
+ id: resource.id,
21
+ title: resource.title,
22
+ slug: resource.slug,
23
+ reference: resource.reference,
24
+ created_at: resource.created_at,
25
+ updated_at: resource.updated_at,
26
+ published_at: resource.published_at,
27
+ follows_count: resource.follows_count,
28
+ hashtag: resource.hashtag,
29
+ short_description: resource.short_description,
30
+ description: resource.description,
31
+ promoted: resource.promoted
32
+ }
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :resource
38
+
39
+ def serialize_categories
40
+ return unless resource.categories.first_class.any?
41
+
42
+ resource.categories.first_class.map do |category|
43
+ {
44
+ id: category.try(:id),
45
+ name: category.try(:name),
46
+ description: category.try(:description),
47
+ parent_id: category.try(:parent_id),
48
+ subcategories: serialize_subcategories(category.subcategories)
49
+ }
50
+ end
51
+ end
52
+
53
+ def serialize_subcategories(subcategories)
54
+ return unless subcategories.any?
55
+
56
+ subcategories.map do |subcategory|
57
+ {
58
+ id: subcategory.try(:id),
59
+ name: subcategory.try(:name),
60
+ description: subcategory.try(:description),
61
+ parent_id: subcategory.try(:parent_id)
62
+ }
63
+ end
64
+ end
65
+
66
+ def serialize_attachment_collections
67
+ return unless resource.attachment_collections.any?
68
+
69
+ resource.attachment_collections.map do |collection|
70
+ {
71
+ id: collection.try(:id),
72
+ name: collection.try(:name),
73
+ weight: collection.try(:weight),
74
+ description: collection.try(:description)
75
+ }
76
+ end
77
+ end
78
+
79
+ def serialize_attachments
80
+ return unless resource.attachments.any?
81
+
82
+ resource.attachments.map do |attachment|
83
+ {
84
+ id: attachment.try(:id),
85
+ title: attachment.try(:title),
86
+ weight: attachment.try(:weight),
87
+ description: attachment.try(:description),
88
+ attachment_collection: {
89
+ name: attachment.attachment_collection.try(:name),
90
+ weight: attachment.attachment_collection.try(:weight),
91
+ description: attachment.attachment_collection.try(:description)
92
+ },
93
+ remote_file_url: Decidim::AttachmentPresenter.new(attachment).attachment_file_url
94
+ }
95
+ end
96
+ end
97
+
98
+ def serialize_components
99
+ serializer = Decidim::Exporters::ParticipatorySpaceComponentsSerializer.new(resource)
100
+ serializer.run
101
+ end
102
+ end
103
+ end
104
+ end
@@ -54,6 +54,31 @@ module Decidim
54
54
  def event_name
55
55
  ActiveSupport::Inflector.underscore(self.class.to_s).sub("/", ".serialize.").gsub("/", ".")
56
56
  end
57
+
58
+ protected
59
+
60
+ delegate :component, to: :resource
61
+
62
+ def profile_url(user)
63
+ return "" if user.respond_to?(:deleted?) && user.deleted?
64
+
65
+ EngineRouter.new("decidim", { host: }).profile_url(user.nickname)
66
+ end
67
+
68
+ def root_url
69
+ Decidim::Core::Engine.routes.url_helpers.root_url(host:)
70
+ end
71
+
72
+ def host
73
+ resource.organization.host
74
+ end
75
+
76
+ # helper method to serialize taxonomies for any resource
77
+ def taxonomies
78
+ {
79
+ ids: resource.taxonomies.map(&:id)
80
+ }.merge(resource.taxonomies.to_h { |taxonomy| [taxonomy.id, taxonomy.name] })
81
+ end
57
82
  end
58
83
  end
59
84
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module Decidim
6
+ class SchemaOrgBreadcrumbListSerializer < Decidim::Exporters::Serializer
7
+ include Decidim::SanitizeHelper
8
+
9
+ # Public: Initializes the serializer with a list of breadcrumb items.
10
+ def initialize(options)
11
+ @breadcrumb_items = options[:breadcrumb_items]
12
+ @base_url = options[:base_url]
13
+ @organization_name = options[:organization_name]
14
+ end
15
+
16
+ # Serializes a breadcrumb items list for the Schema.org BreadcrumbList type
17
+ #
18
+ # @see https://schema.org/BreadcrumbList
19
+ # @see https://developers.google.com/search/docs/appearance/structured-data/breadcrumb?hl=en
20
+ def serialize
21
+ return {} if breadcrumb_items.none? { |item| item.has_key?(:url) }
22
+
23
+ {
24
+ "@context": "https://schema.org",
25
+ "@type": "BreadcrumbList",
26
+ name: "#{organization_name} breadcrumb",
27
+ itemListElement: breadcrumb_items_serialized
28
+ }
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :breadcrumb_items, :base_url, :organization_name
34
+
35
+ def breadcrumb_items_serialized
36
+ all_items = []
37
+
38
+ breadcrumb_items.each_with_index do |item, index|
39
+ next if item.empty?
40
+
41
+ all_items << {
42
+ "@type": "ListItem",
43
+ position: index + 1,
44
+ name: decidim_sanitize_translated(item[:label]),
45
+ item: URI.join(base_url, item[:url]).to_s
46
+ }
47
+ end
48
+
49
+ all_items
50
+ end
51
+ end
52
+ end
@@ -88,23 +88,32 @@ module Decidim
88
88
  def unauthorized?
89
89
  @code == :unauthorized
90
90
  end
91
+
92
+ def ephemeral?
93
+ @authorization_handler.ephemeral?
94
+ end
91
95
  end
92
96
 
93
97
  class AuthorizationStatusCollection
94
98
  attr_reader :statuses
95
99
 
96
100
  def initialize(authorization_handlers, user, component, resource)
101
+ @ephemeral_user = user&.ephemeral?
97
102
  @authorization_handlers = authorization_handlers
98
- @statuses = authorization_handlers&.map do |name, opts|
103
+ @statuses = authorization_handlers&.filter_map do |name, opts|
99
104
  handler = Verifications::Adapter.from_element(name)
105
+ next if @ephemeral_user && !handler.ephemeral?
106
+
100
107
  authorization = user ? Verifications::Authorizations.new(organization: user.organization, user:, name:).first : nil
101
108
  status_code, data = handler.authorize(authorization, opts["options"], component, resource)
102
109
  AuthorizationStatus.new(status_code, handler, data)
103
- end
110
+ end || []
104
111
  end
105
112
 
106
113
  def ok?
107
- return true if statuses.blank?
114
+ # When no statuses are present for the action ephemeral users
115
+ # are not allowed to perform the action
116
+ return !@ephemeral_user if statuses.blank?
108
117
 
109
118
  statuses.all?(&:ok?)
110
119
  end
@@ -126,6 +135,26 @@ module Decidim
126
135
  def codes
127
136
  @codes ||= statuses.map(&:code)
128
137
  end
138
+
139
+ def pending_authorizations_count
140
+ return 0 if @statuses.blank?
141
+
142
+ @statuses.count
143
+ end
144
+
145
+ def single_authorization_required?
146
+ pending_authorizations_count == 1 && [:ok, :unauthorized].exclude?(global_code)
147
+ end
148
+
149
+ def ephemeral?
150
+ return if statuses.blank?
151
+
152
+ statuses.all?(&:ephemeral?)
153
+ end
154
+
155
+ def user_pending?
156
+ !global_code && statuses.any? { |status| [:missing, :expired, :incomplete].include?(status.code) }
157
+ end
129
158
  end
130
159
 
131
160
  class AuthorizationError < StandardError; end
@@ -46,7 +46,7 @@ module Decidim
46
46
  last_value = values.last.try(:[], locale)
47
47
  next if first_value == last_value
48
48
 
49
- attribute_locale = "#{attribute}_#{locale}".to_sym
49
+ attribute_locale = :"#{attribute}_#{locale}"
50
50
  diff.update(
51
51
  attribute_locale => {
52
52
  type:,