decidim-core 0.29.3 → 0.30.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (532) 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/flag.erb +6 -0
  7. data/app/cells/decidim/author/flag_user.erb +14 -0
  8. data/app/cells/decidim/author_cell.rb +1 -1
  9. data/app/cells/decidim/card_l/extra_data.erb +1 -0
  10. data/app/cells/decidim/card_metadata_cell.rb +9 -16
  11. data/app/cells/decidim/comments_button_cell.rb +14 -2
  12. data/app/cells/decidim/content_blocks/highlighted_elements_cell.rb +2 -0
  13. data/app/cells/decidim/content_blocks/highlighted_elements_with_cell_for_list_cell.rb +1 -1
  14. data/app/cells/decidim/endorsement_block/show.erb +0 -1
  15. data/app/cells/decidim/endorsement_block_cell.rb +6 -0
  16. data/app/cells/decidim/endorsement_buttons/button_content.erb +1 -1
  17. data/app/cells/decidim/endorsement_buttons/select_identity_button.erb +1 -1
  18. data/app/cells/decidim/endorsement_buttons/show.erb +7 -7
  19. data/app/cells/decidim/endorsement_buttons/verification_modal.erb +4 -2
  20. data/app/cells/decidim/endorsers_list/empty.erb +3 -0
  21. data/app/cells/decidim/endorsers_list/full.erb +17 -5
  22. data/app/cells/decidim/endorsers_list/show.erb +19 -10
  23. data/app/cells/decidim/endorsers_list_cell.rb +19 -6
  24. data/app/cells/decidim/flag_modal/flag_user.erb +34 -0
  25. data/app/cells/decidim/flag_modal/show.erb +52 -0
  26. data/app/cells/decidim/flag_modal_cell.rb +56 -0
  27. data/app/cells/decidim/follow_button/show.erb +1 -2
  28. data/app/cells/decidim/follow_button_cell.rb +5 -0
  29. data/app/cells/decidim/map/show.erb +3 -0
  30. data/app/cells/decidim/map/template.erb +14 -0
  31. data/app/cells/decidim/map_cell.rb +39 -0
  32. data/app/cells/decidim/notification_actions/buttons_cell.rb +1 -1
  33. data/app/cells/decidim/onboarding_action_message/show.erb +15 -0
  34. data/app/cells/decidim/onboarding_action_message_cell.rb +81 -0
  35. data/app/cells/decidim/participatory_space_dropdown_metadata/show.erb +3 -5
  36. data/app/cells/decidim/participatory_space_private_user/show.erb +23 -0
  37. data/app/cells/decidim/participatory_space_private_user_cell.rb +21 -0
  38. data/app/cells/decidim/profile_actions/show.erb +1 -1
  39. data/app/cells/decidim/profile_sidebar/show.erb +167 -0
  40. data/app/cells/decidim/profile_sidebar_cell.rb +68 -0
  41. data/app/cells/decidim/progress_bar/show.erb +2 -2
  42. data/app/cells/decidim/report_button/already_reported_modal.erb +2 -2
  43. data/app/cells/decidim/report_button/flag_modal.erb +27 -13
  44. data/app/cells/decidim/report_button_cell.rb +9 -2
  45. data/app/cells/decidim/resource_history/show.erb +20 -0
  46. data/app/cells/decidim/resource_history_cell.rb +66 -0
  47. data/app/cells/decidim/resource_types_filter/show.erb +1 -1
  48. data/app/cells/decidim/resource_types_filter_cell.rb +6 -6
  49. data/app/cells/decidim/share_button_cell.rb +0 -4
  50. data/app/cells/decidim/share_widget/modal.erb +26 -0
  51. data/app/cells/decidim/share_widget/show.erb +2 -0
  52. data/app/cells/decidim/share_widget_cell.rb +20 -0
  53. data/app/cells/decidim/tags/show.erb +7 -4
  54. data/app/cells/decidim/tags_cell.rb +11 -72
  55. data/app/cells/decidim/user_activity/show.erb +1 -1
  56. data/app/commands/decidim/amendable/create_draft.rb +2 -2
  57. data/app/commands/decidim/create_ephemeral_user.rb +52 -0
  58. data/app/commands/decidim/create_omniauth_registration.rb +21 -17
  59. data/app/commands/decidim/create_report.rb +7 -6
  60. data/app/commands/decidim/create_user_group.rb +6 -2
  61. data/app/commands/decidim/destroy_ephemeral_user.rb +47 -0
  62. data/app/commands/decidim/search.rb +0 -14
  63. data/app/commands/decidim/update_account.rb +11 -3
  64. data/app/commands/decidim/update_notifications_settings.rb +1 -0
  65. data/app/commands/decidim/update_resources_taxonomies.rb +67 -0
  66. data/app/commands/decidim/update_user_group.rb +7 -1
  67. data/app/constraints/decidim/current_component.rb +1 -1
  68. data/app/controllers/concerns/decidim/ajax_permission_handler.rb +21 -0
  69. data/app/controllers/concerns/decidim/devise_authentication_methods.rb +3 -6
  70. data/app/controllers/concerns/decidim/devise_controllers.rb +2 -0
  71. data/app/controllers/concerns/decidim/disable_redirection_to_external_host.rb +1 -1
  72. data/app/controllers/concerns/decidim/ephemeral_session_checker.rb +87 -0
  73. data/app/controllers/concerns/decidim/filter_resource.rb +4 -2
  74. data/app/controllers/concerns/decidim/has_members_page.rb +25 -0
  75. data/app/controllers/concerns/decidim/headers/browser_feature_permissions.rb +50 -0
  76. data/app/controllers/concerns/decidim/locale_switcher.rb +2 -2
  77. data/app/controllers/concerns/decidim/needs_password_change.rb +0 -1
  78. data/app/controllers/concerns/decidim/needs_permission.rb +2 -1
  79. data/app/controllers/concerns/decidim/needs_tos_accepted.rb +4 -5
  80. data/app/controllers/concerns/decidim/onboarding_action_methods.rb +52 -0
  81. data/app/controllers/decidim/application_controller.rb +10 -0
  82. data/app/controllers/decidim/authorization_modals_controller.rb +8 -2
  83. data/app/controllers/decidim/components/base_controller.rb +3 -7
  84. data/app/controllers/decidim/devise/confirmations_controller.rb +4 -0
  85. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +8 -1
  86. data/app/controllers/decidim/devise/registrations_controller.rb +1 -1
  87. data/app/controllers/decidim/devise/sessions_controller.rb +2 -0
  88. data/app/controllers/decidim/download_your_data_controller.rb +33 -2
  89. data/app/controllers/decidim/editor_images_controller.rb +1 -11
  90. data/app/controllers/decidim/follows_controller.rb +1 -1
  91. data/app/controllers/decidim/geolocation_controller.rb +19 -0
  92. data/app/controllers/decidim/homepage_controller.rb +0 -1
  93. data/app/controllers/decidim/open_data_controller.rb +33 -8
  94. data/app/controllers/decidim/profiles_controller.rb +2 -2
  95. data/app/controllers/decidim/reports_controller.rb +1 -1
  96. data/app/controllers/decidim/user_activities_controller.rb +1 -1
  97. data/app/controllers/decidim/user_conversations_controller.rb +1 -11
  98. data/app/events/decidim/soft_delete_resource_event.rb +15 -0
  99. data/app/forms/decidim/account_form.rb +2 -5
  100. data/app/forms/decidim/amendable/form.rb +4 -2
  101. data/app/forms/decidim/ephemeral_user_form.rb +22 -0
  102. data/app/forms/decidim/notifications_settings_form.rb +1 -0
  103. data/app/forms/decidim/omniauth_registration_form.rb +14 -1
  104. data/app/helpers/concerns/decidim/flash_helper_extensions.rb +17 -2
  105. data/app/helpers/decidim/action_authorization_helper.rb +75 -14
  106. data/app/helpers/decidim/amendments_helper.rb +0 -9
  107. data/app/helpers/decidim/application_helper.rb +6 -2
  108. data/app/helpers/decidim/breadcrumb_helper.rb +6 -0
  109. data/app/helpers/decidim/cache_helper.rb +1 -1
  110. data/app/helpers/decidim/check_boxes_tree_helper.rb +25 -53
  111. data/app/helpers/decidim/decidim_form_helper.rb +0 -44
  112. data/app/helpers/decidim/endorsable_helper.rb +0 -10
  113. data/app/helpers/decidim/layout_helper.rb +6 -0
  114. data/app/helpers/decidim/messaging/conversation_helper.rb +2 -3
  115. data/app/helpers/decidim/meta_tags_helper.rb +32 -23
  116. data/app/helpers/decidim/modal_helper.rb +23 -0
  117. data/app/helpers/decidim/omniauth_helper.rb +5 -5
  118. data/app/helpers/decidim/onboarding_action_helper.rb +13 -0
  119. data/app/helpers/decidim/orders_helper.rb +1 -2
  120. data/app/helpers/decidim/participatory_space_helpers.rb +1 -1
  121. data/app/helpers/decidim/passwords_helper.rb +2 -2
  122. data/app/helpers/decidim/taxonomies_helper.rb +40 -0
  123. data/app/jobs/decidim/download_your_data_export_job.rb +2 -19
  124. data/app/jobs/decidim/event_publisher_job.rb +18 -9
  125. data/app/jobs/decidim/export_job.rb +5 -1
  126. data/app/jobs/decidim/export_participatory_space_job.rb +4 -1
  127. data/app/jobs/decidim/open_data_job.rb +4 -4
  128. data/app/mailers/decidim/export_mailer.rb +7 -12
  129. data/app/mailers/decidim/reported_mailer.rb +0 -1
  130. data/app/models/decidim/action_log.rb +20 -1
  131. data/app/models/decidim/category.rb +4 -0
  132. data/app/models/decidim/component.rb +25 -3
  133. data/app/models/decidim/metric.rb +2 -1
  134. data/app/models/decidim/moderation.rb +16 -0
  135. data/app/models/decidim/newsletter.rb +12 -8
  136. data/app/models/decidim/organization.rb +7 -3
  137. data/app/models/decidim/participatory_space_private_user.rb +20 -0
  138. data/app/models/decidim/private_export.rb +24 -0
  139. data/app/models/decidim/push_notification_message.rb +1 -1
  140. data/app/models/decidim/report.rb +1 -1
  141. data/app/models/decidim/scope.rb +4 -0
  142. data/app/models/decidim/share_token.rb +36 -10
  143. data/app/models/decidim/taxonomization.rb +23 -0
  144. data/app/models/decidim/taxonomy.rb +139 -0
  145. data/app/models/decidim/taxonomy_filter.rb +130 -0
  146. data/app/models/decidim/taxonomy_filter_item.rb +33 -0
  147. data/app/models/decidim/user.rb +13 -23
  148. data/app/models/decidim/user_base_entity.rb +12 -4
  149. data/app/models/decidim/user_moderation.rb +9 -0
  150. data/app/models/decidim/user_report.rb +4 -0
  151. data/app/packs/entrypoints/decidim_core.js +1 -0
  152. data/app/packs/entrypoints/decidim_geocoding.js +2 -0
  153. data/app/packs/images/decidim/brands/facebook.svg +10 -0
  154. data/app/packs/images/decidim/brands/google.svg +7 -1
  155. data/app/packs/images/decidim/brands/twitter-x.svg +3 -0
  156. data/app/packs/src/decidim/check_boxes_tree.js +0 -1
  157. data/app/packs/src/decidim/clipboard.js +18 -9
  158. data/app/packs/src/decidim/confirm.js +79 -59
  159. data/app/packs/src/decidim/datepicker/datepicker_functions.js +3 -3
  160. data/app/packs/src/decidim/decidim_application.js +1 -0
  161. data/app/packs/src/decidim/form_remote.js +1 -1
  162. data/app/packs/src/decidim/geocoding/reverse_geocoding.js +60 -0
  163. data/app/packs/src/decidim/impersonation.js +1 -1
  164. data/app/packs/src/decidim/index.js +13 -5
  165. data/app/packs/src/decidim/map/provider/here.js +1 -1
  166. data/app/packs/src/decidim/onboarding_pending_action.js +24 -0
  167. data/app/packs/src/decidim/session_timeouter.js +1 -1
  168. data/app/packs/src/decidim/sticky_footer.js +29 -0
  169. data/app/packs/src/decidim/sticky_header.js +6 -31
  170. data/app/packs/src/decidim/user_registrations.js +13 -0
  171. data/app/packs/src/decidim/utilities/dom.js +148 -0
  172. data/app/packs/src/decidim/vendor/leaflet-tilelayer-here.js +212 -0
  173. data/app/packs/stylesheets/decidim/_accordion.scss +30 -0
  174. data/app/packs/stylesheets/decidim/_buttons.scss +19 -0
  175. data/app/packs/stylesheets/decidim/_content_blocks.scss +0 -4
  176. data/app/packs/stylesheets/decidim/_dropdown.scss +1 -1
  177. data/app/packs/stylesheets/decidim/_endorsers_list.scss +26 -20
  178. data/app/packs/stylesheets/decidim/_forms.scss +2 -2
  179. data/app/packs/stylesheets/decidim/_header.scss +2 -6
  180. data/app/packs/stylesheets/decidim/_layout.scss +32 -2
  181. data/app/packs/stylesheets/decidim/_login.scss +53 -6
  182. data/app/packs/stylesheets/decidim/_modal.scss +42 -0
  183. data/app/packs/stylesheets/decidim/_modal_tos_refuse.scss +4 -0
  184. data/app/packs/stylesheets/decidim/_participatory_spaces.scss +46 -0
  185. data/app/packs/stylesheets/decidim/_profile.scss +1 -1
  186. data/app/packs/stylesheets/decidim/_success_image.scss +64 -0
  187. data/app/packs/stylesheets/decidim/_tribute.scss +36 -0
  188. data/app/packs/stylesheets/decidim/application.scss +1 -1
  189. data/app/packs/stylesheets/decidim/geocoding_addons.scss +5 -0
  190. data/app/packs/stylesheets/decidim/map.scss +7 -10
  191. data/app/packs/stylesheets/decidim/resource_history.scss +31 -0
  192. data/app/permissions/decidim/permissions.rb +8 -2
  193. data/app/presenters/decidim/admin_log/base_user_presenter.rb +67 -0
  194. data/app/presenters/decidim/admin_log/component_presenter.rb +32 -3
  195. data/app/presenters/decidim/admin_log/moderation_presenter.rb +30 -3
  196. data/app/presenters/decidim/admin_log/share_token_presenter.rb +39 -0
  197. data/app/presenters/decidim/admin_log/taxonomy_filter_presenter.rb +57 -0
  198. data/app/presenters/decidim/admin_log/taxonomy_presenter.rb +48 -0
  199. data/app/presenters/decidim/admin_log/user_group_presenter.rb +6 -6
  200. data/app/presenters/decidim/admin_log/user_presenter.rb +4 -18
  201. data/app/presenters/decidim/log/user_presenter.rb +0 -1
  202. data/app/presenters/decidim/log/value_types/date_presenter.rb +1 -0
  203. data/app/presenters/decidim/log/value_types/taxonomy_presenter.rb +29 -0
  204. data/app/presenters/decidim/participatory_space_private_user_presenter.rb +50 -0
  205. data/app/presenters/decidim/taxonomy_filter_presenter.rb +19 -0
  206. data/app/presenters/decidim/taxonomy_presenter.rb +14 -0
  207. data/app/presenters/decidim/user_presenter.rb +1 -1
  208. data/app/queries/decidim/metrics/blocked_users_metric_manage.rb +2 -2
  209. data/app/queries/decidim/metrics/users_metric_manage.rb +2 -2
  210. data/app/queries/decidim/public_activities.rb +1 -12
  211. data/app/queries/decidim/stats_users_count.rb +2 -2
  212. data/app/resolvers/decidim/meta_image_url_resolver.rb +128 -0
  213. data/app/serializers/decidim/exporters/open_data_blocked_user_serializer.rb +25 -0
  214. data/app/serializers/decidim/exporters/open_data_metric_serializer.rb +22 -0
  215. data/app/serializers/decidim/exporters/open_data_moderation_serializer.rb +30 -0
  216. data/app/serializers/decidim/exporters/open_data_taxonomy_serializer.rb +30 -0
  217. data/app/serializers/decidim/exporters/open_data_user_group_serializer.rb +38 -0
  218. data/app/serializers/decidim/exporters/open_data_user_serializer.rb +39 -0
  219. data/app/serializers/decidim/exporters/participatory_space_serializer.rb +104 -0
  220. data/app/serializers/decidim/exporters/serializer.rb +25 -0
  221. data/app/serializers/decidim/schema_org_breadcrumb_list_serializer.rb +52 -0
  222. data/app/services/decidim/action_authorizer.rb +32 -3
  223. data/app/services/decidim/base_diff_renderer.rb +1 -3
  224. data/app/services/decidim/download_your_data_exporter.rb +58 -24
  225. data/app/services/decidim/onboarding_manager.rb +272 -0
  226. data/app/services/decidim/open_data_exporter.rb +139 -13
  227. data/app/services/decidim/static_map_generator.rb +1 -1
  228. data/app/services/decidim/traceability.rb +13 -0
  229. data/app/uploaders/decidim/application_uploader.rb +1 -1
  230. data/app/validators/etiquette_validator.rb +9 -2
  231. data/app/validators/passthru_validator.rb +1 -1
  232. data/app/validators/translated_etiquette_validator.rb +32 -0
  233. data/app/views/decidim/account/_password_fields.html.erb +2 -2
  234. data/app/views/decidim/application/_accordion_section.html.erb +14 -0
  235. data/app/views/decidim/application/_collection.html.erb +30 -18
  236. data/app/views/decidim/devise/omniauth_registrations/new.html.erb +5 -1
  237. data/app/views/decidim/devise/omniauth_registrations/new_tos_fields.html.erb +29 -0
  238. data/app/views/decidim/devise/registrations/new.html.erb +10 -22
  239. data/app/views/decidim/devise/sessions/new.html.erb +24 -29
  240. data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +2 -4
  241. data/app/views/decidim/devise/shared/_tos_fields.html.erb +16 -0
  242. data/app/views/decidim/download_your_data/_export.html.erb +15 -0
  243. data/app/views/decidim/download_your_data/show.html.erb +51 -5
  244. data/app/views/decidim/endorsements/update_buttons_and_counters.js.erb +16 -19
  245. data/app/views/decidim/export_mailer/download_your_data_export.html.erb +2 -2
  246. data/app/views/decidim/export_mailer/export.html.erb +5 -1
  247. data/app/views/decidim/last_activities/index.html.erb +1 -1
  248. data/app/views/decidim/notifications_settings/show.html.erb +22 -0
  249. data/app/views/decidim/open_data/_how_to_open_accordion_section.html.erb +15 -0
  250. data/app/views/decidim/open_data/index.html.erb +108 -0
  251. data/app/views/decidim/pages/show.html.erb +2 -1
  252. data/app/views/decidim/participatory_space_private_users/_participatory_space_private_user.html.erb +1 -0
  253. data/app/views/decidim/reported_mailer/hide.html.erb +1 -17
  254. data/app/views/decidim/reported_mailer/report.html.erb +1 -1
  255. data/app/views/decidim/searches/_count.html.erb +1 -1
  256. data/app/views/decidim/searches/_filters.html.erb +38 -40
  257. data/app/views/decidim/shared/_login_modal.html.erb +26 -20
  258. data/app/views/decidim/shared/_orders.html.erb +2 -2
  259. data/app/views/decidim/shared/_resource_actions.html.erb +21 -0
  260. data/app/views/decidim/shared/filters/_check_boxes_tree.html.erb +1 -2
  261. data/app/views/decidim/shared/filters/_collection.html.erb +1 -1
  262. data/app/views/decidim/shared/filters/_dropdown_label.html.erb +7 -4
  263. data/app/views/layouts/decidim/_application.html.erb +0 -1
  264. data/app/views/layouts/decidim/_js_configuration.html.erb +1 -0
  265. data/app/views/layouts/decidim/_logo.html.erb +1 -1
  266. data/app/views/layouts/decidim/_logo_mobile.html.erb +1 -1
  267. data/app/views/layouts/decidim/_meta_tags_config.html.erb +6 -11
  268. data/app/views/layouts/decidim/_schema_org_breadcrumb_list.html.erb +3 -0
  269. data/app/views/layouts/decidim/_wrapper.html.erb +15 -9
  270. data/app/views/layouts/decidim/footer/_main_legal.html.erb +1 -1
  271. data/app/views/layouts/decidim/footer/_main_links.html.erb +1 -1
  272. data/app/views/layouts/decidim/header/_close_ephemeral_session.html.erb +25 -0
  273. data/app/views/layouts/decidim/header/_main.html.erb +14 -10
  274. data/app/views/layouts/decidim/header/_menu_breadcrumb_items.html.erb +2 -0
  275. data/app/views/layouts/decidim/shared/_layout_item.html.erb +1 -1
  276. data/config/assets.rb +2 -1
  277. data/config/locales/ar.yml +29 -74
  278. data/config/locales/bg.yml +27 -74
  279. data/config/locales/bs-BA.yml +0 -2
  280. data/config/locales/ca.yml +369 -90
  281. data/config/locales/cs.yml +370 -84
  282. data/config/locales/de.yml +348 -72
  283. data/config/locales/el.yml +16 -58
  284. data/config/locales/en.yml +349 -70
  285. data/config/locales/eo.yml +0 -4
  286. data/config/locales/es-MX.yml +362 -86
  287. data/config/locales/es-PY.yml +367 -91
  288. data/config/locales/es.yml +369 -90
  289. data/config/locales/eu.yml +422 -140
  290. data/config/locales/fi-plain.yml +360 -76
  291. data/config/locales/fi.yml +364 -77
  292. data/config/locales/fr-CA.yml +172 -83
  293. data/config/locales/fr.yml +172 -80
  294. data/config/locales/ga-IE.yml +4 -25
  295. data/config/locales/gl.yml +15 -58
  296. data/config/locales/hu.yml +24 -62
  297. data/config/locales/id-ID.yml +16 -57
  298. data/config/locales/is-IS.yml +0 -25
  299. data/config/locales/it.yml +31 -94
  300. data/config/locales/ja.yml +226 -97
  301. data/config/locales/lb.yml +23 -76
  302. data/config/locales/lt.yml +18 -64
  303. data/config/locales/lv.yml +16 -58
  304. data/config/locales/nl.yml +18 -75
  305. data/config/locales/no.yml +18 -70
  306. data/config/locales/pl.yml +24 -72
  307. data/config/locales/pt-BR.yml +35 -63
  308. data/config/locales/pt.yml +18 -70
  309. data/config/locales/ro-RO.yml +109 -188
  310. data/config/locales/ru.yml +8 -43
  311. data/config/locales/sk.yml +19 -70
  312. data/config/locales/sl.yml +0 -4
  313. data/config/locales/sr-CS.yml +0 -2
  314. data/config/locales/sv.yml +127 -79
  315. data/config/locales/tr-TR.yml +24 -74
  316. data/config/locales/uk.yml +1 -29
  317. data/config/locales/zh-CN.yml +16 -68
  318. data/config/locales/zh-TW.yml +17 -62
  319. data/config/routes.rb +4 -10
  320. data/db/migrate/20181025082245_add_timestamps_to_components.rb +2 -0
  321. data/db/migrate/20240628111905_add_visible_to_components.rb +7 -0
  322. data/db/migrate/20240704115429_create_decidim_taxonomies.rb +23 -0
  323. data/db/migrate/20240717093514_add_registered_only_to_decidim_share_tokens.rb +7 -0
  324. data/db/migrate/20240722215500_change_object_changes_on_versions.rb +39 -0
  325. data/db/migrate/20240806065417_create_decidim_taxonomy_filters.rb +23 -0
  326. data/db/migrate/20240822161348_add_deleted_at_to_decidim_components.rb +8 -0
  327. data/db/migrate/20240906162524_add_part_of_to_taxonomies.rb +26 -0
  328. data/db/migrate/20241001135825_add_role_to_participatory_space_private_users.rb +7 -0
  329. data/db/migrate/20241001140408_add_published_to_participatory_space_private_users.rb +7 -0
  330. data/db/migrate/20241022002600_create_private_exports.rb +18 -0
  331. data/db/migrate/20241028114430_add_component_counter_to_taxonomy_filters.rb +7 -0
  332. data/db/migrate/20241111104357_add_names_and_space_boolean_to_taxonomy_filters.rb +9 -0
  333. data/db/migrate/20241127093708_add_taxonomy_to_metrics.rb +7 -0
  334. data/db/migrate/20241204121445_add_participatory_space_manifests_from_taxonomy_filters.rb +9 -0
  335. data/decidim-core.gemspec +14 -17
  336. data/lib/decidim/action_authorization.rb +3 -2
  337. data/lib/decidim/amendable.rb +1 -1
  338. data/lib/decidim/api/input_filters/category_input_filter.rb +5 -3
  339. data/lib/decidim/api/input_filters/component_input_filter.rb +33 -20
  340. data/lib/decidim/api/input_filters/user_entity_input_filter.rb +53 -44
  341. data/lib/decidim/api/input_sorts/component_input_sort.rb +15 -13
  342. data/lib/decidim/api/input_sorts/user_entity_input_sort.rb +4 -4
  343. data/lib/decidim/api/interfaces/author_interface.rb +3 -2
  344. data/lib/decidim/api/interfaces/coauthorable_interface.rb +5 -5
  345. data/lib/decidim/api/interfaces/endorsable_interface.rb +2 -2
  346. data/lib/decidim/api/interfaces/participatory_space_interface.rb +5 -10
  347. data/lib/decidim/api/interfaces/taxonomizable_interface.rb +13 -0
  348. data/lib/decidim/api/types/amendment_type.rb +5 -7
  349. data/lib/decidim/api/types/area_api_type.rb +3 -3
  350. data/lib/decidim/api/types/attachment_type.rb +3 -3
  351. data/lib/decidim/api/types/category_type.rb +2 -2
  352. data/lib/decidim/api/types/decidim_type.rb +5 -1
  353. data/lib/decidim/api/types/fingerprint_type.rb +1 -1
  354. data/lib/decidim/api/types/localized_string_type.rb +1 -1
  355. data/lib/decidim/api/types/metric_history_type.rb +2 -0
  356. data/lib/decidim/api/types/metric_type.rb +1 -1
  357. data/lib/decidim/api/types/organization_type.rb +5 -0
  358. data/lib/decidim/api/types/participatory_space_link_type.rb +2 -2
  359. data/lib/decidim/api/types/participatory_space_manifest_type.rb +1 -1
  360. data/lib/decidim/api/types/quantifiable_translated_field_type.rb +1 -1
  361. data/lib/decidim/api/types/scope_api_type.rb +2 -3
  362. data/lib/decidim/api/types/session_type.rb +1 -2
  363. data/lib/decidim/api/types/taxonomy_type.rb +15 -0
  364. data/lib/decidim/api/types/trace_version_type.rb +2 -2
  365. data/lib/decidim/api/types/translated_field_type.rb +3 -5
  366. data/lib/decidim/api/types/user_group_type.rb +7 -20
  367. data/lib/decidim/api/types/user_type.rb +7 -20
  368. data/lib/decidim/asset_router/storage.rb +6 -11
  369. data/lib/decidim/assets/tailwind/tailwind.config.js.erb +2 -1
  370. data/lib/decidim/attachment_attributes.rb +1 -1
  371. data/lib/decidim/attribute_encryptor.rb +1 -1
  372. data/lib/decidim/attribute_object/nested_validator.rb +1 -1
  373. data/lib/decidim/attributes/integer_with_units.rb +27 -0
  374. data/lib/decidim/attributes/time_with_zone.rb +1 -5
  375. data/lib/decidim/attributes.rb +2 -0
  376. data/lib/decidim/authorization_form_builder.rb +0 -7
  377. data/lib/decidim/coauthorable.rb +1 -1
  378. data/lib/decidim/command.rb +3 -3
  379. data/lib/decidim/commands/destroy_resource.rb +5 -1
  380. data/lib/decidim/commands/resource_handler.rb +2 -2
  381. data/lib/decidim/commands/restore_resource.rb +45 -0
  382. data/lib/decidim/commands/soft_delete_resource.rb +63 -0
  383. data/lib/decidim/component_manifest.rb +7 -0
  384. data/lib/decidim/content_parsers/blob_parser.rb +8 -10
  385. data/lib/decidim/content_parsers/user_parser.rb +1 -1
  386. data/lib/decidim/core/api.rb +2 -0
  387. data/lib/decidim/core/engine.rb +21 -7
  388. data/lib/decidim/core/menu.rb +0 -5
  389. data/lib/decidim/core/seeds.rb +42 -2
  390. data/lib/decidim/core/test/factories.rb +105 -2
  391. data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +85 -0
  392. data/lib/decidim/core/test/shared_examples/comments_examples.rb +393 -38
  393. data/lib/decidim/core/test/shared_examples/components_controller_hide_shared_examples.rb +11 -0
  394. data/lib/decidim/core/test/shared_examples/components_controller_reorder_shared_examples.rb +21 -0
  395. data/lib/decidim/core/test/shared_examples/download_open_data_shared_context.rb +36 -0
  396. data/lib/decidim/core/test/shared_examples/download_open_data_shared_examples.rb +45 -0
  397. data/lib/decidim/core/test/shared_examples/download_your_data_shared_examples.rb +17 -0
  398. data/lib/decidim/core/test/shared_examples/etiquette_validator_examples.rb +25 -0
  399. data/lib/decidim/core/test/shared_examples/follows_examples.rb +43 -0
  400. data/lib/decidim/core/test/shared_examples/has_taxonomies.rb +94 -0
  401. data/lib/decidim/core/test/shared_examples/manage_share_tokens_examples.rb +237 -0
  402. data/lib/decidim/core/test/shared_examples/map_examples.rb +2 -0
  403. data/lib/decidim/core/test/shared_examples/open_data_exporter_examples.rb +102 -0
  404. data/lib/decidim/core/test/shared_examples/participatory_space_members_page_examples.rb +46 -0
  405. data/lib/decidim/core/test/shared_examples/participatory_space_search_examples.rb +98 -0
  406. data/lib/decidim/core/test/shared_examples/permissions.rb +7 -7
  407. data/lib/decidim/core/test/shared_examples/preview_with_share_token_examples.rb +94 -0
  408. data/lib/decidim/core/test/shared_examples/reports_examples.rb +15 -53
  409. data/lib/decidim/core/test/shared_examples/resource_endorsed_event_examples.rb +2 -2
  410. data/lib/decidim/core/test/shared_examples/resource_search_examples.rb +75 -69
  411. data/lib/decidim/core/test/shared_examples/searchable_resources_shared_context.rb +1 -1
  412. data/lib/decidim/core/test/shared_examples/simple_event.rb +33 -19
  413. data/lib/decidim/core/test/shared_examples/social_share_examples.rb +7 -14
  414. data/lib/decidim/core/test/shared_examples/softdeleteable_components_examples.rb +173 -0
  415. data/lib/decidim/core/test/shared_examples/system_endorse_resource_examples.rb +54 -8
  416. data/lib/decidim/core/test/shared_examples/taxonomizable_interface_examples.rb +20 -0
  417. data/lib/decidim/core/test/shared_examples/taxonomizable_resource_examples.rb +37 -0
  418. data/lib/decidim/core/test/shared_examples/taxonomy_settings.rb +49 -0
  419. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +1 -1
  420. data/lib/decidim/core/test/shared_examples/uncommentable_component_examples.rb +0 -26
  421. data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +2 -28
  422. data/lib/decidim/core/test/shared_examples/with_endorsable_permissions_examples.rb +1 -1
  423. data/lib/decidim/core/test.rb +9 -5
  424. data/lib/decidim/core/version.rb +1 -1
  425. data/lib/decidim/core.rb +58 -0
  426. data/lib/decidim/download_your_data_serializers/download_your_data_identity_serializer.rb +0 -4
  427. data/lib/decidim/download_your_data_serializers/download_your_data_participatory_space_private_user_serializer.rb +3 -1
  428. data/lib/decidim/download_your_data_serializers/download_your_data_report_serializer.rb +2 -1
  429. data/lib/decidim/download_your_data_serializers/download_your_data_user_serializer.rb +6 -7
  430. data/lib/decidim/download_your_data_serializers.rb +19 -0
  431. data/lib/decidim/exporters/csv.rb +6 -0
  432. data/lib/decidim/exporters/export_manifest.rb +14 -0
  433. data/lib/decidim/exporters/pdf.rb +26 -22
  434. data/lib/decidim/filter_form_builder.rb +12 -15
  435. data/lib/decidim/form_builder.rb +6 -129
  436. data/lib/decidim/has_category.rb +5 -1
  437. data/lib/decidim/has_private_users.rb +4 -0
  438. data/lib/decidim/has_taxonomy_settings.rb +47 -0
  439. data/lib/decidim/has_upload_validations.rb +1 -1
  440. data/lib/decidim/legacy_form_builder.rb +118 -0
  441. data/lib/decidim/maintenance/import_models/application_record.rb +93 -0
  442. data/lib/decidim/maintenance/import_models/area.rb +82 -0
  443. data/lib/decidim/maintenance/import_models/area_type.rb +12 -0
  444. data/lib/decidim/maintenance/import_models/assembly_type.rb +49 -0
  445. data/lib/decidim/maintenance/import_models/categorization.rb +14 -0
  446. data/lib/decidim/maintenance/import_models/category.rb +107 -0
  447. data/lib/decidim/maintenance/import_models/participatory_process_type.rb +21 -0
  448. data/lib/decidim/maintenance/import_models/scope.rb +163 -0
  449. data/lib/decidim/maintenance/import_models.rb +19 -0
  450. data/lib/decidim/maintenance/taxonomy_importer.rb +132 -0
  451. data/lib/decidim/maintenance/taxonomy_plan.rb +78 -0
  452. data/lib/decidim/maintenance.rb +12 -0
  453. data/lib/decidim/map/autocomplete.rb +52 -8
  454. data/lib/decidim/map/dynamic_map.rb +1 -1
  455. data/lib/decidim/map/provider/dynamic_map/here.rb +40 -1
  456. data/lib/decidim/map/provider/geocoding/here.rb +9 -3
  457. data/lib/decidim/map/provider/static_map/here.rb +0 -34
  458. data/lib/decidim/map.rb +3 -6
  459. data/lib/decidim/moderation_tools.rb +16 -19
  460. data/lib/decidim/newsletter_encryptor.rb +1 -1
  461. data/lib/decidim/nicknamizable.rb +1 -1
  462. data/lib/decidim/paddable.rb +1 -1
  463. data/lib/decidim/participable.rb +10 -10
  464. data/lib/decidim/participatory_space_user.rb +10 -0
  465. data/lib/decidim/private_download_helper.rb +15 -0
  466. data/lib/decidim/record_encryptor.rb +51 -46
  467. data/lib/decidim/reportable.rb +2 -6
  468. data/lib/decidim/resourceable.rb +16 -0
  469. data/lib/decidim/seeds.rb +18 -20
  470. data/lib/decidim/settings_manifest.rb +34 -1
  471. data/lib/decidim/soft_deletable.rb +17 -0
  472. data/lib/decidim/taxonomizable.rb +72 -0
  473. data/lib/decidim/translatable_attributes.rb +1 -5
  474. data/lib/decidim/view_model.rb +0 -1
  475. data/lib/tasks/decidim_download_your_data_tasks.rake +2 -4
  476. data/lib/tasks/decidim_procfile.rake +6 -0
  477. data/lib/tasks/decidim_tasks.rake +1 -0
  478. data/lib/tasks/decidim_taxonomies.rake +155 -0
  479. data/lib/tasks/upgrade/{decidim_fix_categorization.rake → clean.rake} +25 -18
  480. data/lib/tasks/upgrade/decidim_active_storage_migration_tasks.rake +1 -1
  481. data/lib/tasks/upgrade/decidim_fix_nickname_uniqueness.rake +20 -23
  482. data/lib/tasks/upgrade/migrations.rake +91 -0
  483. metadata +202 -110
  484. data/app/cells/decidim/amendable/amenders_list/show.erb +0 -0
  485. data/app/cells/decidim/content_blocks/base/content.erb +0 -0
  486. data/app/cells/decidim/endorsers_list/full_endorsers_list.erb +0 -3
  487. data/app/cells/decidim/endorsers_list_button/content.erb +0 -1
  488. data/app/cells/decidim/endorsers_list_button_cell.rb +0 -15
  489. data/app/cells/decidim/report_user_button/already_reported_modal.erb +0 -11
  490. data/app/cells/decidim/report_user_button/flag_modal.erb +0 -46
  491. data/app/cells/decidim/report_user_button/show.erb +0 -2
  492. data/app/cells/decidim/report_user_button_cell.rb +0 -59
  493. data/app/cells/decidim/scopes_picker/scope_picker_prompt.erb +0 -3
  494. data/app/cells/decidim/scopes_picker/scope_picker_values.erb +0 -5
  495. data/app/cells/decidim/scopes_picker/show.erb +0 -14
  496. data/app/cells/decidim/scopes_picker_cell.rb +0 -92
  497. data/app/commands/decidim/update_user_interests.rb +0 -41
  498. data/app/controllers/decidim/scopes_controller.rb +0 -84
  499. data/app/controllers/decidim/user_interests_controller.rb +0 -30
  500. data/app/forms/decidim/user_interest_scope_form.rb +0 -25
  501. data/app/forms/decidim/user_interests_form.rb +0 -17
  502. data/app/helpers/decidim/categories_helper.rb +0 -26
  503. data/app/helpers/decidim/scopes_helper.rb +0 -105
  504. data/app/jobs/decidim/hide_child_resources_job.rb +0 -24
  505. data/app/packs/images/decidim/vendor/leaflet/layers-2x.png +0 -0
  506. data/app/packs/images/decidim/vendor/leaflet/layers.png +0 -0
  507. data/app/packs/images/decidim/vendor/leaflet/marker-icon-2x.png +0 -0
  508. data/app/packs/images/decidim/vendor/leaflet/marker-icon.png +0 -0
  509. data/app/packs/images/decidim/vendor/leaflet/marker-shadow.png +0 -0
  510. data/app/packs/stylesheets/decidim/_hashtags.scss +0 -5
  511. data/app/packs/stylesheets/decidim/legacy/MarkerCluster.Default.scss +0 -67
  512. data/app/packs/stylesheets/decidim/legacy/MarkerCluster.scss +0 -18
  513. data/app/packs/stylesheets/decidim/legacy/leaflet.scss +0 -705
  514. data/app/validators/scope_belongs_to_component_validator.rb +0 -16
  515. data/app/views/decidim/account/_user_groups.html.erb +0 -0
  516. data/app/views/decidim/scopes/_scopes_picker_input.html.erb +0 -19
  517. data/app/views/decidim/scopes/picker.html.erb +0 -53
  518. data/app/views/decidim/shared/_comments.html.erb +0 -0
  519. data/app/views/decidim/shared/_share_modal.html.erb +0 -26
  520. data/app/views/decidim/shared/_tags.html.erb +0 -1
  521. data/app/views/decidim/user_interests/_areas.html.erb +0 -14
  522. data/app/views/decidim/user_interests/_scopes.html.erb +0 -22
  523. data/app/views/decidim/user_interests/show.html.erb +0 -22
  524. data/config/initializers/foundation_rails_helper.rb +0 -4
  525. data/config/locales/ca-IT.yml +0 -2111
  526. data/lib/decidim/core/test/shared_examples/has_category.rb +0 -38
  527. data/lib/decidim/core/test/shared_examples/has_scope.rb +0 -11
  528. data/lib/decidim/core/test/shared_examples/manage_component_share_tokens.rb +0 -83
  529. data/lib/decidim/core/test/shared_examples/preview_component_with_share_token_examples.rb +0 -49
  530. data/lib/decidim/core/test/shared_examples/scope_helper_examples.rb +0 -93
  531. data/lib/decidim/seven_zip_wrapper.rb +0 -29
  532. data/lib/tasks/upgrade/clean_hidden_resources.rake +0 -33
