decidim-core 0.27.4 → 0.27.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/cells/decidim/activity_cell.rb +2 -2
- data/app/cells/decidim/card_cell.rb +2 -2
- data/app/cells/decidim/card_m/top.erb +1 -1
- data/app/cells/decidim/card_m_cell.rb +1 -1
- data/app/cells/decidim/scopes_picker/scope_picker_values.erb +1 -1
- data/app/cells/decidim/tags_cell.rb +3 -1
- data/app/cells/decidim/upload_modal/modal.erb +4 -1
- data/app/cells/decidim/upload_modal_cell.rb +8 -4
- data/app/cells/decidim/user_profile_cell.rb +1 -1
- data/app/cells/decidim/version_cell.rb +1 -1
- data/app/cells/decidim/versions_list_cell.rb +1 -1
- data/app/commands/decidim/create_omniauth_registration.rb +2 -4
- data/app/commands/decidim/endorse_resource.rb +2 -0
- data/app/commands/decidim/messaging/reply_to_conversation.rb +3 -0
- data/app/commands/decidim/messaging/start_conversation.rb +3 -0
- data/app/commands/decidim/search.rb +1 -1
- data/app/commands/decidim/unendorse_resource.rb +1 -1
- data/app/controllers/concerns/decidim/devise_authentication_methods.rb +36 -0
- data/app/controllers/concerns/decidim/force_authentication.rb +6 -2
- data/app/controllers/concerns/decidim/paginable.rb +1 -1
- data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +1 -22
- data/app/controllers/decidim/devise/registrations_controller.rb +1 -1
- data/app/controllers/decidim/devise/sessions_controller.rb +1 -24
- data/app/controllers/decidim/links_controller.rb +1 -1
- data/app/controllers/decidim/searches_controller.rb +1 -1
- data/app/controllers/decidim/user_timeline_controller.rb +1 -1
- data/app/controllers/decidim/widgets_controller.rb +6 -0
- data/app/events/decidim/welcome_notification_event.rb +6 -9
- data/app/forms/decidim/account_form.rb +1 -1
- data/app/forms/decidim/notifications_settings_form.rb +0 -8
- data/app/forms/decidim/registration_form.rb +1 -1
- data/app/helpers/decidim/cells_paginate_helper.rb +1 -1
- data/app/helpers/decidim/check_boxes_tree_helper.rb +4 -4
- data/app/helpers/decidim/decidim_form_helper.rb +1 -0
- data/app/helpers/decidim/newsletters_helper.rb +83 -16
- data/app/helpers/decidim/omniauth_helper.rb +2 -0
- data/app/helpers/decidim/resource_helper.rb +3 -1
- data/app/helpers/decidim/sanitize_helper.rb +9 -0
- data/app/helpers/decidim/short_link_helper.rb +1 -1
- data/app/helpers/decidim/user_profile_helper.rb +7 -2
- data/app/jobs/decidim/download_your_data_export_job.rb +2 -1
- data/app/jobs/decidim/open_data_job.rb +2 -0
- data/app/mailers/decidim/messaging/conversation_mailer.rb +3 -72
- data/app/models/decidim/push_notification_message.rb +39 -0
- data/app/models/decidim/user.rb +9 -1
- data/app/packs/images/decidim/icons.svg +1 -1
- data/app/packs/images/decidim/vendor/social-share-button/x.svg +6 -0
- data/app/packs/src/decidim/autocomplete.js +11 -2
- data/app/packs/src/decidim/data_picker.js +1 -0
- data/app/packs/src/decidim/direct_uploads/upload_field.js +6 -4
- data/app/packs/src/decidim/direct_uploads/upload_modal.js +10 -8
- data/app/packs/src/decidim/direct_uploads/uploader.js +4 -1
- data/app/packs/src/decidim/geocoding/attach_input.js +4 -1
- data/app/packs/src/decidim/geocoding/provider/here.js +17 -21
- data/app/packs/src/decidim/geocoding/provider/photon.js +1 -1
- data/app/packs/src/decidim/input_hashtags.js +1 -1
- data/app/packs/src/decidim/input_mentions.js +1 -1
- data/app/packs/src/decidim/input_multiple_mentions.js +1 -1
- data/app/packs/src/decidim/utilities/text.js +17 -0
- data/app/packs/src/decidim/vizzs/index.js +1 -1
- data/app/packs/stylesheets/decidim/_variables.scss +1 -1
- data/app/packs/stylesheets/decidim/plugins/leaflet.scss +118 -114
- data/app/packs/stylesheets/decidim/vendor/_social_share_button.scss +4 -0
- data/app/presenters/decidim/admin_log/oauth_application_resource_presenter.rb +1 -1
- data/app/presenters/decidim/notification_to_mailer_presenter.rb +9 -0
- data/app/services/decidim/events_manager.rb +6 -0
- data/app/services/decidim/push_notification_message_sender.rb +36 -0
- data/app/services/decidim/send_push_notification.rb +22 -8
- data/app/views/decidim/devise/registrations/new.html.erb +2 -2
- data/app/views/decidim/notifications_digest_mailer/_email_content.html.erb +7 -0
- data/app/views/decidim/notifications_settings/show.html.erb +1 -1
- data/app/views/decidim/scopes/_scopes_picker_input.html.erb +1 -1
- data/app/views/decidim/searches/_filters.html.erb +3 -1
- data/app/views/decidim/shared/_address_details.html.erb +2 -2
- data/app/views/decidim/shared/_share_modal.html.erb +1 -1
- data/app/views/decidim/shared/participatory_space_filters/_filters.html.erb +1 -1
- data/app/views/layouts/decidim/_js_configuration.html.erb +1 -0
- data/app/views/layouts/decidim/_social_media_links.html.erb +2 -2
- data/config/locales/ar.yml +12 -16
- data/config/locales/bg.yml +77 -15
- data/config/locales/ca.yml +34 -30
- data/config/locales/cs.yml +18 -14
- data/config/locales/de.yml +62 -58
- data/config/locales/el.yml +11 -16
- data/config/locales/en.yml +5 -1
- data/config/locales/eo.yml +2 -3
- data/config/locales/es-MX.yml +15 -11
- data/config/locales/es-PY.yml +15 -11
- data/config/locales/es.yml +30 -26
- data/config/locales/eu.yml +500 -342
- data/config/locales/fi-plain.yml +7 -3
- data/config/locales/fi.yml +21 -17
- data/config/locales/fr-CA.yml +17 -13
- data/config/locales/fr.yml +12 -8
- data/config/locales/ga-IE.yml +5 -5
- data/config/locales/gl.yml +5 -19
- data/config/locales/he-IL.yml +1 -0
- data/config/locales/hu.yml +63 -23
- data/config/locales/id-ID.yml +4 -19
- data/config/locales/is-IS.yml +4 -2
- data/config/locales/it.yml +15 -17
- data/config/locales/ja.yml +26 -22
- data/config/locales/lb.yml +15 -17
- data/config/locales/lt.yml +55 -10
- data/config/locales/lv.yml +4 -16
- data/config/locales/nl.yml +12 -12
- data/config/locales/no.yml +8 -10
- data/config/locales/pl.yml +151 -1
- data/config/locales/pt-BR.yml +267 -22
- data/config/locales/pt.yml +8 -10
- data/config/locales/ro-RO.yml +4 -10
- data/config/locales/ru.yml +13 -17
- data/config/locales/sk.yml +7 -17
- data/config/locales/sl.yml +0 -5
- data/config/locales/sq-AL.yml +1 -0
- data/config/locales/sv.yml +55 -17
- data/config/locales/th-TH.yml +1 -0
- data/config/locales/tr-TR.yml +18 -15
- data/config/locales/uk.yml +17 -14
- data/config/locales/zh-CN.yml +6 -10
- data/config/locales/zh-TW.yml +0 -9
- data/db/migrate/20231027142329_change_default_value_for_decidim_endorsements.rb +11 -0
- data/db/seeds.rb +1 -0
- data/decidim-core.gemspec +78 -0
- data/lib/decidim/acts_as_tree.rb +14 -1
- data/lib/decidim/asset_router/storage.rb +4 -0
- data/lib/decidim/attribute_encryptor.rb +6 -4
- data/lib/decidim/core/engine.rb +7 -3
- data/lib/decidim/core/test/factories.rb +309 -95
- data/lib/decidim/core/test/shared_examples/amendable/amendment_created_event_examples.rb +6 -26
- data/lib/decidim/core/test/shared_examples/amendable/amendment_promoted_event_examples.rb +8 -26
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +56 -0
- data/lib/decidim/core/test/shared_examples/embed_resource_examples.rb +187 -11
- data/lib/decidim/core/test/shared_examples/errors.rb +2 -0
- data/lib/decidim/core/test/shared_examples/has_attachment_collections.rb +8 -6
- data/lib/decidim/core/test/shared_examples/has_attachments.rb +4 -4
- data/lib/decidim/core/test/shared_examples/has_category.rb +27 -0
- data/lib/decidim/core/test/shared_examples/has_reference.rb +1 -1
- data/lib/decidim/core/test/shared_examples/has_space_in_mcell_examples.rb +1 -2
- data/lib/decidim/core/test/shared_examples/resource_endorsed_event_examples.rb +6 -3
- data/lib/decidim/core/test/shared_examples/resource_locator_presenter_examples.rb +134 -0
- data/lib/decidim/core/test/shared_examples/searchable_results_examples.rb +1 -1
- data/lib/decidim/core/test/shared_examples/simple_event.rb +50 -2
- data/lib/decidim/core/test.rb +1 -0
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/core.rb +2 -1
- data/lib/decidim/endorsable.rb +1 -1
- data/lib/decidim/engine_router.rb +17 -4
- data/lib/decidim/events/base_event.rb +5 -2
- data/lib/decidim/events/simple_event.rb +3 -17
- data/lib/decidim/exporters.rb +10 -1
- data/lib/decidim/form_builder.rb +1 -0
- data/lib/decidim/has_category.rb +3 -3
- data/lib/decidim/has_conversations.rb +91 -0
- data/lib/decidim/participable.rb +17 -0
- data/lib/decidim/view_model.rb +1 -0
- data/lib/decidim/webpacker/webpack/.modernizrrc +9 -0
- data/lib/premailer/adapter/decidim.rb +5 -4
- data/lib/tasks/decidim_reminders_tasks.rake +1 -0
- data/lib/tasks/upgrade/decidim_deduplicate_endorsements.rake +53 -0
- data/lib/tasks/upgrade/decidim_fix_categorization.rake +15 -0
- data/lib/tasks/upgrade/decidim_fix_short_url_resolver.rake +22 -0
- metadata +37 -32
- data/app/helpers/decidim/layout_helper.rb.orig +0 -225
- data/app/packs/stylesheets/decidim/modules/_dropdown_menu.scss +0 -9
- data/app/views/decidim/devise/registrations/new.html.erb.orig +0 -231
- /data/{config/environment.rb → app/packs/images/decidim/.keep} +0 -0
@@ -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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
@@ -48,6 +48,38 @@ shared_examples "comments" do
|
|
48
48
|
expect(page).to have_css(".comments > div:nth-child(2)", text: "Most Rated Comment")
|
49
49
|
end
|
50
50
|
|
51
|
+
context "when there are comments and replies" do
|
52
|
+
let!(:single_comment) { create(:comment, commentable: commentable) }
|
53
|
+
let!(:reply) { create(:comment, commentable: single_comment, root_commentable: commentable) }
|
54
|
+
|
55
|
+
it "displays the show replies link on comment with reply" do
|
56
|
+
visit resource_path
|
57
|
+
expect(page).not_to have_content("Comments are disabled at this time")
|
58
|
+
expect(page).to have_css(".comment", minimum: 1)
|
59
|
+
|
60
|
+
within "#comment_#{single_comment.id}" do
|
61
|
+
expect(page).to have_content "Hide replies"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when there is a comment with the same parent id but different type with replies" do
|
66
|
+
let!(:other_component) { create(:component, manifest_name: :dummy, organization: organization) }
|
67
|
+
let!(:other_commentable) { create(:dummy_resource, component: other_component, author: user, id: single_comment.id) }
|
68
|
+
let!(:reply) { create(:comment, commentable: other_commentable, root_commentable: other_commentable) }
|
69
|
+
let!(:other_reply) { create(:comment, commentable: reply, root_commentable: other_commentable) }
|
70
|
+
|
71
|
+
it "displays the show replies link on comment with reply" do
|
72
|
+
visit resource_path
|
73
|
+
expect(page).not_to have_content("Comments are disabled at this time")
|
74
|
+
expect(page).to have_css(".comment", minimum: 1)
|
75
|
+
|
76
|
+
within "#comment_#{single_comment.id}" do
|
77
|
+
expect(page).not_to have_content "Hide replies"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
51
83
|
context "when there are deleted comments" do
|
52
84
|
let(:deleted_comment) { comments[0] }
|
53
85
|
|
@@ -838,5 +870,29 @@ shared_examples "comments" do
|
|
838
870
|
expect(page).to have_link "#decidim", href: "/search?term=%23decidim"
|
839
871
|
end
|
840
872
|
end
|
873
|
+
|
874
|
+
describe "export_serializer" do
|
875
|
+
let(:comment) { comments.first }
|
876
|
+
|
877
|
+
it "returns the serializer for the comment" do
|
878
|
+
expect(comment.class.export_serializer).to eq(Decidim::Comments::CommentSerializer)
|
879
|
+
end
|
880
|
+
|
881
|
+
context "with instance" do
|
882
|
+
subject { comment.class.export_serializer.new(comment).serialize }
|
883
|
+
|
884
|
+
it { is_expected.to have_key(:id) }
|
885
|
+
it { is_expected.to have_key(:created_at) }
|
886
|
+
it { is_expected.to have_key(:body) }
|
887
|
+
it { is_expected.to have_key(:locale) }
|
888
|
+
it { is_expected.to have_key(:author) }
|
889
|
+
it { is_expected.to have_key(:alignment) }
|
890
|
+
it { is_expected.to have_key(:depth) }
|
891
|
+
it { is_expected.to have_key(:user_group) }
|
892
|
+
it { is_expected.to have_key(:commentable_id) }
|
893
|
+
it { is_expected.to have_key(:commentable_type) }
|
894
|
+
it { is_expected.to have_key(:root_commentable_url) }
|
895
|
+
end
|
896
|
+
end
|
841
897
|
end
|
842
898
|
end
|
@@ -1,5 +1,50 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "decidim/admin/test/admin_participatory_space_access_examples"
|
4
|
+
|
5
|
+
shared_examples "rendering the embed page correctly" do
|
6
|
+
before do
|
7
|
+
visit widget_path
|
8
|
+
end
|
9
|
+
|
10
|
+
it "renders" do
|
11
|
+
if resource.title.is_a?(Hash)
|
12
|
+
expect(page).to have_i18n_content(resource.title)
|
13
|
+
else
|
14
|
+
expect(page).to have_content(resource.title)
|
15
|
+
end
|
16
|
+
|
17
|
+
expect(page).to have_content(organization.name)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
shared_examples "rendering the embed link in the resource page" do
|
22
|
+
before do
|
23
|
+
visit resource_locator(resource).path
|
24
|
+
end
|
25
|
+
|
26
|
+
it "has the embed link" do
|
27
|
+
expect(page).to have_button("Embed")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
shared_examples "showing the unauthorized message in the widget_path" do
|
32
|
+
it do
|
33
|
+
visit widget_path
|
34
|
+
expect(page).to have_content "You are not authorized to perform this action"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
shared_examples "not rendering the embed link in the resource page" do
|
39
|
+
before do
|
40
|
+
visit resource_locator(resource).path
|
41
|
+
end
|
42
|
+
|
43
|
+
it "does not have the embed link" do
|
44
|
+
expect(page).to have_no_button("Embed")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
3
48
|
shared_examples_for "an embed resource" do |options|
|
4
49
|
if options.is_a?(Hash) && options[:skip_space_checks]
|
5
50
|
let(:organization) { resource.organization }
|
@@ -11,22 +56,29 @@ shared_examples_for "an embed resource" do |options|
|
|
11
56
|
include_context "with a component"
|
12
57
|
end
|
13
58
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
59
|
+
unless options.is_a?(Hash) && options[:skip_publication_checks]
|
60
|
+
context "when the resource is not published" do
|
61
|
+
before do
|
62
|
+
resource.unpublish!
|
63
|
+
end
|
64
|
+
|
65
|
+
it_behaves_like "not rendering the embed link in the resource page"
|
19
66
|
|
20
|
-
|
21
|
-
|
22
|
-
expect(page).to have_i18n_content(resource.title)
|
23
|
-
else
|
24
|
-
expect(page).to have_content(resource.title)
|
67
|
+
it_behaves_like "a 404 page" do
|
68
|
+
let(:target_path) { widget_path }
|
25
69
|
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it_behaves_like "rendering the embed link in the resource page" unless options.is_a?(Hash) && options[:skip_link_checks]
|
26
74
|
|
27
|
-
|
75
|
+
context "when visiting the embed page for a resource" do
|
76
|
+
before do
|
77
|
+
visit widget_path
|
28
78
|
end
|
29
79
|
|
80
|
+
it_behaves_like "rendering the embed page correctly"
|
81
|
+
|
30
82
|
unless options.is_a?(Hash) && options[:skip_space_checks]
|
31
83
|
context "when the participatory_space is a process" do
|
32
84
|
it "shows the process name" do
|
@@ -47,3 +99,127 @@ shared_examples_for "an embed resource" do |options|
|
|
47
99
|
end
|
48
100
|
end
|
49
101
|
end
|
102
|
+
|
103
|
+
shared_examples_for "a private embed resource" do
|
104
|
+
let(:organization) { resource.organization }
|
105
|
+
let!(:other_user) { create(:user, :confirmed, organization: organization) }
|
106
|
+
let!(:participatory_space_private_user) { create(:participatory_space_private_user, user: other_user, privatable_to: resource) }
|
107
|
+
|
108
|
+
before do
|
109
|
+
switch_to_host(organization.host)
|
110
|
+
end
|
111
|
+
|
112
|
+
context "when the resource is private" do
|
113
|
+
before do
|
114
|
+
resource.update!(private_space: true)
|
115
|
+
resource.update!(is_transparent: false) if resource.respond_to?(:is_transparent)
|
116
|
+
end
|
117
|
+
|
118
|
+
context "and user is a visitor" do
|
119
|
+
let(:user) { nil }
|
120
|
+
|
121
|
+
it_behaves_like "not rendering the embed link in the resource page"
|
122
|
+
|
123
|
+
it_behaves_like "a 404 page" do
|
124
|
+
let(:target_path) { widget_path }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "and user is a registered user" do
|
129
|
+
let(:user) { create(:user, :confirmed, organization: organization) }
|
130
|
+
|
131
|
+
before do
|
132
|
+
sign_in user, scope: :user
|
133
|
+
end
|
134
|
+
|
135
|
+
it_behaves_like "not rendering the embed link in the resource page"
|
136
|
+
|
137
|
+
it_behaves_like "a 404 page" do
|
138
|
+
let(:target_path) { widget_path }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "and user is a private user" do
|
143
|
+
let(:user) { other_user }
|
144
|
+
|
145
|
+
before do
|
146
|
+
sign_in user, scope: :user
|
147
|
+
end
|
148
|
+
|
149
|
+
it_behaves_like "a 404 page" do
|
150
|
+
let(:target_path) { widget_path }
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
shared_examples_for "a transparent private embed resource" do
|
157
|
+
let(:organization) { resource.organization }
|
158
|
+
let!(:other_user) { create(:user, :confirmed, organization: organization) }
|
159
|
+
let!(:participatory_space_private_user) { create(:participatory_space_private_user, user: other_user, privatable_to: resource) }
|
160
|
+
|
161
|
+
before do
|
162
|
+
switch_to_host(organization.host)
|
163
|
+
end
|
164
|
+
|
165
|
+
context "when the resource is private" do
|
166
|
+
before do
|
167
|
+
resource.update!(private_space: true)
|
168
|
+
resource.update!(is_transparent: true) if resource.respond_to?(:is_transparent)
|
169
|
+
end
|
170
|
+
|
171
|
+
context "and user is a visitor" do
|
172
|
+
let(:user) { nil }
|
173
|
+
|
174
|
+
it_behaves_like "rendering the embed page correctly"
|
175
|
+
end
|
176
|
+
|
177
|
+
context "and user is a registered user" do
|
178
|
+
let(:user) { create(:user, :confirmed, organization: organization) }
|
179
|
+
|
180
|
+
before do
|
181
|
+
sign_in user, scope: :user
|
182
|
+
end
|
183
|
+
|
184
|
+
it_behaves_like "rendering the embed page correctly"
|
185
|
+
end
|
186
|
+
|
187
|
+
context "and user is a private user" do
|
188
|
+
let(:user) { other_user }
|
189
|
+
|
190
|
+
before do
|
191
|
+
sign_in user, scope: :user
|
192
|
+
end
|
193
|
+
|
194
|
+
it_behaves_like "rendering the embed page correctly"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
shared_examples_for "a moderated embed resource" do
|
200
|
+
include_context "with a component"
|
201
|
+
|
202
|
+
context "when the resource is moderated" do
|
203
|
+
let!(:moderation) { create(:moderation, reportable: resource, hidden_at: 2.days.ago) }
|
204
|
+
|
205
|
+
it_behaves_like "a 404 page" do
|
206
|
+
let(:target_path) { widget_path }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
shared_examples_for "a withdrawn embed resource" do
|
212
|
+
include_context "with a component"
|
213
|
+
|
214
|
+
context "when the resource is withdrawn" do
|
215
|
+
before do
|
216
|
+
resource.update!(state: "withdrawn")
|
217
|
+
end
|
218
|
+
|
219
|
+
it_behaves_like "not rendering the embed link in the resource page"
|
220
|
+
|
221
|
+
it_behaves_like "a 404 page" do
|
222
|
+
let(:target_path) { widget_path }
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -14,14 +14,14 @@ shared_examples_for "has attachment collections" do
|
|
14
14
|
|
15
15
|
it "shows them" do
|
16
16
|
within ".attachments .documents" do
|
17
|
-
expect(page).to have_content(
|
17
|
+
expect(page).to have_content(translated(attachment_collection.name))
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
it "show their documents" do
|
22
22
|
within ".attachments .documents #docs-collection-#{attachment_collection.id}", visible: false do
|
23
|
-
expect(page).to have_content(:all,
|
24
|
-
expect(page).not_to have_content(:all,
|
23
|
+
expect(page).to have_content(:all, translated(document.title))
|
24
|
+
expect(page).not_to have_content(:all, translated(other_document.title))
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -39,7 +39,9 @@ shared_examples_for "has attachment collections" do
|
|
39
39
|
|
40
40
|
it "shows them ordered" do
|
41
41
|
within ".attachments .documents" do
|
42
|
-
expect(
|
42
|
+
expect(decidim_escape_translated(first_attachment_collection.name).gsub(""",
|
43
|
+
"\"")).to appear_before(decidim_escape_translated(last_attachment_collection.name).gsub(""",
|
44
|
+
"\""))
|
43
45
|
end
|
44
46
|
end
|
45
47
|
end
|
@@ -55,8 +57,8 @@ shared_examples_for "has attachment collections" do
|
|
55
57
|
|
56
58
|
it "is not present" do
|
57
59
|
within ".attachments .documents" do
|
58
|
-
expect(page).to have_content(
|
59
|
-
expect(page).not_to have_content(
|
60
|
+
expect(page).to have_content(translated(attachment_collection.name))
|
61
|
+
expect(page).not_to have_content(translated(empty_attachment_collection.name))
|
60
62
|
end
|
61
63
|
end
|
62
64
|
end
|
@@ -14,7 +14,7 @@ shared_examples_for "has attachments" do
|
|
14
14
|
|
15
15
|
it "shows them" do
|
16
16
|
within "div.wrapper .documents" do
|
17
|
-
expect(page).to have_content(
|
17
|
+
expect(page).to have_content(translated(document.title))
|
18
18
|
end
|
19
19
|
|
20
20
|
within "div.wrapper .images" do
|
@@ -27,7 +27,7 @@ shared_examples_for "has attachments" do
|
|
27
27
|
let!(:last_document) { create(:attachment, :with_pdf, attached_to: attached_to, weight: 2) }
|
28
28
|
let!(:first_document) { create(:attachment, :with_pdf, attached_to: attached_to, weight: 1) }
|
29
29
|
let!(:last_image) { create(:attachment, attached_to: attached_to, weight: 2) }
|
30
|
-
let!(:
|
30
|
+
let!(:first_image) { create(:attachment, attached_to: attached_to, weight: 1) }
|
31
31
|
|
32
32
|
before do
|
33
33
|
visit current_path
|
@@ -35,11 +35,11 @@ shared_examples_for "has attachments" do
|
|
35
35
|
|
36
36
|
it "shows them ordered" do
|
37
37
|
within "div.wrapper .documents" do
|
38
|
-
expect(
|
38
|
+
expect(decidim_escape_translated(first_document.title).gsub(""", "\"")).to appear_before(decidim_escape_translated(last_document.title).gsub(""", "\""))
|
39
39
|
end
|
40
40
|
|
41
41
|
within "div.wrapper .images" do
|
42
|
-
expect(strip_tags(translated(
|
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
|
@@ -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: 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: 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(/[
|
11
|
+
expect(subject.reference).to match(/[a-zA-Z]+/)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
@@ -8,8 +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
|
12
|
-
expect(cell_html).to have_content(translated(model.component.participatory_space.title, locale: :en))
|
11
|
+
expect(cell_html).to have_content(translated(model.component.participatory_space.title))
|
13
12
|
end
|
14
13
|
end
|
15
14
|
end
|
@@ -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
|
-
.to eq("#{author.name} #{author_presenter.nickname}, who you are following," \
|
41
|
-
"
|
41
|
+
.to eq("#{author.name} #{author_presenter.nickname}, who you are following, " \
|
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}\">#{
|
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: organization) }
|
8
|
+
let(:component) { create(:component, id: 1, participatory_space: participatory_space) }
|
9
|
+
let(:resource) { create(:dummy_resource, id: 1, component: 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
|