decidim-core 0.28.0 → 0.28.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (246) hide show
  1. checksums.yaml +4 -4
  2. data/app/cells/decidim/activity_cell.rb +2 -2
  3. data/app/cells/decidim/address/online.erb +27 -9
  4. data/app/cells/decidim/address/show.erb +27 -12
  5. data/app/cells/decidim/address_cell.rb +29 -0
  6. data/app/cells/decidim/announcement/show.erb +2 -2
  7. data/app/cells/decidim/author/show.erb +5 -5
  8. data/app/cells/decidim/authorization_modal/show.erb +8 -4
  9. data/app/cells/decidim/authorization_modal_cell.rb +1 -0
  10. data/app/cells/decidim/card/show.erb +1 -1
  11. data/app/cells/decidim/card_metadata/show.erb +2 -2
  12. data/app/cells/decidim/card_metadata_cell.rb +3 -3
  13. data/app/cells/decidim/coauthorships_cell.rb +1 -1
  14. data/app/cells/decidim/content_blocks/menu_breadcrumb_last_activity_cell.rb +6 -0
  15. data/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb +20 -4
  16. data/app/cells/decidim/content_blocks/participatory_space_hero_settings_form/show.erb +8 -0
  17. data/app/cells/decidim/content_blocks/participatory_space_hero_settings_form_cell.rb +13 -0
  18. data/app/cells/decidim/content_blocks/participatory_space_metadata_cell.rb +1 -1
  19. data/app/cells/decidim/data_consent/category.erb +1 -1
  20. data/app/cells/decidim/footer_pages_cell.rb +3 -3
  21. data/app/cells/decidim/nav_links/show.erb +2 -2
  22. data/app/cells/decidim/notification/moderated.erb +12 -0
  23. data/app/cells/decidim/notification_cell.rb +5 -1
  24. data/app/cells/decidim/profile/details.erb +1 -1
  25. data/app/cells/decidim/profile/tabs.erb +3 -2
  26. data/app/cells/decidim/progress_bar/show.erb +1 -1
  27. data/app/cells/decidim/progress_bar_cell.rb +2 -0
  28. data/app/cells/decidim/report_button/flag_modal.erb +5 -1
  29. data/app/cells/decidim/resource_types_filter/show.erb +3 -3
  30. data/app/cells/decidim/statistic/show.erb +2 -2
  31. data/app/cells/decidim/tags_cell.rb +3 -1
  32. data/app/cells/decidim/upload_modal/modal.erb +1 -2
  33. data/app/commands/decidim/create_omniauth_registration.rb +1 -3
  34. data/app/commands/decidim/messaging/reply_to_conversation.rb +3 -0
  35. data/app/commands/decidim/messaging/start_conversation.rb +3 -0
  36. data/app/controllers/concerns/decidim/devise_authentication_methods.rb +36 -0
  37. data/app/controllers/concerns/decidim/force_authentication.rb +1 -1
  38. data/app/controllers/concerns/decidim/paginable.rb +1 -1
  39. data/app/controllers/concerns/decidim/use_organization_time_zone.rb +1 -1
  40. data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +1 -22
  41. data/app/controllers/decidim/devise/sessions_controller.rb +1 -24
  42. data/app/controllers/decidim/gamification/badges_controller.rb +2 -0
  43. data/app/controllers/decidim/links_controller.rb +15 -2
  44. data/app/events/decidim/welcome_notification_event.rb +6 -9
  45. data/app/helpers/concerns/decidim/flash_helper_extensions.rb +2 -2
  46. data/app/helpers/decidim/application_helper.rb +0 -18
  47. data/app/helpers/decidim/cells_paginate_helper.rb +1 -1
  48. data/app/helpers/decidim/check_boxes_tree_helper.rb +7 -8
  49. data/app/helpers/decidim/layout_helper.rb +1 -1
  50. data/app/helpers/decidim/map_helper.rb +1 -1
  51. data/app/helpers/decidim/menu_helper.rb +2 -0
  52. data/app/helpers/decidim/newsletters_helper.rb +83 -16
  53. data/app/helpers/decidim/paginate_helper.rb +1 -1
  54. data/app/helpers/decidim/sanitize_helper.rb +9 -0
  55. data/app/helpers/decidim/social_share_button_helper.rb +1 -1
  56. data/app/helpers/decidim/user_profile_helper.rb +7 -2
  57. data/app/mailers/decidim/application_mailer.rb +40 -6
  58. data/app/mailers/decidim/messaging/conversation_mailer.rb +3 -72
  59. data/app/models/decidim/push_notification_message.rb +38 -0
  60. data/app/packs/entrypoints/decidim_overrides.scss +2 -0
  61. data/app/packs/images/decidim/.keep +0 -0
  62. data/app/packs/src/decidim/a11y.js +15 -1
  63. data/app/packs/src/decidim/abide_form_validator_fixer.js +44 -0
  64. data/app/packs/src/decidim/account_form.js +1 -1
  65. data/app/packs/src/decidim/data_consent/consent_manager.test.js +1 -1
  66. data/app/packs/src/decidim/data_consent/index.js +1 -1
  67. data/app/packs/src/decidim/direct_uploads/upload_field.js +1 -1
  68. data/app/packs/src/decidim/direct_uploads/upload_modal.js +5 -5
  69. data/app/packs/src/decidim/editor/extensions/hashtag/index.js +1 -1
  70. data/app/packs/src/decidim/editor/extensions/mention/index.js +1 -1
  71. data/app/packs/src/decidim/editor/extensions/video_embed/index.js +3 -0
  72. data/app/packs/src/decidim/editor/test/editor/create.test.js +1 -1
  73. data/app/packs/src/decidim/editor/test/extensions/bold.test.js +2 -3
  74. data/app/packs/src/decidim/editor/test/extensions/character_count.test.js +2 -2
  75. data/app/packs/src/decidim/editor/test/extensions/decidim_kit.test.js +2 -3
  76. data/app/packs/src/decidim/editor/test/extensions/dialog.test.js +2 -2
  77. data/app/packs/src/decidim/editor/test/extensions/emoji.test.js +2 -2
  78. data/app/packs/src/decidim/editor/test/extensions/hashtag.test.js +2 -2
  79. data/app/packs/src/decidim/editor/test/extensions/heading.test.js +2 -2
  80. data/app/packs/src/decidim/editor/test/extensions/image.test.js +4 -4
  81. data/app/packs/src/decidim/editor/test/extensions/indent.test.js +2 -2
  82. data/app/packs/src/decidim/editor/test/extensions/link.test.js +3 -3
  83. data/app/packs/src/decidim/editor/test/extensions/mention.test.js +2 -2
  84. data/app/packs/src/decidim/editor/test/extensions/ordered_list.test.js +2 -2
  85. data/app/packs/src/decidim/editor/test/extensions/video_embed.test.js +3 -3
  86. data/app/packs/src/decidim/editor/test/helpers.js +5 -4
  87. data/app/packs/src/decidim/editor/test/toolbar/basic.test.js +2 -2
  88. data/app/packs/src/decidim/editor/test/toolbar/content.test.js +2 -2
  89. data/app/packs/src/decidim/editor/test/toolbar/full.test.js +3 -3
  90. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic.js +6 -6
  91. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_block.js +2 -2
  92. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_formatting.js +1 -1
  93. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_indent.js +2 -2
  94. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_link.js +2 -2
  95. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_list.js +2 -2
  96. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_styling.js +2 -2
  97. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_content.js +7 -7
  98. data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_content_styling.js +2 -2
  99. data/app/packs/src/decidim/editor/test/toolbar/shared/context.js +1 -1
  100. data/app/packs/src/decidim/editor/test/utilities/paste_transform.test.js +2 -2
  101. data/app/packs/src/decidim/external_domain_warning.js +13 -0
  102. data/app/packs/src/decidim/external_domain_warning.test.js +1 -1
  103. data/app/packs/src/decidim/external_link.js +48 -9
  104. data/app/packs/src/decidim/external_link.test.js +1 -1
  105. data/app/packs/src/decidim/focus_guard.js +8 -20
  106. data/app/packs/src/decidim/form_filter.component_for_testing.js +1 -1
  107. data/app/packs/src/decidim/form_filter.js +3 -3
  108. data/app/packs/src/decidim/geocoding/attach_input.js +1 -1
  109. data/app/packs/src/decidim/i18n.test.js +1 -1
  110. data/app/packs/src/decidim/index.js +33 -2
  111. data/app/packs/src/decidim/input_hashtags.js +1 -1
  112. data/app/packs/src/decidim/input_mentions.js +1 -1
  113. data/app/packs/src/decidim/input_multiple_mentions.js +1 -1
  114. data/app/packs/src/decidim/sw/index.js +3 -3
  115. data/app/packs/src/decidim/user_registrations.js +1 -1
  116. data/app/packs/src/decidim/vizzs/index.js +1 -1
  117. data/app/packs/stylesheets/decidim/_accordion.scss +2 -2
  118. data/app/packs/stylesheets/decidim/_cards.scss +4 -4
  119. data/app/packs/stylesheets/decidim/_dropdown.scss +2 -2
  120. data/app/packs/stylesheets/decidim/_layout.scss +7 -7
  121. data/app/packs/stylesheets/decidim/_modal_update.scss +1 -3
  122. data/app/packs/stylesheets/decidim/application.scss +0 -3
  123. data/app/packs/stylesheets/decidim/decidim_application.scss +4 -0
  124. data/app/packs/stylesheets/decidim/legacy/leaflet.scss +88 -107
  125. data/app/presenters/decidim/admin_log/oauth_application_resource_presenter.rb +1 -1
  126. data/app/presenters/decidim/admin_log/organization_presenter.rb +1 -1
  127. data/app/presenters/decidim/log/diff_presenter.rb +1 -1
  128. data/app/presenters/decidim/log/resource_presenter.rb +7 -1
  129. data/app/presenters/decidim/notification_to_mailer_presenter.rb +9 -0
  130. data/app/services/decidim/events_manager.rb +6 -0
  131. data/app/services/decidim/iframe_disabler.rb +4 -0
  132. data/app/services/decidim/log/diff_changeset_calculator.rb +1 -1
  133. data/app/services/decidim/push_notification_message_sender.rb +40 -0
  134. data/app/services/decidim/send_push_notification.rb +22 -8
  135. data/app/uploaders/decidim/background_image_uploader.rb +11 -0
  136. data/app/views/decidim/account/show.html.erb +2 -2
  137. data/app/views/decidim/application/_collection.html.erb +2 -2
  138. data/app/views/decidim/application/_document.html.erb +3 -3
  139. data/app/views/decidim/devise/registrations/new.html.erb +2 -2
  140. data/app/views/decidim/endorsements/update_buttons_and_counters.js.erb +2 -1
  141. data/app/views/decidim/gamification/badges/index.html.erb +34 -33
  142. data/app/views/decidim/links/_modal.html.erb +1 -1
  143. data/app/views/decidim/links/new.html.erb +3 -1
  144. data/app/views/decidim/manifests/show.json.erb +1 -1
  145. data/app/views/decidim/messaging/conversations/create.js.erb +1 -1
  146. data/app/views/decidim/notifications_digest_mailer/_email_content.html.erb +7 -0
  147. data/app/views/decidim/notifications_settings/show.html.erb +6 -6
  148. data/app/views/decidim/offline/show.html.erb +15 -9
  149. data/app/views/decidim/pages/_tabbed.html.erb +2 -2
  150. data/app/views/decidim/searches/_filters.html.erb +2 -2
  151. data/app/views/decidim/shared/_filters.html.erb +2 -2
  152. data/app/views/decidim/shared/_orders.html.erb +2 -2
  153. data/app/views/decidim/shared/filters/_collection.html.erb +5 -3
  154. data/app/views/decidim/shared/filters/_dropdown_label.html.erb +21 -19
  155. data/app/views/layouts/decidim/_head.html.erb +1 -0
  156. data/app/views/layouts/decidim/_js_configuration.html.erb +3 -1
  157. data/app/views/layouts/decidim/_wrapper.html.erb +1 -1
  158. data/app/views/layouts/decidim/footer/_main_links.html.erb +3 -1
  159. data/app/views/layouts/decidim/footer/_main_social_media_links.html.erb +5 -5
  160. data/app/views/layouts/decidim/footer/_mini.html.erb +2 -2
  161. data/app/views/layouts/decidim/header/_main_links_desktop.html.erb +4 -2
  162. data/app/views/layouts/decidim/header/_menu_breadcrumb_items.html.erb +2 -0
  163. data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +1 -1
  164. data/app/views/layouts/decidim/shared/_layout_user_profile.html.erb +2 -2
  165. data/config/assets.rb +1 -0
  166. data/config/locales/ar.yml +60 -8
  167. data/config/locales/bg.yml +909 -2
  168. data/config/locales/ca.yml +31 -24
  169. data/config/locales/cs.yml +7 -3
  170. data/config/locales/de.yml +37 -30
  171. data/config/locales/el.yml +11 -7
  172. data/config/locales/en.yml +10 -3
  173. data/config/locales/es-MX.yml +17 -10
  174. data/config/locales/es-PY.yml +17 -10
  175. data/config/locales/es.yml +59 -52
  176. data/config/locales/eu.yml +26 -10
  177. data/config/locales/fi-plain.yml +11 -4
  178. data/config/locales/fi.yml +14 -7
  179. data/config/locales/fr-CA.yml +14 -7
  180. data/config/locales/fr.yml +14 -7
  181. data/config/locales/ga-IE.yml +9 -0
  182. data/config/locales/gl.yml +5 -2
  183. data/config/locales/he-IL.yml +1 -0
  184. data/config/locales/hu.yml +264 -8
  185. data/config/locales/id-ID.yml +0 -2
  186. data/config/locales/it.yml +9 -6
  187. data/config/locales/ja.yml +14 -7
  188. data/config/locales/kaa.yml +5 -0
  189. data/config/locales/lb.yml +9 -6
  190. data/config/locales/lt.yml +8 -12
  191. data/config/locales/lv.yml +8 -3
  192. data/config/locales/nl.yml +8 -3
  193. data/config/locales/no.yml +9 -6
  194. data/config/locales/pl.yml +616 -2
  195. data/config/locales/pt-BR.yml +202 -19
  196. data/config/locales/pt.yml +9 -6
  197. data/config/locales/ro-RO.yml +10 -5
  198. data/config/locales/ru.yml +15 -2
  199. data/config/locales/sk.yml +8 -3
  200. data/config/locales/sl.yml +8 -0
  201. data/config/locales/sv.yml +32 -6
  202. data/config/locales/tr-TR.yml +24 -9
  203. data/config/locales/uk.yml +22 -2
  204. data/config/locales/zh-CN.yml +0 -6
  205. data/config/locales/zh-TW.yml +10 -11
  206. data/decidim-core.gemspec +90 -0
  207. data/lib/decidim/asset_router/storage.rb +2 -0
  208. data/lib/decidim/attribute_encryptor.rb +6 -4
  209. data/lib/decidim/attributes/time_with_zone.rb +1 -1
  210. data/lib/decidim/core/engine.rb +7 -6
  211. data/lib/decidim/core/seeds.rb +37 -33
  212. data/lib/decidim/core/test/factories.rb +296 -89
  213. data/lib/decidim/core/test/shared_examples/amendable/amendment_created_event_examples.rb +6 -26
  214. data/lib/decidim/core/test/shared_examples/amendable/amendment_promoted_event_examples.rb +8 -26
  215. data/lib/decidim/core/test/shared_examples/comments_examples.rb +76 -6
  216. data/lib/decidim/core/test/shared_examples/has_attachment_collections.rb +8 -6
  217. data/lib/decidim/core/test/shared_examples/has_attachments.rb +8 -8
  218. data/lib/decidim/core/test/shared_examples/has_category.rb +27 -0
  219. data/lib/decidim/core/test/shared_examples/has_reference.rb +1 -1
  220. data/lib/decidim/core/test/shared_examples/has_space_in_mcell_examples.rb +1 -1
  221. data/lib/decidim/core/test/shared_examples/logo_email.rb +2 -2
  222. data/lib/decidim/core/test/shared_examples/map_examples.rb +3 -0
  223. data/lib/decidim/core/test/shared_examples/resource_endorsed_event_examples.rb +5 -2
  224. data/lib/decidim/core/test/shared_examples/resource_locator_presenter_examples.rb +134 -0
  225. data/lib/decidim/core/test/shared_examples/simple_event.rb +18 -2
  226. data/lib/decidim/core/test.rb +1 -0
  227. data/lib/decidim/core/version.rb +1 -1
  228. data/lib/decidim/core.rb +7 -1
  229. data/lib/decidim/engine_router.rb +17 -4
  230. data/lib/decidim/events/base_event.rb +7 -3
  231. data/lib/decidim/events/simple_event.rb +3 -17
  232. data/lib/decidim/form_builder.rb +8 -2
  233. data/lib/decidim/has_category.rb +1 -1
  234. data/lib/decidim/has_conversations.rb +91 -0
  235. data/lib/decidim/organization_settings.rb +10 -2
  236. data/lib/decidim/participable.rb +17 -0
  237. data/lib/decidim/upgrade/wysiwyg_migrator.rb +7 -0
  238. data/lib/decidim/view_model.rb +1 -0
  239. data/lib/decidim/webpacker/webpack/.modernizrrc +9 -0
  240. data/lib/premailer/adapter/decidim.rb +5 -4
  241. data/lib/tasks/decidim_reminders_tasks.rake +1 -0
  242. data/lib/tasks/upgrade/decidim_fix_categorization.rake +15 -0
  243. metadata +26 -27
  244. data/app/views/decidim/searches/index.js.erb +0 -7
  245. data/config/brakeman.ignore +0 -37
  246. data/config/environment.rb +0 -3