@@ -26,23 +26,23 @@ module Decidim
26
26
  sent_at.present?
27
27
  end
28
28
 
29
- def sent_scopes_ids
30
- extended_data["scope_ids"] || []
29
+ def sent_to_all_users?
30
+ extended_data["send_to_all_users"]
31
31
  end
32
32
 
33
- def sent_scopes
34
- @sent_scopes ||= organization.scopes.where(id: sent_scopes_ids)
33
+ def sent_to_verified_users?
34
+ extended_data["send_to_verified_users"]
35
35
  end
36
36
 
37
- def sended_to_all_users?
38
- extended_data["send_to_all_users"]
37
+ def sent_to_users_with_verification_types
38
+ extended_data["verification_types"]
39
39
  end
40
40
 
41
- def sended_to_followers?
41
+ def sent_to_followers?
42
42
  extended_data["send_to_followers"]
43
43
  end
44
44
 
45
- def sended_to_participants?
45
+ def sent_to_participants?
46
46
  extended_data["send_to_participants"]
47
47
  end
48
48
 
@@ -50,6 +50,10 @@ module Decidim
50
50
  extended_data["participatory_space_types"]
51
51
  end
52
52
 
53
+ def sent_to_private_members?
54
+ extended_data["send_to_private_members"]
55
+ end
56
+
53
57
  def template
