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
@@ -38,7 +38,7 @@ shared_examples "comments" do
38
38
  expect(page).to have_css(".comment", minimum: 1)
39
39
 
40
40
  within ".comment-order-by" do
41
- click_on "Best rated"
41
+ select "Best rated", from: "order"
42
42
  end
43
43
 
44
44
  expect(page).to have_css(".comments > div:nth-child(2)", text: "Most Rated Comment")
@@ -54,7 +54,7 @@ shared_examples "comments" do
54
54
  expect(page).to have_css(".comment", minimum: 1)
55
55
 
56
56
  within("#accordion-#{single_comment.id}") do
57
- expect(page).to have_content "Hide reply"
57
+ expect(page).to have_content "1 answer"
58
58
  end
59
59
  end
60
60
 
@@ -120,6 +120,24 @@ shared_examples "comments" do
120
120
  expect(page).to have_no_css(".add-comment form")
121
121
  expect(page).to have_css(".comment-thread")
122
122
  end
123
+
124
+ context "when user visit a mobile browser" do
125
+ before do
126
+ driven_by(:iphone)
127
+ switch_to_host(organization.host)
128
+ visit decidim.root_path
129
+ click_on "Accept all"
130
+ visit resource_path
131
+ end
132
+
133
+ it "does not show the add comment button" do
134
+ expect(page).to have_no_content("Add comment")
135
+ end
136
+
137
+ it "shows a message so user can Log in or create an account" do
138
+ expect(page).to have_content("Log in or create an account to add your comment.")
139
+ end
140
+ end
123
141
  end
124
142
 
125
143
  context "when authenticated" do
@@ -132,6 +150,62 @@ shared_examples "comments" do
132
150
  expect(page).to have_css(".add-comment form")
133
151
  end
134
152
 
153
+ context "when user visit a computer browser" do
154
+ before do
155
+ switch_to_host(organization.host)
156
+ visit decidim.root_path
157
+ login_as user, scope: :user
158
+ visit resource_path
159
+ end
160
+
161
+ it "does not show a modal with form to add comments" do
162
+ expect(page).to have_no_css(".fullscreen")
163
+ end
164
+
165
+ it "does not show the add comment button" do
166
+ expect(page).to have_no_content("Add comment")
167
+ end
168
+
169
+ it "allows user to comment" do
170
+ find("textarea[name='comment[body]']").set("Test comment with a computer.")
171
+ click_on "Publish comment"
172
+ expect(page).to have_content("Test comment with a computer.")
173
+ end
174
+ end
175
+
176
+ context "when user visit a mobile browser" do
177
+ before do
178
+ driven_by(:iphone)
179
+ switch_to_host(organization.host)
180
+ visit decidim.root_path
181
+ click_on "Accept all"
182
+ login_as user, scope: :user
183
+ visit resource_path
184
+ end
185
+
186
+ it "shows the add comment button" do
187
+ expect(page).to have_content("Add comment")
188
+ end
189
+
190
+ it "does not show a message so user can Log in or create an account" do
191
+ expect(page).to have_no_content("Log in or create an account to add your comment.")
192
+ end
193
+
194
+ it "shows a modal with the comment form" do
195
+ sleep 1
196
+ click_on "Add comment"
197
+ sleep 1
198
+ expect(page).to have_content("Add comment")
199
+ expect(page).to have_content("1000 characters left")
200
+ expect(page).to have_css(".add-comment form")
201
+ expect(page).to have_css(".fullscreen")
202
+
203
+ find("textarea[name='comment[body]']").set("Test comment with a mobile phone.")
204
+ click_on "Publish comment"
205
+ expect(page).to have_content("Test comment with a mobile phone.")
206
+ end
207
+ end
208
+
135
209
  context "when user is not authorized to comment" do
136
210
  let(:permissions) do
