decidim-core 0.29.2 → 0.30.0.rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (484) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/amendable/amend_button_card/show.erb +6 -4
  3. data/app/cells/decidim/amendable/amend_button_card_cell.rb +8 -0
  4. data/app/cells/decidim/amendable/amendments/show.erb +1 -1
  5. data/app/cells/decidim/amendable/promote_button_card/show.erb +2 -0
  6. data/app/cells/decidim/author_cell.rb +1 -1
  7. data/app/cells/decidim/card_l/extra_data.erb +1 -0
  8. data/app/cells/decidim/card_metadata_cell.rb +9 -16
  9. data/app/cells/decidim/comments_button_cell.rb +14 -2
  10. data/app/cells/decidim/content_blocks/highlighted_elements_cell.rb +2 -0
  11. data/app/cells/decidim/content_blocks/highlighted_elements_with_cell_for_list_cell.rb +1 -1
  12. data/app/cells/decidim/endorsement_block/show.erb +0 -1
  13. data/app/cells/decidim/endorsement_block_cell.rb +6 -0
  14. data/app/cells/decidim/endorsement_buttons/button_content.erb +1 -1
  15. data/app/cells/decidim/endorsement_buttons/select_identity_button.erb +1 -1
  16. data/app/cells/decidim/endorsement_buttons/show.erb +7 -7
  17. data/app/cells/decidim/endorsement_buttons/verification_modal.erb +4 -2
  18. data/app/cells/decidim/endorsers_list/empty.erb +3 -0
  19. data/app/cells/decidim/endorsers_list/full.erb +17 -5
  20. data/app/cells/decidim/endorsers_list/show.erb +19 -10
  21. data/app/cells/decidim/endorsers_list_cell.rb +19 -6
  22. data/app/cells/decidim/follow_button/show.erb +1 -2
  23. data/app/cells/decidim/follow_button_cell.rb +5 -0
  24. data/app/cells/decidim/map/show.erb +3 -0
  25. data/app/cells/decidim/map/template.erb +14 -0
  26. data/app/cells/decidim/map_cell.rb +39 -0
  27. data/app/cells/decidim/notification_actions/buttons_cell.rb +1 -1
  28. data/app/cells/decidim/onboarding_action_message/show.erb +15 -0
  29. data/app/cells/decidim/onboarding_action_message_cell.rb +81 -0
  30. data/app/cells/decidim/participatory_space_private_user/show.erb +23 -0
  31. data/app/cells/decidim/participatory_space_private_user_cell.rb +21 -0
  32. data/app/cells/decidim/progress_bar/show.erb +2 -2
  33. data/app/cells/decidim/report_button_cell.rb +1 -0
  34. data/app/cells/decidim/resource_history/show.erb +20 -0
  35. data/app/cells/decidim/resource_history_cell.rb +66 -0
  36. data/app/cells/decidim/share_button_cell.rb +0 -4
  37. data/app/cells/decidim/share_widget/modal.erb +26 -0
  38. data/app/cells/decidim/share_widget/show.erb +2 -0
  39. data/app/cells/decidim/share_widget_cell.rb +20 -0
  40. data/app/cells/decidim/tags/show.erb +7 -4
  41. data/app/cells/decidim/tags_cell.rb +11 -72
  42. data/app/commands/decidim/amendable/create_draft.rb +2 -2
  43. data/app/commands/decidim/create_ephemeral_user.rb +52 -0
  44. data/app/commands/decidim/create_omniauth_registration.rb +13 -3
  45. data/app/commands/decidim/create_report.rb +1 -5
  46. data/app/commands/decidim/create_user_group.rb +6 -2
  47. data/app/commands/decidim/destroy_ephemeral_user.rb +47 -0
  48. data/app/commands/decidim/update_account.rb +11 -3
  49. data/app/commands/decidim/update_notifications_settings.rb +1 -0
  50. data/app/commands/decidim/update_resources_taxonomies.rb +67 -0
  51. data/app/commands/decidim/update_user_group.rb +7 -1
  52. data/app/constraints/decidim/current_component.rb +1 -1
  53. data/app/controllers/concerns/decidim/ajax_permission_handler.rb +21 -0
  54. data/app/controllers/concerns/decidim/devise_authentication_methods.rb +3 -6
  55. data/app/controllers/concerns/decidim/devise_controllers.rb +2 -0
  56. data/app/controllers/concerns/decidim/disable_redirection_to_external_host.rb +1 -1
  57. data/app/controllers/concerns/decidim/ephemeral_session_checker.rb +87 -0
  58. data/app/controllers/concerns/decidim/filter_resource.rb +4 -2
  59. data/app/controllers/concerns/decidim/has_members_page.rb +25 -0
  60. data/app/controllers/concerns/decidim/headers/browser_feature_permissions.rb +50 -0
  61. data/app/controllers/concerns/decidim/locale_switcher.rb +2 -2
  62. data/app/controllers/concerns/decidim/needs_password_change.rb +0 -1
  63. data/app/controllers/concerns/decidim/needs_permission.rb +2 -1
  64. data/app/controllers/concerns/decidim/needs_tos_accepted.rb +4 -5
  65. data/app/controllers/concerns/decidim/onboarding_action_methods.rb +52 -0
  66. data/app/controllers/decidim/application_controller.rb +10 -0
  67. data/app/controllers/decidim/authorization_modals_controller.rb +8 -2
  68. data/app/controllers/decidim/components/base_controller.rb +3 -7
  69. data/app/controllers/decidim/devise/confirmations_controller.rb +4 -0
  70. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +8 -1
  71. data/app/controllers/decidim/devise/registrations_controller.rb +1 -1
  72. data/app/controllers/decidim/devise/sessions_controller.rb +2 -0
  73. data/app/controllers/decidim/download_your_data_controller.rb +33 -2
  74. data/app/controllers/decidim/editor_images_controller.rb +1 -11
  75. data/app/controllers/decidim/follows_controller.rb +1 -1
  76. data/app/controllers/decidim/geolocation_controller.rb +19 -0
  77. data/app/controllers/decidim/homepage_controller.rb +0 -1
  78. data/app/controllers/decidim/open_data_controller.rb +33 -8
  79. data/app/controllers/decidim/user_conversations_controller.rb +1 -11
  80. data/app/events/decidim/soft_delete_resource_event.rb +15 -0
  81. data/app/forms/decidim/amendable/form.rb +4 -2
  82. data/app/forms/decidim/ephemeral_user_form.rb +22 -0
  83. data/app/forms/decidim/notifications_settings_form.rb +1 -0
  84. data/app/forms/decidim/omniauth_registration_form.rb +14 -1
  85. data/app/helpers/concerns/decidim/flash_helper_extensions.rb +17 -2
  86. data/app/helpers/decidim/action_authorization_helper.rb +75 -14
  87. data/app/helpers/decidim/amendments_helper.rb +0 -9
  88. data/app/helpers/decidim/application_helper.rb +6 -2
  89. data/app/helpers/decidim/breadcrumb_helper.rb +6 -0
  90. data/app/helpers/decidim/cache_helper.rb +1 -1
  91. data/app/helpers/decidim/check_boxes_tree_helper.rb +25 -53
  92. data/app/helpers/decidim/decidim_form_helper.rb +0 -44
  93. data/app/helpers/decidim/endorsable_helper.rb +0 -10
  94. data/app/helpers/decidim/layout_helper.rb +6 -0
  95. data/app/helpers/decidim/messaging/conversation_helper.rb +2 -3
  96. data/app/helpers/decidim/meta_tags_helper.rb +32 -23
  97. data/app/helpers/decidim/modal_helper.rb +23 -0
  98. data/app/helpers/decidim/omniauth_helper.rb +5 -5
  99. data/app/helpers/decidim/onboarding_action_helper.rb +13 -0
  100. data/app/helpers/decidim/orders_helper.rb +2 -1
  101. data/app/helpers/decidim/participatory_space_helpers.rb +1 -1
  102. data/app/helpers/decidim/passwords_helper.rb +2 -2
  103. data/app/helpers/decidim/taxonomies_helper.rb +40 -0
  104. data/app/jobs/decidim/download_your_data_export_job.rb +2 -19
  105. data/app/jobs/decidim/event_publisher_job.rb +18 -9
  106. data/app/jobs/decidim/export_job.rb +5 -1
  107. data/app/jobs/decidim/export_participatory_space_job.rb +4 -1
  108. data/app/jobs/decidim/hide_child_resources_job.rb +24 -0
  109. data/app/jobs/decidim/open_data_job.rb +4 -4
  110. data/app/mailers/decidim/export_mailer.rb +7 -12
  111. data/app/models/decidim/action_log.rb +11 -0
  112. data/app/models/decidim/category.rb +4 -0
  113. data/app/models/decidim/component.rb +25 -3
  114. data/app/models/decidim/metric.rb +2 -1
  115. data/app/models/decidim/moderation.rb +16 -0
  116. data/app/models/decidim/newsletter.rb +12 -8
  117. data/app/models/decidim/organization.rb +7 -3
  118. data/app/models/decidim/participatory_space_private_user.rb +20 -0
  119. data/app/models/decidim/private_export.rb +24 -0
  120. data/app/models/decidim/push_notification_message.rb +1 -1
  121. data/app/models/decidim/report.rb +1 -1
  122. data/app/models/decidim/scope.rb +4 -0
  123. data/app/models/decidim/share_token.rb +36 -10
  124. data/app/models/decidim/taxonomization.rb +23 -0
  125. data/app/models/decidim/taxonomy.rb +139 -0
  126. data/app/models/decidim/taxonomy_filter.rb +130 -0
  127. data/app/models/decidim/taxonomy_filter_item.rb +33 -0
  128. data/app/models/decidim/user.rb +9 -23
  129. data/app/models/decidim/user_base_entity.rb +12 -0
  130. data/app/models/decidim/user_moderation.rb +9 -0
  131. data/app/models/decidim/user_report.rb +4 -0
  132. data/app/packs/entrypoints/decidim_core.js +1 -0
  133. data/app/packs/entrypoints/decidim_geocoding.js +2 -0
  134. data/app/packs/images/decidim/brands/facebook.svg +10 -0
  135. data/app/packs/images/decidim/brands/google.svg +7 -1
  136. data/app/packs/images/decidim/brands/twitter-x.svg +3 -0
  137. data/app/packs/src/decidim/check_boxes_tree.js +0 -1
  138. data/app/packs/src/decidim/clipboard.js +18 -9
  139. data/app/packs/src/decidim/confirm.js +79 -59
  140. data/app/packs/src/decidim/decidim_application.js +1 -0
  141. data/app/packs/src/decidim/form_remote.js +1 -1
  142. data/app/packs/src/decidim/geocoding/reverse_geocoding.js +60 -0
  143. data/app/packs/src/decidim/impersonation.js +1 -1
  144. data/app/packs/src/decidim/index.js +11 -1
  145. data/app/packs/src/decidim/map/provider/here.js +1 -1
  146. data/app/packs/src/decidim/onboarding_pending_action.js +24 -0
  147. data/app/packs/src/decidim/session_timeouter.js +1 -1
  148. data/app/packs/src/decidim/sticky_footer.js +29 -0
  149. data/app/packs/src/decidim/sticky_header.js +6 -31
  150. data/app/packs/src/decidim/user_registrations.js +13 -0
  151. data/app/packs/src/decidim/utilities/dom.js +148 -0
  152. data/app/packs/stylesheets/decidim/_accordion.scss +30 -0
  153. data/app/packs/stylesheets/decidim/_buttons.scss +19 -0
  154. data/app/packs/stylesheets/decidim/_dropdown.scss +1 -1
  155. data/app/packs/stylesheets/decidim/_endorsers_list.scss +26 -20
  156. data/app/packs/stylesheets/decidim/_forms.scss +2 -2
  157. data/app/packs/stylesheets/decidim/_hashtags.scss +5 -0
  158. data/app/packs/stylesheets/decidim/_header.scss +5 -3
  159. data/app/packs/stylesheets/decidim/_layout.scss +32 -2
  160. data/app/packs/stylesheets/decidim/_login.scss +53 -6
  161. data/app/packs/stylesheets/decidim/_modal.scss +42 -0
  162. data/app/packs/stylesheets/decidim/_modal_tos_refuse.scss +4 -0
  163. data/app/packs/stylesheets/decidim/_participatory_spaces.scss +46 -0
  164. data/app/packs/stylesheets/decidim/_profile.scss +1 -1
  165. data/app/packs/stylesheets/decidim/_success_image.scss +64 -0
  166. data/app/packs/stylesheets/decidim/_tribute.scss +36 -0
  167. data/app/packs/stylesheets/decidim/application.scss +2 -0
  168. data/app/packs/stylesheets/decidim/geocoding_addons.scss +5 -0
  169. data/app/packs/stylesheets/decidim/map.scss +7 -10
  170. data/app/packs/stylesheets/decidim/resource_history.scss +31 -0
  171. data/app/permissions/decidim/permissions.rb +8 -2
  172. data/app/presenters/decidim/admin_log/base_user_presenter.rb +67 -0
  173. data/app/presenters/decidim/admin_log/component_presenter.rb +32 -3
  174. data/app/presenters/decidim/admin_log/moderation_presenter.rb +30 -3
  175. data/app/presenters/decidim/admin_log/share_token_presenter.rb +39 -0
  176. data/app/presenters/decidim/admin_log/taxonomy_filter_presenter.rb +57 -0
  177. data/app/presenters/decidim/admin_log/taxonomy_presenter.rb +48 -0
  178. data/app/presenters/decidim/admin_log/user_group_presenter.rb +6 -6
  179. data/app/presenters/decidim/admin_log/user_presenter.rb +4 -18
  180. data/app/presenters/decidim/log/value_types/date_presenter.rb +1 -0
  181. data/app/presenters/decidim/log/value_types/taxonomy_presenter.rb +29 -0
  182. data/app/presenters/decidim/participatory_space_private_user_presenter.rb +50 -0
  183. data/app/presenters/decidim/taxonomy_filter_presenter.rb +19 -0
  184. data/app/presenters/decidim/taxonomy_presenter.rb +14 -0
  185. data/app/queries/decidim/metrics/blocked_users_metric_manage.rb +2 -2
  186. data/app/queries/decidim/metrics/users_metric_manage.rb +2 -2
  187. data/app/queries/decidim/public_activities.rb +1 -12
  188. data/app/queries/decidim/stats_users_count.rb +2 -2
  189. data/app/resolvers/decidim/meta_image_url_resolver.rb +128 -0
  190. data/app/serializers/decidim/exporters/open_data_blocked_user_serializer.rb +25 -0
  191. data/app/serializers/decidim/exporters/open_data_metric_serializer.rb +22 -0
  192. data/app/serializers/decidim/exporters/open_data_moderation_serializer.rb +30 -0
  193. data/app/serializers/decidim/exporters/open_data_taxonomy_serializer.rb +30 -0
  194. data/app/serializers/decidim/exporters/open_data_user_group_serializer.rb +38 -0
  195. data/app/serializers/decidim/exporters/open_data_user_serializer.rb +39 -0
  196. data/app/serializers/decidim/exporters/participatory_space_serializer.rb +104 -0
  197. data/app/serializers/decidim/exporters/serializer.rb +25 -0
  198. data/app/serializers/decidim/schema_org_breadcrumb_list_serializer.rb +52 -0
  199. data/app/services/decidim/action_authorizer.rb +32 -3
  200. data/app/services/decidim/base_diff_renderer.rb +1 -1
  201. data/app/services/decidim/download_your_data_exporter.rb +58 -24
  202. data/app/services/decidim/onboarding_manager.rb +272 -0
  203. data/app/services/decidim/open_data_exporter.rb +139 -13
  204. data/app/services/decidim/traceability.rb +13 -0
  205. data/app/uploaders/decidim/application_uploader.rb +1 -1
  206. data/app/validators/etiquette_validator.rb +9 -2
  207. data/app/validators/passthru_validator.rb +1 -1
  208. data/app/validators/translated_etiquette_validator.rb +32 -0
  209. data/app/views/decidim/account/_password_fields.html.erb +2 -2
  210. data/app/views/decidim/application/_accordion_section.html.erb +14 -0
  211. data/app/views/decidim/application/_collection.html.erb +30 -18
  212. data/app/views/decidim/devise/omniauth_registrations/new.html.erb +5 -1
  213. data/app/views/decidim/devise/omniauth_registrations/new_tos_fields.html.erb +29 -0
  214. data/app/views/decidim/devise/registrations/new.html.erb +10 -22
  215. data/app/views/decidim/devise/sessions/new.html.erb +24 -29
  216. data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +2 -4
  217. data/app/views/decidim/devise/shared/_tos_fields.html.erb +16 -0
  218. data/app/views/decidim/download_your_data/_export.html.erb +15 -0
  219. data/app/views/decidim/download_your_data/show.html.erb +51 -5
  220. data/app/views/decidim/endorsements/update_buttons_and_counters.js.erb +16 -19
  221. data/app/views/decidim/export_mailer/download_your_data_export.html.erb +2 -2
  222. data/app/views/decidim/export_mailer/export.html.erb +5 -1
  223. data/app/views/decidim/notifications_settings/show.html.erb +22 -0
  224. data/app/views/decidim/open_data/_how_to_open_accordion_section.html.erb +15 -0
  225. data/app/views/decidim/open_data/index.html.erb +108 -0
  226. data/app/views/decidim/pages/show.html.erb +2 -1
  227. data/app/views/decidim/participatory_space_private_users/_participatory_space_private_user.html.erb +1 -0
  228. data/app/views/decidim/shared/_login_modal.html.erb +26 -20
  229. data/app/views/decidim/shared/_orders.html.erb +2 -2
  230. data/app/views/decidim/shared/_resource_actions.html.erb +21 -0
  231. data/app/views/decidim/shared/filters/_check_boxes_tree.html.erb +1 -2
  232. data/app/views/decidim/shared/filters/_collection.html.erb +1 -1
  233. data/app/views/decidim/shared/filters/_dropdown_label.html.erb +7 -4
  234. data/app/views/layouts/decidim/_application.html.erb +0 -1
  235. data/app/views/layouts/decidim/_js_configuration.html.erb +1 -0
  236. data/app/views/layouts/decidim/_logo.html.erb +1 -1
  237. data/app/views/layouts/decidim/_logo_mobile.html.erb +1 -1
  238. data/app/views/layouts/decidim/_meta_tags_config.html.erb +6 -11
  239. data/app/views/layouts/decidim/_schema_org_breadcrumb_list.html.erb +3 -0
  240. data/app/views/layouts/decidim/_wrapper.html.erb +15 -9
  241. data/app/views/layouts/decidim/footer/_main_links.html.erb +1 -1
  242. data/app/views/layouts/decidim/header/_close_ephemeral_session.html.erb +25 -0
  243. data/app/views/layouts/decidim/header/_main.html.erb +14 -10
  244. data/app/views/layouts/decidim/header/_menu_breadcrumb_items.html.erb +2 -0
  245. data/app/views/layouts/decidim/shared/_layout_item.html.erb +1 -1
  246. data/config/assets.rb +2 -1
  247. data/config/locales/ar.yml +27 -59
  248. data/config/locales/bg.yml +3 -64
  249. data/config/locales/ca.yml +370 -61
  250. data/config/locales/cs.yml +371 -54
  251. data/config/locales/de.yml +365 -54
  252. data/config/locales/el.yml +1 -48
  253. data/config/locales/en.yml +363 -54
  254. data/config/locales/eo.yml +0 -2
  255. data/config/locales/es-MX.yml +363 -57
  256. data/config/locales/es-PY.yml +363 -57
  257. data/config/locales/es.yml +367 -58
  258. data/config/locales/eu.yml +373 -65
  259. data/config/locales/fi-plain.yml +365 -57
  260. data/config/locales/fi.yml +370 -59
  261. data/config/locales/fr-CA.yml +178 -54
  262. data/config/locales/fr.yml +179 -52
  263. data/config/locales/ga-IE.yml +0 -21
  264. data/config/locales/gl.yml +1 -34
  265. data/config/locales/hu.yml +1 -53
  266. data/config/locales/id-ID.yml +1 -34
  267. data/config/locales/is-IS.yml +0 -16
  268. data/config/locales/it.yml +5 -60
  269. data/config/locales/ja.yml +215 -56
  270. data/config/locales/lb.yml +1 -52
  271. data/config/locales/lt.yml +1 -59
  272. data/config/locales/lv.yml +1 -40
  273. data/config/locales/nl.yml +1 -53
  274. data/config/locales/no.yml +2 -52
  275. data/config/locales/pl.yml +4 -66
  276. data/config/locales/pt-BR.yml +11 -52
  277. data/config/locales/pt.yml +2 -52
  278. data/config/locales/ro-RO.yml +219 -117
  279. data/config/locales/ru.yml +0 -20
  280. data/config/locales/sk.yml +1 -41
  281. data/config/locales/sv.yml +138 -59
  282. data/config/locales/tr-TR.yml +1 -50
  283. data/config/locales/uk.yml +0 -18
  284. data/config/locales/zh-CN.yml +1 -50
  285. data/config/locales/zh-TW.yml +1 -54
  286. data/config/routes.rb +4 -10
  287. data/db/migrate/20181025082245_add_timestamps_to_components.rb +2 -0
  288. data/db/migrate/20240628111905_add_visible_to_components.rb +7 -0
  289. data/db/migrate/20240704115429_create_decidim_taxonomies.rb +23 -0
  290. data/db/migrate/20240717093514_add_registered_only_to_decidim_share_tokens.rb +7 -0
  291. data/db/migrate/20240722215500_change_object_changes_on_versions.rb +39 -0
  292. data/db/migrate/20240806065417_create_decidim_taxonomy_filters.rb +23 -0
  293. data/db/migrate/20240822161348_add_deleted_at_to_decidim_components.rb +8 -0
  294. data/db/migrate/20240906162524_add_part_of_to_taxonomies.rb +26 -0
  295. data/db/migrate/20241001135825_add_role_to_participatory_space_private_users.rb +7 -0
  296. data/db/migrate/20241001140408_add_published_to_participatory_space_private_users.rb +7 -0
  297. data/db/migrate/20241022002600_create_private_exports.rb +18 -0
  298. data/db/migrate/20241028114430_add_component_counter_to_taxonomy_filters.rb +7 -0
  299. data/db/migrate/20241111104357_add_names_and_space_boolean_to_taxonomy_filters.rb +9 -0
  300. data/db/migrate/20241127093708_add_taxonomy_to_metrics.rb +7 -0
  301. data/db/migrate/20241204121445_add_participatory_space_manifests_from_taxonomy_filters.rb +9 -0
  302. data/decidim-core.gemspec +14 -17
  303. data/lib/decidim/action_authorization.rb +3 -2
  304. data/lib/decidim/amendable.rb +1 -1
  305. data/lib/decidim/api/input_filters/category_input_filter.rb +5 -3
  306. data/lib/decidim/api/input_filters/component_input_filter.rb +33 -20
  307. data/lib/decidim/api/input_filters/user_entity_input_filter.rb +53 -44
  308. data/lib/decidim/api/input_sorts/component_input_sort.rb +15 -13
  309. data/lib/decidim/api/input_sorts/user_entity_input_sort.rb +4 -4
  310. data/lib/decidim/api/interfaces/author_interface.rb +3 -2
  311. data/lib/decidim/api/interfaces/coauthorable_interface.rb +5 -5
  312. data/lib/decidim/api/interfaces/endorsable_interface.rb +2 -2
  313. data/lib/decidim/api/interfaces/participatory_space_interface.rb +5 -10
  314. data/lib/decidim/api/interfaces/taxonomizable_interface.rb +13 -0
  315. data/lib/decidim/api/types/amendment_type.rb +5 -7
  316. data/lib/decidim/api/types/area_api_type.rb +3 -3
  317. data/lib/decidim/api/types/attachment_type.rb +3 -3
  318. data/lib/decidim/api/types/category_type.rb +2 -2
  319. data/lib/decidim/api/types/decidim_type.rb +5 -1
  320. data/lib/decidim/api/types/fingerprint_type.rb +1 -1
  321. data/lib/decidim/api/types/localized_string_type.rb +1 -1
  322. data/lib/decidim/api/types/metric_history_type.rb +2 -0
  323. data/lib/decidim/api/types/metric_type.rb +1 -1
  324. data/lib/decidim/api/types/organization_type.rb +5 -0
  325. data/lib/decidim/api/types/participatory_space_link_type.rb +2 -2
  326. data/lib/decidim/api/types/participatory_space_manifest_type.rb +1 -1
  327. data/lib/decidim/api/types/quantifiable_translated_field_type.rb +1 -1
  328. data/lib/decidim/api/types/scope_api_type.rb +2 -3
  329. data/lib/decidim/api/types/session_type.rb +1 -2
  330. data/lib/decidim/api/types/taxonomy_type.rb +15 -0
  331. data/lib/decidim/api/types/trace_version_type.rb +2 -2
  332. data/lib/decidim/api/types/translated_field_type.rb +3 -5
  333. data/lib/decidim/api/types/user_group_type.rb +7 -20
  334. data/lib/decidim/api/types/user_type.rb +7 -20
  335. data/lib/decidim/asset_router/storage.rb +4 -4
  336. data/lib/decidim/assets/tailwind/tailwind.config.js.erb +2 -1
  337. data/lib/decidim/attachment_attributes.rb +1 -1
  338. data/lib/decidim/attribute_encryptor.rb +1 -1
  339. data/lib/decidim/attribute_object/nested_validator.rb +1 -1
  340. data/lib/decidim/attributes/integer_with_units.rb +27 -0
  341. data/lib/decidim/attributes.rb +2 -0
  342. data/lib/decidim/authorization_form_builder.rb +0 -7
  343. data/lib/decidim/coauthorable.rb +1 -1
  344. data/lib/decidim/command.rb +3 -3
  345. data/lib/decidim/commands/destroy_resource.rb +5 -1
  346. data/lib/decidim/commands/resource_handler.rb +2 -2
  347. data/lib/decidim/commands/restore_resource.rb +45 -0
  348. data/lib/decidim/commands/soft_delete_resource.rb +63 -0
  349. data/lib/decidim/component_manifest.rb +7 -0
  350. data/lib/decidim/core/api.rb +2 -0
  351. data/lib/decidim/core/engine.rb +21 -7
  352. data/lib/decidim/core/menu.rb +0 -5
  353. data/lib/decidim/core/seeds.rb +42 -2
  354. data/lib/decidim/core/test/factories.rb +105 -2
  355. data/lib/decidim/core/test/shared_examples/admin_resource_gallery_examples.rb +85 -0
  356. data/lib/decidim/core/test/shared_examples/comments_examples.rb +393 -38
  357. data/lib/decidim/core/test/shared_examples/components_controller_hide_shared_examples.rb +11 -0
  358. data/lib/decidim/core/test/shared_examples/components_controller_reorder_shared_examples.rb +21 -0
  359. data/lib/decidim/core/test/shared_examples/download_open_data_shared_context.rb +36 -0
  360. data/lib/decidim/core/test/shared_examples/download_open_data_shared_examples.rb +45 -0
  361. data/lib/decidim/core/test/shared_examples/download_your_data_shared_examples.rb +17 -0
  362. data/lib/decidim/core/test/shared_examples/etiquette_validator_examples.rb +25 -0
  363. data/lib/decidim/core/test/shared_examples/follows_examples.rb +43 -0
  364. data/lib/decidim/core/test/shared_examples/has_taxonomies.rb +94 -0
  365. data/lib/decidim/core/test/shared_examples/manage_share_tokens_examples.rb +237 -0
  366. data/lib/decidim/core/test/shared_examples/map_examples.rb +2 -0
  367. data/lib/decidim/core/test/shared_examples/open_data_exporter_examples.rb +102 -0
  368. data/lib/decidim/core/test/shared_examples/participatory_space_members_page_examples.rb +46 -0
  369. data/lib/decidim/core/test/shared_examples/participatory_space_search_examples.rb +98 -0
  370. data/lib/decidim/core/test/shared_examples/permissions.rb +7 -7
  371. data/lib/decidim/core/test/shared_examples/preview_with_share_token_examples.rb +94 -0
  372. data/lib/decidim/core/test/shared_examples/reports_examples.rb +60 -5
  373. data/lib/decidim/core/test/shared_examples/resource_endorsed_event_examples.rb +2 -2
  374. data/lib/decidim/core/test/shared_examples/resource_search_examples.rb +75 -69
  375. data/lib/decidim/core/test/shared_examples/searchable_resources_shared_context.rb +1 -1
  376. data/lib/decidim/core/test/shared_examples/simple_event.rb +33 -19
  377. data/lib/decidim/core/test/shared_examples/social_share_examples.rb +46 -0
  378. data/lib/decidim/core/test/shared_examples/softdeleteable_components_examples.rb +173 -0
  379. data/lib/decidim/core/test/shared_examples/system_endorse_resource_examples.rb +54 -8
  380. data/lib/decidim/core/test/shared_examples/taxonomizable_interface_examples.rb +20 -0
  381. data/lib/decidim/core/test/shared_examples/taxonomizable_resource_examples.rb +37 -0
  382. data/lib/decidim/core/test/shared_examples/taxonomy_settings.rb +49 -0
  383. data/lib/decidim/core/test/shared_examples/translated_event_examples.rb +1 -1
  384. data/lib/decidim/core/test/shared_examples/versions_controller_examples.rb +2 -2
  385. data/lib/decidim/core/test/shared_examples/with_endorsable_permissions_examples.rb +1 -1
  386. data/lib/decidim/core/test.rb +9 -5
  387. data/lib/decidim/core/version.rb +1 -1
  388. data/lib/decidim/core.rb +58 -0
  389. data/lib/decidim/download_your_data_serializers/download_your_data_identity_serializer.rb +0 -4
  390. data/lib/decidim/download_your_data_serializers/download_your_data_participatory_space_private_user_serializer.rb +3 -1
  391. data/lib/decidim/download_your_data_serializers/download_your_data_report_serializer.rb +2 -1
  392. data/lib/decidim/download_your_data_serializers/download_your_data_user_serializer.rb +6 -7
  393. data/lib/decidim/download_your_data_serializers.rb +19 -0
  394. data/lib/decidim/exporters/csv.rb +6 -0
  395. data/lib/decidim/exporters/export_manifest.rb +14 -0
  396. data/lib/decidim/exporters/pdf.rb +26 -22
  397. data/lib/decidim/filter_form_builder.rb +12 -15
  398. data/lib/decidim/form_builder.rb +6 -129
  399. data/lib/decidim/has_category.rb +5 -1
  400. data/lib/decidim/has_private_users.rb +4 -0
  401. data/lib/decidim/has_taxonomy_settings.rb +47 -0
  402. data/lib/decidim/has_upload_validations.rb +1 -1
  403. data/lib/decidim/legacy_form_builder.rb +118 -0
  404. data/lib/decidim/maintenance/import_models/application_record.rb +93 -0
  405. data/lib/decidim/maintenance/import_models/area.rb +82 -0
  406. data/lib/decidim/maintenance/import_models/area_type.rb +12 -0
  407. data/lib/decidim/maintenance/import_models/assembly_type.rb +49 -0
  408. data/lib/decidim/maintenance/import_models/categorization.rb +14 -0
  409. data/lib/decidim/maintenance/import_models/category.rb +139 -0
  410. data/lib/decidim/maintenance/import_models/participatory_process_type.rb +21 -0
  411. data/lib/decidim/maintenance/import_models/scope.rb +163 -0
  412. data/lib/decidim/maintenance/import_models.rb +19 -0
  413. data/lib/decidim/maintenance/taxonomy_importer.rb +142 -0
  414. data/lib/decidim/maintenance/taxonomy_plan.rb +78 -0
  415. data/lib/decidim/maintenance.rb +12 -0
  416. data/lib/decidim/map/autocomplete.rb +52 -8
  417. data/lib/decidim/map/dynamic_map.rb +1 -1
  418. data/lib/decidim/map/provider/dynamic_map/here.rb +1 -40
  419. data/lib/decidim/map/provider/geocoding/here.rb +9 -3
  420. data/lib/decidim/map.rb +3 -6
  421. data/lib/decidim/moderation_tools.rb +29 -5
  422. data/lib/decidim/newsletter_encryptor.rb +1 -1
  423. data/lib/decidim/paddable.rb +1 -1
  424. data/lib/decidim/participable.rb +10 -10
  425. data/lib/decidim/participatory_space_user.rb +10 -0
  426. data/lib/decidim/private_download_helper.rb +15 -0
  427. data/lib/decidim/record_encryptor.rb +51 -46
  428. data/lib/decidim/resourceable.rb +16 -0
  429. data/lib/decidim/seeds.rb +18 -20
  430. data/lib/decidim/settings_manifest.rb +34 -1
  431. data/lib/decidim/soft_deletable.rb +17 -0
  432. data/lib/decidim/taxonomizable.rb +72 -0
  433. data/lib/decidim/view_model.rb +0 -1
  434. data/lib/tasks/decidim_download_your_data_tasks.rake +2 -4
  435. data/lib/tasks/decidim_procfile.rake +6 -0
  436. data/lib/tasks/decidim_tasks.rake +1 -0
  437. data/lib/tasks/decidim_taxonomies.rake +160 -0
  438. data/lib/tasks/upgrade/{decidim_fix_categorization.rake → clean.rake} +25 -18
  439. data/lib/tasks/upgrade/clean_hidden_resources.rake +33 -0
  440. data/lib/tasks/upgrade/decidim_active_storage_migration_tasks.rake +1 -1
  441. data/lib/tasks/upgrade/migrations.rake +94 -0
  442. metadata +198 -103
  443. data/app/cells/decidim/amendable/amenders_list/show.erb +0 -0
  444. data/app/cells/decidim/content_blocks/base/content.erb +0 -0
  445. data/app/cells/decidim/endorsers_list/full_endorsers_list.erb +0 -3
  446. data/app/cells/decidim/endorsers_list_button/content.erb +0 -1
  447. data/app/cells/decidim/endorsers_list_button_cell.rb +0 -15
  448. data/app/cells/decidim/scopes_picker/scope_picker_prompt.erb +0 -3
  449. data/app/cells/decidim/scopes_picker/scope_picker_values.erb +0 -5
  450. data/app/cells/decidim/scopes_picker/show.erb +0 -14
  451. data/app/cells/decidim/scopes_picker_cell.rb +0 -92
  452. data/app/commands/decidim/update_user_interests.rb +0 -41
  453. data/app/controllers/decidim/scopes_controller.rb +0 -84
  454. data/app/controllers/decidim/user_interests_controller.rb +0 -30
  455. data/app/forms/decidim/user_interest_scope_form.rb +0 -25
  456. data/app/forms/decidim/user_interests_form.rb +0 -17
  457. data/app/helpers/decidim/categories_helper.rb +0 -26
  458. data/app/helpers/decidim/scopes_helper.rb +0 -105
  459. data/app/packs/images/decidim/vendor/leaflet/layers-2x.png +0 -0
  460. data/app/packs/images/decidim/vendor/leaflet/layers.png +0 -0
  461. data/app/packs/images/decidim/vendor/leaflet/marker-icon-2x.png +0 -0
  462. data/app/packs/images/decidim/vendor/leaflet/marker-icon.png +0 -0
  463. data/app/packs/images/decidim/vendor/leaflet/marker-shadow.png +0 -0
  464. data/app/packs/src/decidim/vendor/leaflet-tilelayer-here.js +0 -212
  465. data/app/packs/stylesheets/decidim/legacy/MarkerCluster.Default.scss +0 -67
  466. data/app/packs/stylesheets/decidim/legacy/MarkerCluster.scss +0 -18
  467. data/app/packs/stylesheets/decidim/legacy/leaflet.scss +0 -705
  468. data/app/validators/scope_belongs_to_component_validator.rb +0 -16
  469. data/app/views/decidim/account/_user_groups.html.erb +0 -0
  470. data/app/views/decidim/scopes/_scopes_picker_input.html.erb +0 -19
  471. data/app/views/decidim/scopes/picker.html.erb +0 -53
  472. data/app/views/decidim/shared/_comments.html.erb +0 -0
  473. data/app/views/decidim/shared/_share_modal.html.erb +0 -26
  474. data/app/views/decidim/shared/_tags.html.erb +0 -1
  475. data/app/views/decidim/user_interests/_areas.html.erb +0 -14
  476. data/app/views/decidim/user_interests/_scopes.html.erb +0 -22
  477. data/app/views/decidim/user_interests/show.html.erb +0 -22
  478. data/config/initializers/foundation_rails_helper.rb +0 -4
  479. data/lib/decidim/core/test/shared_examples/has_category.rb +0 -38
  480. data/lib/decidim/core/test/shared_examples/has_scope.rb +0 -11
  481. data/lib/decidim/core/test/shared_examples/manage_component_share_tokens.rb +0 -83
  482. data/lib/decidim/core/test/shared_examples/preview_component_with_share_token_examples.rb +0 -49
  483. data/lib/decidim/core/test/shared_examples/scope_helper_examples.rb +0 -93
  484. data/lib/decidim/seven_zip_wrapper.rb +0 -29