54
58
  @template ||= Decidim::ContentBlock
55
59
  .for_scope(:newsletter_template, organization:)
@@ -35,6 +35,8 @@ module Decidim
35
35
 
36
36
  has_many :templates, foreign_key: "decidim_organization_id", class_name: "Decidim::Templates::Template", dependent: :destroy if defined? Decidim::Templates
37
37
 
38
+ has_many :taxonomies, foreign_key: "decidim_organization_id", class_name: "Decidim::Taxonomy", inverse_of: :organization, dependent: :destroy
39
+
38
40
  # Users registration mode. Whether users can register or access the system. Does not affect users that access through Omniauth integrations.
39
41
  # enabled: Users registration and sign in are enabled (default value).
40
42
  # existing: Users cannot be registered in the system. Only existing users can sign in.
@@ -58,7 +60,7 @@ module Decidim
58
60
  has_one_attached :highlighted_content_banner_image
59
61
  validates_upload :highlighted_content_banner_image, uploader: Decidim::ImageUploader
60
62
 
61
- has_one_attached :open_data_file
63
+ has_many_attached :open_data_files
62
64
 
63
65
  validate :unique_name
64
66
 
@@ -148,8 +150,10 @@ module Decidim
148
150
  !users_registration_mode_disabled?
149
151
  end
