diff --git a/Gemfile b/Gemfile index a33f8c0198..fbe02a049a 100644 --- a/Gemfile +++ b/Gemfile @@ -26,6 +26,7 @@ gem "decidim-category_enhanced", "~> 0.0.1" gem "decidim-cleaner" gem "decidim-custom_proposal_states", git: "https://github.com/alecslupu-pfa/decidim-module-custom_proposal_states", branch: DECIDIM_BRANCH gem "decidim-decidim_awesome", git: "https://github.com/decidim-ice/decidim-module-decidim_awesome", branch: DECIDIM_BRANCH +gem "decidim-emitter", git: "https://github.com/OpenSourcePolitics/decidim-module-emitter.git" gem "decidim-extended_socio_demographic_authorization_handler", git: "https://github.com/OpenSourcePolitics/decidim-module-extended_socio_demographic_authorization_handler.git", branch: DECIDIM_BRANCH gem "decidim-extra_user_fields", git: "https://github.com/OpenSourcePolitics/decidim-module-extra_user_fields.git", branch: "temp/twilio-compatibility-0.27" diff --git a/Gemfile.lock b/Gemfile.lock index 2364e94449..979cd98b7a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,6 +7,14 @@ GIT decidim-core (>= 0.27.0) deface (~> 1.5) +GIT + remote: https://github.com/OpenSourcePolitics/decidim-module-emitter.git + revision: 8633ea56b422eecfe7d8730c89f191387f860e55 + specs: + decidim-emitter (0.1.0) + decidim-core (~> 0.27.0) + decidim-participatory_processes (~> 0.27.0) + GIT remote: https://github.com/OpenSourcePolitics/decidim-module-extended_socio_demographic_authorization_handler.git revision: adec5e66cd07b5e5fdce5562453a7e8d6de88013 @@ -1179,6 +1187,7 @@ DEPENDENCIES decidim-custom_proposal_states! decidim-decidim_awesome! decidim-dev (~> 0.27.0) + decidim-emitter! decidim-extended_socio_demographic_authorization_handler! decidim-extra_user_fields! decidim-friendly_signup! diff --git a/app/views/decidim/participatory_processes/admin/participatory_processes/_form.html.erb b/app/views/decidim/participatory_processes/admin/participatory_processes/_form.html.erb new file mode 100644 index 0000000000..258a900133 --- /dev/null +++ b/app/views/decidim/participatory_processes/admin/participatory_processes/_form.html.erb @@ -0,0 +1,234 @@ +
+
+

<%= t(".title") %>

+
+ +
+
+ <%= form.translated :text_field, :title, autofocus: true %> +
+ +
+ <%= form.translated :text_field, :subtitle %> +
+ +
+ <%= form.number_field :weight %> +
+ +
+
+ <%= form.text_field :slug %> +

+ <%== t(".slug_help", url: decidim_form_slug_url(:processes, form.object.slug)) %> +

+
+ +
+ <%= form.text_field :hashtag %> +
+
+ +
+ <%= form.translated :editor, :short_description %> +
+ +
+ <%= form.translated :editor, :description, toolbar: :full, lines: 25 %> +
+ +
+ <%= form.translated :editor, :announcement %> +

<%== t(".announcement_help") %>

+
+
+ + <% if Decidim::Map.available?(:geocoding) %> +
+ <%= form.text_field :address %> +

<%== t(".address_help") %>

+
+ <% end %> + +
+

<%= t(".duration") %>

+
+ +
+
+
+ <%= form.date_field :start_date %> +
+ +
+ <%= form.date_field :end_date %> +
+
+
+ +
+

<%= t(".images") %>

+
+ +
+
+
+ <%= form.upload :hero_image %> +
+ +
+ <%= form.upload :banner_image %> +
+
+
+ +
+

<%= t(".metadata") %>

+
+ +
+
+
+ <%= form.translated :text_field, :developer_group %> +
+ +
+ <%= form.translated :text_field, :local_area %> +
+
+ +
+ <%= form.translated :text_field, :meta_scope %> +
+ +
+ <%= form.translated :text_field, :target %> +
+ +
+ <%= form.translated :text_field, :participatory_scope %> +
+ +
+ <%= form.translated :text_field, :participatory_structure %> +
+
+ +
+

<%= t(".filters") %>

+
+ +
+
+ <%= form.check_box :scopes_enabled %> +
+ +
+ <%= scopes_picker_field form, :scope_id, root: nil %> + +
+ <%= form.collection_select :scope_type_max_depth_id, + organization_scope_depths, + :id, + :name, + scope_type_depth_select_options, + scope_type_depth_select_html_options %> +

