decidim-core 0.28.0 → 0.28.1
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/address/online.erb +27 -9
- data/app/cells/decidim/address/show.erb +27 -12
- data/app/cells/decidim/address_cell.rb +29 -0
- data/app/cells/decidim/authorization_modal/show.erb +8 -4
- data/app/cells/decidim/authorization_modal_cell.rb +1 -0
- data/app/cells/decidim/card_metadata_cell.rb +3 -3
- data/app/cells/decidim/coauthorships_cell.rb +1 -1
- data/app/cells/decidim/content_blocks/menu_breadcrumb_last_activity_cell.rb +6 -0
- data/app/cells/decidim/content_blocks/participatory_space_hero_cell.rb +20 -4
- data/app/cells/decidim/content_blocks/participatory_space_hero_settings_form/show.erb +8 -0
- data/app/cells/decidim/content_blocks/participatory_space_hero_settings_form_cell.rb +13 -0
- data/app/cells/decidim/content_blocks/participatory_space_metadata_cell.rb +1 -1
- data/app/cells/decidim/footer_pages_cell.rb +3 -3
- data/app/cells/decidim/profile/tabs.erb +3 -2
- data/app/cells/decidim/tags_cell.rb +3 -1
- data/app/cells/decidim/upload_modal/modal.erb +2 -2
- data/app/commands/decidim/create_omniauth_registration.rb +1 -3
- data/app/commands/decidim/messaging/reply_to_conversation.rb +3 -0
- data/app/commands/decidim/messaging/start_conversation.rb +3 -0
- data/app/controllers/concerns/decidim/devise_authentication_methods.rb +36 -0
- 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/sessions_controller.rb +1 -24
- data/app/events/decidim/welcome_notification_event.rb +6 -9
- data/app/helpers/decidim/application_helper.rb +0 -18
- data/app/helpers/decidim/cells_paginate_helper.rb +1 -1
- data/app/helpers/decidim/check_boxes_tree_helper.rb +6 -6
- data/app/helpers/decidim/layout_helper.rb +1 -1
- data/app/helpers/decidim/map_helper.rb +1 -1
- data/app/helpers/decidim/menu_helper.rb +2 -0
- data/app/helpers/decidim/newsletters_helper.rb +83 -16
- data/app/helpers/decidim/paginate_helper.rb +1 -1
- data/app/helpers/decidim/sanitize_helper.rb +9 -0
- data/app/helpers/decidim/social_share_button_helper.rb +1 -1
- data/app/helpers/decidim/user_profile_helper.rb +7 -2
- data/app/mailers/decidim/messaging/conversation_mailer.rb +3 -72
- data/app/models/decidim/push_notification_message.rb +38 -0
- data/app/packs/entrypoints/decidim_overrides.scss +2 -0
- data/app/packs/images/decidim/.keep +0 -0
- data/app/packs/src/decidim/a11y.js +1 -1
- data/app/packs/src/decidim/account_form.js +1 -1
- data/app/packs/src/decidim/data_consent/consent_manager.test.js +1 -1
- data/app/packs/src/decidim/data_consent/index.js +1 -1
- data/app/packs/src/decidim/direct_uploads/upload_field.js +1 -1
- data/app/packs/src/decidim/direct_uploads/upload_modal.js +10 -6
- data/app/packs/src/decidim/editor/extensions/hashtag/index.js +1 -1
- data/app/packs/src/decidim/editor/extensions/mention/index.js +1 -1
- data/app/packs/src/decidim/editor/extensions/video_embed/index.js +3 -0
- data/app/packs/src/decidim/editor/test/editor/create.test.js +1 -1
- data/app/packs/src/decidim/editor/test/extensions/bold.test.js +2 -3
- data/app/packs/src/decidim/editor/test/extensions/character_count.test.js +2 -2
- data/app/packs/src/decidim/editor/test/extensions/decidim_kit.test.js +2 -3
- data/app/packs/src/decidim/editor/test/extensions/dialog.test.js +2 -2
- data/app/packs/src/decidim/editor/test/extensions/emoji.test.js +2 -2
- data/app/packs/src/decidim/editor/test/extensions/hashtag.test.js +2 -2
- data/app/packs/src/decidim/editor/test/extensions/heading.test.js +2 -2
- data/app/packs/src/decidim/editor/test/extensions/image.test.js +4 -4
- data/app/packs/src/decidim/editor/test/extensions/indent.test.js +2 -2
- data/app/packs/src/decidim/editor/test/extensions/link.test.js +3 -3
- data/app/packs/src/decidim/editor/test/extensions/mention.test.js +2 -2
- data/app/packs/src/decidim/editor/test/extensions/ordered_list.test.js +2 -2
- data/app/packs/src/decidim/editor/test/extensions/video_embed.test.js +3 -3
- data/app/packs/src/decidim/editor/test/helpers.js +5 -4
- data/app/packs/src/decidim/editor/test/toolbar/basic.test.js +2 -2
- data/app/packs/src/decidim/editor/test/toolbar/content.test.js +2 -2
- data/app/packs/src/decidim/editor/test/toolbar/full.test.js +3 -3
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic.js +6 -6
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_block.js +2 -2
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_formatting.js +1 -1
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_indent.js +2 -2
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_link.js +2 -2
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_list.js +2 -2
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_basic_styling.js +2 -2
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_content.js +7 -7
- data/app/packs/src/decidim/editor/test/toolbar/shared/behaves_like_content_styling.js +2 -2
- data/app/packs/src/decidim/editor/test/toolbar/shared/context.js +1 -1
- data/app/packs/src/decidim/editor/test/utilities/paste_transform.test.js +2 -2
- data/app/packs/src/decidim/external_domain_warning.js +13 -0
- data/app/packs/src/decidim/external_domain_warning.test.js +1 -1
- data/app/packs/src/decidim/external_link.js +48 -9
- data/app/packs/src/decidim/external_link.test.js +1 -1
- data/app/packs/src/decidim/focus_guard.js +8 -20
- data/app/packs/src/decidim/form_filter.component_for_testing.js +1 -1
- data/app/packs/src/decidim/form_filter.js +3 -3
- data/app/packs/src/decidim/geocoding/attach_input.js +1 -1
- data/app/packs/src/decidim/i18n.test.js +1 -1
- data/app/packs/src/decidim/index.js +4 -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/sw/index.js +3 -3
- data/app/packs/src/decidim/user_registrations.js +1 -1
- data/app/packs/src/decidim/vizzs/index.js +1 -1
- data/app/packs/stylesheets/decidim/_cards.scss +2 -2
- data/app/packs/stylesheets/decidim/_dropdown.scss +2 -2
- data/app/packs/stylesheets/decidim/_layout.scss +4 -4
- data/app/packs/stylesheets/decidim/application.scss +0 -3
- data/app/packs/stylesheets/decidim/decidim_application.scss +4 -0
- data/app/packs/stylesheets/decidim/legacy/leaflet.scss +88 -107
- data/app/presenters/decidim/admin_log/oauth_application_resource_presenter.rb +1 -1
- data/app/presenters/decidim/log/diff_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/iframe_disabler.rb +4 -0
- data/app/services/decidim/push_notification_message_sender.rb +40 -0
- data/app/services/decidim/send_push_notification.rb +22 -8
- data/app/uploaders/decidim/background_image_uploader.rb +11 -0
- data/app/views/decidim/application/_collection.html.erb +2 -2
- data/app/views/decidim/application/_document.html.erb +1 -1
- 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/offline/show.html.erb +15 -9
- data/app/views/layouts/decidim/_head.html.erb +1 -0
- data/app/views/layouts/decidim/_js_configuration.html.erb +3 -1
- data/app/views/layouts/decidim/footer/_main_social_media_links.html.erb +5 -5
- data/app/views/layouts/decidim/footer/_mini.html.erb +2 -2
- data/app/views/layouts/decidim/header/_menu_breadcrumb_mobile_tablet.html.erb +1 -1
- data/config/assets.rb +1 -0
- data/config/locales/ar.yml +63 -7
- data/config/locales/bg.yml +32 -2
- data/config/locales/ca.yml +29 -24
- data/config/locales/cs.yml +6 -2
- data/config/locales/de.yml +34 -29
- data/config/locales/el.yml +3 -6
- data/config/locales/en.yml +7 -2
- data/config/locales/es-MX.yml +9 -4
- data/config/locales/es-PY.yml +9 -4
- data/config/locales/es.yml +27 -22
- data/config/locales/eu.yml +22 -8
- data/config/locales/fi-plain.yml +8 -3
- data/config/locales/fi.yml +10 -5
- data/config/locales/fr-CA.yml +12 -7
- data/config/locales/fr.yml +12 -7
- data/config/locales/ga-IE.yml +1 -0
- data/config/locales/gl.yml +4 -2
- data/config/locales/he-IL.yml +1 -0
- data/config/locales/hu.yml +264 -7
- data/config/locales/id-ID.yml +0 -2
- data/config/locales/it.yml +2 -5
- data/config/locales/ja.yml +11 -6
- data/config/locales/lb.yml +2 -5
- data/config/locales/lt.yml +0 -10
- data/config/locales/lv.yml +0 -2
- data/config/locales/nl.yml +1 -2
- data/config/locales/no.yml +2 -5
- data/config/locales/pl.yml +581 -2
- data/config/locales/pt-BR.yml +202 -18
- data/config/locales/pt.yml +2 -5
- data/config/locales/ro-RO.yml +2 -5
- data/config/locales/ru.yml +7 -2
- data/config/locales/sk.yml +0 -2
- data/config/locales/sv.yml +24 -5
- data/config/locales/tr-TR.yml +3 -5
- data/config/locales/uk.yml +12 -2
- data/config/locales/zh-CN.yml +0 -5
- data/config/locales/zh-TW.yml +2 -10
- data/decidim-core.gemspec +90 -0
- data/lib/decidim/asset_router/storage.rb +2 -0
- data/lib/decidim/attribute_encryptor.rb +6 -4
- data/lib/decidim/attributes/time_with_zone.rb +1 -1
- data/lib/decidim/core/engine.rb +7 -6
- data/lib/decidim/core/seeds.rb +36 -32
- data/lib/decidim/core/test/factories.rb +296 -89
- 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/has_attachment_collections.rb +8 -6
- data/lib/decidim/core/test/shared_examples/has_attachments.rb +8 -8
- 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 -1
- data/lib/decidim/core/test/shared_examples/map_examples.rb +3 -0
- data/lib/decidim/core/test/shared_examples/resource_endorsed_event_examples.rb +5 -2
- data/lib/decidim/core/test/shared_examples/resource_locator_presenter_examples.rb +134 -0
- data/lib/decidim/core/test/shared_examples/simple_event.rb +18 -2
- data/lib/decidim/core/test.rb +1 -0
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/core.rb +1 -0
- data/lib/decidim/engine_router.rb +17 -4
- data/lib/decidim/events/base_event.rb +3 -3
- data/lib/decidim/events/simple_event.rb +3 -17
- data/lib/decidim/form_builder.rb +8 -2
- data/lib/decidim/has_category.rb +1 -1
- data/lib/decidim/has_conversations.rb +91 -0
- data/lib/decidim/participable.rb +17 -0
- data/lib/decidim/upgrade/wysiwyg_migrator.rb +7 -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_fix_categorization.rake +15 -0
- metadata +27 -30
- data/app/views/decidim/searches/index.js.erb +0 -7
- data/config/brakeman.ignore +0 -37
- 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
|
-
|
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
|
@@ -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(
|
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,
|
22
|
-
expect(page).not_to have_content(:all,
|
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(
|
39
|
+
expect(decidim_escape_translated(first_attachment_collection.name).gsub(""",
|
40
|
+
"\"")).to appear_before(decidim_escape_translated(last_attachment_collection.name).gsub(""",
|
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(
|
54
|
-
expect(page).not_to have_content(
|
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(
|
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!(:
|
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(
|
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 "[data-content] [data-gallery]" 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
|
@@ -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(
|
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!(:
|
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(
|
84
|
+
expect(decidim_escape_translated(first_document.title).gsub(""", "\"")).to appear_before(decidim_escape_translated(last_document.title).gsub(""", "\""))
|
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(
|
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(/[
|
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(
|
11
|
+
expect(cell_html).to have_content(decidim_escape_translated(model.component.participatory_space.title))
|
12
12
|
end
|
13
13
|
end
|
14
14
|
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 \"#{
|
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:) }
|
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
|
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
|
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
|
data/lib/decidim/core/test.rb
CHANGED
@@ -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"
|
data/lib/decidim/core/version.rb
CHANGED
data/lib/decidim/core.rb
CHANGED
@@ -122,6 +122,7 @@ module Decidim
|
|
122
122
|
autoload :ModerationTools, "decidim/moderation_tools"
|
123
123
|
autoload :ContentSecurityPolicy, "decidim/content_security_policy"
|
124
124
|
autoload :IconRegistry, "decidim/icon_registry"
|
125
|
+
autoload :HasConversations, "decidim/has_conversations"
|
125
126
|
|
126
127
|
include ActiveSupport::Configurable
|
127
128
|
# Loads seeds from all engines.
|
@@ -16,7 +16,7 @@ module Decidim
|
|
16
16
|
#
|
17
17
|
# @return [EngineRouter] The new engine router
|
18
18
|
def self.main_proxy(target)
|
19
|
-
new(target.mounted_engine, target.mounted_params)
|
19
|
+
new(target.mounted_engine, target.mounted_params, target)
|
20
20
|
end
|
21
21
|
|
22
22
|
# Instantiates a router to the backend engine for an object.
|
@@ -25,12 +25,13 @@ module Decidim
|
|
25
25
|
#
|
26
26
|
# @return [EngineRouter] The new engine router
|
27
27
|
def self.admin_proxy(target)
|
28
|
-
new(target.mounted_admin_engine, target.mounted_params)
|
28
|
+
new(target.mounted_admin_engine, target.mounted_params, target)
|
29
29
|
end
|
30
30
|
|
31
|
-
def initialize(engine, default_url_options)
|
31
|
+
def initialize(engine, default_url_options, target = nil)
|
32
32
|
@engine = engine
|
33
33
|
@default_url_options = default_url_options
|
34
|
+
@target = target
|
34
35
|
end
|
35
36
|
|
36
37
|
def default_url_options
|
@@ -44,11 +45,23 @@ module Decidim
|
|
44
45
|
def method_missing(method_name, *args)
|
45
46
|
return super unless route_helper?(method_name)
|
46
47
|
|
47
|
-
|
48
|
+
filter_slug_params!(method_name)
|
49
|
+
|
50
|
+
send(engine).send(method_name, *args)
|
48
51
|
end
|
49
52
|
|
50
53
|
private
|
51
54
|
|
55
|
+
attr_reader :engine, :target
|
56
|
+
|
57
|
+
def filter_slug_params!(method_name)
|
58
|
+
return if target.nil?
|
59
|
+
return unless target.respond_to?(:mounted_params)
|
60
|
+
|
61
|
+
skip_space_slug = target.respond_to?(:slug_param_name) && target.respond_to?(:skip_space_slug?) && target.skip_space_slug?(method_name)
|
62
|
+
@default_url_options.except!(target.slug_param_name) if skip_space_slug == true
|
63
|
+
end
|
64
|
+
|
52
65
|
def route_helper?(method_name)
|
53
66
|
method_name.to_s.match?(/_(url|path)$/)
|
54
67
|
end
|
@@ -7,7 +7,7 @@ module Decidim
|
|
7
7
|
# notifications dashboard and to generate other notifications (emails, for example).
|
8
8
|
class BaseEvent
|
9
9
|
extend ActiveModel::Translation
|
10
|
-
include Decidim::
|
10
|
+
include Decidim::SanitizeHelper
|
11
11
|
|
12
12
|
class_attribute :types
|
13
13
|
self.types = []
|
@@ -103,9 +103,9 @@ module Decidim
|
|
103
103
|
return unless resource
|
104
104
|
|
105
105
|
title = if resource.respond_to?(:title)
|
106
|
-
|
106
|
+
decidim_sanitize_translated(resource.title)
|
107
107
|
elsif resource.respond_to?(:name)
|
108
|
-
|
108
|
+
decidim_sanitize_translated(resource.name)
|
109
109
|
end
|
110
110
|
|
111
111
|
Decidim::ContentProcessor.render_without_format(title, links: false).html_safe
|
@@ -11,7 +11,6 @@ module Decidim
|
|
11
11
|
include Decidim::Events::EmailEvent
|
12
12
|
include Decidim::Events::NotificationEvent
|
13
13
|
include Decidim::ComponentPathHelper
|
14
|
-
include Decidim::SanitizeHelper
|
15
14
|
|
16
15
|
delegate :created_at, to: :resource
|
17
16
|
|
@@ -34,14 +33,7 @@ module Decidim
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def email_subject
|
37
|
-
I18n.t("email_subject", **
|
38
|
-
end
|
39
|
-
|
40
|
-
def email_subject_i18n_options
|
41
|
-
sanitized_values = { resource_title: decidim_sanitize(resource_title) }
|
42
|
-
sanitized_values[:mentioned_proposal_title] = decidim_sanitize(mentioned_proposal_title) if i18n_options.has_key?(:mentioned_proposal_title)
|
43
|
-
sanitized_values[:participatory_space_title] = decidim_sanitize(participatory_space_title) if i18n_options.has_key?(:participatory_space_title)
|
44
|
-
i18n_options.merge(sanitized_values)
|
36
|
+
I18n.t("email_subject", **i18n_options).html_safe
|
45
37
|
end
|
46
38
|
|
47
39
|
def email_intro
|
@@ -77,13 +69,7 @@ module Decidim
|
|
77
69
|
|
78
70
|
# Public: The Hash of options to pass to the I18.t method.
|
79
71
|
def i18n_options
|
80
|
-
default_i18n_options.merge(event_interpolations)
|
81
|
-
if value.is_a?(String)
|
82
|
-
decidim_html_escape(value)
|
83
|
-
else
|
84
|
-
value
|
85
|
-
end
|
86
|
-
end
|
72
|
+
default_i18n_options.merge(event_interpolations)
|
87
73
|
end
|
88
74
|
|
89
75
|
# Caches the path for the given resource when it is a Decidim::Component.
|
@@ -136,7 +122,7 @@ module Decidim
|
|
136
122
|
end
|
137
123
|
|
138
124
|
def participatory_space_title
|
139
|
-
|
125
|
+
decidim_sanitize_translated(participatory_space.try(:title))
|
140
126
|
end
|
141
127
|
end
|
142
128
|
end
|