@@ -12,36 +12,16 @@ shared_examples "amendment created event" do
12
12
  end
13
13
 
14
14
  it_behaves_like "a simple event"
15
+ it_behaves_like "a simple event email"
16
+ it_behaves_like "a simple event notification"
15
17
 
16
18
  let(:emendation_author_nickname) { "@#{emendation.creator_author.nickname}" }
17
19
  let(:emendation_path) { Decidim::ResourceLocatorPresenter.new(emendation).path }
18
20
  let(:emendation_author_path) { Decidim::UserPresenter.new(emendation.creator_author).profile_path }
19
21
  let(:amendable_path) { Decidim::ResourceLocatorPresenter.new(amendable).path }
20
22
 
21
- describe "email_subject" do
22
- it "is generated correctly" do
23
- expect(subject.email_subject).to eq("New amendment for #{amendable_title}")
24
- end
25
- end
26
-
27
- describe "email_intro" do
28
- it "is generated correctly" do
29
- expect(subject.email_intro)
30
- .to eq("A new amendment has been created for #{amendable_title}. You can see it from this page:")
31
- end
32
- end
33
-
34
- describe "email_outro" do
35
- it "is generated correctly" do
36
- expect(subject.email_outro)
37
- .to eq("You have received this notification because you are following #{amendable_title}. You can stop receiving notifications following the previous link.")
38
- end
39
- end
40
-
41
- describe "notification_title" do
42
- it "is generated correctly" do
43
- expect(subject.notification_title)
44
- .to eq("A new amendment has been created for <a href=\"#{amendable_path}\">#{amendable_title}</a>.")
45
- end
46
- end
23
+ let(:email_subject) { "New amendment for #{amendable_title}" }
24
+ let(:email_intro) { "A new amendment has been created for #{amendable_title}. You can see it from this page:" }
25
+ let(:email_outro) { "You have received this notification because you are following #{amendable_title}. You can stop receiving notifications following the previous link." }
26
+ let(:notification_title) { "A new amendment has been created for <a href=\"#{amendable_path}\">#{amendable_title}</a>." }
47
27
  end