137
211
  {
@@ -560,19 +634,29 @@ shared_examples "comments" do
560
634
  let(:new_reply_body) { "Hey, I just jumped inside the thread!" }
561
635
  let!(:new_reply) { create(:comment, commentable: thread, root_commentable: commentable, body: new_reply_body) }
562
636
 
563
- it "displays the hide button" do
637
+ it "displays a way to to display content" do
564
638
  visit current_path
565
639
  within "#comment_#{thread.id}" do
566
- expect(page).to have_content("Hide reply")
640
+ expect(page).to have_content("1 answer")
641
+ click_on "1 answer"
567
642
  expect(page).to have_content(new_reply_body)
643
+ click_on "Reply", match: :first
644
+ expect(page).to have_content("Publish reply")
645
+ find("textarea[name='comment[body]']").set("Test reply comments.")
646
+ click_on "Publish reply"
647
+ expect(page).to have_content("Show 2 replies")
648
+ click_on "Show 2 replies"
649
+ expect(page).to have_content("Test reply comments.")
568
650
  end
569
651
  end
570
652
 
571
- it "displays the show button" do
653
+ it "displays a way hide content" do
572
654
  visit current_path
573
655
  within "#comment_#{thread.id}" do
574
- click_on "Hide reply"
575
- expect(page).to have_content("Show reply")
656
+ expect(page).to have_content("1 answer")
657
+ click_on "1 answer"
658
+ expect(page).to have_content("1 answer")
659
+ click_on "1 answer"
576
660
  expect(page).to have_no_content(new_reply_body)
577
661
  end
578
662
  end
@@ -583,9 +667,10 @@ shared_examples "comments" do
583
667
  it "displays the show button" do
584
668
  visit current_path
585
669
  within "#comment_#{thread.id}" do
586
- click_on "Hide 3 replies"
587
- expect(page).to have_content("Show 3 replies")
670
+ expect(page).to have_content("3 answers")
588
671
  expect(page).to have_no_content(new_reply_body)
672
+ click_on "3 answers"
673
+ expect(page).to have_content(new_reply_body)
589
674
  end
590
675
  end
591
676
  end
@@ -633,7 +718,6 @@ shared_examples "comments" do
633
718
  field = find("#add-comment-#{commentable.commentable_type.demodulize}-#{commentable.id}")
634
719
  field.set " "
635
720
  field.native.send_keys content
636
- select user_group.name, from: "Comment as"
637
721
  click_on "Publish comment"
638
722
  end
639
723
 
@@ -815,29 +899,6 @@ shared_examples "comments" do
815
899
 
816
900
  expect(page).to have_css(".add-comment form")
817
901
  end
818
-
819
- it "works according to the setting in the commentable" do
820
- if commentable.comments_have_alignment?
821
- page.find("[data-toggle-ok=true]").click
822
- expect(page.find("[data-toggle-ok=true]")["aria-pressed"]).to eq("true")
823
- expect(page.find("[data-toggle-meh=true]")["aria-pressed"]).to eq("false")
824
- expect(page.find("[data-toggle-ko=true]")["aria-pressed"]).to eq("false")
825
- expect(page.find("div[data-opinion-toggle] .selected-state", visible: false)).to have_content("Your opinion about this topic is positive")
826
-
827
- within "form#new_comment_for_#{commentable.commentable_type.demodulize}_#{commentable.id}" do
828
- field = find("#add-comment-#{commentable.commentable_type.demodulize}-#{commentable.id}")
829
- field.set " "
830
- field.native.send_keys "I am in favor about this!"
831
- click_on "Publish comment"
832
- end
833
-
834
- within "#comments" do
835
- expect(page).to have_css "span.success.label", text: "In favor", wait: 20
836
- end
837
- else
838
- expect(page).to have_no_css("[data-toggle-ok=true]")
839
- end
840
- end
841
902
  end
842
903
  end
843
904
 
@@ -866,10 +927,11 @@ shared_examples "comments" do
866
927
  skip "Commentable comments has no votes" unless commentable.comments_have_votes?
867
928
 
868
929
  visit current_path
869
- expect(page).to have_css("#comment_#{comments[0].id} > [data-comment-footer] > .comment__footer-grid .comment__votes .js-comment__votes--up", text: /0/)
930
+ expect(page).to have_css("#comment_#{comments[0].id} > [data-comment-footer] > .comment__footer-grid .comment__votes .js-comment__votes--up", text: /0/, visible: :all)
870
931
  page.find("#comment_#{comments[0].id} > [data-comment-footer] > .comment__footer-grid .comment__votes .js-comment__votes--up").click
871
- expect(page).to have_css("#comment_#{comments[0].id} > [data-comment-footer] > .comment__footer-grid .comment__votes .js-comment__votes--up", text: /1/)
872
- expect(page).to have_css("#comment_#{comment_on_comment.id} > [data-comment-footer] > .comment__footer-grid .comment__votes .js-comment__votes--up", text: /0/)
932
+ expect(page).to have_css("#comment_#{comments[0].id} > [data-comment-footer] > .comment__footer-grid .comment__votes .js-comment__votes--up", text: /1/, visible: :all)
933
+ expect(page).to have_css("#comment_#{comment_on_comment.id} > [data-comment-footer] >.comment__footer-grid .comment__votes .js-comment__votes--up", text: /0/,
934
+ visible: :all)
873
935
  end
874
936
  end
875
937
  end
@@ -1038,7 +1100,7 @@ shared_examples "comments blocked" do
1038
1100
 
1039
1101
  it "shows a message indicating that comments are disabled" do
1040
1102
  visit resource_path
1041
- expect(page).to have_content("Comments are disabled at this time")
1103
+ expect(page).to have_content("Comments are currently disabled, only administrators can reply or post new ones.")
1042
1104
  expect(page).to have_no_content("You need to be verified to comment at this moment")
1043
1105
  end
1044
1106
  end
@@ -1053,6 +1115,26 @@ shared_examples "comments blocked" do
1053
1115
  visit resource_path
1054
1116
  end
1055
1117
 
1118
+ shared_examples "can answer comments" do
1119
+ it "can answer" do
1120
+ visit resource_path
1121
+ expect(page).to have_link("Comment")
1122
+ page.find("a", text: "Comment").click
1123
+ find("textarea[name='comment[body]']").set("Test admin commenting in a closed comment.")
1124
+ click_on "Publish comment"
1125
+ expect(page).to have_content("Test admin commenting in a closed comment.")
1126
+
1127
+ expect(page).to have_button("Reply")
1128
+ first("button", text: "Reply").click
1129
+ expect(page).to have_css(".comment-thread")
1130
+ within first(".comment-thread") do
1131
+ find("textarea[name='comment[body]']").set("Test admin replying a closed comment.")
1132
+ click_on "Publish reply"
1133
+ end
1134
+ expect(page).to have_content("Test admin replying a closed comment.")
1135
+ end
1136
+ end
1137
+
1056
1138
  context "when comments are blocked" do
1057
1139
  let(:active_step_id) { component.participatory_space.active_step.id }
1058
1140
 
@@ -1062,9 +1144,282 @@ shared_examples "comments blocked" do
1062
1144
 
1063
1145
  it "shows a message indicating that comments are disabled" do
1064
1146
  visit resource_path
1065
- expect(page).to have_content("Comments are disabled at this time")
1147
+ expect(page).to have_content("Comments are currently disabled, only administrators can reply or post new ones.")
1066
1148
  expect(page).to have_no_content("You need to be verified to comment at this moment")
1067
1149
  end
1150
+
1151
+ context "when the user is an administrator" do
1152
+ let!(:user) { create(:user, :admin, :confirmed, organization:) }
1153
+
1154
+ it_behaves_like "can answer comments"
1155
+ end
1156
+
1157
+ context "when the user has a role of user manager" do
1158
+ let!(:user) { create(:user, :user_manager, :confirmed, organization:) }
1159
+
1160
+ it_behaves_like "can answer comments"
1161
+ end
1162
+
1163
+ context "when the user has an evaluator role in the same participatory space" do
1164
+ let!(:valuator_role) { create(:participatory_process_user_role, role: :valuator, user:, participatory_process: participatory_space) }
1165
+
1166
+ it_behaves_like "can answer comments"
1167
+ end
1168
+
1169
+ shared_examples "evaluator role in different participatory space" do |space_type|
1170
+ let!(:another_space_valuator_role) do
1171
+ create(:"#{space_type}_user_role", role: :valuator, user:, "#{space_type}": create(space_type, organization:))
1172
+ end
1173
+
1174
+ it "cannot answer" do
1175
+ visit resource_path
1176
+ expect(page).to have_content("Comments are currently disabled, only administrators can reply or post new ones.")
1177
+ expect(page).to have_no_content("You need to be verified to comment at this moment")
1178
+ expect(page).to have_no_css("textarea#add-comment-Proposal-1")
1179
+ end
1180
+ end
1181
+
1182
+ context "when the user has an evaluator role in a different participatory space" do
1183
+ include_examples "evaluator role in different participatory space", :participatory_process
1184
+ include_examples "evaluator role in different participatory space", :conference
1185
+ include_examples "evaluator role in different participatory space", :assembly
1186
+ end
1187
+ end
1188
+ end
1189
+ end
1190
+
1191
+ shared_examples "comments with two columns" do
1192
+ let!(:user) { create(:user, :confirmed, organization:) }
1193
+
1194
+ before do
1195
+ login_as user, scope: :user
1196
+ end
1197
+
1198
+ context "displays comments list in two columns" do
1199
+ let!(:comments_in_favor) { create_list(:comment, 2, :in_favor, commentable:) }
1200
+ let!(:comments_against) { create_list(:comment, 1, :against, commentable:) }
1201
+
1202
+ it "shows the list of comments for the resource" do
1203
+ visit resource_path
1204
+
1205
+ expect(page).to have_css("#comments")
1206
+ expect(page).to have_css(".comment", count: comments.length)
1207
+
1208
+ within(".comments-two-columns") do
1209
+ check_comments_order(".comments-section__in-favor", comments_in_favor)
1210
+ check_comments_order(".comments-section__against", comments_against)
1211
+ end
1212
+ end
1213
+ end
1214
+
1215
+ context "in mobile view" do
1216
+ it "shows kebab menu functionality" do
1217
+ resize_window_to_mobile
1218
+ visit resource_path
1219
+
1220
+ within "#comment_#{comments.first.id}" do
1221
+ page.find("[id^='dropdown-trigger']").click
1222
+ expect(page).to have_css("ul.dropdown.dropdown__bottom", visible: :visible)
1223
+ end
1224
+
1225
+ resize_window_to_desktop
1226
+ end
1227
+
1228
+ context "when commentable is closed" do
1229
+ let!(:commentable) { closed_commentable }
1230
+ let!(:highest_voted_comment_in_favor) { create(:comment, :in_favor, commentable:, created_at: 2.days.ago, up_votes_count: 15) }
1231
+ let!(:high_voted_comment_in_favor) { create(:comment, :in_favor, commentable:, created_at: 4.days.ago, up_votes_count: 10) }
1232
+ let!(:older_comment_in_favor) { create(:comment, :in_favor, commentable:, created_at: 3.days.ago, up_votes_count: 5) }
1233
+
1234
+ let!(:highest_voted_comment_against) { create(:comment, :against, commentable:, created_at: 2.days.ago, up_votes_count: 12) }
1235
+ let!(:high_voted_comment_against) { create(:comment, :against, commentable:, created_at: 5.days.ago, up_votes_count: 8) }
1236
+ let!(:older_comment_against) { create(:comment, :against, commentable:, created_at: 3.days.ago, up_votes_count: 4) }
1237
+
1238
+ it "shows comments with top comments at the beginning and interleaved order after" do
1239
+ resize_window_to_mobile
1240
+ visit resource_path
1241
+
1242
+ within(".comment-threads") do
1243
+ interleaved_comments = [
1244
+ highest_voted_comment_in_favor,
1245
+ highest_voted_comment_against,
1246
+ high_voted_comment_in_favor,
1247
+ high_voted_comment_against,
1248
+ older_comment_in_favor,
1249
+ older_comment_against
1250
+ ]
1251
+
1252
+ all_comments = all(".comment-thread")
1253
+
1254
+ interleaved_comments.each_with_index do |comment, index|
1255
+ expect(all_comments[index]).to have_content(comment.body["en"])
1256
+ end
1257
+
1258
+ expect(page).to have_css(".most-upvoted-label", text: "Most upvoted", count: 2)
1259
+ end
1260
+
1261
+ resize_window_to_desktop
1262
+ end
1263
+ end
1264
+ end
1265
+
1266
+ context "when viewing a single comment" do
1267
+ let!(:single_comment) { create(:comment, commentable:, body: { "en" => "This is a single comment" }) }
1268
+
1269
+ before do
1270
+ visit "#{resource_locator(commentable).path}?commentId=#{single_comment.id}"
1271
+ end
1272
+
1273
+ it "displays only the single comment without columns" do
1274
+ expect(page).to have_css("#comments")
1275
+ expect(page).to have_css(".comment-thread", count: 1)
1276
+ expect(page).to have_content("This is a single comment")
1277
+ expect(page).to have_no_css(".comments-two-columns")
1278
+ expect(page).to have_no_content("In Favor")
1279
+ expect(page).to have_no_content("Against")
1280
+ expect(page).to have_no_content("You are viewing only one comment")
1281
+ end
1282
+ end
1283
+
1284
+ context "when commentable is not closed" do
1285
+ let!(:oldest_in_favor_comment) { create(:comment, :in_favor, commentable:, created_at: 3.days.ago) }
1286
+ let!(:older_in_favor_comment) { create(:comment, :in_favor, commentable:, created_at: 2.days.ago) }
1287
+ let!(:oldest_against_comment) { create(:comment, :against, commentable:, created_at: 4.days.ago) }
1288
+ let!(:newer_against_comment) { create(:comment, :against, commentable:, created_at: 1.day.ago) }
1289
+
1290
+ it "shows the comments in two columns sorted by creation date in ascending order" do
1291
+ visit resource_path
1292
+
1293
+ within(".comments-two-columns") do
1294
+ check_comments_order(".comments-section__in-favor", [oldest_in_favor_comment, older_in_favor_comment])
1295
+ check_comments_order(".comments-section__against", [oldest_against_comment, newer_against_comment])
1296
+ end
1297
+ end
1298
+
1299
+ it "allows the user to add a new comment at the end of the respective column" do
1300
+ visit resource_path
1301
+
1302
+ add_new_comment("In favor", "This is a new comment in favor")
1303
+
1304
+ within(".comments-section__in-favor") do
1305
+ expect(page).to have_content("This is a new comment in favor")
1306
+ end
1307
+ end
1308
+
1309
+ it "disables the publish button until 'in favor' or 'against' is selected" do
1310
+ visit resource_path
1311
+
1312
+ expect(page).to have_button("Publish comment", disabled: true)
1313
+
1314
+ within(".comment__opinion-container") do
1315
+ click_on "In favor"
1316
+ end
1317
+
1318
+ within "form#new_comment_for_#{commentable.commentable_type.demodulize}_#{commentable.id}" do
1319
+ fill_in_comment_field("This is a new comment in favor")
1320
+ click_on "Publish comment"
1321
+ end
1322
+ end
1323
+
1324
+ it "shows comments sorted by creation date when viewed on a small screen" do
1325
+ resize_window_to_mobile
1326
+ visit resource_path
1327
+
1328
+ within(".comment-threads") do
1329
+ comments = all(".comment-thread")
1330
+
1331
+ expect(comments[0]).to have_content(oldest_in_favor_comment.body["en"])
1332
+ expect(comments[1]).to have_content(oldest_against_comment.body["en"])
1333
+ expect(comments[2]).to have_content(older_in_favor_comment.body["en"])
1334
+ expect(comments[3]).to have_content(newer_against_comment.body["en"])
1335
+ end
1336
+
1337
+ resize_window_to_desktop
1338
+ end
1339
+ end
1340
+
1341
+ context "when commentable is closed" do
1342
+ let!(:commentable) { closed_commentable }
1343
+ let!(:highest_voted_comment_in_favor) { create(:comment, :in_favor, commentable:, created_at: 2.days.ago, up_votes_count: 15) }
1344
+ let!(:high_voted_comment_in_favor) { create(:comment, :in_favor, commentable:, created_at: 4.days.ago, up_votes_count: 10) }
1345
+ let!(:older_comment_in_favor) { create(:comment, :in_favor, commentable:, created_at: 3.days.ago, up_votes_count: 5) }
1346
+ let!(:recent_comment_in_favor) { create(:comment, :in_favor, commentable:, created_at: 2.days.ago, up_votes_count: 3) }
1347
+ let!(:latest_comment_in_favor) { create(:comment, :in_favor, commentable:, created_at: 1.day.ago, up_votes_count: 1) }
1348
+
1349
+ let!(:highest_voted_comment_against) { create(:comment, :against, commentable:, created_at: 2.days.ago, up_votes_count: 12) }
1350
+ let!(:high_voted_comment_against) { create(:comment, :against, commentable:, created_at: 5.days.ago, up_votes_count: 8) }
1351
+ let!(:older_comment_against) { create(:comment, :against, commentable:, created_at: 3.days.ago, up_votes_count: 4) }
1352
+ let!(:recent_comment_against) { create(:comment, :against, commentable:, created_at: 2.days.ago, up_votes_count: 2) }
1353
+ let!(:latest_comment_against) { create(:comment, :against, commentable:, created_at: 1.day.ago, up_votes_count: 1) }
1354
+
1355
+ before do
1356
+ visit resource_path
1357
+ end
1358
+
1359
+ it "shows the top voted comments at the top of each column, followed by comments in ascending chronological order" do
1360
+ within(".comments-two-columns") do
1361
+ check_comments_order(".comments-section__in-favor", [
1362
+ highest_voted_comment_in_favor,
1363
+ high_voted_comment_in_favor,
1364
+ older_comment_in_favor,
1365
+ recent_comment_in_favor,
1366
+ latest_comment_in_favor
1367
+ ])
1368
+
1369
+ check_comments_order(".comments-section__against", [
1370
+ highest_voted_comment_against,
1371
+ high_voted_comment_against,
1372
+ older_comment_against,
1373
+ recent_comment_against,
1374
+ latest_comment_against
1375
+ ])
1376
+ end
1068
1377
  end
1378
+
1379
+ it "shows the top voted comments with label at the top of each column" do
1380
+ within(".comments-two-columns") do
1381
+ within(".comments-section__in-favor") do
1382
+ expect(page).to have_css(".most-upvoted-label", text: "Most upvoted")
1383
+ expect(page).to have_content(highest_voted_comment_in_favor.body["en"])
1384
+ end
1385
+
1386
+ within(".comments-section__against") do
1387
+ expect(page).to have_css(".most-upvoted-label", text: "Most upvoted")
1388
+ expect(page).to have_content(highest_voted_comment_against.body["en"])
1389
+ end
1390
+ end
1391
+ end
1392
+ end
1393
+
1394
+ def check_comments_order(section_selector, comments)
1395
+ comments_section = all("#{section_selector} .comment-thread")
1396
+ comments.each_with_index do |comment, index|
1397
+ expect(comments_section[index]).to have_content(comment.body["en"])
1398
+ end
1399
+ end
1400
+
1401
+ def add_new_comment(opinion, comment_text)
1402
+ within(".comment__opinion-container") do
1403
+ click_on opinion
1404
+ end
1405
+
1406
+ within "form#new_comment_for_#{commentable.commentable_type.demodulize}_#{commentable.id}" do
1407
+ fill_in_comment_field(comment_text)
1408
+ click_on "Publish comment"
1409
+ end
1410
+ end
1411
+
1412
+ def fill_in_comment_field(comment_text)
1413
+ field = find("#add-comment-#{commentable.commentable_type.demodulize}-#{commentable.id}")
1414
+ field.set " "
1415
+ field.native.send_keys comment_text
1416
+ end
1417
+
1418
+ def resize_window_to_mobile
1419
+ page.driver.browser.manage.window.resize_to(375, 667)
1420
+ end
1421
+
1422
+ def resize_window_to_desktop
1423
+ page.driver.browser.manage.window.resize_to(1920, 1080)
1069
1424
  end
1070
1425
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples_for "a components controller to hide" do |params|
4
+ describe "PUT hide" do
5
+ it "hides the components" do
6
+ put :hide, params: { "#{params[:slug_attribute]}": space.slug, id: component.id }
7
+
8
+ expect(component.reload.visible).to eq(false)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples_for "a reorder components controller" do |params|
4
+ describe "PUT reorder" do
5
+ let(:other_component) do
6
+ create(
7
+ :component,
8
+ manifest_name: :dummy,
9
+ participatory_space: space
10
+ )
11
+ end
12
+
13
+ it "reorders the components" do
14
+ expect([component.id, other_component.id]).to eq(space.components.pluck(:id))
15
+
16
+ put :reorder, params: { "#{params[:slug_attribute]}": space.slug, order_ids: [other_component.id, component.id] }
17
+
18
+ expect([other_component.id, component.id]).to eq(space.components.pluck(:id))
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_context "when downloading open data files" do
4
+ # Workaround to ignore Bullet warnings in these examples, until we found a way to actually fix these issues
5
+ before do
6
+ Bullet.n_plus_one_query_enable = false
7
+ Bullet.unused_eager_loading_enable = false
8
+ end
9
+
10
+ after do
11
+ Bullet.n_plus_one_query_enable = Decidim::Env.new("DECIDIM_BULLET_N_PLUS_ONE", "false").present?
12
+ Bullet.unused_eager_loading_enable = Decidim::Env.new("DECIDIM_BULLET_UNUSED_EAGER", "false").present?
13
+ end
14
+
15
+ def download_open_data_file
16
+ # Prevent using the same cached file
17
+ open_data_file = Rails.root.join("tmp/#{organization.open_data_file_path}")
18
+ FileUtils.rm_f(open_data_file)
19
+ Decidim::OpenDataJob.perform_now(organization)
20
+
21
+ switch_to_host(organization.host)
22
+ visit decidim.root_path
23
+
24
+ click_on "Open Data"
25
+ click_on "Download all the Open Data files"
26
+ end
27
+
28
+ def extract_content_from_zip(download_path, file_name)
29
+ Zip::File.open(download_path) do |zipfile|
30
+ entry = zipfile.select { |an_entry| an_entry.name.match?(/.*#{file_name}/) }.first
31
+ content = entry.get_input_stream.read
32
+
33
+ return content
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "decidim/core/test/shared_examples/download_open_data_shared_context"
4
+
5
+ RSpec.shared_examples "includes it in the open data ZIP file" do
6
+ include_context "when downloading open data files"
7
+
8
+ it do
9
+ download_open_data_file
10
+ content = extract_content_from_zip(download_path, file_name)
11
+ expect(content).to include(resource_title)
12
+ end
13
+ end
14
+
15
+ RSpec.shared_examples "does not include it in the open data ZIP file" do
16
+ include_context "when downloading open data files"
17
+
18
+ it do
19
+ download_open_data_file
20
+ content = extract_content_from_zip(download_path, file_name)
21
+ expect(content).not_to include(resource_title)
22
+ end
23
+ end
24
+
25
+ RSpec.shared_examples "includes it in the open data CSV file" do
26
+ def download_open_data_csv_file(resource_type)
27
+ open_data_file = Rails.root.join("tmp/#{organization.open_data_file_path(resource_type)}")
28
+ FileUtils.rm_f(open_data_file)
29
+ Decidim::OpenDataJob.perform_now(organization, resource_type)
30
+ end
31
+
32
+ it do
33
+ download_open_data_csv_file(resource_type)
34
+
35
+ switch_to_host(organization.host)
36
+ visit decidim.root_path
37
+ click_on "Open Data"
38
+
39
+ expect(page).to have_content("What are these files?")
40
+ click_on "Download #{resource_type} in CSV format"
41
+
42
+ expect(File.basename(download_path)).to include("#{resource_type}.csv")
43
+ expect(File.read(download_path)).to include(resource_title)
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples_for "a download your data entity" do
4
+ let(:data) { subject.send(:readme) }
5
+
6
+ before do
7
+ subject.send(:data_and_attachments_for_user) # to create the data and get the help definitions
8
+ end
9
+
10
+ it "does not have any missing translation" do
11
+ expect(data).not_to include("Translation missing"), data
12
+ end
13
+
14
+ it "has the correct help definition" do
15
+ expect(data).to include(help_definition_string)
16
+ end
17
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples "etiquette validator" do |options|
4
+ options[:fields].map(&:to_sym).each do |field|
5
+ let!(field) { options[:i18n] ? { en: string } : string }
6
+
7
+ context "when #{field} contains too many caps" do
8
+ let(:string) { "#{"A" * 50}#{"a" * 49}" }
9
+
10
+ it { is_expected.to be_invalid }
11
+ end
12
+
13
+ context "when #{field} not starting with caps" do
14
+ let(:string) { "aa#{"A" * 50}#{"a" * 49}" }
15
+
16
+ it { is_expected.to be_invalid }
17
+ end
18
+
19
+ context "when #{field} containing too many marks" do
20
+ let(:string) { "#{"A" * 5}#{"a" * 49}!!??" }
21
+
22
+ it { is_expected.to be_invalid }
23
+ end
24
+ end
25
+ end