decidim-core 0.20.1 → 0.21.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of decidim-core might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/assets/fonts/decidim/Roboto-Regular.eot +0 -0
- data/app/assets/fonts/decidim/Roboto-Regular.svg +10520 -0
- data/app/assets/fonts/decidim/Roboto-Regular.ttf +0 -0
- data/app/assets/fonts/decidim/Roboto-Regular.woff +0 -0
- data/app/assets/fonts/decidim/Roboto-Regular.woff2 +0 -0
- data/app/assets/images/decidim/brands/google.svg +1 -0
- data/app/assets/javascripts/decidim.js.es6 +5 -0
- data/app/assets/javascripts/decidim/check_boxes_tree.js.es6 +190 -0
- data/app/assets/javascripts/decidim/core/bundle.js +1 -1
- data/app/assets/javascripts/decidim/core/bundle.js.map +1 -1
- data/app/assets/javascripts/decidim/delayed.js.es6 +26 -0
- data/app/assets/javascripts/decidim/diff_mode_dropdown.js.es6 +25 -4
- data/app/assets/javascripts/decidim/form_filter.component.js.es6 +86 -38
- data/app/assets/javascripts/decidim/form_filter.component.test.js +40 -6
- data/app/assets/javascripts/decidim/history.js.es6 +16 -1
- data/app/assets/javascripts/decidim/vizzs/orgchart.js.es6 +1 -1
- data/app/assets/stylesheets/decidim/_variables.scss +1 -1
- data/app/assets/stylesheets/decidim/extras/_results-per-page.scss +0 -1
- data/app/assets/stylesheets/decidim/modules/_buttons.scss +76 -3
- data/app/assets/stylesheets/decidim/modules/_comments.scss +78 -2
- data/app/assets/stylesheets/decidim/modules/_filters.scss +36 -2
- data/app/assets/stylesheets/decidim/modules/_layout.scss +13 -0
- data/app/assets/stylesheets/decidim/modules/_modules.scss +1 -0
- data/app/assets/stylesheets/decidim/modules/_navbar.scss +11 -5
- data/app/assets/stylesheets/decidim/modules/_process-stats.scss +53 -0
- data/app/assets/stylesheets/decidim/modules/_status-labels.scss +5 -0
- data/app/assets/stylesheets/decidim/modules/_tags.scss +7 -1
- data/app/assets/stylesheets/decidim/modules/_typography.scss +49 -4
- data/app/assets/stylesheets/decidim/utils/_fontface.scss +10 -0
- data/app/assets/stylesheets/decidim/utils/_toggle-expand.scss +14 -0
- data/app/cells/decidim/activity/show.erb +1 -1
- data/app/cells/decidim/author/profile_inline.erb +2 -2
- data/app/cells/decidim/diff/attribute.erb +15 -5
- data/app/cells/decidim/diff/diff_mode_html.erb +31 -0
- data/app/cells/decidim/diff/diff_split.erb +1 -1
- data/app/cells/decidim/diff/diff_unified.erb +1 -1
- data/app/cells/decidim/diff/show.erb +1 -0
- data/app/cells/decidim/diff_cell.rb +21 -8
- data/app/cells/decidim/follow_button/show.erb +20 -7
- data/app/cells/decidim/navbar_admin_link/show.erb +6 -0
- data/app/cells/decidim/navbar_admin_link_cell.rb +43 -0
- data/app/cells/decidim/tags_cell.rb +2 -2
- data/app/commands/decidim/amendable/accept.rb +9 -4
- data/app/commands/decidim/amendable/publish_draft.rb +5 -0
- data/app/commands/decidim/amendable/reject.rb +5 -0
- data/app/commands/decidim/amendable/withdraw.rb +3 -12
- data/app/commands/decidim/create_registration.rb +5 -6
- data/app/controllers/concerns/decidim/use_organization_time_zone.rb +32 -0
- data/app/controllers/decidim/application_controller.rb +3 -0
- data/app/controllers/decidim/components/base_controller.rb +1 -0
- data/app/controllers/decidim/data_portability_controller.rb +12 -19
- data/app/controllers/decidim/devise/omniauth_registrations_controller.rb +1 -1
- data/app/controllers/decidim/devise/registrations_controller.rb +1 -0
- data/app/controllers/decidim/scopes_controller.rb +41 -7
- data/app/forms/decidim/registration_form.rb +5 -0
- data/app/functions/decidim/core/component_finder_base.rb +33 -0
- data/app/functions/decidim/core/component_list.rb +38 -0
- data/app/functions/decidim/core/component_list_base.rb +61 -0
- data/app/functions/decidim/core/needs_api_filter_and_order.rb +52 -0
- data/app/functions/decidim/core/participatory_space_finder.rb +11 -0
- data/app/functions/decidim/core/participatory_space_finder_base.rb +29 -0
- data/app/functions/decidim/core/participatory_space_list.rb +11 -0
- data/app/functions/decidim/core/participatory_space_list_base.rb +34 -0
- data/app/helpers/decidim/amendments_helper.rb +27 -1
- data/app/helpers/decidim/application_helper.rb +31 -3
- data/app/helpers/decidim/categories_helper.rb +26 -0
- data/app/helpers/decidim/check_boxes_tree_helper.rb +115 -0
- data/app/helpers/decidim/omniauth_helper.rb +6 -13
- data/app/helpers/decidim/resource_versions_helper.rb +29 -0
- data/app/helpers/decidim/rich_text_editor_helper.rb +22 -0
- data/app/helpers/decidim/sanitize_helper.rb +3 -1
- data/app/helpers/decidim/scopes_helper.rb +3 -2
- data/app/jobs/decidim/data_portability_export_job.rb +18 -10
- data/app/jobs/decidim/export_job.rb +1 -1
- data/app/mailers/decidim/export_mailer.rb +9 -5
- data/app/models/decidim/omniauth_provider.rb +28 -0
- data/app/models/decidim/organization.rb +41 -0
- data/app/models/decidim/participatory_space_role_config/admin.rb +8 -0
- data/app/models/decidim/participatory_space_role_config/base.rb +31 -0
- data/app/models/decidim/participatory_space_role_config/collaborator.rb +8 -0
- data/app/models/decidim/participatory_space_role_config/moderator.rb +11 -0
- data/app/models/decidim/participatory_space_role_config/null_object.rb +11 -0
- data/app/models/decidim/participatory_space_role_config/participatory_space_admin.rb +8 -0
- data/app/models/decidim/participatory_space_role_config/valuator.rb +11 -0
- data/app/models/decidim/scope.rb +4 -2
- data/app/models/decidim/user.rb +19 -3
- data/app/presenters/decidim/home_stats_presenter.rb +5 -2
- data/app/presenters/decidim/resource_locator_presenter.rb +9 -0
- data/app/serializers/decidim/exporters/participatory_space_components_serializer.rb +1 -1
- data/app/serializers/decidim/importers/participatory_space_components_importer.rb +14 -5
- data/app/services/decidim/data_portability_exporter.rb +72 -0
- data/app/services/decidim/resource_search.rb +29 -13
- data/app/services/decidim/zip_stream/zip_stream_writer.rb +56 -0
- data/app/types/decidim/core/amendment_type.rb +26 -0
- data/app/types/decidim/core/area_api_type.rb +16 -0
- data/app/types/decidim/core/area_type_type.rb +14 -0
- data/app/types/decidim/core/base_input_filter.rb +8 -0
- data/app/types/decidim/core/base_input_sort.rb +22 -0
- data/app/types/decidim/core/component_input_filter.rb +50 -0
- data/app/types/decidim/core/component_input_sort.rb +32 -0
- data/app/types/decidim/core/fingerprint_type.rb +15 -0
- data/app/types/decidim/core/has_hastaggable_input_filter.rb +15 -0
- data/app/types/decidim/core/has_localized_input_filter.rb +21 -0
- data/app/types/decidim/core/has_localized_input_sort.rb +21 -0
- data/app/types/decidim/core/has_publishable_input_filter.rb +34 -0
- data/app/types/decidim/core/has_publishable_input_sort.rb +13 -0
- data/app/types/decidim/core/participatory_space_input_filter.rb +26 -0
- data/app/types/decidim/core/participatory_space_input_sort.rb +14 -0
- data/app/types/decidim/core/participatory_space_link_type.rb +24 -0
- data/app/types/decidim/core/trace_version_type.rb +29 -0
- data/app/uploaders/decidim/data_portability_uploader.rb +2 -7
- data/app/validators/time_zone_validator.rb +10 -0
- data/app/views/decidim/amendments/_edit_form_fields.html.erb +5 -13
- data/app/views/decidim/amendments/preview_draft.html.erb +1 -1
- data/app/views/decidim/devise/shared/_omniauth_buttons.html.erb +10 -12
- data/app/views/decidim/devise/shared/_omniauth_buttons_mini.html.erb +6 -8
- data/app/views/decidim/export_mailer/data_portability_export.html.erb +2 -2
- data/app/views/decidim/scopes/picker.html.erb +7 -3
- data/app/views/decidim/shared/_check_boxes_tree.html.erb +54 -0
- data/app/views/decidim/shared/_extended_navigation_bar.html.erb +1 -1
- data/app/views/decidim/widgets/show.html.erb +4 -0
- data/app/views/layouts/decidim/_admin_links.html.erb +2 -0
- data/app/views/layouts/decidim/_wrapper.html.erb +4 -3
- data/app/views/layouts/decidim/widget.html.erb +1 -43
- data/config/initializers/browser.rb +5 -0
- data/config/initializers/devise.rb +0 -22
- data/config/initializers/omniauth.rb +50 -0
- data/config/locales/ar.yml +6 -3
- data/config/locales/ca.yml +15 -6
- data/config/locales/cs.yml +12 -3
- data/config/locales/de.yml +5 -3
- data/config/locales/el-GR.yml +0 -2
- data/config/locales/el.yml +153 -0
- data/config/locales/en.yml +16 -7
- data/config/locales/eo-UY.yml +2 -2
- data/config/locales/es-MX.yml +12 -3
- data/config/locales/es-PY.yml +12 -3
- data/config/locales/es.yml +15 -6
- data/config/locales/eu.yml +4 -3
- data/config/locales/fi-plain.yml +12 -3
- data/config/locales/fi.yml +12 -3
- data/config/locales/fr.yml +5 -3
- data/config/locales/gl.yml +4 -3
- data/config/locales/hu.yml +12 -3
- data/config/locales/id-ID.yml +4 -3
- data/config/locales/it.yml +11 -3
- data/config/locales/nl.yml +8 -3
- data/config/locales/no.yml +12 -3
- data/config/locales/pl.yml +4 -3
- data/config/locales/pt-BR.yml +4 -3
- data/config/locales/pt.yml +4 -3
- data/config/locales/ru.yml +5 -3
- data/config/locales/sv.yml +5 -3
- data/config/locales/tr-TR.yml +4 -3
- data/config/locales/uk.yml +1 -3
- data/db/migrate/20191113092826_add_omniauth_settings_to_decidim_organization.rb +7 -0
- data/db/migrate/20191113144432_add_rich_text_editor_in_public_views_to_organizations.rb +10 -0
- data/db/migrate/20191118123154_add_admin_terms_of_use_body_field_to_organization.rb +9 -0
- data/db/migrate/20200107142226_add_organization_timezone.rb +7 -0
- data/db/seeds.rb +2 -1
- data/lib/decidim/amendable.rb +7 -4
- data/lib/decidim/api/amendable_entity_interface.rb +18 -0
- data/lib/decidim/api/amendable_interface.rb +18 -0
- data/lib/decidim/api/attachable_interface.rb +1 -1
- data/lib/decidim/api/categorizable_interface.rb +1 -1
- data/lib/decidim/api/coauthorable_interface.rb +29 -0
- data/lib/decidim/api/fingerprint_interface.rb +13 -0
- data/lib/decidim/api/participatory_space_interface.rb +9 -9
- data/lib/decidim/api/participatory_space_resourceable_interface.rb +21 -0
- data/lib/decidim/api/scopable_interface.rb +1 -1
- data/lib/decidim/api/timestamps_interface.rb +21 -0
- data/lib/decidim/api/traceable_interface.rb +14 -0
- data/lib/decidim/coauthorable.rb +9 -2
- data/lib/decidim/component_manifest.rb +1 -1
- data/lib/decidim/content_processor.rb +4 -2
- data/lib/decidim/content_renderers/link_renderer.rb +1 -1
- data/lib/decidim/core.rb +3 -3
- data/lib/decidim/core/api.rb +7 -0
- data/lib/decidim/core/test.rb +1 -0
- data/lib/decidim/core/test/factories.rb +16 -0
- data/lib/decidim/core/test/shared_examples/amendable_interface_examples.rb +14 -0
- data/lib/decidim/core/test/shared_examples/amendable_proposals_interface_examples.rb +50 -0
- data/lib/decidim/core/test/shared_examples/authorable_interface_examples.rb +3 -0
- data/lib/decidim/core/test/shared_examples/coauthorable_interface_examples.rb +60 -0
- data/lib/decidim/core/test/shared_examples/comments_examples.rb +8 -8
- data/lib/decidim/core/test/shared_examples/fingerprintable_interface_examples.rb +17 -0
- data/lib/decidim/core/test/shared_examples/follows_examples.rb +16 -0
- data/lib/decidim/core/test/shared_examples/input_filter_examples.rb +118 -0
- data/lib/decidim/core/test/shared_examples/input_sort_examples.rb +105 -0
- data/lib/decidim/core/test/shared_examples/participatory_space_resourcable_interface_examples.rb +43 -0
- data/lib/decidim/core/test/shared_examples/rich_text_editor_examples.rb +59 -0
- data/lib/decidim/core/test/shared_examples/timestamps_interface_examples.rb +21 -0
- data/lib/decidim/core/test/shared_examples/traceable_interface_examples.rb +47 -0
- data/lib/decidim/core/version.rb +1 -1
- data/lib/decidim/deprecations.rb +19 -0
- data/lib/decidim/diffy_extension.rb +26 -0
- data/lib/decidim/exporters/export_manifest.rb +6 -2
- data/lib/decidim/filter_form_builder.rb +25 -7
- data/lib/decidim/form_builder.rb +2 -2
- data/lib/decidim/has_settings.rb +10 -4
- data/lib/decidim/participatory_space_manifest.rb +20 -0
- data/lib/decidim/participatory_space_resourceable.rb +35 -1
- data/lib/decidim/query_extensions.rb +9 -23
- data/lib/decidim/scopable.rb +10 -0
- data/lib/tasks/decidim_data_portability_tasks.rake +66 -5
- data/lib/tasks/decidim_metrics_tasks.rake +18 -7
- data/vendor/assets/javascripts/datepicker-locales/foundation-datepicker.el.js +14 -0
- metadata +142 -16
- data/app/models/decidim/participatory_process_user_role.rb +0 -32
- data/app/views/layouts/decidim/_edit_link.html.erb +0 -8
- data/lib/decidim/data_portability_file_reader.rb +0 -56
- data/lib/decidim/data_portability_file_zipper.rb +0 -67
data/lib/decidim/core/api.rb
CHANGED
@@ -6,9 +6,16 @@ module Decidim
|
|
6
6
|
autoload :ComponentInterface, "decidim/api/component_interface"
|
7
7
|
autoload :AuthorInterface, "decidim/api/author_interface"
|
8
8
|
autoload :AuthorableInterface, "decidim/api/authorable_interface"
|
9
|
+
autoload :CoauthorableInterface, "decidim/api/coauthorable_interface"
|
9
10
|
autoload :CategorizableInterface, "decidim/api/categorizable_interface"
|
10
11
|
autoload :ScopableInterface, "decidim/api/scopable_interface"
|
11
12
|
autoload :AttachableInterface, "decidim/api/attachable_interface"
|
12
13
|
autoload :HashtagInterface, "decidim/api/hashtag_interface"
|
14
|
+
autoload :ParticipatorySpaceResourceableInterface, "decidim/api/participatory_space_resourceable_interface"
|
15
|
+
autoload :FingerprintInterface, "decidim/api/fingerprint_interface"
|
16
|
+
autoload :AmendableInterface, "decidim/api/amendable_interface"
|
17
|
+
autoload :AmendableEntityInterface, "decidim/api/amendable_entity_interface"
|
18
|
+
autoload :TraceableInterface, "decidim/api/traceable_interface"
|
19
|
+
autoload :TimestampsInterface, "decidim/api/timestamps_interface"
|
13
20
|
end
|
14
21
|
end
|
data/lib/decidim/core/test.rb
CHANGED
@@ -46,3 +46,4 @@ require "decidim/core/test/shared_examples/uncommentable_component_examples"
|
|
46
46
|
require "decidim/core/test/shared_examples/searchable_resources_shared_context"
|
47
47
|
require "decidim/core/test/shared_examples/searchable_participatory_space_examples"
|
48
48
|
require "decidim/core/test/shared_examples/has_private_users"
|
49
|
+
require "decidim/core/test/shared_examples/rich_text_editor_examples"
|
@@ -69,6 +69,7 @@ FactoryBot.define do
|
|
69
69
|
factory :organization, class: "Decidim::Organization" do
|
70
70
|
name { Faker::Company.unique.name }
|
71
71
|
reference_prefix { Faker::Name.suffix }
|
72
|
+
time_zone { "UTC" }
|
72
73
|
twitter_handler { Faker::Hipster.word }
|
73
74
|
facebook_handler { Faker::Hipster.word }
|
74
75
|
instagram_handler { Faker::Hipster.word }
|
@@ -88,6 +89,7 @@ FactoryBot.define do
|
|
88
89
|
badges_enabled { true }
|
89
90
|
user_groups_enabled { true }
|
90
91
|
send_welcome_notification { true }
|
92
|
+
admin_terms_of_use_body { Decidim::Faker::Localized.wrapped("<p>", "</p>") { generate_localized_title } }
|
91
93
|
force_users_to_authenticate_before_access_organization { false }
|
92
94
|
smtp_settings do
|
93
95
|
{
|
@@ -130,12 +132,18 @@ FactoryBot.define do
|
|
130
132
|
deleted_at { Time.current }
|
131
133
|
end
|
132
134
|
|
135
|
+
trait :admin_terms_accepted do
|
136
|
+
admin_terms_accepted_at { Time.current }
|
137
|
+
end
|
138
|
+
|
133
139
|
trait :admin do
|
134
140
|
admin { true }
|
141
|
+
admin_terms_accepted
|
135
142
|
end
|
136
143
|
|
137
144
|
trait :user_manager do
|
138
145
|
roles { ["user_manager"] }
|
146
|
+
admin_terms_accepted
|
139
147
|
end
|
140
148
|
|
141
149
|
trait :managed do
|
@@ -325,6 +333,14 @@ FactoryBot.define do
|
|
325
333
|
}
|
326
334
|
end
|
327
335
|
|
336
|
+
trait :with_one_step do
|
337
|
+
step_settings do
|
338
|
+
{
|
339
|
+
1 => { dummy_step_setting: true }
|
340
|
+
}
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
328
344
|
trait :unpublished do
|
329
345
|
published_at { nil }
|
330
346
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
shared_examples_for "amendable interface" do
|
6
|
+
describe "amendments" do
|
7
|
+
let(:query) { "{ amendments { id } }" }
|
8
|
+
|
9
|
+
it "includes the amendments id" do
|
10
|
+
amendments_ids = response["amendments"].map { |amendment| amendment["id"].to_i }
|
11
|
+
expect(amendments_ids).to include(*model.amendments.map(&:id))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
shared_examples_for "amendable proposals interface" do
|
6
|
+
describe "amendments" do
|
7
|
+
let(:query) do
|
8
|
+
"{ amendments {
|
9
|
+
state
|
10
|
+
amendable { ...on Proposal { title } }
|
11
|
+
amendableType
|
12
|
+
emendation { ...on Proposal { title } }
|
13
|
+
emendationType
|
14
|
+
amender { name }
|
15
|
+
} }"
|
16
|
+
end
|
17
|
+
|
18
|
+
it "includes the amendments states" do
|
19
|
+
amendments_states = response["amendments"].map { |amendment| amendment["state"] }
|
20
|
+
expect(amendments_states).to include(*model.amendments.map(&:state))
|
21
|
+
end
|
22
|
+
|
23
|
+
it "amendable types matches Proposals Type" do
|
24
|
+
response["amendments"].each do |amendment|
|
25
|
+
expect(amendment["amendableType"]).to eq("Decidim::Proposals::Proposal")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "emendation types matches Proposals Type" do
|
30
|
+
response["amendments"].each do |amendment|
|
31
|
+
expect(amendment["emendationType"]).to eq("Decidim::Proposals::Proposal")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "returns amendable as parent proposal" do
|
36
|
+
amendment_amendables = response["amendments"].map { |amendment| amendment["amendable"] }
|
37
|
+
expect(amendment_amendables).to include(*model.amendments.map(&:amendable).map { |p| { "title" => p.title } })
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns emendations received" do
|
41
|
+
amendment_emendations = response["amendments"].map { |amendment| amendment["emendation"] }
|
42
|
+
expect(amendment_emendations).to include(*model.amendments.map(&:emendation).map { |p| { "title" => p.title } })
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns amender as emendation author" do
|
46
|
+
amendment_amenders = response["amendments"].map { |amendment| amendment["amender"] }
|
47
|
+
expect(amendment_amenders).to include(*model.amendments.map(&:amender).map { |p| { "name" => p.name } })
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -27,5 +27,65 @@ shared_examples_for "coauthorable interface" do
|
|
27
27
|
expect(response["author"]["name"]).to eq(user_group.name)
|
28
28
|
end
|
29
29
|
end
|
30
|
+
|
31
|
+
describe "with a several coauthors" do
|
32
|
+
let(:query) { "{ author { name } authors { name } authorsCount }" }
|
33
|
+
let(:coauthor) { create(:user, :confirmed, organization: model.participatory_space.organization) }
|
34
|
+
|
35
|
+
before do
|
36
|
+
model.add_coauthor coauthor
|
37
|
+
model.save!
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when both are users" do
|
41
|
+
it "returns 2 total co-authors" do
|
42
|
+
expect(response["authorsCount"]).to eq(2)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "returns an array of authors" do
|
46
|
+
expect(response["authors"].count).to eq(2)
|
47
|
+
expect(response["authors"]).to include("name" => author.name)
|
48
|
+
expect(response["authors"]).to include("name" => coauthor.name)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "returns a main author" do
|
52
|
+
expect(response["author"]["name"]).to eq(author.name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when author is the organization" do
|
57
|
+
let(:model) { create(:proposal, :official, component: component) }
|
58
|
+
|
59
|
+
it "returns 2 total co-authors" do
|
60
|
+
expect(response["authorsCount"]).to eq(2)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "returns 1 author in authors array" do
|
64
|
+
expect(response["authors"].count).to eq(1)
|
65
|
+
expect(response["authors"]).to include("name" => coauthor.name)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "do not return a main author" do
|
69
|
+
expect(response["author"]).to eq(nil)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when author is a meeting" do
|
74
|
+
let(:model) { create(:proposal, :official_meeting, component: component) }
|
75
|
+
|
76
|
+
it "returns 2 total co-authors" do
|
77
|
+
expect(response["authorsCount"]).to eq(2)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "returns 1 author in authors array" do
|
81
|
+
expect(response["authors"].count).to eq(1)
|
82
|
+
expect(response["authors"]).to include("name" => coauthor.name)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "do not return a main author" do
|
86
|
+
expect(response["author"]).to eq(nil)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
30
90
|
end
|
31
91
|
end
|
@@ -9,7 +9,7 @@ shared_examples "comments" do
|
|
9
9
|
switch_to_host(organization.host)
|
10
10
|
end
|
11
11
|
|
12
|
-
it "shows the list of comments for the
|
12
|
+
it "shows the list of comments for the resource" do
|
13
13
|
visit resource_path
|
14
14
|
|
15
15
|
expect(page).to have_selector("#comments")
|
@@ -64,7 +64,7 @@ shared_examples "comments" do
|
|
64
64
|
end
|
65
65
|
|
66
66
|
it "shows comment to the user" do
|
67
|
-
expect(page).to have_comment_from(user, "This is a new comment")
|
67
|
+
expect(page).to have_comment_from(user, "This is a new comment", wait: 20)
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -86,7 +86,7 @@ shared_examples "comments" do
|
|
86
86
|
click_button "Send"
|
87
87
|
end
|
88
88
|
|
89
|
-
expect(page).to have_comment_from(user_group, "This is a new comment")
|
89
|
+
expect(page).to have_comment_from(user_group, "This is a new comment", wait: 20)
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
@@ -110,7 +110,7 @@ shared_examples "comments" do
|
|
110
110
|
click_button "Send"
|
111
111
|
end
|
112
112
|
|
113
|
-
expect(page).to have_selector(".comment-thread .comment--nested")
|
113
|
+
expect(page).to have_selector(".comment-thread .comment--nested", wait: 20)
|
114
114
|
expect(page).to have_selector(".comment__additionalreply")
|
115
115
|
expect(page).to have_reply_to(comment, "This is a reply")
|
116
116
|
end
|
@@ -150,7 +150,7 @@ shared_examples "comments" do
|
|
150
150
|
end
|
151
151
|
|
152
152
|
within "#comments" do
|
153
|
-
expect(page).to have_selector "span.success.label", text: "In favor"
|
153
|
+
expect(page).to have_selector "span.success.label", text: "In favor", wait: 20
|
154
154
|
end
|
155
155
|
else
|
156
156
|
expect(page).to have_no_selector(".opinion-toggle--ok")
|
@@ -247,7 +247,7 @@ shared_examples "comments" do
|
|
247
247
|
let(:content) { "A valid user mention: @#{mentioned_user.nickname}." }
|
248
248
|
|
249
249
|
it "replaces the mention with a link to the user's profile" do
|
250
|
-
expect(page).to have_comment_from(user, "A valid user mention: @#{mentioned_user.nickname}")
|
250
|
+
expect(page).to have_comment_from(user, "A valid user mention: @#{mentioned_user.nickname}", wait: 20)
|
251
251
|
expect(page).to have_link "@#{mentioned_user.nickname}", href: "/profiles/#{mentioned_user.nickname}"
|
252
252
|
end
|
253
253
|
end
|
@@ -257,7 +257,7 @@ shared_examples "comments" do
|
|
257
257
|
let(:content) { "This text mentions a user outside current organization: @#{mentioned_user.nickname}" }
|
258
258
|
|
259
259
|
it "ignores the mention" do
|
260
|
-
expect(page).to have_comment_from(user, "This text mentions a user outside current organization: @#{mentioned_user.nickname}")
|
260
|
+
expect(page).to have_comment_from(user, "This text mentions a user outside current organization: @#{mentioned_user.nickname}", wait: 20)
|
261
261
|
expect(page).not_to have_link "@#{mentioned_user.nickname}"
|
262
262
|
end
|
263
263
|
end
|
@@ -266,7 +266,7 @@ shared_examples "comments" do
|
|
266
266
|
let(:content) { "This text mentions a @nonexistent user" }
|
267
267
|
|
268
268
|
it "ignores the mention" do
|
269
|
-
expect(page).to have_comment_from(user, "This text mentions a @nonexistent user")
|
269
|
+
expect(page).to have_comment_from(user, "This text mentions a @nonexistent user", wait: 20)
|
270
270
|
expect(page).not_to have_link "@nonexistent"
|
271
271
|
end
|
272
272
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
shared_examples_for "fingerprintable interface" do
|
6
|
+
describe "fingerprint" do
|
7
|
+
let(:query) { "{ fingerprint { value source } }" }
|
8
|
+
|
9
|
+
it "returns the fingerprint value" do
|
10
|
+
expect(response["fingerprint"]["value"]).to eq(model.fingerprint.value)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns the fingerprint source" do
|
14
|
+
expect(response["fingerprint"]["source"]).to eq(model.fingerprint.source)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -34,4 +34,20 @@ shared_examples "follows" do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
|
+
|
38
|
+
context "when the user is following the followable's participatory space" do
|
39
|
+
before do
|
40
|
+
create(:follow, followable: followable.participatory_space, user: user)
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when user clicks the Follow button" do
|
44
|
+
it "makes the user follow the followable" do
|
45
|
+
visit resource_locator(followable).path
|
46
|
+
expect do
|
47
|
+
click_button "Already following the participatory space"
|
48
|
+
expect(page).to have_content "Stop following"
|
49
|
+
end.to change(Decidim::Follow, :count).by(1)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
37
53
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
shared_examples_for "collection has before/since input filter" do |collection, field|
|
4
|
+
context "when date is before the past" do
|
5
|
+
let(:query) { %[{ #{collection}(filter: {#{field}Before: "#{2.days.ago.to_date}"}) { id } }] }
|
6
|
+
|
7
|
+
it "finds nothing" do
|
8
|
+
ids = response[collection].map { |item| item["id"] }
|
9
|
+
expect(ids).to eq([])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context "when date is before the future" do
|
14
|
+
let(:query) { %[{ #{collection}(filter: {#{field}Before: "#{2.days.from_now.to_date}"}) { id } }] }
|
15
|
+
|
16
|
+
it "finds the models " do
|
17
|
+
ids = response[collection].map { |item| item["id"] }
|
18
|
+
expect(ids).to match_array(models.map(&:id).map(&:to_s))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when date is after the future" do
|
23
|
+
let(:query) { %[{ #{collection}(filter: {#{field}Since: "#{2.days.from_now.to_date}"}) { id } }] }
|
24
|
+
|
25
|
+
it "finds nothing " do
|
26
|
+
ids = response[collection].map { |item| item["id"] }
|
27
|
+
expect(ids).to eq([])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when date is after the past" do
|
32
|
+
let(:query) { %[{ #{collection}(filter: {#{field}Since: "#{2.days.ago.to_date}"}) { id } }] }
|
33
|
+
|
34
|
+
it "finds the models " do
|
35
|
+
ids = response[collection].map { |item| item["id"] }
|
36
|
+
expect(ids).to match_array(models.map(&:id).map(&:to_s))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
shared_examples_for "connection has before/since input filter" do |connection, field|
|
42
|
+
context "when date is before the past" do
|
43
|
+
let(:query) { %[{ #{connection}(filter: {#{field}Before: "#{2.days.ago.to_date}"}) { edges { node { id } } } }] }
|
44
|
+
|
45
|
+
it "finds nothing" do
|
46
|
+
ids = response[connection]["edges"].map { |edge| edge["node"]["id"] }
|
47
|
+
expect(ids).to eq([])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when date is before the future" do
|
52
|
+
let(:query) { %[{ #{connection}(filter: {#{field}Before: "#{2.days.from_now.to_date}"}) { edges { node { id } } } }] }
|
53
|
+
|
54
|
+
it "finds the models " do
|
55
|
+
ids = response[connection]["edges"].map { |edge| edge["node"]["id"] }
|
56
|
+
expect(ids).to match_array(models.map(&:id).map(&:to_s))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when date is after the future" do
|
61
|
+
let(:query) { %[{ #{connection}(filter: {#{field}Since: "#{2.days.from_now.to_date}"}) { edges { node { id } } } }] }
|
62
|
+
|
63
|
+
it "finds nothing " do
|
64
|
+
ids = response[connection]["edges"].map { |edge| edge["node"]["id"] }
|
65
|
+
expect(ids).to eq([])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when date is after the past" do
|
70
|
+
let(:query) { %[{ #{connection}(filter: {#{field}Since: "#{2.days.ago.to_date}"}) { edges { node { id } } } }] }
|
71
|
+
|
72
|
+
it "finds the models " do
|
73
|
+
ids = response[connection]["edges"].map { |edge| edge["node"]["id"] }
|
74
|
+
expect(ids).to match_array(models.map(&:id).map(&:to_s))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
shared_examples_for "collection has hashtag input filter" do |collection|
|
80
|
+
let(:query) { %[{ #{collection}(filter: { hashtag: "#{hashtag}" }) { id }}] }
|
81
|
+
|
82
|
+
before do
|
83
|
+
models.first.hashtag = "#someWeirdHashtag"
|
84
|
+
models.first.save!
|
85
|
+
models.second.hashtag = "#anotherWeirdHashtag"
|
86
|
+
models.second.save!
|
87
|
+
end
|
88
|
+
|
89
|
+
context "when hashtag starts with #" do
|
90
|
+
let(:hashtag) { "#someWeirdHashtag" }
|
91
|
+
|
92
|
+
it "finds the model" do
|
93
|
+
ids = response[collection].map { |item| item["id"] }
|
94
|
+
expect(ids).to include(models.first.id.to_s)
|
95
|
+
expect(ids).not_to include(models.second.id.to_s)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "when hashtag starts without #" do
|
100
|
+
let(:hashtag) { "anotherWeirdHashtag" }
|
101
|
+
|
102
|
+
it "finds the model" do
|
103
|
+
ids = response[collection].map { |item| item["id"] }
|
104
|
+
expect(ids).not_to include(models.first.id.to_s)
|
105
|
+
expect(ids).to include(models.second.id.to_s)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "when hashtag is different" do
|
110
|
+
let(:hashtag) { "someEvenWeirderHashtag" }
|
111
|
+
|
112
|
+
it "does not find the model" do
|
113
|
+
ids = response[collection].map { |item| item["id"] }
|
114
|
+
expect(ids).not_to include(models.first.id.to_s)
|
115
|
+
expect(ids).not_to include(models.second.id.to_s)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
shared_examples_for "collection has input sort" do |collection, field|
|
4
|
+
describe "ASC" do
|
5
|
+
let(:query) { %[{ #{collection}(order: {#{field}: "ASC"}) { id } }] }
|
6
|
+
|
7
|
+
it "returns expected order" do
|
8
|
+
ids = response[collection].map { |item| item["id"] }
|
9
|
+
replies_ids = models.sort_by(&field.underscore.to_sym).map(&:id).map(&:to_s)
|
10
|
+
expect(ids).to eq(replies_ids)
|
11
|
+
expect(ids).not_to eq(replies_ids.reverse)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "DESC" do
|
16
|
+
let(:query) { %[{ #{collection}(order: {#{field}: "DESC"}) { id } }] }
|
17
|
+
|
18
|
+
it "returns reversed order" do
|
19
|
+
ids = response[collection].map { |item| item["id"] }
|
20
|
+
replies_ids = models.sort_by(&field.underscore.to_sym).map(&:id).map(&:to_s)
|
21
|
+
expect(ids).not_to eq(replies_ids)
|
22
|
+
expect(ids).to eq(replies_ids.reverse)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
shared_examples_for "collection has i18n input sort" do |collection, field|
|
28
|
+
context "when locale is not specified" do
|
29
|
+
describe "ASC" do
|
30
|
+
let(:query) { %[{ #{collection}(order: { #{field}: "ASC" }) { id } }] }
|
31
|
+
|
32
|
+
it "returns alphabetical order" do
|
33
|
+
response_ids = response[collection].map { |item| item["id"].to_i }
|
34
|
+
ids = models.sort_by { |item| item.public_send(field.to_sym)[current_organization.default_locale] }.map { |item| item.id.to_i }
|
35
|
+
expect(response_ids).to eq(ids)
|
36
|
+
expect(response_ids).not_to eq(ids.reverse)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "DESC" do
|
41
|
+
let(:query) { %[{ #{collection}(order: { #{field}: "DESC" }) { id } }] }
|
42
|
+
|
43
|
+
it "returns revered alphabetical order" do
|
44
|
+
response_ids = response[collection].map { |item| item["id"].to_i }
|
45
|
+
ids = models.sort_by { |item| item.public_send(field.to_sym)[current_organization.default_locale] }.map { |item| item.id.to_i }
|
46
|
+
expect(response_ids).not_to eq(ids)
|
47
|
+
expect(response_ids).to eq(ids.reverse)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when locale is specified" do
|
53
|
+
describe "ASC" do
|
54
|
+
let(:query) { %[{ #{collection}(order: { #{field}: "ASC", locale: "ca" }) { id } }] }
|
55
|
+
|
56
|
+
it "returns alphabetical order" do
|
57
|
+
response_ids = response[collection].map { |item| item["id"].to_i }
|
58
|
+
ids = models.sort_by { |item| item.public_send(field.to_sym)["ca"] }.map { |item| item.id.to_i }
|
59
|
+
expect(response_ids).to eq(ids)
|
60
|
+
expect(response_ids).not_to eq(ids.reverse)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "DESC" do
|
65
|
+
let(:query) { %[{ #{collection}(order: { #{field}: "DESC", locale: "ca" }) { id } }] }
|
66
|
+
|
67
|
+
it "returns revered alphabetical order" do
|
68
|
+
response_ids = response[collection].map { |item| item["id"].to_i }
|
69
|
+
ids = models.sort_by { |item| item.public_send(field.to_sym)["ca"] }.map { |item| item.id.to_i }
|
70
|
+
expect(response_ids).not_to eq(ids)
|
71
|
+
expect(response_ids).to eq(ids.reverse)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "when locale does not exist in the organization" do
|
76
|
+
let(:query) { %[{ #{collection}(order: { #{field}: "DESC", locale: "de" }) { id } }] }
|
77
|
+
|
78
|
+
it "returns all the component ordered" do
|
79
|
+
expect { response }.to raise_exception(Exception)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
shared_examples_for "connection has input sort" do |connection, field|
|
86
|
+
describe "ASC" do
|
87
|
+
let(:query) { %[{ #{connection}(order: {#{field}: "ASC"}) { edges { node { id } } } }] }
|
88
|
+
|
89
|
+
it "returns expected order" do
|
90
|
+
ids = response[connection]["edges"].map { |edge| edge["node"]["id"] }
|
91
|
+
replies_ids = models.sort_by(&field.underscore.to_sym).map(&:id).map(&:to_s)
|
92
|
+
expect(ids).to eq(replies_ids)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "DESC" do
|
97
|
+
let(:query) { %[{ #{connection}(order: {#{field}: "DESC"}) { edges { node { id } } } }] }
|
98
|
+
|
99
|
+
it "returns reversed order" do
|
100
|
+
ids = response[connection]["edges"].map { |edge| edge["node"]["id"] }
|
101
|
+
replies_ids = models.sort_by(&field.underscore.to_sym).map(&:id).map(&:to_s)
|
102
|
+
expect(ids).to eq(replies_ids.reverse)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|