150
152
 
151
- def open_data_file_path
152
- "#{host}-open-data.zip"
153
+ def open_data_file_path(resource = nil)
154
+ return "#{host}-open-data.zip" if resource.nil?
155
+
156
+ "#{host}-open-data-#{resource}.csv"
153
157
  end
154
158
 
155
159
  def enabled_omniauth_providers
@@ -5,15 +5,25 @@ module Decidim
5
5
  class ParticipatorySpacePrivateUser < ApplicationRecord
6
6
  include Decidim::DownloadYourData
7
7
  include ParticipatorySpaceUser
8
+ include Decidim::TranslatableResource
8
9
 
9
10
  belongs_to :privatable_to, polymorphic: true
10
11
 
12
+ translatable_fields :role
13
+
14
+ delegate :email, :name, to: :user
15
+
11
16
  scope :by_participatory_space, ->(privatable_to) { where(privatable_to_id: privatable_to.id, privatable_to_type: privatable_to.class.to_s) }
17
+ scope :published, -> { where(published: true) }
12
18
 
13
19
  def self.user_collection(user)
14
20
  where(decidim_user_id: user.id)
15
21
  end
16
22
 
23
+ def self.private_user_ids_for_participatory_spaces(spaces)
24
+ joins(:user).where(privatable_to: spaces).distinct.pluck(:decidim_user_id)
25
+ end
26
+
17
27
  def self.export_serializer