@@ -14,6 +14,8 @@ shared_examples "followable content for users" do
14
14
  context "when user clicks the Follow button" do
15
15
  it "makes the user follow the followable" do
16
16
  visit followable_path
17
+ find("#dropdown-trigger-resource-#{followable.id}").click
18
+
17
19
  expect do
18
20
  click_on "Follow"
19
21
  expect(page).to have_content "Stop following"
@@ -30,6 +32,45 @@ shared_examples "followable content for users" do
30
32
  context "when user clicks the Follow button" do
31
33
  it "makes the user follow the followable" do
32
34
  visit followable_path
35
+ find("#dropdown-trigger-resource-#{followable.id}").click
36
+
37
+ expect do
38
+ click_on "Stop following"
39
+ expect(page).to have_content "Follow"
40
+ end.to change(Decidim::Follow, :count).by(-1)
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ shared_examples "followable space content for users" do
47
+ before do
48
+ switch_to_host(organization.host)
49
+ login_as user, scope: :user
50
+ end
51
+
52
+ context "when not following the followable" do
53
+ context "when user clicks the Follow button" do
54
+ it "makes the user follow the followable" do
55
+ visit followable_path
56
+
57
+ expect do
58
+ click_on "Follow"
59
+ expect(page).to have_content "Stop following"
60
+ end.to change(Decidim::Follow, :count).by(1)
61
+ end
62
+ end
63
+ end
64
+
65
+ context "when the user is following the followable" do
66
+ before do
67
+ create(:follow, followable:, user:)
68
+ end
69
+
70
+ context "when user clicks the Follow button" do
71
+ it "makes the user follow the followable" do
72
+ visit followable_path
73
+
33
74
  expect do