@@ -7,36 +7,18 @@ shared_examples "amendment promoted event" do
7
7
  let(:event_name) { "decidim.events.amendments.amendment_promoted" }
8
8
 
9
9
  it_behaves_like "a simple event"
10
+ it_behaves_like "a simple event email"
11
+ it_behaves_like "a simple event notification"
10
12
 
11
13
  let(:emendation_author_nickname) { "@#{emendation.creator_author.nickname}" }
12
14
  let(:emendation_path) { Decidim::ResourceLocatorPresenter.new(emendation).path }
13
15
  let(:emendation_author_path) { Decidim::UserPresenter.new(emendation.creator_author).profile_path }
14
16
  let(:amendable_path) { Decidim::ResourceLocatorPresenter.new(amendable).path }
15
17
 
16
- describe "email_subject" do
17
- it "is generated correctly" do
18
- expect(subject.email_subject).to eq("An amendment from #{emendation_author_nickname} has been published as a new proposal")
19
- end
20
- end
21
-
22
- describe "email_intro" do
23
- it "is generated correctly" do
24
- expect(subject.email_intro)
25
- .to eq("A rejected amendment for #{amendable_title} has been published as a new #{amendable_type}. You can see it from this page:")
26
- end
27
- end
28
-
29
- describe "email_outro" do
30
- it "is generated correctly" do
31
- expect(subject.email_outro)
32
- .to eq("You have received this notification because you are following #{amendable_title}. You can stop receiving notifications following the previous link.")
33
- end
34
- end
35
-
36
- describe "notification_title" do
37
- it "is generated correctly" do
38
- expect(subject.notification_title)
39
- .to eq("A <a href=\"#{emendation_path}\">rejected amendment</a> for <a href=\"#{amendable_path}\">#{amendable_title}</a> has been published as a new #{amendable_type} by <a href=\"#{emendation_author_path}\">#{emendation_author_nickname}</a>.") # rubocop:disable Layout/LineLength
40
- end
41
- end
18
+ let(:email_subject) { "An amendment from #{emendation_author_nickname} has been published as a new proposal" }
19
+ let(:email_intro) { "A rejected amendment for #{amendable_title} has been published as a new #{amendable_type}. You can see it from this page:" }
20
+ let(:email_outro) { "You have received this notification because you are following #{amendable_title}. You can stop receiving notifications following the previous link." }
21
+ # rubocop:disable Layout/LineLength
22
+ let(:notification_title) { "A <a href=\"#{emendation_path}\">rejected amendment</a> for <a href=\"#{amendable_path}\">#{amendable_title}</a> has been published as a new #{amendable_type} by <a href=\"#{emendation_author_path}\">#{emendation_author_nickname}</a>." }
23
+ # rubocop:enable Layout/LineLength
42
24
  end