+ <%== t(".scope_type_max_depth_help") %> +

+
+
+ +
+ <%= form.areas_select :area_id, + areas_for_select(current_organization), + selected: current_participatory_process.try(:decidim_area_id), + include_blank: t(".select_an_area") %> +
+
+ +
+

<%= t(".visbility") %>

+
+ +
+
+ <% if process_groups_for_select %> + <%= form.select :participatory_process_group_id, + process_groups_for_select, + include_blank: t(".select_process_group") %> + <% end %> +
+ +
+ <%= form.check_box :private_space %> +
+
+ <%= form.check_box :promoted %> +
+
+ +
+

<%= t(".emitter") %>

+
+ +
+
+ <%= form.select :emitter_select, options_for_select(emitter_options), { :include_blank => true, label: t(".emitter_logo_select") }, class: "select-emitter" %> +
+
+ +
+ <%= form.text_field :emitter_name_image, label: t(".emitter_name") %> +
+
+ <%= form.upload :emitter_image, label: t(".emitter_logo"), help_i18n_scope: "decidim.admin.forms.file_help.emitter" %> +
+ <% if form.object.emitter_name.present? %> +
+ <%= form.text_field :emitter_read_name, { :readonly => true, :label => t(".emitter_now") } %> +
+ <% end %> +
+ +
+

<%= t(".related_processes") %>

+
+ +
+
+ <%= form.select( + :related_process_ids, + @form.processes.order(title: :asc).map{|process| [translated_attribute(process.title), process.id]}, + { include_blank: true }, + { multiple: true, class: "chosen-select" } + ) %> +
+
+ +
+

<%= t(".other") %>