18
28
  Decidim::DownloadYourDataSerializers::DownloadYourDataParticipatorySpacePrivateUserSerializer
19
29
  end
@@ -26,6 +36,16 @@ module Decidim
26
36
  Arel.sql(%{("invitation_sent_at")::text})
27
37
  end
28
38
 
39
+ def self.ransackable_attributes(auth_object = nil)
40
+ return [] unless auth_object&.admin?
41
+
42
+ %w(name nickname email invitation_accepted_at last_sign_in_at invitation_sent_at role)
43
+ end
44
+
45
+ def self.ransackable_associations(_auth_object = nil)
46
+ %w(user)
47
+ end
48
+
29
49
  def target_space_association = :privatable_to
30
50
  end
31
51
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ class PrivateExport < ApplicationRecord
5
+ belongs_to :attached_to, polymorphic: true
6
+
7
+ has_one_attached :file
8
+ validates :content_type, presence: true
9
+
10
+ before_validation :set_content_type_and_size, if: :attached?
11
+ delegate :attached?, to: :file
12
+
13
+ default_scope { order(created_at: :desc) }
14
+
15
+ def expired?
16
+ expires_at < Time.zone.now
17
+ end
18
+
19
+ def set_content_type_and_size
20
+ self.content_type = file.content_type
21
+ self.file_size = file.byte_size
22
+ end
23
+ end
24
+ end
@@ -26,7 +26,7 @@ module Decidim
26
26
  end
