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
@@ -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).freeze
8
+ REASONS = %w(spam offensive does_not_belong hidden_during_block parent_hidden).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
@@ -35,6 +35,7 @@ module Decidim
35
35
  has_many :access_grants, class_name: "Doorkeeper::AccessGrant", foreign_key: :resource_owner_id, dependent: :destroy
36
36
  has_many :access_tokens, class_name: "Doorkeeper::AccessToken", foreign_key: :resource_owner_id, dependent: :destroy
37
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
38
39
 
39
40
  validates :name, presence: true, unless: -> { deleted? }
40
41
  validates :nickname,
@@ -45,6 +46,7 @@ module Decidim
45
46
  validates :locale, inclusion: { in: :available_locales }, allow_blank: true
46
47
  validates :tos_agreement, acceptance: true, allow_nil: false, on: :create
47
48
  validates :tos_agreement, acceptance: true, if: :user_invited?
49
+ validates :tos_agreement, acceptance: true, if: :ephemeral?
48
50
  validates :email, :nickname, uniqueness: { scope: :organization }, unless: -> { deleted? || managed? || nickname.blank? }
49
51
 
50
52
  validate :all_roles_are_valid
@@ -59,25 +61,13 @@ module Decidim
59
61
  scope :officialized, -> { where.not(officialized_at: nil) }
60
62
  scope :not_officialized, -> { where(officialized_at: nil) }
61
63
 
62
- scope :interested_in_scopes, lambda { |scope_ids|
63
- actual_ids = scope_ids.select(&:presence)
64
- if actual_ids.count.positive?
65
- ids = actual_ids.map(&:to_i).join(",")
66
- where(Arel.sql("extended_data->'interested_scopes' @> ANY('{#{ids}}')").to_s)
67
- else
68
- # Do not apply the scope filter when there are scope ids available. Note
69
- # that the active record scope must always return an active record
70
- # collection.
71
- self
72
- end
73
- }
74
-
75
64
  scope :org_admins_except_me, ->(user) { where(organization: user.organization, admin: true).where.not(id: user.id) }
76
65
 
66
+ scope :ephemeral, -> { where("extended_data @> ?", Arel.sql({ ephemeral: true }.to_json)) }
67
+
77
68
  attr_accessor :newsletter_notifications
78
69
 
79
70
  searchable_fields({
80
- # scope_id: :decidim_scope_id,
81
71
  organization_id: :decidim_organization_id,
82
72
  A: :name,
83
73
  B: :nickname,
@@ -195,7 +185,7 @@ module Decidim
195
185
  end
196
186
 
197
187
  def tos_accepted?
198
- return true if managed
188
+ return true if managed && !ephemeral?
199
189
  return false if accepted_tos_version.nil?
200
190
 
201
191
  # For some reason, if we do not use `#to_i` here we get some
@@ -217,14 +207,6 @@ module Decidim
217
207
  ImpersonationLog.active.exists?(user: self)
218
208
  end
219
209
 
220
- def interested_scopes_ids
221
- extended_data["interested_scopes"] || []
222
- end
223
-
224
- def interested_scopes
225
- @interested_scopes ||= organization.scopes.where(id: interested_scopes_ids)
226
- end
227
-
228
210
  def user_name
229
211
  extended_data["user_name"] || name
230
212
  end
@@ -278,6 +260,10 @@ module Decidim
278
260
  false
279
261
  end
280
262
 
263
+ def ephemeral?
264
+ extended_data["ephemeral"]
265
+ end
266
+
281
267
  def after_confirmation
282
268
  return unless organization.send_welcome_notification?
283
269
 
@@ -65,6 +65,18 @@ module Decidim
65
65
  Decidim::UserBaseEntity.joins(:follows).where(decidim_follows: { user: self }).blocked.exists?
66
66
  end
67
67
 
68
+ def self.ransackable_attributes(auth_object = nil)
69
+ base = %w(name email nickname last_sign_in_at)
70
+
71
+ return base unless auth_object&.admin?
72
+
73
+ base + %w(invitation_sent_at invitation_accepted_at officialized_at)
74
+ end
75
+
76
+ def self.ransackable_associations(_auth_object = nil)
77
+ []
78
+ end
79
+
68
80
  private
69
81
 
70
82
  def only_public(klass, ids)