@@ -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 replies"
57
+ expect(page).to have_content "Hide reply"
58
58
  end
59
59
  end
60
60
 
@@ -70,7 +70,7 @@ shared_examples "comments" do
70
70
  expect(page).to have_css(".comment", minimum: 1)
71
71
 
72
72
  within("#accordion-#{single_comment.id}") do
73
- expect(page).not_to have_content "Hide replies"
73
+ expect(page).not_to have_content "Hide reply"
74
74
  end
75
75
  end
76
76
  end
@@ -117,7 +117,8 @@ shared_examples "comments" do
117
117
  context "when not authenticated" do
118
118
  it "does not show form to add comments to user" do
119
119
  visit resource_path
120
- expect(page).not_to have_selector(".add-comment form")
120
+ expect(page).not_to have_css(".add-comment form")
121
+ expect(page).to have_css(".comment-thread")
121
122
  end
122
123
  end
123
124
 
@@ -131,6 +132,32 @@ shared_examples "comments" do
131
132
  expect(page).to have_selector(".add-comment form")
132
133
  end
133
134
 
135
+ context "when user is not authorized to comment" do
136
+ let(:permissions) do
137
+ {
138
+ comment: {
139
+ authorization_handlers: {
140
+ "dummy_authorization_handler" => { "options" => {} }
141
+ }
142
+ }
143
+ }
144
+ end
145
+
146
+ before do
147
+ organization.available_authorizations = ["dummy_authorization_handler"]
148
+ organization.save!
149
+ commentable.create_resource_permission(permissions:)
150
+ allow(commentable).to receive(:user_allowed_to_comment?).with(user).and_return(false)
151
+ allow(commentable).to receive(:user_authorized_to_comment?).with(user).and_return(true)
152
+ end
153
+
154
+ it "shows a message indicating that comments are restricted" do
155
+ visit resource_path
156
+ expect(page).not_to have_content("Comments are disabled at this time")
157
+ expect(page).to have_content("You need to be verified to comment at this moment")
158
+ end
159
+ end
160
+
134
161
  describe "when using emojis" do