27
27
 
28
28
  def url
29
- EngineRouter.new("decidim", {}).public_send(:conversation_path, host: organization.host, id: @conversation)
29
+ EngineRouter.new("decidim", {}).conversation_path(host: organization.host, id: @conversation)
30
30
  end
31
31
 
32
32
  private
@@ -5,7 +5,7 @@ module Decidim
5
5
  class Report < ApplicationRecord
6
6
  include Decidim::DownloadYourData
7
7
 
8
- REASONS = %w(spam offensive does_not_belong hidden_during_block parent_hidden).freeze
8
+ REASONS = %w(spam offensive does_not_belong hidden_during_block).freeze
9
9
 
10
10
  belongs_to :moderation, foreign_key: "decidim_moderation_id", class_name: "Decidim::Moderation"
11
11
  belongs_to :user, foreign_key: "decidim_user_id", class_name: "Decidim::User"
@@ -76,6 +76,10 @@ module Decidim
76
76
  # Allow ransacker to search for a key in a hstore column (`name`.`en`)
77
77
  ransacker_i18n :name
78
78
 
79
+ def self.ransackable_attributes(_auth_object = nil)
80
+ %w(name id)
81
+ end
82
+
79
83
  private
80
84
 
81
85
  def forbid_cycles
@@ -2,33 +2,63 @@
2
2
 
3
3
  module Decidim
4
4
  class ShareToken < ApplicationRecord
5
- validates :token, presence: true, uniqueness: { scope: [:decidim_organization_id, :token_for_type, :token_for_id] }
5
+ include Decidim::Traceable
6
6
 
7
7
  belongs_to :organization, foreign_key: "decidim_organization_id", class_name: "Decidim::Organization"
8
8
  belongs_to :user, foreign_key: "decidim_user_id", class_name: "Decidim::User"
9
9
  belongs_to :token_for, foreign_type: "token_for_type", polymorphic: true
10
10
 
11
- after_initialize :generate, :set_default_expiration
11
+ validates :token, presence: true, uniqueness: { scope: [:decidim_organization_id, :token_for_type, :token_for_id] }
12
+ # validates token no spaces or strange characters
13
+ validates :token, format: { with: /\A[a-zA-Z0-9_-]+\z/ }
14
+
15
+ after_initialize :generate
16
+
17
+ def self.log_presenter_class_for(_log)
18
+ Decidim::AdminLog::ShareTokenPresenter
19
+ end
12
20
 
13
- def self.use!(token_for:, token:)
21
+ def self.use!(token_for:, token:, user: nil)
14
22
  record = find_by!(token_for:, token:)
15
- record.use!
23
+ record.use!(user:)
16
24
  end
17
25
 
18
- def use!
26
+ def use!(user: nil)
19
27
  return raise StandardError, "Share token '#{token}' for '#{token_for_type}' with id = #{token_for_id} has expired." if expired?
28
+ return raise StandardError, "Share token '#{token}' for '#{token_for_type}' with id = #{token_for_id} requires a registered user." if registered_only? && user.nil?
20
29
 
21
30
  update!(times_used: times_used + 1, last_used_at: Time.zone.now)
22
31
  end
23
32
 
24
33
  def expired?
25
- expires_at.past?
34
+ expires_at.past? unless expires_at.nil?
26
35
  end
27
36
 
28
37
  def url
29
38
  token_for.shareable_url(self)
30
39
  end
31
40
 