+
+ +
+
+ <%= form.check_box :show_statistics %> +
+ +
+ <%= form.check_box :show_metrics %> +
+ + <% if @form.participatory_process_types_for_select.present? %> +
+ <%= form.select( + :participatory_process_type_id, + @form.participatory_process_types_for_select, + include_blank: t(".select_participatory_process_type") + ) %> +
+ <% end %> +
+
+ +<%= javascript_pack_tag "decidim_participatory_processes_admin" %> \ No newline at end of file diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 7a81861781..db9522009e 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -119,6 +119,7 @@ ignore_missing: - decidim.term_customizer.admin.actions.* - decidim.term_customizer.admin.add_translations.index.* - decidim.term_customizer.admin.models.translations.fields.* + - decidim.participatory_processes.admin.participatory_processes.form.* # Consider these keys used: ignore_unused: diff --git a/config/initializers/half_signup.rb b/config/initializers/half_signup.rb index 29512c6406..33b729485b 100644 --- a/config/initializers/half_signup.rb +++ b/config/initializers/half_signup.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +return unless defined?(Decidim::HalfSignup) + Decidim::HalfSignup.configure do |config| config.show_tos_page_after_signup = Rails.application.secrets.dig(:decidim, :half_signup, :show_tos_page_after_signup) config.auth_code_length = 4 diff --git a/db/migrate/20241118114335_add_emitter_to_decidim_participatory_process.decidim_emitter.rb b/db/migrate/20241118114335_add_emitter_to_decidim_participatory_process.decidim_emitter.rb new file mode 100644 index 0000000000..ba525aa3c4 --- /dev/null +++ b/db/migrate/20241118114335_add_emitter_to_decidim_participatory_process.decidim_emitter.rb @@ -0,0 +1,14 @@ +# This migration comes from decidim_emitter (originally 20240417082337) +class AddEmitterToDecidimParticipatoryProcess < ActiveRecord::Migration[6.1] + def up + # Ensure that the column is a string and check if it exists + add_column :decidim_participatory_processes, :emitter, :string, if_not_exists: true + change_column :decidim_participatory_processes, :emitter, :string + + add_column :decidim_participatory_processes, :emitter_name, :text, if_not_exists: true + end + + def down + remove_column :decidim_participatory_processes, :emitter_name, if_exists: true + end +end diff --git a/db/schema.rb b/db/schema.rb index b817eee201..4432bd4822 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2024_10_28_094242) do +ActiveRecord::Schema.define(version: 2024_11_18_114335) do # These are extensions that must be enabled in order to support this database enable_extension "ltree" @@ -1518,6 +1518,8 @@ t.float "longitude" t.boolean "display_linked_assemblies", default: false t.bigint "decidim_participatory_process_type_id" + t.string "emitter" + t.text "emitter_name" t.index ["decidim_area_id"], name: "index_decidim_participatory_processes_on_decidim_area_id" t.index ["decidim_organization_id", "slug"], name: "index_unique_process_slug_and_organization", unique: true t.index ["decidim_organization_id"], name: "index_decidim_processes_on_decidim_organization_id" diff --git a/spec/factories.rb b/spec/factories.rb index febc0d8333..2c9271e1b1 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -4,6 +4,7 @@ require "decidim/proposals/test/factories" require "decidim/budgets/test/factories" require "decidim/debates/test/factories" +require "decidim/emitter/test/factories" require "decidim/meetings/test/factories" require "decidim/accountability/test/factories" require "decidim/system/test/factories" diff --git a/spec/shared/manage_processes_examples.rb b/spec/shared/manage_processes_examples.rb new file mode 100644 index 0000000000..b72c16f0a4 --- /dev/null +++ b/spec/shared/manage_processes_examples.rb @@ -0,0 +1,194 @@ +# frozen_string_literal: true + +shared_examples "manage processes examples" do + context "when viewing the processes list" do + let!(:process_group) { create(:participatory_process_group, organization: organization) } + let!(:process_with_group) { create(:participatory_process, organization: organization, participatory_process_group: process_group) } + let!(:process_without_group) { create(:participatory_process, organization: organization) } + let(:model_name) { participatory_process.class.model_name } + let(:resource_controller) { Decidim::ParticipatoryProcesses::Admin::ParticipatoryProcessesController } + + def filter_by_group(group_title) + visit current_path + within(".card-title") do + click_button("Process Groups") + click_link(group_title) + end + end + + it "allows the user to filter processes by process_group" do + filter_by_group(translated(process_group.title)) + + expect(page).to have_content(translated(process_with_group.title)) + expect(page).not_to have_content(translated(process_without_group.title)) + end + + describe "listing processes" do + it_behaves_like "filtering collection by published/unpublished" + it_behaves_like "filtering collection by private/public" + end + + context "when processes are filtered by process_group" do + before { filter_by_group(translated(process_group.title)) } + + it "allows the user to edit the process_group" do + click_link translated(process_group.title) + + expect(page).to have_content("Edit process group") + end + + describe "listing processes filtered by group" do + it_behaves_like "filtering collection by published/unpublished" do + let!(:published_space) { process_with_group } + let!(:unpublished_space) { create(:participatory_process, :unpublished, organization: organization, participatory_process_group: process_group) } + end + + it_behaves_like "filtering collection by private/public" do + let!(:public_space) { process_with_group } + let!(:private_space) { create(:participatory_process, :private, organization: organization, participatory_process_group: process_group) } + end + end + end + end + + context "when previewing processes" do + context "when the process is unpublished" do + let!(:participatory_process) { create(:participatory_process, :unpublished, organization: organization) } + + it "allows the user to preview the unpublished process" do + within find("tr", text: translated(participatory_process.title)) do + click_link "Preview" + end + + expect(page).to have_css(".process-header") + expect(page).to have_content(translated(participatory_process.title)) + end + end + + context "when the process is published" do + let!(:participatory_process) { create(:participatory_process, organization: organization) } + + it "allows the user to preview the published process" do + within find("tr", text: translated(participatory_process.title)) do + click_link "Preview" + end + + expect(page).to have_current_path decidim_participatory_processes.participatory_process_path(participatory_process) + expect(page).to have_content(translated(participatory_process.title)) + end + end + end + + context "when viewing a missing process" do + it_behaves_like "a 404 page" do + let(:target_path) { decidim_admin_participatory_processes.participatory_process_path(99_999_999) } + end + end + + context "when updating a participatory process" do + let(:image3_filename) { "city3.jpeg" } + let(:image3_path) { Decidim::Dev.asset(image3_filename) } + + before do + click_link translated(participatory_process.title) + end + + it "updates a participatory_process" do + fill_in_i18n( + :participatory_process_title, + "#participatory_process-title-tabs", + en: "My new title", + es: "Mi nuevo título", + ca: "El meu nou títol" + ) + dynamically_attach_file(:participatory_process_banner_image, image3_path, remove_before: true) + + page.execute_script("$('#participatory_process_end_date').focus()") + page.find(".datepicker-dropdown .day", text: "22").click + + within ".edit_participatory_process" do + find("*[type=submit]").click + end + + expect(page).to have_admin_callout("successfully") + + within ".container" do + expect(page).to have_selector("input[value='My new title']") + expect(page).to have_css("img[src*='#{image3_filename}']") + end + end + end + + context "when publishing a process" do + let!(:participatory_process) { create(:participatory_process, :unpublished, organization: organization) } + + before do + click_link translated(participatory_process.title) + end + + it "publishes the process" do + click_link "Publish" + expect(page).to have_content("successfully published") + expect(page).to have_content("Unpublish") + expect(page).to have_current_path decidim_admin_participatory_processes.edit_participatory_process_path(participatory_process) + + participatory_process.reload + expect(participatory_process).to be_published + end + end + + context "when unpublishing a process" do + let!(:participatory_process) { create(:participatory_process, organization: organization) } + + before do + click_link translated(participatory_process.title) + end + + it "unpublishes the process" do + click_link "Unpublish" + expect(page).to have_content("successfully unpublished") + expect(page).to have_content("Publish") + expect(page).to have_current_path decidim_admin_participatory_processes.edit_participatory_process_path(participatory_process) + + participatory_process.reload + expect(participatory_process).not_to be_published + end + end + + context "when there are multiple organizations in the system" do + let!(:external_participatory_process) { create(:participatory_process) } + + before do + visit decidim_admin_participatory_processes.participatory_processes_path + end + + it "doesn't let the admin manage processes form other organizations" do + within "table" do + expect(page).to have_no_content(external_participatory_process.title["en"]) + end + end + end + + context "when the process has a scope" do + let(:scope) { create(:scope, organization: organization) } + + before do + participatory_process.update!(scopes_enabled: true, scope: scope) + end + + it "disables the scope for a participatory process" do + click_link translated(participatory_process.title) + + uncheck :participatory_process_scopes_enabled + + expect(page).to have_selector("#participatory_process_scope_id.disabled") + expect(page).to have_selector("#participatory_process_scope_id .picker-values div input[disabled]", visible: :all) + + within ".edit_participatory_process" do + find("*[type=submit]").click + end + + expect(page).to have_admin_callout("successfully") + end + end +end diff --git a/spec/shared/participatory_process_administration_by_admin_shared_context.rb b/spec/shared/participatory_process_administration_by_admin_shared_context.rb new file mode 100644 index 0000000000..014fd52a16 --- /dev/null +++ b/spec/shared/participatory_process_administration_by_admin_shared_context.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +shared_context "when admin administrating a participatory process" do + let!(:user) do + create(:user, :admin, :confirmed, organization: organization) + end + include_context "when administrating a participatory process" +end diff --git a/spec/shared/participatory_process_administration_shared_context.rb b/spec/shared/participatory_process_administration_shared_context.rb new file mode 100644 index 0000000000..ff0cc89db9 --- /dev/null +++ b/spec/shared/participatory_process_administration_shared_context.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +shared_context "when administrating a participatory process" do + let(:organization) { create(:organization) } + let!(:participatory_process) { create(:participatory_process, organization: organization) } +end diff --git a/spec/system/admin/admin_manages_participatory_processes_spec.rb b/spec/system/admin/admin_manages_participatory_processes_spec.rb new file mode 100644 index 0000000000..ec97e30dbb --- /dev/null +++ b/spec/system/admin/admin_manages_participatory_processes_spec.rb @@ -0,0 +1,560 @@ +# frozen_string_literal: true + +require "spec_helper" +require "decidim/core/test/shared_examples/has_contextual_help" + +describe "Participatory Processes", type: :system do + let(:organization) { create(:organization) } + let(:show_metrics) { true } + let(:show_statistics) { true } + let(:hashtag) { true } + let(:base_description) { { en: "Description", ca: "Descripció", es: "Descripción" } } + let(:short_description) { { en: "Short description", ca: "Descripció curta", es: "Descripción corta" } } + let(:base_process) do + create( + :participatory_process, + :active, + organization: organization, + description: base_description, + short_description: short_description, + show_metrics: show_metrics, + show_statistics: show_statistics + ) + end + + before do + switch_to_host(organization.host) + end + + context "when there are no processes and directly accessing form URL" do + it_behaves_like "a 404 page" do + let(:target_path) { decidim_participatory_processes.participatory_processes_path } + end + end + + context "when there are no processes and accessing from the homepage" do + it "does not show the menu link" do + visit decidim.root_path + + within ".main-nav" do + expect(page).to have_no_content("Processes") + end + end + end + + context "when the process does not exist" do + it_behaves_like "a 404 page" do + let(:target_path) { decidim_participatory_processes.participatory_process_path(99_999_999) } + end + end + + context "when there are some processes and all are unpublished" do + before do + create(:participatory_process, :unpublished, organization: organization) + create(:participatory_process, :published) + end + + context "and directly accessing from URL" do + it_behaves_like "a 404 page" do + let(:target_path) { decidim_participatory_processes.participatory_processes_path } + end + end + + context "and accessing from the homepage" do + it "the menu link is not shown" do + visit decidim.root_path + + within ".main-nav" do + expect(page).to have_no_content("Processes") + end + end + end + end + + context "when there are some published processes" do + let!(:participatory_process) { base_process } + let!(:promoted_process) { create(:participatory_process, :promoted, organization: organization) } + let!(:unpublished_process) { create(:participatory_process, :unpublished, organization: organization) } + let!(:past_process) { create :participatory_process, :past, organization: organization } + let!(:upcoming_process) { create :participatory_process, :upcoming, organization: organization } + let!(:grouped_process) { create :participatory_process, organization: organization } + let!(:group) { create :participatory_process_group, participatory_processes: [grouped_process], organization: organization } + + it_behaves_like "shows contextual help" do + let(:index_path) { decidim_participatory_processes.participatory_processes_path } + let(:manifest_name) { :participatory_processes } + end + + it_behaves_like "editable content for admins" do + let(:target_path) { decidim_participatory_processes.participatory_processes_path } + end + + context "when requesting the processes path" do + before do + visit decidim_participatory_processes.participatory_processes_path + end + + it_behaves_like "accessible page" + + context "when emitter is defined", :slow do + context "when no emitter" do + it "doesn't displays logo or text" do + within "#participatory_process_#{promoted_process.id}" do + expect(page).not_to have_css(".emitter-header") + end + end + end + + context "when emitter" do + let(:base_process) do + create( + :participatory_process, + :active, + :with_emitter, + organization: organization, + description: { en: "Description", ca: "Descripció", es: "Descripción" }, + short_description: { en: "Short description", ca: "Descripció curta", es: "Descripción corta" }, + show_metrics: show_metrics, + show_statistics: show_statistics, + developer_group: { en: "Developer group" } + ) + end + + it "displays logo and text" do + within "#participatory_process_#{base_process.id}" do + within ".emitter-header" do + expect(page).to have_css("img", count: 1) + expect(page).to have_content("Consultation published by Developer group") + end + end + end + end + end + + context "and accessing from the homepage" do + it "the menu link is not shown" do + visit decidim.root_path + + within ".main-nav" do + expect(page).to have_content("Processes") + click_link "Processes" + end + + expect(page).to have_current_path decidim_participatory_processes.participatory_processes_path + end + end + + context "with highlighted processes" do + before do + promoted_process.title["en"] = "D'Artagnan #{promoted_process.title["en"]}" + promoted_process.save! + visit decidim_participatory_processes.participatory_processes_path + end + + it_behaves_like "accessible page" + + context "when emitter is defined", :slow do + context "when no emitter" do + it "doesn't displays logo or text" do + within "#participatory_process_#{promoted_process.id}" do + expect(page).not_to have_css(".emitter-header") + end + end + end + + context "when emitter" do + let(:base_process) do + create( + :participatory_process, + :active, + :with_emitter, + organization: organization, + description: { en: "Description", ca: "Descripció", es: "Descripción" }, + short_description: { en: "Short description", ca: "Descripció curta", es: "Descripción corta" }, + show_metrics: show_metrics, + show_statistics: show_statistics, + developer_group: { en: "Developer group" } + ) + end + + it "displays logo and text" do + within "#participatory_process_#{base_process.id}" do + within ".emitter-header" do + expect(page).to have_css("img", count: 1) + expect(page).to have_content("Consultation published by Developer group") + end + end + end + end + + it "lists all the highlighted processes" do + within "#highlighted-processes" do + expect(page).to have_content(translated(promoted_process.title, locale: :en)) + expect(page).to have_selector(".card--full", count: 1) + end + end + end + + it "lists the active processes" do + within "#processes-grid" do + within "#processes-grid h3" do + expect(page).to have_content("3 ACTIVE PROCESSES") + end + + expect(page).to have_content(translated(participatory_process.title, locale: :en)) + expect(page).to have_content(translated(promoted_process.title, locale: :en)) + expect(page).to have_content(translated(group.title, locale: :en)) + expect(page).to have_selector(".card", count: 3) + + expect(page).to have_no_content(translated(unpublished_process.title, locale: :en)) + expect(page).to have_no_content(translated(past_process.title, locale: :en)) + expect(page).to have_no_content(translated(upcoming_process.title, locale: :en)) + expect(page).to have_no_content(translated(grouped_process.title, locale: :en)) + end + end + + it "links to the individual process page" do + first(".card__link", text: translated(participatory_process.title, locale: :en)).click + + expect(page).to have_current_path decidim_participatory_processes.participatory_process_path(participatory_process) + end + + context "with active steps" do + let!(:step) { create(:participatory_process_step, participatory_process: participatory_process) } + let!(:active_step) do + create(:participatory_process_step, + :active, + participatory_process: participatory_process, + title: { en: "Active step", ca: "Fase activa", es: "Fase activa" }) + end + + it "links to the active step" do + visit decidim_participatory_processes.participatory_processes_path + + within find("#processes-grid .column", text: translated(participatory_process.title)) do + within ".card__footer" do + expect(page).to have_content("Current phase:\nActive step") + end + end + end + + context "when the active step has CTA text and url set" do + let(:cta_path) { "my_path" } + let(:cta_text) { { en: "Take action!", ca: "Take action!", es: "Take action!" } } + + before do + active_step.update!(cta_path: cta_path, cta_text: cta_text) + end + + it "shows a CTA button" do + visit decidim_participatory_processes.participatory_processes_path + + within "#participatory_process_#{participatory_process.id}" do + expect(page).to have_link("Take action!") + end + end + + context "when cta_text is empty in current locale" do + let(:cta_text) { { en: "", ca: "Take action!", es: "Take action!" } } + + it "displays the regular cta button" do + visit decidim_participatory_processes.participatory_processes_path + + within "#participatory_process_#{participatory_process.id}" do + expect(page).not_to have_link("Take action!") + expect(page).to have_link("More info") + end + end + end + + context "when process is promoted" do + let(:cta_text) { { en: "Take promoted action!", ca: "Take promoted action!", es: "Take promoted action!" } } + let!(:active_step) do + create(:participatory_process_step, + :active, + participatory_process: promoted_process, + title: { en: "Active step", ca: "Fase activa", es: "Fase activa" }) + end + + it "shows a CTA button" do + visit decidim_participatory_processes.participatory_processes_path + + within "#highlighted-processes" do + expect(page).to have_link("Take promoted action!") + end + end + end + + context "when user switch locale" do + before do + visit decidim_participatory_processes.participatory_processes_path + within_language_menu do + click_link "Català" + end + end + + it "displays the regular cta button" do + within "#participatory_process_#{participatory_process.id}" do + expect(page).to have_link("Take action!", href: "/processes/#{participatory_process.slug}/my_path") + end + end + end + end + end + + context "when there are promoted participatory process groups" do + let!(:promoted_group) { create(:participatory_process_group, :promoted, :with_participatory_processes, organization: organization) } + let(:promoted_items_titles) { page.all("#highlighted-processes .card__title").map(&:text) } + + before do + promoted_group.title["en"] = "D'Artagnan #{promoted_group.title["en"]}" + promoted_group.save! + visit decidim_participatory_processes.participatory_processes_path + end + + it "shows a highligted processes section" do + expect(page).to have_content("HIGHLIGHTED PROCESSES") + end + + it "lists only promoted groups" do + expect(promoted_items_titles).to include(translated(promoted_group.title, locale: :en)) + expect(promoted_items_titles).not_to include(translated(group.title, locale: :en)) + end + + it "lists all the highlighted process groups" do + within "#highlighted-processes" do + expect(page).to have_content(translated(promoted_group.title, locale: :en)) + expect(page).to have_selector(".card--full", count: 2) + end + end + + context "and promoted group has defined a CTA content block" do + let(:cta_settings) do + { + button_url: "https://example.org/action", + button_text_en: "cta text", + description_en: "cta description" + } + end + + before do + create( + :content_block, + organization: organization, + scope_name: :participatory_process_group_homepage, + scoped_resource_id: promoted_group.id, + manifest_name: :cta, + settings: cta_settings + ) + visit decidim_participatory_processes.participatory_processes_path + end + + it "shows a CTA button inside group card" do + within("#highlighted-processes") do + expect(page).to have_link(cta_settings[:button_text_en], href: cta_settings[:button_url]) + end + end + + context "and promoted group belongs to another organization" do + let!(:promoted_group) { create(:participatory_process_group, :promoted, :with_participatory_processes) } + + it "shows a CTA button inside group card" do + within("#highlighted-processes") do + expect(page).not_to have_link(cta_settings[:button_text_en], href: cta_settings[:button_url]) + end + end + end + end + end + end + end + + context "when going to the participatory process page" do + let!(:participatory_process) { base_process } + let!(:proposals_component) { create(:extended_proposal_component, :published, participatory_space: participatory_process, manifest_name: :proposals) } + let!(:meetings_component) { create(:component, :unpublished, participatory_space: participatory_process, manifest_name: :meetings) } + + before do + create_list(:extended_proposal, 3, component: proposals_component) + allow(Decidim).to receive(:component_manifests).and_return([proposals_component.manifest, meetings_component.manifest]) + end + + it_behaves_like "editable content for admins" do + let(:target_path) { decidim_participatory_processes.participatory_process_path(participatory_process) } + end + + context "when requesting the participatory process path" do + before do + visit decidim_participatory_processes.participatory_process_path(participatory_process) + end + + context "when requesting the process path" do + it "shows the details of the given process" do + within "main" do + expect(page).to have_content(translated(participatory_process.title, locale: :en)) + expect(page).to have_content(translated(participatory_process.subtitle, locale: :en)) + expect(page).to have_content(translated(participatory_process.description, locale: :en)) + expect(page).to have_content(translated(participatory_process.short_description, locale: :en)) + expect(page).to have_content(translated(participatory_process.meta_scope, locale: :en)) + expect(page).to have_content(translated(participatory_process.developer_group, locale: :en)) + expect(page).to have_content(translated(participatory_process.local_area, locale: :en)) + expect(page).to have_content(translated(participatory_process.target, locale: :en)) + expect(page).to have_content(translated(participatory_process.participatory_scope, locale: :en)) + expect(page).to have_content(translated(participatory_process.participatory_structure, locale: :en)) + expect(page).to have_content(I18n.l(participatory_process.end_date, format: :long)) + expect(page).to have_content(participatory_process.hashtag) + end + end + + it_behaves_like "has attachments" do + let(:attached_to) { participatory_process } + end + + it_behaves_like "has attachment collections" do + let(:attached_to) { participatory_process } + let(:collection_for) { participatory_process } + end + + context "and it belongs to a group" do + let!(:group) { create :participatory_process_group, participatory_processes: [participatory_process], organization: organization } + + it "has a link to the group the process belongs to" do + visit decidim_participatory_processes.participatory_process_path(participatory_process) + + expect(page).to have_link(translated(group.title, locale: :en), href: decidim_participatory_processes.participatory_process_group_path(group)) + end + end + + context "when it has some linked processes" do + let(:published_process) { create :participatory_process, :published, organization: organization } + let(:unpublished_process) { create :participatory_process, :unpublished, organization: organization } + + it "only shows the published linked processes" do + participatory_process + .link_participatory_space_resources( + [published_process, unpublished_process], + "related_processes" + ) + visit decidim_participatory_processes.participatory_process_path(participatory_process) + expect(page).to have_content(translated(published_process.title)) + expect(page).to have_no_content(translated(unpublished_process.title)) + end + end + + context "and the process has some components" do + it "shows the components" do + within ".process-nav" do + expect(page).to have_content(translated(proposals_component.name, locale: :en).upcase) + expect(page).to have_no_content(translated(meetings_component.name, locale: :en).upcase) + end + end + + context "and the process metrics are enabled" do + let(:organization) { create(:organization) } + let(:metrics) do + Decidim.metrics_registry.filtered(highlight: true, scope: "participatory_process").each do |metric_registry| + create(:metric, metric_type: metric_registry.metric_name, day: Time.zone.today - 1.week, organization: organization, participatory_space_type: Decidim::ParticipatoryProcess.name, participatory_space_id: participatory_process.id, cumulative: 5, quantity: 2) + end + end + + before do + metrics + visit current_path + end + + it "shows the metrics charts" do + expect(page).to have_css("h3.section-heading", text: "METRICS") + + within "#metrics" do + expect(page).to have_css("input#metrics-space_type[value='Decidim::ParticipatoryProcess']", visible: :hidden) + expect(page).to have_css("input#metrics-space_id[value='#{participatory_process.id}']", visible: :hidden) + Decidim.metrics_registry.filtered(highlight: true, scope: "participatory_process").each do |metric_registry| + expect(page).to have_css(%(##{metric_registry.metric_name}_chart)) + end + end + end + + it "renders a link to all metrics" do + within "#metrics" do + expect(page).to have_link("Show all metrics") + end + end + + it "click link" do + click_link("Show all metrics") + have_current_path(decidim_participatory_processes.all_metrics_participatory_process_path(participatory_process)) + end + end + + context "and the process statistics are enabled" do + let(:show_statistics) { true } + + it "the stats for those components are visible" do + within ".section-statistics" do + expect(page).to have_css("h3.section-heading", text: "STATISTICS") + expect(page).to have_css(".statistic__title", text: "PROPOSALS") + expect(page).to have_css(".statistic__number", text: "3") + expect(page).to have_no_css(".statistic__title", text: "MEETINGS") + expect(page).to have_no_css(".statistic__number", text: "0") + end + end + end + + context "and the process statistics are not enabled" do + let(:show_statistics) { false } + + it "the stats for those components are not visible" do + expect(page).to have_no_css("h3.section-heading", text: "STATISTICS") + expect(page).to have_no_css(".statistic__title", text: "PROPOSALS") + expect(page).to have_no_css(".statistic__number", text: "3") + end + end + + context "and the process metrics are not enabled" do + let(:show_metrics) { false } + + it "the metrics for the participatory processes are not rendered" do + expect(page).to have_no_css("h4.section-heading", text: "METRICS") + end + + it "has no link to all metrics" do + expect(page).to have_no_link("Show all metrics") + end + end + + context "and the process doesn't have hashtag" do + let(:hashtag) { false } + + it "the hashtags for those components are not visible" do + expect(page).to have_no_content("#") + end + end + end + + context "when assemblies are linked to participatory process" do + let!(:published_assembly) { create(:assembly, :published, organization: organization) } + let!(:unpublished_assembly) { create(:assembly, :unpublished, organization: organization) } + let!(:private_assembly) { create(:assembly, :published, :private, :opaque, organization: organization) } + let!(:transparent_assembly) { create(:assembly, :published, :private, :transparent, organization: organization) } + + before do + published_assembly.link_participatory_space_resources(participatory_process, "included_participatory_processes") + unpublished_assembly.link_participatory_space_resources(participatory_process, "included_participatory_processes") + private_assembly.link_participatory_space_resources(participatory_process, "included_participatory_processes") + transparent_assembly.link_participatory_space_resources(participatory_process, "included_participatory_processes") + visit decidim_participatory_processes.participatory_process_path(participatory_process) + end + + it "display related assemblies" do + expect(page).to have_content("RELATED ASSEMBLIES") + expect(page).to have_content(translated(published_assembly.title)) + expect(page).to have_content(translated(transparent_assembly.title)) + expect(page).to have_no_content(translated(unpublished_assembly.title)) + expect(page).to have_no_content(translated(private_assembly.title)) + end + end + end + end + end + end +end diff --git a/spec/system/participatory_processes_spec.rb b/spec/system/participatory_processes_spec.rb index cacfdff136..f635bb873b 100644 --- a/spec/system/participatory_processes_spec.rb +++ b/spec/system/participatory_processes_spec.rb @@ -94,6 +94,41 @@ it_behaves_like "accessible page" + context "when emitter is defined", :slow do + context "when no emitter" do + it "doesn't displays logo or text" do + within "#participatory_process_#{promoted_process.id}" do + expect(page).not_to have_css(".emitter-header") + end + end + end + + context "when emitter" do + let(:base_process) do + create( + :participatory_process, + :active, + :with_emitter, + organization: organization, + description: { en: "Description", ca: "Descripció", es: "Descripción" }, + short_description: { en: "Short description", ca: "Descripció curta", es: "Descripción corta" }, + show_metrics: show_metrics, + show_statistics: show_statistics, + developer_group: { en: "Developer group" } + ) + end + + it "displays logo and text" do + within "#participatory_process_#{base_process.id}" do + within ".emitter-header" do + expect(page).to have_css("img", count: 1) + expect(page).to have_content("Consultation published by Developer group") + end + end + end + end + end + context "and accessing from the homepage" do it "the menu link is not shown" do visit decidim.root_path @@ -116,6 +151,41 @@ it_behaves_like "accessible page" + context "when emitter is defined", :slow do + context "when no emitter" do + it "doesn't displays logo or text" do + within "#participatory_process_#{promoted_process.id}" do + expect(page).not_to have_css(".emitter-header") + end + end + end + + context "when emitter" do + let(:base_process) do + create( + :participatory_process, + :active, + :with_emitter, + organization: organization, + description: { en: "Description", ca: "Descripció", es: "Descripción" }, + short_description: { en: "Short description", ca: "Descripció curta", es: "Descripción corta" }, + show_metrics: show_metrics, + show_statistics: show_statistics, + developer_group: { en: "Developer group" } + ) + end + + it "displays logo and text" do + within "#participatory_process_#{base_process.id}" do + within ".emitter-header" do + expect(page).to have_css("img", count: 1) + expect(page).to have_content("Consultation published by Developer group") + end + end + end + end + end + it "lists all the highlighted processes" do within "#highlighted-processes" do expect(page).to have_content(translated(promoted_process.title, locale: :en))