34
75
  click_on "Stop following"
35
76
  expect(page).to have_content "Follow"
@@ -51,6 +92,8 @@ shared_examples "followable content for users with a component" do
51
92
  context "when user clicks the Follow button" do
52
93
  it "makes the user follow the followable" do
53
94
  visit followable_path
95
+ find("#dropdown-trigger-resource-#{followable.id}").click
96
+
54
97
  expect do
55
98
  click_on "Follow"
56
99
  expect(page).to have_content "Stop following"
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples_for "has taxonomies" do
4
+ describe "taxonomies" do
5
+ context "when valid taxonomies are assigned" do
6
+ let(:taxonomy) { create(:taxonomy, :with_parent, organization: subject.organization) }
7
+ before do
8
+ subject.taxonomies = [taxonomy]
9
+ end
10
+
11
+ it { is_expected.to be_valid }
12
+ end
13
+
14
+ context "when a root taxonomy is assigned" do
15
+ let!(:taxonomy) { create(:taxonomy, organization: subject.organization) }
16
+
17
+ it "is not valid" do
18
+ expect { subject.taxonomies = [taxonomy] }.to raise_error(ActiveRecord::RecordInvalid).or change { subject.valid? }.to(false)
19
+ end
20
+ end
21
+
22
+ context "when a taxonomy from another organization is assigned" do
23
+ let(:taxonomy) { create(:taxonomy, :with_parent) }
24
+ before do
25
+ subject.taxonomies = [taxonomy]
26
+ end
27
+
28
+ it { is_expected.to be_invalid }
29
+ end
30
+ end
31
+
32
+ describe "scopes" do
33
+ let(:root_taxonomy) { create(:taxonomy, organization: subject.organization) }
34
+ let(:taxonomy) { create(:taxonomy, parent: root_taxonomy, organization: subject.organization) }
35
+
36
+ let(:another_taxonomy) { create(:taxonomy, parent: root_taxonomy, organization: subject.organization) }
37
+ let!(:taxonomization) { create(:taxonomization, taxonomizable: subject, taxonomy:) }
38
+ let!(:another_taxonomization) { create(:taxonomization, taxonomy: another_taxonomy) }
39
+
40
+ describe ".with_taxonomy" do
41
+ it "returns the taxonomizable" do
42
+ expect(described_class.with_taxonomy(taxonomy.id)).to eq([subject])
43
+ expect(described_class.with_taxonomy(root_taxonomy.id)).to eq([subject])
44
+ end
45
+
46
+ it "returns empty if not in the taxonomy" do
47
+ expect(described_class.with_taxonomy(another_taxonomy.id)).to be_empty
48
+ end
49
+ end
50
+
51
+ describe ".with_taxonomies" do
52
+ it "returns the taxonomizable" do
53
+ expect(described_class.with_taxonomies(taxonomy.id, another_taxonomization.id)).to eq([subject])
54
+ expect(described_class.with_taxonomies(root_taxonomy.id, another_taxonomization.id)).to eq([subject])
55
+ end
56
+
57
+ it "returns empty if not in the taxonomy" do
58
+ expect(described_class.with_taxonomies(another_taxonomy.id)).to be_empty
59
+ end
60
+ end
61
+
62
+ describe ".with_any_taxonomies" do
63
+ let!(:missing_taxonomy) { create(:taxonomy, parent: root_taxonomy, organization: subject.organization) }
64
+ let(:second_root_taxonomy) { create(:taxonomy, organization: subject.organization) }
65
+ let(:second_taxonomy) { create(:taxonomy, parent: second_root_taxonomy, organization: subject.organization) }
66
+ let!(:second_taxonomization) { create(:taxonomization, taxonomizable: subject, taxonomy: second_taxonomy) }
67
+ let(:third_root_taxonomy) { create(:taxonomy, organization: subject.organization) }
68
+ let(:third_taxonomy) { create(:taxonomy, parent: third_root_taxonomy, organization: subject.organization) }
69
+ let!(:third_taxonomization) { create(:taxonomization, taxonomizable: subject, taxonomy: third_taxonomy) }
70
+
71
+ it "returns the taxonomizable matching all subsets" do
72
+ subset1 = [root_taxonomy.id, [taxonomy.id, another_taxonomy.id]]
73
+ subset2 = [second_root_taxonomy.id, [second_taxonomy.id]]
74
+ subset3 = [third_root_taxonomy.id, [third_taxonomy.id]]
75
+ expect(described_class.with_any_taxonomies(subset1, subset2, subset3)).to eq([subject])
76
+ end
77
+
78
+ it "returns empty if one subset is missing" do
79
+ subset1 = [root_taxonomy.id, [missing_taxonomy.id]]
80
+ subset2 = [second_root_taxonomy.id, [second_taxonomy.id]]
81
+ subset3 = [third_root_taxonomy.id, [third_taxonomy.id]]
82
+ expect(described_class.with_any_taxonomies(subset1, subset2, subset3)).to be_empty
83
+ end
84
+
85
+ it "returns the taxonomizable if all taxonomies are present in the missing subset" do
86
+ subset1 = [root_taxonomy.id, [missing_taxonomy.id, "all"]]
87
+ subset2 = [second_root_taxonomy.id, [second_taxonomy.id]]
88
+ subset3 = [third_root_taxonomy.id, [third_taxonomy.id]]
89
+
90
+ expect(described_class.with_any_taxonomies(subset1, subset2, subset3)).to eq([subject])
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,237 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples "manage resource share tokens" do
4
+ context "when there are no tokens" do
5
+ let(:last_token) { Decidim::ShareToken.last }
6
+ before do
7
+ visit_share_tokens_page
8
+ end
9
+
10
+ it "displays empty message" do
11
+ expect(page).to have_content "There are no active access links"
12
+ end
13
+
14
+ it "can create a new token with default options" do
15
+ click_on "New access link"
16
+
17
+ click_on "Create"
18
+
19
+ expect(page).to have_content("Access link created successfully")
20
+ expect(page).to have_css("tbody tr", count: 1)
21
+ within "tbody tr:last-child td", text: last_token.token do
22
+ expect(page).to have_content(last_token.token)
23
+ end
24
+ within "tbody tr:last-child td:nth-child(2)" do
25
+ expect(page).to have_content("Never")
26
+ end
27
+ within "tbody tr:last-child td:nth-child(3)" do
28
+ expect(page).to have_content("No")
29
+ end
30
+ end
31
+
32
+ it "can create a new token with custom options" do
33
+ click_on "New access link"
34
+
35
+ find_by_id("share_token_automatic_token_false").click
36
+ find_by_id("share_token_no_expiration_false").click
37
+ find_by_id("share_token_registered_only_true").click
38
+ click_on "Create"
39
+ expect(page).to have_content("cannot be blank", count: 2)
40
+
41
+ fill_in "share_token_token", with: " custom token "
42
+ fill_in_datepicker :share_token_expires_at_date, with: 1.day.from_now.strftime("%d/%m/%Y")
43
+ fill_in_timepicker :share_token_expires_at_time, with: "00:00"
44
+ click_on "Create"
45
+
46
+ expect(page).to have_content("Access link created successfully")
47
+ expect(page).to have_css("tbody tr", count: 1)
48
+ within "tbody tr:last-child td", text: last_token.token do
49
+ expect(page).to have_content("CUSTOM-TOKEN")
50
+ end
51
+ within "tbody tr:last-child td:nth-child(2)" do
52
+ expect(page).to have_content(1.day.from_now.strftime("%d/%m/%Y 00:00"))
53
+ end
54
+ within "tbody tr:last-child td:nth-child(3)" do
55
+ expect(page).to have_content("Yes")
56
+ end
57
+ end
58
+ end
59
+
60
+ context "when there are tokens" do
61
+ let!(:share_tokens) { create_list(:share_token, 3, :with_token, token_for: resource, organization:, registered_only: true) }
62
+ let(:last_token) { share_tokens.last }
63
+
64
+ before do
65
+ visit_share_tokens_page
66
+ end
67
+
68
+ it "displays all tokens" do
69
+ within ".share_tokens" do
70
+ expect(page).to have_css("tbody tr", count: 3)
71
+ end
72
+ end
73
+
74
+ it "displays relevant attributes for each token" do
75
+ share_tokens.each do |share_token|
76
+ within ".share_tokens tbody" do
77
+ expect(page).to have_content share_token.token
78
+ expect(page).to have_content share_token.expires_at.to_s
79
+ end
80
+ end
81
+ end
82
+
83
+ context "when ordering" do
84
+ let(:share_tokens) do
85
+ [
86
+ create(:share_token, :with_token, token_for: resource, organization:, token: "b", expires_at: 1.day.from_now, registered_only: true, times_used: 3),
87
+ create(:share_token, :with_token, token_for: resource, organization:, token: "a", expires_at: 3.days.from_now, registered_only: true, times_used: 2),
88
+ create(:share_token, :with_token, token_for: resource, organization:, token: "c", expires_at: 2.days.from_now, registered_only: false, times_used: 1)
89
+ ]
90
+ end
91
+
92
+ it "can be ordered by token and other attributes" do
93
+ within ".share_tokens" do
94
+ click_on "Access link" # order by token
95
+ expect(page).to have_css("tbody tr:first-child", text: "c")
96
+ click_on "Access link" # order by token
97
+ expect(page).to have_css("tbody tr:first-child", text: "a")
98
+ click_on "Expires at" # order by expires_at
99
+ expect(page).to have_css("tbody tr:first-child", text: share_tokens.second.expires_at.strftime("%d/%m/%Y %H:%M"))
100
+ click_on "Expires at" # order by expires_at
101
+ expect(page).to have_css("tbody tr:first-child", text: share_tokens.first.expires_at.strftime("%d/%m/%Y %H:%M"))
102
+ click_on "Registered only" # order by registered_only
103
+ expect(page).to have_css("tbody tr:first-child", text: "Yes")
104
+ click_on "Registered only" # order by registered_only
105
+ expect(page).to have_css("tbody tr:first-child", text: "No")
106
+ click_on "Times used" # order by times_used
107
+ expect(page).to have_css("tbody tr:first-child", text: "3")
108
+ click_on "Times used" # order by times_used
109
+ expect(page).to have_css("tbody tr:first-child", text: "1")
110
+ end
111
+ end
112
+ end
113
+
114
+ it "can edit a share token" do
115
+ within "tbody tr", text: last_token.token do
116
+ expect(page).to have_content("Yes")
117
+ end
118
+ within ".share_tokens tbody tr", text: last_token.token do
119
+ click_on "Edit"
120
+ end
121
+
122
+ expect(page).to have_content("Edit access links for: #{resource_name}")
123
+ find_by_id("share_token_no_expiration_false").click
124
+ find_by_id("share_token_registered_only_false").click
125
+ click_on "Update"
126
+ expect(page).to have_content("cannot be blank", count: 1)
127
+
128
+ fill_in_datepicker :share_token_expires_at_date, with: 1.day.from_now.strftime("%d/%m/%Y")
129
+ fill_in_timepicker :share_token_expires_at_time, with: "00:00"
130
+
131
+ click_on "Update"
132
+
133
+ expect(page).to have_content("Access link updated successfully")
134
+ expect(page).to have_css("tbody tr", count: 3)
135
+ within "tbody tr", text: last_token.token do
136
+ expect(page).to have_content(1.day.from_now.strftime("%d/%m/%Y 00:00"))
137
+ end
138
+ within "tbody tr", text: last_token.token do
139
+ expect(page).to have_content("No")
140
+ end
141
+ end
142
+
143
+ it "allows copying the share link from the share token" do
144
+ within ".share_tokens tbody tr", text: last_token.token do
145
+ click_on "Copy link"
146
+ expect(page).to have_content("copied!")
147
+ expect(page).to have_css("[data-clipboard-copy-label]")
148
+ expect(page).to have_css("[data-clipboard-copy-message]")
149
+ expect(page).to have_css("[data-clipboard-content]")
150
+ end
151
+ end
152
+
153
+ it "has a share link for each token" do
154
+ urls = share_tokens.map(&:url)
155
+ within ".share_tokens tbody tr", text: last_token.token do
156
+ share_window = window_opened_by { click_on "Preview" }
157
+
158
+ within_window share_window do
159
+ expect(urls).to include(page.current_url)
160
+ end
161
+ end
162
+ end
163
+
164
+ it "has a share button that opens the share url for the resource" do
165
+ within ".share_tokens tbody tr", text: last_token.token do
166
+ share_window = window_opened_by { click_on "Preview", wait: 2 }
167
+
168
+ within_window share_window do
169
+ expect(current_url).to include(last_token.url)
170
+ end
171
+ end
172
+ end
173
+
174
+ it "can delete tokens" do
175
+ within ".share_tokens tbody tr", text: last_token.token do
176
+ accept_confirm { click_on "Delete" }
177
+ end
178
+
179
+ expect(page).to have_admin_callout("Access link successfully destroyed")
180
+ expect(page).to have_css("tbody tr", count: 2)
181
+ end
182
+ end
183
+
184
+ context "when there are many pages" do
185
+ let!(:share_tokens) { create_list(:share_token, 26, :with_token, token_for: resource, organization:) }
186
+
187
+ before do
188
+ visit_share_tokens_page
189
+ end
190
+
191
+ it "displays pagination" do
192
+ expect(page).to have_css("tbody tr", count: 25)
193
+ within '[aria-label="Pagination"]' do
194
+ click_on "Next"
195
+ end
196
+ expect(page).to have_css("tbody tr", count: 1)
197
+ end
198
+ end
199
+ end
200
+
201
+ shared_examples "manage component share tokens" do
202
+ let!(:components_path) { participatory_space_engine.components_path(participatory_space) }
203
+ let!(:component) { create(:component, participatory_space:, published_at: nil) }
204
+ let(:resource) { component }
205
+ let(:resource_name) { translated(component.name) }
206
+
207
+ before do
208
+ switch_to_host(organization.host)
209
+ login_as user, scope: :user
210
+ end
211
+
212
+ def visit_share_tokens_page
213
+ visit components_path
214
+ within ".table-list" do
215
+ click_on "Access links"
216
+ end
217
+ end
218
+
219
+ it_behaves_like "manage resource share tokens"
220
+ end
221
+
222
+ shared_examples "manage participatory space share tokens" do
223
+ let(:resource) { participatory_space }
224
+ let(:resource_name) { translated(resource.title) }
225
+
226
+ before do
227
+ switch_to_host(organization.host)
228
+ login_as user, scope: :user
229
+ end
230
+
231
+ def visit_share_tokens_page
232
+ visit participatory_spaces_path
233
+ click_on "Access links"
234
+ end
235
+
236
+ it_behaves_like "manage resource share tokens"
237
+ end
@@ -14,6 +14,8 @@ shared_context "with frontend map builder" do
14
14
 