41
+ def participatory_space
42
+ return token_for if token_for.try(:manifest).is_a?(Decidim::ParticipatorySpaceManifest)
43
+ return token_for.participatory_space if token_for.respond_to?(:participatory_space)
44
+
45
+ component&.participatory_space
46
+ end
47
+
48
+ def component
49
+ return token_for if token_for.is_a?(Decidim::Component)
50
+
51
+ token_for.component if token_for.respond_to?(:component)
52
+ end
53
+
54
+ def self.ransackable_attributes(_auth_object = nil)
55
+ %w(token expires_at last_used_at registered_only times_used)
56
+ end
57
+
58
+ def self.ransackable_associations(_auth_object = nil)
59
+ %w(organization token_for user)
60
+ end
61
+
32
62
  private
33
63
 
34
64
  def generate
@@ -39,9 +69,5 @@ module Decidim
39
69
  break if ShareToken.find_by(token:).blank?
40
70
  end
41
71
  end
42
-
43
- def set_default_expiration
44
- self.expires_at ||= 1.day.from_now
45
- end
46
72
  end
47
73
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # Represents the link between a taxonomy and any taxonomizable entity.
5
+ class Taxonomization < ApplicationRecord
6
+ belongs_to :taxonomy,
7
+ class_name: "Decidim::Taxonomy",
8
+ counter_cache: :taxonomizations_count,
9
+ inverse_of: :taxonomizations
10
+
11
+ belongs_to :taxonomizable, polymorphic: true
12
+
13
+ validate :prevent_root_taxonomization
14
+
15
+ private
16
+
17
+ def prevent_root_taxonomization
18
+ return unless taxonomy.root?
19
+
20
+ errors.add(:taxonomy, :invalid)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # Represents a hierarchical classification used to organize various entities within the system.
5
+ # Taxonomies are primarily used to categorize and manage different aspects of participatory spaces,
6
+ # such as proposals, assemblies, and other components, within an organization.
7
+ class Taxonomy < ApplicationRecord
8
+ include Decidim::TranslatableResource
9
+ include Decidim::FilterableResource
10
+ include Decidim::Traceable
11
+
12
+ before_create :set_default_weight
13
+ before_validation :update_part_of, on: [:update, :create]
14
+ after_create_commit :create_part_of
15
+
16
+ translatable_fields :name
17
+
18
+ belongs_to :organization,
19
+ foreign_key: "decidim_organization_id",
20
+ class_name: "Decidim::Organization",
21
+ inverse_of: :taxonomies
22
+
23
+ belongs_to :parent,
24
+ class_name: "Decidim::Taxonomy",
25
+ counter_cache: :children_count,
26
+ inverse_of: :children,
27
+ optional: true
28
+
29
+ has_many :children,
30
+ foreign_key: "parent_id",
31
+ class_name: "Decidim::Taxonomy",
32
+ inverse_of: :parent,
33
+ dependent: :destroy
34
+
35
+ has_many :taxonomizations, class_name: "Decidim::Taxonomization", dependent: :destroy
36
+ has_many :taxonomy_filters, foreign_key: "root_taxonomy_id", class_name: "Decidim::TaxonomyFilter", dependent: :destroy
37
+ has_many :taxonomy_filter_items, foreign_key: "taxonomy_item_id", class_name: "Decidim::TaxonomyFilterItem", dependent: :destroy
38
+
39
+ validates :name, presence: true
40
+ validates :weight, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
41
+ validate :validate_max_children_levels
42
+ validate :forbid_cycles
43
+
44
+ default_scope { order(:weight) }
45
+ scope :for, ->(organization) { where(organization:) }
46
+ scope :roots, -> { where(parent_id: nil) }
47
+ scope :non_roots, -> { where.not(parent_id: nil) }
48
+
49
+ ransacker_i18n :name
50
+
51
+ scope :search_by_name, lambda { |name|
52
+ where("name ->> ? ILIKE ?", I18n.locale.to_s, "%#{name}%")
53
+ }
54
+
55
+ scope :part_of, lambda { |id|
56
+ where("part_of @> ARRAY[?]", id.to_i)
57
+ }
58
+
59
+ def self.log_presenter_class_for(_log)
60
+ Decidim::AdminLog::TaxonomyPresenter
61
+ end
62
+
63
+ def self.ransackable_scopes(_auth_object = nil)
64
+ [:search_by_name, :part_of]
65
+ end
66
+
67
+ def self.ransackable_attributes(_auth_object = nil)
68
+ %w(id name parent_id part_of)
69
+ end
70
+
71
+ def self.ransackable_associations(_auth_object = nil)
72
+ %w(children)
73
+ end
74
+
75
+ def translated_name
76
+ Decidim::TaxonomyPresenter.new(self).translated_name
77
+ end
78
+
79
+ def root_taxonomy
80
+ @root_taxonomy ||= root? ? self : parent.root_taxonomy
81
+ end
82
+
83
+ def parent_ids
84
+ @parent_ids ||= part_of.excluding(id)
85
+ end
86
+
87
+ def root? = parent_id.nil?
88
+
89
+ # this might change in the future if we want to prevent the deletion of taxonomies with associated resources
90
+ def removable?
91
+ true
92
+ end
93
+
94
+ def all_children
95
+ @all_children ||= Decidim::Taxonomy.non_roots.part_of(id).reorder(Arel.sql("array_length(part_of, 1) ASC"), "parent_id ASC", "weight ASC")
96
+ end
97
+
98
+ def reset_all_counters
99
+ Taxonomy.reset_counters(id, :children_count, :taxonomizations_count, :taxonomy_filters_count, :taxonomy_filter_items_count)
100
+ end
101
+
102
+ private
103
+
104
+ def set_default_weight
105
+ return if weight.present?
106
+
107
+ self.weight = Taxonomy.where(parent_id:).count
108
+ end
109
+
110
+ def forbid_cycles
111
+ return unless parent_id
112
+
113
+ errors.add(:parent_id, :invalid) if parent.part_of.include?(id)
114
+ end
115
+
116
+ def create_part_of
117
+ build_part_of
118
+ save if changed?
119
+ end
120
+
121
+ def update_part_of
122
+ build_part_of
123
+ end
124
+
125
+ def build_part_of
126
+ if parent
127
+ part_of.clear.append(id).concat(parent.reload.part_of)
128
+ else
129
+ part_of.clear.append(id)
130
+ end
131
+ end
132
+
133
+ def validate_max_children_levels
134
+ return unless parent_id
135
+
136
+ errors.add(:base, :invalid) if parent_ids.size > 3
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # Represents the association between a taxonomy and a filterable entity within the system.
5
+ class TaxonomyFilter < ApplicationRecord
6
+ include Decidim::TranslatableResource
7
+ include Decidim::Traceable
8
+
9
+ translatable_fields :name, :internal_name
10
+
11
+ belongs_to :root_taxonomy,
12
+ class_name: "Decidim::Taxonomy",
13
+ counter_cache: :filters_count,
14
+ inverse_of: :taxonomy_filters
15
+
16
+ has_many :filter_items,
17
+ class_name: "Decidim::TaxonomyFilterItem",
18
+ inverse_of: :taxonomy_filter,
19
+ dependent: :destroy
20
+
21
+ validate :root_taxonomy_is_root
22
+ validate :space_manifest_is_registered
23
+
24
+ scope :for_manifest, ->(space_manifest) { where("? = ANY(participatory_space_manifests)", space_manifest) }
25
+ scope :space_filters, -> { where.not(participatory_space_manifests: []) }
26
+ # filters for the organization
27
+ scope :for, ->(organization) { joins(:root_taxonomy).where(decidim_taxonomies: { decidim_organization_id: organization.id }) }
28
+
29
+ delegate :organization, to: :root_taxonomy
30
+ delegate :translated_name, :translated_internal_name, to: :presenter
31
+
32
+ def presenter
33
+ Decidim::TaxonomyFilterPresenter.new(self)
34
+ end
35
+
36
+ # Returns the presenter class for this log.
37
+ #
38
+ # log - A Decidim::Log instance.
39
+ #
40
+ # Returns a Decidim::AdminLog::TaxonomyFilterPresenter class
41
+ def self.log_presenter_class_for(_log)
42
+ Decidim::AdminLog::TaxonomyFilterPresenter
43
+ end
44
+
45
+ # Public name for this filter, defaults to the root taxonomy name.
46
+ def name
47
+ return root_taxonomy&.name if super&.compact_blank.blank?
48
+
49
+ super
50
+ end
51
+
52
+ # Internal name for this filter, defaults to the root taxonomy name.
53
+ def internal_name
54
+ return root_taxonomy&.name if super&.compact_blank.blank?
55
+
56
+ super
57
+ end
58
+
59
+ # Components that have this taxonomy filter enabled.
60
+ def components
61
+ @components ||= Decidim::Component.where("(settings->'global'->'taxonomy_filters') @> ?", "\"#{id}\"")
62
+ end
63
+
64
+ def filter_taxonomy_ids
65
+ @filter_taxonomy_ids ||= filter_items.map(&:taxonomy_item_id)
66
+ end
67
+
68
+ # A memoized taxonomy tree hash filtered according to the filter_items
69
+
70
+ # that respects the order given by the taxonomies table.
71
+ # The returned hash structure is:
72
+ # {
73
+ # _object_id_ => {
74
+ # taxonomy: _object_,
75
+ # children: {
76
+ # _sub_object_id_: {
77
+ # taxonomy: _sub_object_,
78
+ # children: {
79
+ # ...
80
+ # }
81
+ # @returns [Hash] a hash with the taxonomy tree structure.
82
+ def taxonomies
83
+ @taxonomies ||= root_taxonomy
84
+ .all_children
85
+ .where(id: filter_taxonomy_ids)
86
+ .each_with_object({}) do |taxonomy, tree|
87
+ insert_child(taxonomy, tree)
88
+ end
89
+ end
90
+
91
+ def update_components_count
92
+ update(components_count: components.count)
93
+ end
94
+
95
+ def reset_all_counters
96
+ Decidim::TaxonomyFilter.reset_counters(id, :filter_items_count)
97
+ update_components_count
98
+ end
99
+
100
+ private
101
+
102
+ def insert_child(taxonomy, tree)
103
+ return if tree[taxonomy.id]
104
+
105
+ if (parent = find_parent(taxonomy, tree))
106
+ insert_child(taxonomy, parent[:children])
107
+ else
108
+ tree[taxonomy.id] = { taxonomy:, children: {} }
109
+ end
110
+ end
111
+
112
+ def find_parent(taxonomy, tree)
113
+ tree[taxonomy.parent_id].presence ||
114
+ tree.values.detect { |v| find_parent(taxonomy, v[:children]) }
115
+ end
116
+
117
+ def root_taxonomy_is_root
118
+ return if root_taxonomy&.root?
119
+
120
+ errors.add(:root_taxonomy, :invalid)
121
+ end
122
+
123
+ def space_manifest_is_registered
124
+ available_manifests = Decidim.participatory_space_manifests.map(&:name)
125
+ return if (participatory_space_manifests.map(&:to_sym) - available_manifests).empty?
126
+
127
+ errors.add(:participatory_space_manifests, :invalid)
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ # Represents the association between a taxonomy and a filterable entity within the system.
5
+ class TaxonomyFilterItem < ApplicationRecord
6
+ belongs_to :taxonomy_filter,
7
+ class_name: "Decidim::TaxonomyFilter",
8
+ counter_cache: :filter_items_count,
9
+ inverse_of: :filter_items
10
+
11
+ belongs_to :taxonomy_item,
12
+ class_name: "Decidim::Taxonomy",
13
+ counter_cache: :filter_items_count,
14
+ inverse_of: :taxonomy_filter_items
15
+
16
+ validate :taxonomy_item_is_not_root
17
+ validate :taxonomy_item_is_child_of_taxonomy_filter_root
18
+
19
+ private
20
+
21
+ def taxonomy_item_is_not_root
22
+ return unless taxonomy_item&.root?
23
+
24
+ errors.add(:taxonomy_item, :invalid)
25
+ end
26
+
27
+ def taxonomy_item_is_child_of_taxonomy_filter_root
28
+ return if taxonomy_item&.root_taxonomy == taxonomy_filter&.root_taxonomy
29
+
30
+ errors.add(:taxonomy_item, :invalid)
31
+ end
32
+ end
33
+ end
@@ -13,6 +13,8 @@ module Decidim
13
13
  include Decidim::UserReportable