135
162
  before do
136
163
  within_language_menu do
@@ -520,7 +547,7 @@ shared_examples "comments" do
520
547
  it "displays the hide button" do
521
548
  visit current_path
522
549
  within "#comment_#{thread.id}" do
523
- expect(page).to have_content("Hide replies")
550
+ expect(page).to have_content("Hide reply")
524
551
  expect(page).to have_content(new_reply_body)
525
552
  end
526
553
  end
@@ -528,7 +555,7 @@ shared_examples "comments" do
528
555
  it "displays the show button" do
529
556
  visit current_path
530
557
  within "#comment_#{thread.id}" do
531
- click_button "Hide replies"
558
+ click_button "Hide reply"
532
559
  expect(page).to have_content("Show reply")
533
560
  expect(page).not_to have_content(new_reply_body)
534
561
  end
@@ -540,7 +567,7 @@ shared_examples "comments" do
540
567
  it "displays the show button" do
541
568
  visit current_path
542
569
  within "#comment_#{thread.id}" do
543
- click_button "Hide replies"
570
+ click_button "Hide 3 replies"
544
571
  expect(page).to have_content("Show 3 replies")
545
572
  expect(page).not_to have_content(new_reply_body)
546
573
  end
@@ -969,3 +996,46 @@ shared_examples "comments" do
969
996
  end
970
997
  end
971
998
  end
999
+
1000
+ shared_examples "comments blocked" do
1001
+ context "when not authenticated" do
1002
+ context "when comments are blocked" do
1003
+ let(:active_step_id) { component.participatory_space.active_step.id }
1004
+
1005
+ before do
1006
+ component.update!(step_settings: { active_step_id => { comments_blocked: true } })
1007
+ end
1008
+
1009
+ it "shows a message indicating that comments are disabled" do
1010
+ visit resource_path
1011
+ expect(page).to have_content("Comments are disabled at this time")
1012
+ expect(page).not_to have_content("You need to be verified to comment at this moment")
1013
+ end
1014
+ end
1015
+ end
1016
+
1017
+ context "when authenticated" do
1018
+ let!(:organization) { create(:organization) }
1019
+ let!(:user) { create(:user, :confirmed, organization:) }
1020
+ let!(:comments) { create_list(:comment, 3, commentable:) }
1021
+
1022
+ before do
1023
+ login_as user, scope: :user
1024
+ visit resource_path
1025
+ end
1026
+
1027
+ context "when comments are blocked" do
1028
+ let(:active_step_id) { component.participatory_space.active_step.id }
1029
+
1030
+ before do
1031
+ component.update!(step_settings: { active_step_id => { comments_blocked: true } })
1032
+ end
1033
+
1034
+ it "shows a message indicating that comments are disabled" do
1035
+ visit resource_path
1036
+ expect(page).to have_content("Comments are disabled at this time")
1037
+ expect(page).not_to have_content("You need to be verified to comment at this moment")
1038
+ end
1039
+ end
1040
+ end
1041
+ end
@@ -13,13 +13,13 @@ shared_examples_for "has attachment collections" do
13
13
  end
14
14
 
15
15
  it "shows them" do