15
15
  let(:template_class) do
16
16
  Class.new(ActionView::Base) do
17
+ include Decidim::LayoutHelper
18
+
17
19
  def protect_against_forgery?
18
20
  false
19
21
  end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples_for "default open data exporter" do
4
+ let(:organization) { create(:organization) }
5
+ let(:path) { "/tmp/test-open-data-#{resource_file_name}.zip" }
6
+ let(:zip_contents) { Zip::File.open(path) }
7
+
8
+ let(:file_name) { "*open-data-#{resource_file_name}.csv" }
9
+ let(:file) { zip_contents.glob(file_name).first }
10
+ let(:data) { file.get_input_stream.read }
11
+
12
+ before do
13
+ subject.export
14
+ end
15
+
16
+ it "includes a CSV" do
17
+ expect(file).not_to be_nil
18
+ end
19
+
20
+ describe "README content" do
21
+ let(:file_name) { "README.md" }
22
+
23
+ it "includes the resource help description" do
24
+ expect(data).to include(resource_title)
25
+ help_lines.each do |line|
26
+ expect(data).to include(line)
27
+ end
28
+ end
29
+
30
+ it "does not have any missing translation" do
31
+ expect(data).not_to include("Translation missing")
32
+ end
33
+ end
34
+ end
35
+
36
+ shared_examples_for "open users data exporter" do
37
+ include_examples "default open data exporter"
38
+
39
+ it "includes the resource data" do
40
+ expect(data).to include(resource.nickname.gsub("\"", "\"\""))
41
+ end
42
+
43
+ context "with unpublished components" do
44
+ it "does not include the resource data" do
45
+ expect(data).not_to include(unpublished_resource.nickname.gsub("\"", "\"\""))
46
+ end
47
+ end
48
+ end
49
+
50
+ shared_examples_for "open moderation data exporter" do
51
+ include_examples "default open data exporter"
52
+
53
+ it "includes the resource data" do
54
+ if resource.respond_to?(:reportable)
55
+ expect(data).to include(resource.reportable.reported_content_url.gsub("\"", "\"\""))
56
+ elsif resource.respond_to?(:reported?)
57
+ expect(data).to include(resource.id.to_s)
58
+ else
59
+ raise "Failed to understand the model"
60
+ end
61
+ end
62
+
63
+ context "with unpublished components" do
64
+ it "does not include the resource data" do
65
+ if unpublished_resource.respond_to?(:reportable)
66
+ expect(data).not_to include(unpublished_resource.reportable.reported_content_url.gsub("\"", "\"\""))
67
+ elsif unpublished_resource.respond_to?(:reported?)
68
+ expect(data).not_to include(unpublished_resource.id.to_s)
69
+ else
70
+ raise "Failed to understand the model"
71
+ end
72
+ end
73
+ end
74
+ end
75
+
76
+ shared_examples_for "open data exporter" do
77
+ include_examples "default open data exporter"
78
+
79
+ it "includes the resource data" do
80
+ if resource.respond_to?(:title)
81
+ expect(data).to include(translated(resource.title).gsub("\"", "\"\""))
82
+ elsif resource.respond_to?(:body)
83
+ # Seems like the comments are always taking the first alphabetical language for the export
84
+ # We should fix it in the future
85
+ expect(data).to include(resource.body.min.second)
86
+ else
87
+ raise "Failed to understand the model"
88
+ end
89
+ end
90
+
91
+ context "with unpublished components" do
92
+ it "does not include the resource data" do
93
+ if unpublished_resource.respond_to?(:title)
94
+ expect(data).not_to include(translated(unpublished_resource.title).gsub("\"", "\"\""))
95
+ elsif unpublished_resource.respond_to?(:body)
96
+ expect(data).not_to include(translated(unpublished_resource.body).gsub("\"", "\"\""))
97
+ else
98
+ raise "Failed to understand the model"
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples "participatory space members page examples" do
4
+ let(:user1) { create(:user, organization: privatable_to.organization) }
5
+ let(:user2) { create(:user, organization: privatable_to.organization) }
6
+ let(:user3) { create(:user, organization: privatable_to.organization) }
7
+
8
+ before do
9
+ request.env["decidim.current_organization"] = organization
10
+ end
11
+
12
+ describe "GET index" do
13
+ context "when participatory space has no members" do
14
+ it "redirects to 404" do
15
+ expect { get :index, params: { slug_param => slug } }
16
+ .to raise_error(ActionController::RoutingError)
17
+ end
18
+ end
19
+
20
+ context "when participatory space has members" do
21
+ let!(:member1) { create(:participatory_space_private_user, privatable_to:, user: user1, published: true) }
22
+ let!(:member2) { create(:participatory_space_private_user, privatable_to:, user: user2, published: true) }
23
+ let!(:non_published) { create(:participatory_space_private_user, privatable_to:, user: user3, published: false) }
24
+
25
+ context "when user has permissions" do
26
+ it "displays list of members" do
27
+ get :index, params: { slug_param => slug }
28
+
29
+ expect(controller.helpers.collection).to contain_exactly(member1, member2)
30
+ end
31
+ end
32
+
33
+ context "when user does not have permissions" do
34
+ before do
35
+ allow(controller).to receive(:current_user_can_visit_space?).and_return(false)
36
+ end
37
+
38
+ it "redirects to participatory space path" do
39
+ get :index, params: { slug_param => slug }
40
+
41
+ expect(response).to redirect_to(privatable_to)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples_for "a participatory space search with taxonomies" do |factory_name|
4
+ let(:factory_params) do
5
+ space_params
6
+ rescue StandardError
7
+ {}
8
+ end
9
+
10
+ let(:filter_params) do
11
+ { with_any_taxonomies: { "#{root_taxonomy.id}": taxonomy_ids } }
12
+ end
13
+
14
+ let(:root_taxonomy) { create(:taxonomy, organization:) }
15
+ let(:taxonomy1) { create(:taxonomy, parent: root_taxonomy, organization:) }
16
+ let(:taxonomy2) { create(:taxonomy, parent: root_taxonomy, organization:) }
17
+ let(:child_taxonomy) { create(:taxonomy, organization:, parent: taxonomy2) }
18
+ let!(:space) { create(factory_name, { organization: }.merge(factory_params)) }
19
+ let!(:space2) { create(factory_name, { organization:, taxonomies: [taxonomy1] }.merge(factory_params)) }
20
+ let!(:space3) { create(factory_name, { organization:, taxonomies: [taxonomy2] }.merge(factory_params)) }
21
+ let!(:space4) { create(factory_name, { organization:, taxonomies: [child_taxonomy] }.merge(factory_params)) }
22
+
23
+ before do
24
+ get(
25
+ request_path,
26
+ params: { filter: filter_params },
27
+ headers: { "HOST" => organization.host }
28
+ )
29
+ end
30
+
31
+ context "when no taxonomy filter is present" do
32
+ let(:filter_params) do
33
+ { with_any_taxonomies: [] }
34
+ end
35
+
36
+ it "includes all spaces" do
37
+ expect(subject).to have_escaped_html(translated(space.try(:title) || space.try(:name)))
38
+ expect(subject).to have_escaped_html(translated(space2.try(:title) || space2.try(:name)))
39
+ expect(subject).to have_escaped_html(translated(space3.try(:title) || space3.try(:name)))
40
+ expect(subject).to have_escaped_html(translated(space4.try(:title) || space4.try(:name)))
41
+ end
42
+ end
43
+
44
+ context "when no ids are specified" do
45
+ let(:taxonomy_ids) { [] }
46
+
47
+ it "includes all spaces" do
48
+ expect(subject).to have_escaped_html(translated(space.try(:title) || space.try(:name)))
49
+ expect(subject).to have_escaped_html(translated(space2.try(:title) || space2.try(:name)))
50
+ expect(subject).to have_escaped_html(translated(space3.try(:title) || space3.try(:name)))
51
+ expect(subject).to have_escaped_html(translated(space4.try(:title) || space4.try(:name)))
52
+ end
53
+ end
54
+
55
+ context "when `all` is being sent" do
56
+ let(:taxonomy_ids) { ["all"] }
57
+
58
+ it "includes all spaces with the root taxonomy" do
59
+ expect(subject).not_to have_escaped_html(translated(space.try(:title) || space.try(:name)))
60
+ expect(subject).to have_escaped_html(translated(space2.try(:title) || space2.try(:name)))
61
+ expect(subject).to have_escaped_html(translated(space3.try(:title) || space3.try(:name)))
62
+ expect(subject).to have_escaped_html(translated(space4.try(:title) || space4.try(:name)))
63
+ end
64
+ end
65
+
66
+ context "when a taxonomy is selected" do
67
+ let(:taxonomy_ids) { [taxonomy2.id] }
68
+
69
+ it "includes only spaces for that taxonomy and its children" do
70
+ expect(subject).not_to have_escaped_html(translated(space.try(:title) || space.try(:name)))
71
+ expect(subject).not_to have_escaped_html(translated(space2.try(:title) || space2.try(:name)))
72
+ expect(subject).to have_escaped_html(translated(space3.try(:title) || space3.try(:name)))
73
+ expect(subject).to have_escaped_html(translated(space4.try(:title) || space4.try(:name)))
74
+ end
75
+ end
76
+
77
+ context "when multiple taxonomies are selected" do
78
+ let(:taxonomy_ids) { [taxonomy1.id, taxonomy2.id] }
79
+
80
+ it "includes only spaces for those taxonomies" do
81
+ expect(subject).not_to have_escaped_html(translated(space.try(:title) || space.try(:name)))
82
+ expect(subject).to have_escaped_html(translated(space2.try(:title) || space2.try(:name)))
83
+ expect(subject).to have_escaped_html(translated(space3.try(:title) || space3.try(:name)))
84
+ expect(subject).to have_escaped_html(translated(space4.try(:title) || space4.try(:name)))
85
+ end
86
+ end
87
+
88
+ context "when a sub_taxonomy is selected" do
89
+ let(:taxonomy_ids) { [child_taxonomy.id] }
90
+
91
+ it "includes only spaces for that taxonomy" do
92
+ expect(subject).not_to have_escaped_html(translated(space.try(:title) || space.try(:name)))
93
+ expect(subject).not_to have_escaped_html(translated(space2.try(:title) || space2.try(:name)))
94
+ expect(subject).not_to have_escaped_html(translated(space3.try(:title) || space3.try(:name)))
95
+ expect(subject).to have_escaped_html(translated(space4.try(:title) || space4.try(:name)))
96
+ end
97
+ end
98
+ end