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
@@ -53,54 +53,59 @@ module Decidim
53
53
  # def name=(value)
54
54
  # super(encrypt_value(value))
55
55
  # end
56
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
57
-
58
- # def full_name
59
- # return @full_name_decrypted if instance_variable_defined?(:@full_name_decrypted)
60
- #
61
- # encrypted_value = begin
62
- # if defined?(super)
63
- # super
64
- # elsif instance_variable_defined?(:@full_name)
65
- # @full_name
66
- # end
67
- # end
68
- # @full_name_decrypted = decrypt_value(encrypted_value)
69
- # end
70
- def #{attribute}
71
- return @#{attribute}_decrypted if instance_variable_defined?(:@#{attribute}_decrypted)
72
-
73
- encrypted_value = begin
74
- if defined?(super)
75
- super
76
- elsif instance_variable_defined?(:@#{attribute})
77
- @#{attribute}
78
- end
79
- end
80
- @#{attribute}_decrypted = decrypt_#{method_suffix}(encrypted_value)
81
- end
56
+ create_encrypted_getter(attribute, method_suffix)
57
+ create_encrypted_setter(attribute, method_suffix)
58
+ end
59
+
60
+ # def full_name
61
+ # return @full_name_decrypted if instance_variable_defined?(:@full_name_decrypted)
62
+ #
63
+ # encrypted_value = begin
64
+ # if defined?(super)
65
+ # super
66
+ # elsif instance_variable_defined?(:@full_name)
67
+ # @full_name
68
+ # end
69
+ # end
70
+ # @full_name_decrypted = decrypt_value(encrypted_value)
71
+ # end
72
+ def create_encrypted_getter(attribute, method_suffix)
73
+ define_method(attribute) do
74
+ return instance_variable_get(:"@#{attribute}_decrypted") if instance_variable_defined?(:"@#{attribute}_decrypted")
75
+
76
+ encrypted_value = if defined?(super)
77
+ super()
78
+ elsif instance_variable_defined?(:"@#{attribute}")
79
+ instance_variable_get(:"@#{attribute}")
80
+ end
81
+
82
+ decrypted_value = send(:"decrypt_#{method_suffix}", encrypted_value)
83
+ instance_variable_set(:"@#{attribute}_decrypted", decrypted_value)
84
+ end
85
+ end
82
86
 
83
- # def full_name=(value)
84
- # remove_instance_variable(:@full_name_decrypted) if instance_variable_defined?(:@full_name_decrypted)
85
- # encrypted_value = encrypt_value(value)
86
- #
87
- # if defined?(super)
88
- # super(encrypted_value)
89
- # else
90
- # @full_name = encrypted_value
91
- # end
92
- # end
93
- def #{attribute}=(value)
94
- remove_instance_variable(:@#{attribute}_decrypted) if instance_variable_defined?(:@#{attribute}_decrypted)
95
- encrypted_value = encrypt_#{method_suffix}(value)
96
-
97
- if defined?(super)
98
- super(encrypted_value)
99
- else
100
- @#{attribute} = encrypted_value
101
- end
87
+ # def full_name=(value)
88
+ # remove_instance_variable(:@full_name_decrypted) if instance_variable_defined?(:@full_name_decrypted)
89
+ # encrypted_value = encrypt_value(value)
90
+ #
91
+ # if defined?(super)
92
+ # super(encrypted_value)
93
+ # else
94
+ # @full_name = encrypted_value
95
+ # end
96
+ # end
97
+ def create_encrypted_setter(attribute, method_suffix)
98
+ define_method("#{attribute}=") do |value|
99
+ remove_instance_variable(:"@#{attribute}_decrypted") if instance_variable_defined?(:"@#{attribute}_decrypted")
100
+
101
+ encrypted_value = send(:"encrypt_#{method_suffix}", value)
102
+
103
+ if defined?(super)
104
+ super(encrypted_value)
105
+ else
106
+ instance_variable_set(:"@#{attribute}", encrypted_value)
102
107
  end
103
- RUBY
108
+ end
104
109
  end
105
110
  end
106
111
 
@@ -50,6 +50,22 @@ module Decidim
50
50
  scope.where(id: from).or(scope.where(id: to))
51
51
  end
52
52
 
53
+ def linked_resources_from(resource_name, link_name, component_published: true)
54
+ scope = sibling_scope(resource_name, component_published:)
55
+
56
+ scope
57
+ .joins(:resource_links_from)
58
+ .where(decidim_resource_links: { name: link_name, to_id: id, to_type: self.class.name })
59
+ end
60
+
61
+ def linked_resources_to(resource_name, link_name, component_published: true)
62
+ scope = sibling_scope(resource_name, component_published:)
63
+
64
+ scope
65
+ .joins(:resource_links_to)
66
+ .where(decidim_resource_links: { name: link_name, from_id: id, from_type: self.class.name })
67
+ end
68
+
53
69
  # Builds an ActiveRecord::Relation in order to load all the resources
54
70
  # that are in the same parent as this model.
55
71
  #
data/lib/decidim/seeds.rb CHANGED
@@ -21,7 +21,7 @@ module Decidim
21
21
  user = Decidim::User.find_or_initialize_by(email:)
22
22
  user.update!(
23
23
  name: ::Faker::Name.name,
24
- nickname: ::Faker::Twitter.unique.screen_name,
24
+ nickname: "#{::Faker::Twitter.unique.screen_name}-#{rand(10_000)}"[0...20],
25
25
  password: "decidim123456789",
26
26
  organization:,
27
27
  confirmed_at: Time.current,
@@ -38,18 +38,6 @@ module Decidim
38
38
  user
39
39
  end
40
40
 
41
- def random_scope(participatory_space:)
42
- if participatory_space.scope
43
- scopes = participatory_space.scope.descendants
44
- global = participatory_space.scope
45
- else
46
- scopes = participatory_space.organization.scopes
47
- global = nil
48
- end
49
-
50
- ::Faker::Boolean.boolean(true_ratio: 0.5) ? global : scopes.sample
51
- end
52
-
53
41
  def seeds_root = File.join(__dir__, "..", "..", "db", "seeds")
54
42
 
55
43
  def hero_image = create_blob!(seeds_file: "city.jpeg", filename: "hero_image.jpeg", content_type: "image/jpeg")
@@ -97,13 +85,23 @@ module Decidim
97
85
  )
98
86
  end
99
87
 
100
- def create_category!(participatory_space:)
101
- Decidim::Category.create!(
102
- name: Decidim::Faker::Localized.sentence(word_count: 5),
103
- description: Decidim::Faker::Localized.wrapped("<p>", "</p>") do
104
- Decidim::Faker::Localized.paragraph(sentence_count: 3)
105
- end,
106
- participatory_space:
88
+ def create_taxonomy!(name:, parent:)
89
+ Decidim::Taxonomy.create!(
90
+ name: Decidim::Faker::Localized.literal(name),
91
+ organization:,
92
+ parent:
93
+ )
94
+ end
95
+
96
+ def create_taxonomy_filter!(root_taxonomy:, taxonomies:, participatory_space_manifests: [])
97
+ Decidim::TaxonomyFilter.create!(
98
+ root_taxonomy:,
99
+ participatory_space_manifests:,
100
+ filter_items: taxonomies.map do |taxonomy_item|
101
+ Decidim::TaxonomyFilterItem.new(
102
+ taxonomy_item:
103
+ )
104
+ end
107
105
  )
108
106
  end
109
107
 
@@ -70,6 +70,8 @@ module Decidim
70
70
  validates name, presence: true if attribute.required
71
71
  validates name, inclusion: { in: attribute.build_choices } if attribute.type == :enum
72
72
  end
73
+
74
+ SettingsManifest.add_integer_with_units_validation(self, name, attribute) if attribute.type == :integer_with_units
73
75
  end
74
76
  end
75
77
 
@@ -77,6 +79,20 @@ module Decidim
77
79
  @schema
78
80
  end
79
81
 
82
+ def self.add_integer_with_units_validation(schema, name, attribute)
83
+ schema.class_eval do
84
+ validate do
85
+ value = send(name)
86
+ value = [value["0"].to_i, value["1"].to_s] if value.is_a?(::Hash)
87
+
88
+ errors.add(name, :invalid) unless value.is_a?(::Array) &&
89
+ value.size == 2 &&
90
+ value[0].is_a?(Integer) &&
91
+ attribute.build_units.include?(value[1])
92
+ end
93
+ end
94
+ end
95
+
80
96
  def required_attributes_for_authorization
81
97
  attributes.select { |_, attribute| attribute.required_for_authorization? }
82
98
  end
@@ -91,6 +107,7 @@ module Decidim
91
107
  TYPES = {
92
108
  boolean: { klass: Boolean, default: false },
93
109
  integer: { klass: Integer, default: 0 },
110
+ integer_with_units: { klass: Decidim::Attributes::IntegerWithUnits, default: [5, "minutes"] },
94
111
  string: { klass: String, default: nil },
95
112
  float: { klass: Float, default: nil },
96
113
  text: { klass: String, default: nil },
@@ -98,7 +115,8 @@ module Decidim
98
115
  enum: { klass: String, default: nil },
99
116
  select: { klass: String, default: nil },
100
117
  scope: { klass: Integer, default: nil },
101
- time: { klass: Decidim::Attributes::TimeWithZone, default: nil }
118
+ time: { klass: Decidim::Attributes::TimeWithZone, default: nil },
119
+ taxonomy_filters: { klass: Array, default: [] }
102
120
  }.freeze
103
121
 
104
122
  attribute :type, Symbol, default: :boolean
@@ -111,9 +129,20 @@ module Decidim
111
129
  attribute :required_for_authorization, Boolean, default: false
112
130
  attribute :readonly
113
131
  attribute :choices
132
+ attribute :units
114
133
  attribute :include_blank, Boolean, default: false
115
134
 
116
135
  validates :type, inclusion: { in: TYPES.keys }
136
+ validate :validate_integer_with_units_structure
137
+
138
+ def validate_integer_with_units_structure
139
+ return unless type == :integer_with_units
140
+
141
+ errors.add(:default, :invalid) unless default_value.is_a?(::Array) &&
142
+ default_value.size == 2 &&
143
+ default_value[0].is_a?(Integer) &&
144
+ build_units.include?(default_value[1])
145
+ end
117
146
 
118
147
  def type_class
119
148
  return Decidim::Attributes::RichText if type == :text && editor == true
@@ -129,6 +158,10 @@ module Decidim
129
158
  choices.try(:call) || choices
130
159
  end
131
160
 
161
+ def build_units
162
+ units.try(:call) || units
163
+ end
164
+
132
165
  def readonly?(context)
133
166
  readonly&.call(context)
134
167
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+ require "paranoia"
5
+
6
+ module Decidim
7
+ # This concern contains the logic related to soft deletion (trashing).
8
+ module SoftDeletable
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ acts_as_paranoid
13
+
14
+ scope :deleted_at_desc, -> { order(deleted_at: :desc) }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Decidim
6
+ # A concern with the components needed when you want a model to have taxonomies.
7
+ #
8
+ # The including model needs to implement the following interface:
9
+ #
10
+ # @abstract method that gives an associated organization
11
+ # @method organization
12
+ # @return [Decidim::Organization]
13
+ #
14
+ module Taxonomizable
15
+ extend ActiveSupport::Concern
16
+
17
+ included do
18
+ has_many :taxonomizations, as: :taxonomizable, class_name: "Decidim::Taxonomization", dependent: :destroy
19
+ has_many :taxonomies, through: :taxonomizations
20
+
21
+ validate :no_root_taxonomies
22
+ validate :taxonomies_belong_to_organization
23
+
24
+ # finds taxonomizables belonging to a specific taxonomy
25
+ scope :with_taxonomy, ->(taxonomy_id) { includes(:taxonomies).references(:decidim_taxonomies).where("? = ANY(decidim_taxonomies.part_of)", taxonomy_id) }
26
+
27
+ # finds taxonomizables belonging to any of the taxonomies specified (or its children)
28
+ scope :with_taxonomies, lambda { |*taxonomy_ids|
29
+ conditions = ["? = ANY(part_of)"] * taxonomy_ids.count
30
+ taxonomies = Decidim::Taxonomy.where(conditions.join(" OR "), *taxonomy_ids.map(&:to_i))
31
+ includes(:taxonomies).joins(:taxonomies).where(decidim_taxonomies: { id: taxonomies })
32
+ }
33
+
34
+ # finds taxonomizables belonging to all groups of taxonomies specified, each group is an array of taxonomy ids that are ORed together
35
+ scope :with_any_taxonomies, lambda { |*taxonomy_groups|
36
+ return with_taxonomies(*taxonomy_groups) unless taxonomy_groups.first.is_a?(Array)
37
+
38
+ queries = []
39
+ taxonomy_groups.each do |root_id, taxonomy_ids|
40
+ taxonomy_ids = taxonomy_ids.flatten.compact_blank
41
+ next if taxonomy_ids.empty?
42
+
43
+ taxonomy_ids = [root_id] if taxonomy_ids.include?("all")
44
+
45
+ queries << with_taxonomies(*taxonomy_ids)
46
+ end
47
+ return self if queries.empty?
48
+ return queries.first if queries.count == 1
49
+
50
+ subquery = queries.map(&:arel).reduce do |memo, query|
51
+ Arel::Nodes::Intersect.new(memo, query)
52
+ end
53
+
54
+ @klass.from(Arel::Nodes::As.new(subquery, Arel.sql(@klass.arel_table.name)))
55
+ }
56
+
57
+ private
58
+
59
+ def no_root_taxonomies
60
+ return unless taxonomies.any?(&:root?)
61
+
62
+ errors.add(:taxonomies, :invalid)
63
+ end
64
+
65
+ def taxonomies_belong_to_organization
66
+ return if taxonomies.all? { |taxonomy| taxonomy.organization == organization }
67
+
68
+ errors.add(:taxonomies, :invalid)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -8,7 +8,6 @@ module Decidim
8
8
  include ActionView::Helpers::TranslationHelper
9
9
  include ::Cell::Translation
10
10
  include Decidim::ResourceHelper
11
- include Decidim::ScopesHelper
12
11
  include ActionController::Helpers
13
12
  include Decidim::ActionAuthorization
14
13
  include Decidim::ActionAuthorizationHelper
@@ -64,7 +64,7 @@ namespace :decidim do
64
64
  input = $stdin.gets.chomp
65
65
  if input.casecmp("y").zero?
66
66
  puts %( Continue...)
67
- Decidim::User.where("newsletter_notifications_at < ?", Time.zone.parse("2018-05-25 00:00 +02:00")).find_each(&:newsletter_opt_in_notify)
67
+ Decidim::User.where(newsletter_notifications_at: ...Time.zone.parse("2018-05-25 00:00 +02:00")).find_each(&:newsletter_opt_in_notify)
68
68
  else
69
69
  puts %( Execution cancelled...)
70
70
  end
@@ -76,9 +76,7 @@ namespace :decidim do
76
76
  attachments = ActiveStorage::Attachment.joins(:blob).where(
77
77
  name: "download_your_data_file",
78
78
  record_type: "Decidim::UserBaseEntity"
79
- ).where(
80
- "active_storage_blobs.created_at < ?", Decidim.download_your_data_expiry_time.ago
81
- )
79
+ ).where(active_storage_blobs: { created_at: ...Decidim.download_your_data_expiry_time.ago })
82
80
  attachments.each do |attachment|
83
81
  delete_download_your_data_file attachment
84
82
  end
@@ -11,6 +11,12 @@ namespace :decidim do
11
11
  shakapacker: bin/shakapacker-dev-server
12
12
  RUBY
13
13
 
14
+ if defined?(Sidekiq)
15
+ actions :append_file, "Procfile.dev", <<~RUBY
16
+ sidekiq: bundle exec sidekiq -C config/sidekiq.yml
17
+ RUBY
18
+ end
19
+
14
20
  actions :create_file, "bin/dev", %(#!/usr/bin/env sh
15
21
 
16
22
  set -e
@@ -6,6 +6,7 @@ namespace :decidim do
6
6
  :choose_target_plugins,
7
7
  :"decidim:upgrade_app",
8
8
  :"railties:install:migrations",
9
+ :"decidim:upgrade:migrations",
9
10
  :"decidim:upgrade:webpacker",
10
11
  :"decidim_api:generate_docs"
11
12
  ]
@@ -0,0 +1,160 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/maintenance"
4
+
5
+ namespace :decidim do
6
+ namespace :taxonomies do
7
+ desc "Creates a JSON file with the taxonomies structure imported from older models"
8
+ task :make_plan, [] => :environment do |_task, _args|
9
+ Decidim::Organization.find_each do |organization|
10
+ log(true).info "Creating a plan for organization #{organization.id} in #{plan_file_path(organization)}"
11
+ FileUtils.mkdir_p(Rails.root.join("tmp/taxonomies"))
12
+ json = planner(organization).to_json do |model|
13
+ log.info "...Exporting taxonomies for #{model.table_name}"
14
+ end
15
+ File.write(plan_file_path(organization), json)
16
+ log.info "Plan created, you can review or edit if needed before importing."
17
+ log.info "Import the plan with this command:"
18
+ log.info "bin/rails decidim:taxonomies:import_plan[#{plan_file_path(organization)}]"
19
+ end
20
+ end
21
+
22
+ desc "Imports taxonomies and filters structure from a JSON file"
23
+ task :import_plan, [:file] => :environment do |_task, args|
24
+ file = args[:file].to_s
25
+ abort "File not found! [#{file}]" unless File.exist?(file)
26
+
27
+ data = JSON.parse(File.read(file))
28
+ organization = Decidim::Organization.find_by(id: data.dig("organization", "id"))
29
+ abort "Organization not found! [#{data["organization"]}]" unless organization
30
+ log(true).info "Importing taxonomies and filters for organization #{organization.id}"
31
+
32
+ planner(organization).import(data) do |importer, model_name|
33
+ taxonomies = importer.roots
34
+ result = importer.result
35
+ log.info "...Importing #{taxonomies.count} root taxonomies from #{model_name}"
36
+ taxonomies.each do |name, taxonomy|
37
+ log.info " - Root taxonomy: #{name}"
38
+ log.info " 1st level taxonomies: #{taxonomy["taxonomies"].count}"
39
+ log.info " Filters: #{taxonomy["filters"].count}"
40
+ taxonomy["filters"].each do |filter|
41
+ log.info " - Filter name: #{filter["name"]}"
42
+ log.info " Internal name: #{filter["internal_name"] || "-"}"
43
+ log.info " Space manifests: #{filter["participatory_space_manifests"]&.join(", ") || "-"}"
44
+ log.info " Items: #{filter["items"].count}"
45
+ log.info " Components: #{filter["components"].count}"
46
+ end
47
+ end
48
+ importer.import! do |type, detail|
49
+ log.info " !#{type}: #{detail}"
50
+ end
51
+ log.info " Created taxonomies: #{result[:taxonomies_created].count}"
52
+ result[:taxonomies_created].each do |name|
53
+ log.info " - #{name}"
54
+ end
55
+ log.info " Created filters: #{result[:filters_created].count}"
56
+ result[:filters_created].each do |name, items|
57
+ log.info " - #{name}: #{items.count} items"
58
+ end
59
+ log.info " Assigned resources: #{result[:taxonomies_assigned].count}"
60
+ result[:taxonomies_assigned].each do |name, items|
61
+ log.info " - #{name}: #{items.count} resources"
62
+ end
63
+ log.info " Assigned components: #{result[:components_assigned].count}"
64
+ result[:components_assigned].each do |name, items|
65
+ log.info " - #{name}: #{items.count} components"
66
+ end
67
+ log.info " Failed resources: #{result[:failed_resources].count}"
68
+ result[:failed_resources].each do |object_id|
69
+ log.info " - #{object_id}"
70
+ end
71
+ log.info " Failed components: #{result[:failed_components].count}"
72
+ result[:failed_components].each do |component_id|
73
+ log.info " - #{component_id}"
74
+ end
75
+ Rails.root.join("tmp/taxonomies", "#{organization.host}_result.json").write(JSON.pretty_generate(result))
76
+ log.info "Result saved in tmp/taxonomies/#{organization.host}_result.json"
77
+ end
78
+ log.info "Taxonomies and filters imported successfully."
79
+ end
80
+
81
+ desc "Imports taxonomies and filters structure from all JSON files inside tmp/taxonomies"
82
+ task :import_all_plans, [] => :environment do |_task, _args|
83
+ Rails.root.glob("tmp/taxonomies/*_plan.json").each do |file|
84
+ log.info "Importing plan from #{file}"
85
+ Rake::Task["decidim:taxonomies:import_plan"].reenable
86
+ Rake::Task["decidim:taxonomies:import_plan"].invoke(file)
87
+ end
88
+ end
89
+
90
+ desc "Adds taxonomies to metrics from old categories"
91
+ task :update_metrics, [:file] => :environment do |_task, args|
92
+ file = args[:file].to_s
93
+ abort "File not found! [#{file}]" unless File.exist?(file)
94
+
95
+ data = JSON.parse(File.read(file))
96
+ taxonomies = data["taxonomy_map"]
97
+ unless taxonomies && taxonomies&.any?
98
+ log.warn "No metric (categories) taxonomies found in the file"
99
+ next
100
+ end
101
+
102
+ total = taxonomies.count
103
+ taxonomies.each_with_index do |(id, object_id), index|
104
+ next unless object_id.include?("ImportModels::Category")
105
+
106
+ category_id = object_id.split("/").last
107
+ percent = ((index + 1) * 100 / total).to_i
108
+
109
+ count = Decidim::Metric.where(decidim_category_id: category_id).count
110
+ log.info "...#{percent}% Updating #{count} metrics for category #{category_id} to taxonomy #{id}"
111
+ Decidim::Metric.where(decidim_category_id: category_id).update_all(decidim_taxonomy_id: id) # rubocop:disable Rails/SkipsModelValidations
112
+ end
113
+ end
114
+
115
+ desc "Processes all metrics for result files in tmp/taxonomies"
116
+ task :update_all_metrics, [] => :environment do |_task, _args|
117
+ Rails.root.glob("tmp/taxonomies/*_result.json").each do |file|
118
+ log.info "Processing metrics from #{file}"
119
+ Rake::Task["decidim:taxonomies:update_metrics"].reenable
120
+ Rake::Task["decidim:taxonomies:update_metrics"].invoke(file)
121
+ end
122
+ end
123
+
124
+ desc "Reset counters for taxonomies and taxonomy filters"
125
+ task :reset_counters, [] => :environment do |_task, _args|
126
+ Decidim::Taxonomy.find_each do |taxonomy|
127
+ taxonomy.reset_all_counters
128
+ log.info "Counters reset for taxonomy #{taxonomy.id}:"
129
+ log.info " Children: #{taxonomy.children_count}"
130
+ log.info " Taxonomizations: #{taxonomy.taxonomizations_count}"
131
+ log.info " Filters: #{taxonomy.filters_count}"
132
+ log.info " Filter items: #{taxonomy.filter_items_count}"
133
+ end
134
+ Decidim::TaxonomyFilter.find_each do |filter|
135
+ filter.reset_all_counters
136
+ log.info "Counters reset for taxonomy filter #{filter.id}:"
137
+ log.info " Filter items: #{filter.filter_items_count}"
138
+ log.info " Components: #{filter.components_count}"
139
+ end
140
+ end
141
+
142
+ def planner(organization)
143
+ models = ENV.fetch("IMPORTS", "ParticipatoryProcessType AssemblyType Scope Area Category").split.map do |model_name|
144
+ "Decidim::Maintenance::ImportModels::#{model_name}".constantize
145
+ end
146
+ Decidim::Maintenance::TaxonomyPlan.new(organization, models)
147
+ end
148
+
149
+ def plan_file_path(organization)
150
+ Rails.root.join("tmp/taxonomies", "#{organization.host}_plan.json")
151
+ end
152
+
153
+ def log(reset = false) # rubocop:disable Style/OptionalBooleanParameter
154
+ @log = nil if reset
155
+ @log ||= Logger.new($stdout, formatter: proc { |_severity, _time, _progname, msg|
156
+ "#{msg}\n"
157
+ })
158
+ end
159
+ end
160
+ end