16
- expect(page).to have_content(/#{translated(attachment_collection.name, locale: :en)}/i)
16
+ expect(page).to have_content(translated(attachment_collection.name))
17
17
  end
18
18
 
19
19
  it "show their documents" do
20
20
  within "[id*=documents-#{attachment_collection.id}]", visible: false do
21
- expect(page).to have_content(:all, /#{translated(document.title, locale: :en)}/i)
22
- expect(page).not_to have_content(:all, /#{translated(other_document.title, locale: :en)}/i)
21
+ expect(page).to have_content(:all, translated(document.title))
22
+ expect(page).not_to have_content(:all, translated(other_document.title))
23
23
  end
24
24
  end
25
25
  end
@@ -36,7 +36,9 @@ shared_examples_for "has attachment collections" do
36
36
  end
37
37
 
38
38
  it "shows them ordered" do
39
- expect(translated(first_attachment_collection.name, locale: :en)).to appear_before(translated(last_attachment_collection.name, locale: :en))
39
+ expect(decidim_escape_translated(first_attachment_collection.name).gsub("&quot;",
40
+ "\"")).to appear_before(decidim_escape_translated(last_attachment_collection.name).gsub("&quot;",
41
+ "\""))
40
42
  end
41
43
  end
42
44
 
@@ -50,8 +52,8 @@ shared_examples_for "has attachment collections" do
50
52
  end
51
53
 
52
54
  it "is not present" do
53
- expect(page).to have_content(/#{translated(attachment_collection.name, locale: :en)}/i)
54
- expect(page).not_to have_content(/#{translated(empty_attachment_collection.name, locale: :en)}/i)
55
+ expect(page).to have_content(translated(attachment_collection.name))
56
+ expect(page).not_to have_content(translated(empty_attachment_collection.name))
55
57
  end
56
58
  end
57
59
  end
@@ -14,7 +14,7 @@ shared_examples_for "has attachments content blocks" do
14
14
 
15
15
  it "shows them" do
16
16
  within "[data-content] .documents__container" do
17
- expect(page).to have_content(/#{translated(document.title, locale: :en)}/i)
17
+ expect(page).to have_content(translated(document.title))
18
18
  end
19
19
 
20
20
  within "[data-content] [data-gallery]" do
@@ -27,7 +27,7 @@ shared_examples_for "has attachments content blocks" do
27
27
  let!(:last_document) { create(:attachment, :with_pdf, attached_to:, weight: 2) }
28
28
  let!(:first_document) { create(:attachment, :with_pdf, attached_to:, weight: 1) }
29
29
  let!(:last_image) { create(:attachment, attached_to:, weight: 2) }
30
- let!(:fist_image) { create(:attachment, attached_to:, weight: 1) }
30
+ let!(:first_image) { create(:attachment, attached_to:, weight: 1) }
31
31
 
32
32
  before do
33
33
  visit current_path
@@ -35,11 +35,11 @@ shared_examples_for "has attachments content blocks" do
35
35
 
36
36
  it "shows them ordered" do
37
37
  within "[data-content] .documents__container" do
38
- expect(translated(first_document.title, locale: :en)).to appear_before(translated(last_document.title, locale: :en))
38
+ expect(decidim_escape_translated(first_document.title).gsub("&quot;", "\"")).to appear_before(decidim_escape_translated(last_document.title).gsub("&quot;", "\""))
39
39
  end
40
40
 
41
41
  within "[data-content] [data-gallery]" do
42
- expect(strip_tags(translated(fist_image.title, locale: :en))).to appear_before(strip_tags(translated(last_image.title, locale: :en)))
42
+ expect(strip_tags(translated(first_image.title, locale: :en))).to appear_before(strip_tags(translated(last_image.title, locale: :en)))
43
43
  end
44
44
  end
45
45
  end
@@ -58,7 +58,7 @@ shared_examples_for "has attachments tabs" do
58
58
  it "shows them" do
59
59
  find("li [data-controls='panel-documents']").click
60
60
  within "#panel-documents" do
61
- expect(page).to have_content(/#{translated(document.title, locale: :en)}/i)
61
+ expect(page).to have_content(translated(document.title))
62
62
  end
63
63
 
64
64
  find("li [data-controls='panel-images']").click
@@ -72,7 +72,7 @@ shared_examples_for "has attachments tabs" do
72
72
  let!(:last_document) { create(:attachment, :with_pdf, attached_to:, weight: 2) }
73
73
  let!(:first_document) { create(:attachment, :with_pdf, attached_to:, weight: 1) }
74
74
  let!(:last_image) { create(:attachment, attached_to:, weight: 2) }
75
- let!(:fist_image) { create(:attachment, attached_to:, weight: 1) }
75
+ let!(:first_image) { create(:attachment, attached_to:, weight: 1) }
76
76
 
77
77
  before do
78
78
  visit current_path
@@ -81,12 +81,12 @@ shared_examples_for "has attachments tabs" do
81
81
  it "shows them ordered" do
82
82
  find("li [data-controls='panel-documents']").click
83
83
  within "#panel-documents" do
84
- expect(translated(first_document.title, locale: :en)).to appear_before(translated(last_document.title, locale: :en))
84
+ expect(decidim_escape_translated(first_document.title).gsub("&quot;", "\"")).to appear_before(decidim_escape_translated(last_document.title).gsub("&quot;", "\""))
85
85
  end
86
86
 
87
87
  find("li [data-controls='panel-images']").click
88
88
  within "#panel-images" do
89
- expect(strip_tags(translated(fist_image.title, locale: :en))).to appear_before(strip_tags(translated(last_image.title, locale: :en)))
89
+ expect(strip_tags(translated(first_image.title, locale: :en))).to appear_before(strip_tags(translated(last_image.title, locale: :en)))
90
90
  end
91
91
  end
92
92
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  shared_examples_for "has category" do
4
+ let(:participatory_space) { subject.participatory_space }
5
+
4
6
  context "when the category is from another organization" do
5
7
  before do
6
8
  subject.category = create(:category)
@@ -8,4 +10,29 @@ shared_examples_for "has category" do
8
10
 
9
11
  it { is_expected.not_to be_valid }
10
12
  end
13
+
14
+ context "when the category is from the same organization" do
15
+ before do
16
+ subject.category = create(:category, participatory_space:)
17
+ end
18
+
19
+ it { is_expected.to be_valid }
20
+ end
21
+
22
+ context "when the resource is being deleted" do
23
+ before do
24
+ subject.category = create(:category, participatory_space:)
25
+ subject.save!
26
+ end
27
+
28
+ it "persists the categorization" do
29
+ expect(subject.categorization).to be_persisted
30
+ end
31
+
32
+ it "deletes the categorization" do
33
+ expect(Decidim::Categorization.count).to eq(1)
34
+ expect { subject.destroy }.to change(Decidim::Categorization, :count).by(-1)
35
+ expect(Decidim::Categorization.count).to eq(0)
36
+ end
37
+ end
11
38
  end
@@ -8,7 +8,7 @@ shared_examples_for "has reference" do
8
8
 
9
9
  context "when there is not a custom resource reference generator present" do
10
10
  it "generates a valid reference" do
11
- expect(subject.reference).to match(/[A-z]+/)
11
+ expect(subject.reference).to match(/[a-zA-Z]+/)
12
12
  end
13
13
  end
14
14
 
@@ -8,7 +8,7 @@ shared_examples_for "has space in m-cell" do
8
8
  let(:show_space) { true }
9
9
 
10
10
  it "renders the space where the model belongs to" do
11
- expect(cell_html).to have_content(translated(model.component.participatory_space.title, locale: :en))
11
+ expect(cell_html).to have_content(decidim_escape_translated(model.component.participatory_space.title))
12
12
  end
13
13
  end
14
14
  end
@@ -5,7 +5,7 @@ require "spec_helper"
5
5
  shared_examples "email with logo" do
6
6
  context "when organization has a logo" do
7
7
  let(:organization_logo) { Decidim::Dev.test_file("city.jpeg", "image/jpeg") }
8
- let(:organization) { create(:organization, logo: organization_logo) }
8
+ let(:organization) { create(:organization, name: "O'Higgins", logo: organization_logo) }
9
9
  let(:mail) { described_class.event_received(event, event_class_name, resource, user, :follower, extra) }
10
10
  let(:logo_path) { Rails.application.routes.url_helpers.rails_representation_path(organization.logo.variant(resize_to_fit: [600, 160]), only_path: true) }
11
11
 
@@ -14,7 +14,7 @@ shared_examples "email with logo" do
14
14
  end
15
15
 
16
16
  it "includes organization logo with full link" do
17
- expect(mail.body).to include("alt=\"#{organization.name}\"")
17
+ expect(mail.body).to include("alt=\"#{decidim_escape_translated(organization.name)}\"")
18
18
  expect(mail.body).to match(%r{https{0,1}://#{organization.host}:#{Capybara.server_port}#{logo_path}})
19
19
  end
20
20
  end
@@ -99,6 +99,8 @@ shared_context "with frontend map elements" do
99
99
  let(:html_body) { "" }
100
100
 
101
101
  before do
102
+ # Create a favicon so it does not fail when trying to fetch it
103
+ favicon = ""
102
104
  # Create a temporary route to display the generated HTML in a correct site
103
105
  # context.
104
106
  final_html = html_document
@@ -106,6 +108,7 @@ shared_context "with frontend map elements" do
106
108
  get "maptiles/:z/:x/:y.png", to: ->(_) { [200, {}, [final_html]] }
107
109
  get "test_dynamic_map", to: ->(_) { [200, {}, [final_html]] }
108
110
  get "offline", to: ->(_) { [200, {}, [""]] }
111
+ get "/favicon.ico", to: ->(_) { [200, {}, [favicon]] }
109
112
  end
110
113
 
111
114
  visit "/test_dynamic_map"
@@ -35,17 +35,20 @@ shared_examples_for "resource endorsed event" do
35
35
  end
36
36
 
37
37
  describe "email_intro" do
38
+ let(:resource_title) { decidim_sanitize_translated(resource.title) }
38
39
  it "is generated correctly" do
39
40
  expect(subject.email_intro)
40
41
  .to eq("#{author.name} #{author_presenter.nickname}, who you are following, " \
41
- "has just endorsed \"#{translated resource.title}\" and we think it may be interesting to you. Check it out and contribute:")
42
+ "has just endorsed \"#{resource_title}\" and we think it may be interesting to you. Check it out and contribute:")
42
43
  end
43
44
  end
44
45
 
45
46
  describe "notification_title" do
47
+ let(:resource_title) { decidim_sanitize_translated(resource.title) }
48
+
46
49
  it "is generated correctly" do
47
50
  expect(subject.notification_title)
48
- .to include("The <a href=\"#{resource_path}\">#{translated resource.title}</a> #{resource_type} has been endorsed by ")
51
+ .to include("The <a href=\"#{resource_path}\">#{resource_title}</a> #{resource_type} has been endorsed by ")
49
52
 
50
53
  expect(subject.notification_title)
51
54
  .to include("<a href=\"/profiles/#{author.nickname}\">#{author.name} #{author_presenter.nickname}</a>.")
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ shared_examples "generates routes without query strings on slug" do
6
+ let(:organization) { create(:organization, host: "1.lvh.me") }
7
+ let(:participatory_space) { create(factory_name, organization:) }
8
+ let(:component) { create(:component, id: 1, participatory_space:) }
9
+ let(:resource) { create(:dummy_resource, id: 1, component:) }
10
+
11
+ context "with a component resource" do
12
+ describe "#url" do
13
+ subject { described_class.new(resource).url }
14
+
15
+ it { is_expected.to eq("http://1.lvh.me:#{Capybara.server_port}/#{route_fragment}/f/1/dummy_resources/1") }
16
+
17
+ context "when specific port configured" do
18
+ before do
19
+ allow(ActionMailer::Base)
20
+ .to receive(:default_url_options)
21
+ .and_return(port: 3000)
22
+ end
23
+
24
+ it { is_expected.to eq("http://1.lvh.me:3000/#{route_fragment}/f/1/dummy_resources/1") }
25
+ end
26
+ end
27
+
28
+ describe "#path" do
29
+ subject { described_class.new(resource).path }
30
+
31
+ it { is_expected.to eq("/#{route_fragment}/f/1/dummy_resources/1") }
32
+ end
33
+
34
+ describe "#show" do
35
+ subject { described_class.new(participatory_space).show }
36
+
37
+ it { is_expected.to eq("/admin/#{admin_route_fragment}") }
38
+ end
39
+
40
+ describe "#edit" do
41
+ subject { described_class.new(participatory_space).edit }
42
+
43
+ it { is_expected.to eq("/admin/#{admin_route_fragment}/edit") }
44
+ end
45
+ end
46
+
47
+ context "with a polymorphic resource" do
48
+ let(:nested_resource) do
49
+ create(:nested_dummy_resource, id: 1, dummy_resource: resource)
50
+ end
51
+
52
+ describe "#url" do
53
+ subject { described_class.new([resource, nested_resource]).url }
54
+
55
+ it { is_expected.to eq("http://1.lvh.me:#{Capybara.server_port}/#{route_fragment}/f/1/dummy_resources/1/nested_dummy_resources/1") }
56
+
57
+ context "when specific port configured" do
58
+ before do
59
+ allow(ActionMailer::Base)
60
+ .to receive(:default_url_options)
61
+ .and_return(port: 3000)
62
+ end
63
+
64
+ it { is_expected.to eq("http://1.lvh.me:3000/#{route_fragment}/f/1/dummy_resources/1/nested_dummy_resources/1") }
65
+ end
66
+ end
67
+
68
+ describe "#path" do
69
+ subject { described_class.new([resource, nested_resource]).path }
70
+
71
+ it { is_expected.to eq("/#{route_fragment}/f/1/dummy_resources/1/nested_dummy_resources/1") }
72
+ end
73
+
74
+ describe "#index" do
75
+ subject { described_class.new([resource, nested_resource]).index }
76
+
77
+ it { is_expected.to eq("/#{route_fragment}/f/1/dummy_resources/1/nested_dummy_resources") }
78
+ end
79
+
80
+ describe "#admin_index" do
81
+ subject { described_class.new([resource, nested_resource]).admin_index }
82
+
83
+ it { is_expected.to eq("/admin/#{admin_route_fragment}/components/1/manage/dummy_resources/1/nested_dummy_resources") }
84
+ end
85
+
86
+ describe "#show" do
87
+ subject { described_class.new([resource, nested_resource]).show }
88
+
89
+ it { is_expected.to eq("/admin/#{admin_route_fragment}/components/1/manage/dummy_resources/1/nested_dummy_resources/1") }
90
+ end
91
+
92
+ describe "#edit" do
93
+ subject { described_class.new([resource, nested_resource]).edit }
94
+
95
+ it { is_expected.to eq("/admin/#{admin_route_fragment}/components/1/manage/dummy_resources/1/nested_dummy_resources/1/edit") }
96
+ end
97
+ end
98
+
99
+ context "with a participatory_space" do
100
+ describe "#url" do
101
+ subject { described_class.new(participatory_space).url }
102
+
103
+ it { is_expected.to eq("http://1.lvh.me:#{Capybara.server_port}/#{route_fragment}") }
104
+
105
+ context "when specific port configured" do
106
+ before do
107
+ allow(ActionMailer::Base)
108
+ .to receive(:default_url_options)
109
+ .and_return(port: 3000)
110
+ end
111
+
112
+ it { is_expected.to eq("http://1.lvh.me:3000/#{route_fragment}") }
113
+ end
114
+ end
115
+
116
+ describe "#path" do
117
+ subject { described_class.new(participatory_space).path }
118
+
119
+ it { is_expected.to eq("/#{route_fragment}") }
120
+ end
121
+
122
+ describe "#show" do
123
+ subject { described_class.new(participatory_space).show }
124
+
125
+ it { is_expected.to eq("/admin/#{admin_route_fragment}") }
126
+ end
127
+
128
+ describe "#edit" do
129
+ subject { described_class.new(participatory_space).edit }
130
+
131
+ it { is_expected.to eq("/admin/#{admin_route_fragment}/edit") }
132
+ end
133
+ end
134
+ end
@@ -28,10 +28,10 @@ shared_context "when a simple event" do
28
28
  let(:extra) { {} }
29
29
  let(:resource_path) { resource_locator(resource).path }
30
30
  let(:resource_url) { resource_locator(resource).url }
31
- let(:resource_title) { resource.title["en"] }
31
+ let(:resource_title) { decidim_sanitize_translated(resource.title) }
32
32
  # to be used when resource is a component resource, not a participatory space, in which case should be overriden
33
33
  let(:participatory_space) { resource.participatory_space }
34
- let(:participatory_space_title) { participatory_space.title["en"] }
34
+ let(:participatory_space_title) { decidim_sanitize_translated(participatory_space.title) }
35
35
  let(:participatory_space_path) { Decidim::ResourceLocatorPresenter.new(participatory_space).path }
36
36
  let(:participatory_space_url) { Decidim::ResourceLocatorPresenter.new(participatory_space).url }
37
37
  let(:author) do
@@ -65,6 +65,7 @@ shared_examples_for "a simple event" do |skip_space_checks|
65
65
  it "is generated correctly" do
66
66
  expect(subject.email_subject).to be_kind_of(String)
67
67
  expect(subject.email_subject).not_to include("translation missing")
68
+ expect(subject.email_subject).not_to include("script")
68
69
  end
69
70
  end
70
71
 
@@ -100,6 +101,7 @@ shared_examples_for "a simple event" do |skip_space_checks|
100
101
  it "is generated correctly" do
101
102
  expect(subject.notification_title).to be_kind_of(String)
102
103
  expect(subject.notification_title).not_to include("translation missing")
104
+ expect(subject.notification_title).not_to include("script")
103
105
  end
104
106
  end
105
107
 
@@ -129,6 +131,12 @@ shared_examples_for "a simple event" do |skip_space_checks|
129
131
  expect(subject.participatory_space_url).to start_with("http")
130
132
  end
131
133
  end
134
+
135
+ describe "participatory_space_title" do
136
+ it "is generated correctly" do
137
+ expect(translated(participatory_space.title)).to include("script")
138
+ end
139
+ end
132
140
  end
133
141
 
134
142
  describe "i18n_options" do
@@ -158,6 +166,10 @@ shared_examples_for "a simple event email" do
158
166
  it "is generated correctly" do
159
167
  expect(subject.email_subject).to eq(email_subject)
160
168
  end
169
+
170
+ it "is html safe" do
171
+ expect(subject.email_subject).not_to include("script")
172
+ end
161
173
  end
162
174
 
163
175
  describe "email_intro" do
@@ -179,5 +191,9 @@ shared_examples_for "a simple event notification" do
179
191
  expect(subject.notification_title)
180
192
  .to eq(notification_title)
181
193
  end
194
+
195
+ it "is html safe" do
196
+ expect(subject.notification_title).not_to include("script")
197
+ end
182
198
  end
183
199
  end
@@ -77,3 +77,4 @@ require "decidim/core/test/shared_examples/digest_mail_examples"
77
77
  require "decidim/core/test/shared_examples/hideable_resource_examples"
78
78
  require "decidim/core/test/shared_examples/active_support_examples"
79
79
  require "decidim/core/test/shared_examples/statistics_cell_examples"
80
+ require "decidim/core/test/shared_examples/resource_locator_presenter_examples"
@@ -4,7 +4,7 @@ module Decidim
4
4
  # This holds the decidim-core version.
5
5
  module Core
6
6
  def self.version
7
- "0.28.0"
7
+ "0.28.2"
8
8
  end
9
9
  end
10
10
  end