14
14
  include Decidim::Traceable
15
15
 
16
+ REGEXP_NICKNAME = /\A[\w-]+\z/
17
+
16
18
  class Roles
17
19
  def self.all
18
20
  Decidim.config.user_roles
@@ -33,6 +35,7 @@ module Decidim
33
35
  has_many :access_grants, class_name: "Doorkeeper::AccessGrant", foreign_key: :resource_owner_id, dependent: :destroy
34
36
  has_many :access_tokens, class_name: "Doorkeeper::AccessToken", foreign_key: :resource_owner_id, dependent: :destroy
35
37
  has_many :reminders, foreign_key: "decidim_user_id", class_name: "Decidim::Reminder", dependent: :destroy
38
+ has_many :private_exports, class_name: "Decidim::PrivateExport", dependent: :destroy, inverse_of: :attached_to, as: :attached_to
36
39
 
37
40
  validates :name, presence: true, unless: -> { deleted? }
38
41
  validates :nickname,
@@ -43,37 +46,28 @@ module Decidim
43
46
  validates :locale, inclusion: { in: :available_locales }, allow_blank: true
44
47
  validates :tos_agreement, acceptance: true, allow_nil: false, on: :create
45
48
  validates :tos_agreement, acceptance: true, if: :user_invited?
49
+ validates :tos_agreement, acceptance: true, if: :ephemeral?
46
50
  validates :email, :nickname, uniqueness: { scope: :organization }, unless: -> { deleted? || managed? || nickname.blank? }
47
51
 
48
52
  validate :all_roles_are_valid
49
53
 
50
54
  has_one_attached :download_your_data_file
51
55
 
56
+ scope :not_deleted, -> { where(deleted_at: nil) }
57
+
52
58
  scope :managed, -> { where(managed: true) }
53
59
  scope :not_managed, -> { where(managed: false) }
54
60
 
55
61
  scope :officialized, -> { where.not(officialized_at: nil) }
56
62
  scope :not_officialized, -> { where(officialized_at: nil) }
57
63
 
58
- scope :interested_in_scopes, lambda { |scope_ids|
59
- actual_ids = scope_ids.select(&:presence)
60
- if actual_ids.count.positive?
61
- ids = actual_ids.map(&:to_i).join(",")
62
- where(Arel.sql("extended_data->'interested_scopes' @> ANY('{#{ids}}')").to_s)
63
- else
64
- # Do not apply the scope filter when there are scope ids available. Note
65
- # that the active record scope must always return an active record
66
- # collection.
67
- self
68
- end
69
- }
70
-
71
64
  scope :org_admins_except_me, ->(user) { where(organization: user.organization, admin: true).where.not(id: user.id) }
72
65
 
66
+ scope :ephemeral, -> { where("extended_data @> ?", Arel.sql({ ephemeral: true }.to_json)) }
67
+
73
68
  attr_accessor :newsletter_notifications
74
69
 
75
70
  searchable_fields({
76
- # scope_id: :decidim_scope_id,
77
71
  organization_id: :decidim_organization_id,
78
72
  A: :name,
79
73
  B: :nickname,
@@ -191,7 +185,7 @@ module Decidim
191
185
  end
192
186
 
193
187
  def tos_accepted?
194
- return true if managed
188
+ return true if managed && !ephemeral?
195
189
  return false if accepted_tos_version.nil?
196
190
 
197
191
  # For some reason, if we do not use `#to_i` here we get some
@@ -213,14 +207,6 @@ module Decidim
213
207
  ImpersonationLog.active.exists?(user: self)
214
208
  end
215
209
 
216
- def interested_scopes_ids
217
- extended_data["interested_scopes"] || []
218
- end
219
-
220
- def interested_scopes
221
- @interested_scopes ||= organization.scopes.where(id: interested_scopes_ids)
222
- end
223
-
224
210
  def user_name
225
211
  extended_data["user_name"] || name
226
212
  end
@@ -274,6 +260,10 @@ module Decidim
274
260
  false
275
261
  end
276
262
 
263
+ def ephemeral?
264
+ extended_data["ephemeral"]
265
+ end
266
+
277
267
  def after_confirmation
278
268
  return unless organization.send_welcome_notification?
279
269