From ed778bf06116f4a14417a58801821101e805beb2 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 15:45:26 +0100 Subject: [PATCH 01/48] feat: update gemfile.lock --- Gemfile.lock | 3 +++ .../decidim/extra_user_fields/entrypoints/extra_user_fields.js | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) delete mode 100644 app/packs/images/decidim/extra_user_fields/entrypoints/extra_user_fields.js diff --git a/Gemfile.lock b/Gemfile.lock index ae42df3..10e135b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -490,6 +490,8 @@ GEM net-smtp (0.3.4) net-protocol nio4r (2.7.3) + nokogiri (1.16.6-x86_64-darwin) + racc (~> 1.4) nokogiri (1.16.6-x86_64-linux) racc (~> 1.4) oauth (1.1.0) @@ -794,6 +796,7 @@ GEM zeitwerk (2.6.16) PLATFORMS + x86_64-darwin-24 x86_64-linux DEPENDENCIES diff --git a/app/packs/images/decidim/extra_user_fields/entrypoints/extra_user_fields.js b/app/packs/images/decidim/extra_user_fields/entrypoints/extra_user_fields.js deleted file mode 100644 index a516e90..0000000 --- a/app/packs/images/decidim/extra_user_fields/entrypoints/extra_user_fields.js +++ /dev/null @@ -1,2 +0,0 @@ -// Images -require.context("../images", true) From bf89bfd56afb4c18c3eac989718a024e79319a9e Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:10:58 +0100 Subject: [PATCH 02/48] feat: modify packs directory --- .../entrypoints/decidim_extra_user_fields.js | 4 ++ .../decidim_extra_user_fields.scss | 1 + .../decidim/extra_user_fields/signup_form.js | 66 +++++++++++++++++++ .../extra_user_fields/signup_form.scss | 3 + 4 files changed, 74 insertions(+) create mode 100644 app/packs/entrypoints/decidim_extra_user_fields.js create mode 100644 app/packs/entrypoints/decidim_extra_user_fields.scss create mode 100644 app/packs/src/decidim/extra_user_fields/signup_form.js create mode 100644 app/packs/stylesheets/decidim/extra_user_fields/signup_form.scss diff --git a/app/packs/entrypoints/decidim_extra_user_fields.js b/app/packs/entrypoints/decidim_extra_user_fields.js new file mode 100644 index 0000000..1264f1e --- /dev/null +++ b/app/packs/entrypoints/decidim_extra_user_fields.js @@ -0,0 +1,4 @@ +// Images +require.context("../images", true) + +import "src/decidim/extra_user_fields/signup_form" diff --git a/app/packs/entrypoints/decidim_extra_user_fields.scss b/app/packs/entrypoints/decidim_extra_user_fields.scss new file mode 100644 index 0000000..6b0fef8 --- /dev/null +++ b/app/packs/entrypoints/decidim_extra_user_fields.scss @@ -0,0 +1 @@ +@import "stylesheets/decidim/extra_user_fields/signup_form"; diff --git a/app/packs/src/decidim/extra_user_fields/signup_form.js b/app/packs/src/decidim/extra_user_fields/signup_form.js new file mode 100644 index 0000000..12739c7 --- /dev/null +++ b/app/packs/src/decidim/extra_user_fields/signup_form.js @@ -0,0 +1,66 @@ +$(document).ready(function() { + const underageCheckbox = $('#registration_underage_checkbox'); + const statutoryRepresentativeEmailField = $('#statutory_representative_email_field'); + const dateOfBirthField = $('#registration_user_date_of_birth'); + const underageFieldSet = $('#underage_fieldset'); + let underageLimit = 18; + + // Function to show or hide underage related fields based on age + function updateUnderageFields() { + const dobValue = dateOfBirthField.val(); + //const dobParts = dobValue.split('-'); + //const dobDate = Date.parse(`${dobParts[1]}-${dobParts[0]}-${dobParts[2]}`); + const dobDate = Date.parse(`${dobValue}`) + const currentDate = Date.now(); + const ageInMilliseconds = currentDate - dobDate; + const age = Math.abs(new Date(ageInMilliseconds).getUTCFullYear() - 1970); + + if (age < underageLimit) { + underageFieldSet.removeClass('hidden'); + underageCheckbox.prop('checked', true); + statutoryRepresentativeEmailField.removeClass('hidden'); + } else { + statutoryRepresentativeEmailField.find('input').val(''); + underageFieldSet.addClass('hidden'); + underageCheckbox.prop('checked', false); + statutoryRepresentativeEmailField.addClass('hidden'); + } + } + + if (underageCheckbox.length && statutoryRepresentativeEmailField.length) { + underageCheckbox.on('change', function() { + if (underageCheckbox.prop('checked')) { + statutoryRepresentativeEmailField.removeClass('hidden'); + } else { + statutoryRepresentativeEmailField.find('input').val(''); + statutoryRepresentativeEmailField.addClass('hidden'); + } + }); + } + + if (dateOfBirthField.length && underageCheckbox.length) { + updateUnderageFields(); + } + + if (underageCheckbox.length) { + $.ajax({ + url: '/extra_user_fields/underage_limit', // Updated to match the new route + type: 'GET', + success: function (data) { + underageLimit = data.underage_limit; + if (dateOfBirthField.length && underageFieldSet.length) { + updateUnderageFields(); + } + }, + error: function (jqXHR, textStatus, errorThrown) { + console.error("Failed to fetch underage limit:", textStatus, errorThrown); + } + }); + } + + if (dateOfBirthField.length && underageFieldSet.length) { + dateOfBirthField.on('change', function() { + updateUnderageFields(); + }); + } +}); diff --git a/app/packs/stylesheets/decidim/extra_user_fields/signup_form.scss b/app/packs/stylesheets/decidim/extra_user_fields/signup_form.scss new file mode 100644 index 0000000..f4d336f --- /dev/null +++ b/app/packs/stylesheets/decidim/extra_user_fields/signup_form.scss @@ -0,0 +1,3 @@ +.hidden { + display: none; +} From 93c27b1d5b03d8c3773ad9226ead177db7f0afa6 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:11:32 +0100 Subject: [PATCH 03/48] feat: add assets file in config --- config/assets.rb | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 config/assets.rb diff --git a/config/assets.rb b/config/assets.rb new file mode 100644 index 0000000..9be6ca7 --- /dev/null +++ b/config/assets.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# This file is located at `config/assets.rb` of your module. + +# Define the base path of your module. Please note that `Rails.root` may not be +# used because we are not inside the Rails environment when this file is loaded. +base_path = File.expand_path("..", __dir__) + +# Register an additional load path for webpack. All the assets within these +# directories will be available for inclusion within the Decidim assets. For +# example, if you have `app/packs/src/decidim/foo.js`, you can include that file +# in your JavaScript entrypoints (or other JavaScript files within Decidim) +# using `import "src/decidim/foo"` after you have registered the additional path +# as follows. +Decidim::Webpacker.register_path("#{base_path}/app/packs") + +# Register the entrypoints for your module. These entrypoints can be included +# within your application using `javascript_pack_tag` and if you include any +# SCSS files within the entrypoints, they become available for inclusion using +# `stylesheet_pack_tag`. +Decidim::Webpacker.register_entrypoints( + decidim_extra_user_fields: "#{base_path}/app/packs/entrypoints/decidim_extra_user_fields.js", + decidim_extra_user_fields_css: "#{base_path}/app/packs/entrypoints/decidim_extra_user_fields.scss" +) + +# If you want to import some extra SCSS files in the Decidim main SCSS file +# without adding any extra stylesheet inclusion tags, you can use the following +# method to register the stylesheet import for the main application. +# Decidim::Webpacker.register_stylesheet_import("stylesheets/decidim/homepage_interactive_map/map.scss") From 4820533cde10b6c92b4043e138f56a3c4fc2e465 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:15:37 +0100 Subject: [PATCH 04/48] feat: update commands --- ...create_registrations_commands_overrides.rb | 34 ++++++++++++++- .../omniauth_commands_overrides.rb | 43 ++++++++++++++++++- .../update_account_commands_overrides.rb | 5 ++- .../admin/update_extra_user_fields.rb | 4 ++ 4 files changed, 83 insertions(+), 3 deletions(-) diff --git a/app/commands/concerns/decidim/extra_user_fields/create_registrations_commands_overrides.rb b/app/commands/concerns/decidim/extra_user_fields/create_registrations_commands_overrides.rb index 6a9d4d5..dd93ac9 100644 --- a/app/commands/concerns/decidim/extra_user_fields/create_registrations_commands_overrides.rb +++ b/app/commands/concerns/decidim/extra_user_fields/create_registrations_commands_overrides.rb @@ -8,6 +8,24 @@ module ExtraUserFields module CreateRegistrationsCommandsOverrides extend ActiveSupport::Concern + def call + return broadcast(:invalid) if same_email_representative? + + if form.invalid? + + user = User.has_pending_invitations?(form.current_organization.id, form.email) + user.invite!(user.invited_by) if user + return broadcast(:invalid) + end + + create_user + send_email_to_statutory_representative + + broadcast(:ok, @user) + rescue ActiveRecord::RecordInvalid + broadcast(:invalid) + end + private def create_user @@ -33,9 +51,23 @@ def extended_data date_of_birth: form.date_of_birth, gender: form.gender, phone_number: form.phone_number, - location: form.location + location: form.location, + underage: form.underage, + statutory_representative_email: form.statutory_representative_email ) end + + def send_email_to_statutory_representative + return if form.statutory_representative_email.blank? || form.underage != "1" + + Decidim::ExtraUserFields::StatutoryRepresentativeMailer.inform(@user).deliver_later + end + + def same_email_representative? + return false if form.statutory_representative_email.blank? + + form.statutory_representative_email == form.email + end end end end diff --git a/app/commands/concerns/decidim/extra_user_fields/omniauth_commands_overrides.rb b/app/commands/concerns/decidim/extra_user_fields/omniauth_commands_overrides.rb index a56d481..1cfe973 100644 --- a/app/commands/concerns/decidim/extra_user_fields/omniauth_commands_overrides.rb +++ b/app/commands/concerns/decidim/extra_user_fields/omniauth_commands_overrides.rb @@ -8,6 +8,33 @@ module ExtraUserFields module OmniauthCommandsOverrides extend ActiveSupport::Concern + def call + return broadcast(:invalid) if same_email_representative? + + verify_oauth_signature! + + begin + if existing_identity + user = existing_identity.user + verify_user_confirmed(user) + + return broadcast(:ok, user) + end + return broadcast(:invalid) if form.invalid? + + transaction do + create_or_find_user + send_email_to_statutory_representative + @identity = create_identity + end + trigger_omniauth_registration + + broadcast(:ok, @user) + rescue ActiveRecord::RecordInvalid => e + broadcast(:error, e.record) + end + end + private def create_or_find_user @@ -51,9 +78,23 @@ def extended_data date_of_birth: form.date_of_birth, gender: form.gender, phone_number: form.phone_number, - location: form.location + location: form.location, + underage: form.underage, + statutory_representative_email: form.statutory_representative_email ) end + + def send_email_to_statutory_representative + return if form.statutory_representative_email.blank? || form.underage != "1" + + Decidim::ExtraUserFields::StatutoryRepresentativeMailer.inform(@user).deliver_later + end + + def same_email_representative? + return false if form.statutory_representative_email.blank? + + form.statutory_representative_email == form.email + end end end end diff --git a/app/commands/concerns/decidim/extra_user_fields/update_account_commands_overrides.rb b/app/commands/concerns/decidim/extra_user_fields/update_account_commands_overrides.rb index 2f0f081..2907c1e 100644 --- a/app/commands/concerns/decidim/extra_user_fields/update_account_commands_overrides.rb +++ b/app/commands/concerns/decidim/extra_user_fields/update_account_commands_overrides.rb @@ -11,6 +11,7 @@ module UpdateAccountCommandsOverrides private def update_personal_data + @user.locale = @form.locale @user.name = @form.name @user.nickname = @form.nickname @user.email = @form.email @@ -26,7 +27,9 @@ def extended_data date_of_birth: @form.date_of_birth, gender: @form.gender, phone_number: @form.phone_number, - location: @form.location + location: @form.location, + underage: @form.underage, + statutory_representative_email: @form.statutory_representative_email ) end end diff --git a/app/commands/decidim/extra_user_fields/admin/update_extra_user_fields.rb b/app/commands/decidim/extra_user_fields/admin/update_extra_user_fields.rb index f3d01c2..252649f 100644 --- a/app/commands/decidim/extra_user_fields/admin/update_extra_user_fields.rb +++ b/app/commands/decidim/extra_user_fields/admin/update_extra_user_fields.rb @@ -39,6 +39,7 @@ def update_extra_user_fields! end # rubocop:disable Style/TrailingCommaInHashLiteral + # rubocop:disable Metrics/CyclomaticComplexity def extra_user_fields { "enabled" => form.enabled.presence || false, @@ -52,12 +53,15 @@ def extra_user_fields "placeholder" => form.phone_number_placeholder.presence }, "location" => { "enabled" => form.location.presence || false }, + "underage" => { "enabled" => form.underage || false }, + "underage_limit" => form.underage_limit || Decidim::ExtraUserFields::Engine::DEFAULT_UNDERAGE_LIMIT # Block ExtraUserFields SaveFieldInConfig # EndBlock } end # rubocop:enable Style/TrailingCommaInHashLiteral + # rubocop:enable Metrics/CyclomaticComplexity end end end From 5d32a7fe32593de4fd92a62a8553f4dde661b25c Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:16:20 +0100 Subject: [PATCH 05/48] test: update commands tests --- .../create_omniauth_registration_spec.rb | 20 +++++++-- .../decidim/create_registration_spec.rb | 41 +++++++++++++++++-- .../admin/update_extra_user_fields_spec.rb | 6 +++ 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/spec/commands/decidim/create_omniauth_registration_spec.rb b/spec/commands/decidim/create_omniauth_registration_spec.rb index 3a44850..bd8fbde 100644 --- a/spec/commands/decidim/create_omniauth_registration_spec.rb +++ b/spec/commands/decidim/create_omniauth_registration_spec.rb @@ -18,6 +18,8 @@ module Comments let(:location) { "Paris" } let(:phone_number) { "0123456789" } let(:postal_code) { "75001" } + let(:underage) { false } + let(:statutory_representative_email) { nil } let(:extended_data) do { country:, @@ -25,7 +27,9 @@ module Comments gender:, location:, phone_number:, - postal_code: + postal_code:, + underage: underage, + statutory_representative_email: statutory_representative_email } end @@ -45,7 +49,9 @@ module Comments "date_of_birth" => date_of_birth, "gender" => gender, "phone_number" => phone_number, - "location" => location + "location" => location, + "underage" => underage, + "statutory_representative_email" => statutory_representative_email } } end @@ -147,7 +153,6 @@ module Comments it "links a previously existing user" do user = create(:user, email:, organization:) expect { command.call }.not_to change(User, :count) - expect(user.identities.length).to eq(1) end @@ -227,6 +232,15 @@ module Comments expect(user).not_to be_confirmed end end + + context "when the user is underage and tries to duplicate email" do + let(:underage) { true } + let(:statutory_representative_email) { email } + + it "broadcasts invalid" do + expect { command.call }.to broadcast(:invalid) + end + end end end end diff --git a/spec/commands/decidim/create_registration_spec.rb b/spec/commands/decidim/create_registration_spec.rb index 6760b25..e734d88 100644 --- a/spec/commands/decidim/create_registration_spec.rb +++ b/spec/commands/decidim/create_registration_spec.rb @@ -21,6 +21,8 @@ module Comments let(:location) { "Paris" } let(:phone_number) { "0123456789" } let(:postal_code) { "75001" } + let(:underage) { "0" } + let(:statutory_representative_email) { nil } let(:extended_data) do { country:, @@ -28,7 +30,9 @@ module Comments gender:, location:, phone_number:, - postal_code: + postal_code:, + underage: underage, + statutory_representative_email: statutory_representative_email } end @@ -46,7 +50,9 @@ module Comments "date_of_birth" => date_of_birth, "gender" => gender, "phone_number" => phone_number, - "location" => location + "location" => location, + "underage" => underage, + "statutory_representative_email" => statutory_representative_email } } end @@ -118,7 +124,9 @@ module Comments gender:, location:, phone_number:, - postal_code: + postal_code:, + underage: underage, + statutory_representative_email: statutory_representative_email } ).and_call_original @@ -140,6 +148,33 @@ module Comments end.to change(User, :count).by(1) end end + + describe "when the user is underage and sends a valid email" do + let(:underage) { "1" } + let(:statutory_representative_email) { "user@example.fr" } + + it "creates a user with the statutory representative email and sends email" do + expect do + expect(Decidim::ExtraUserFields::StatutoryRepresentativeMailer).to receive(:inform).with(instance_of(Decidim::User)).and_call_original + + command.call + + user = User.last + expect(user.extended_data["statutory_representative_email"]).to eq(statutory_representative_email) + end.to change(User, :count).by(1) + end + end + + describe "when the user is underage and tries to duplicate email" do + let(:underage) { "1" } + let(:statutory_representative_email) { email } + + it "broadcasts invalid" do + expect(Decidim::ExtraUserFields::StatutoryRepresentativeMailer).not_to receive(:inform).with(instance_of(Decidim::User)).and_call_original + + expect { command.call }.to broadcast(:invalid) + end + end end end end diff --git a/spec/commands/decidim/extra_user_fields/admin/update_extra_user_fields_spec.rb b/spec/commands/decidim/extra_user_fields/admin/update_extra_user_fields_spec.rb index 1acb5ba..3631000 100644 --- a/spec/commands/decidim/extra_user_fields/admin/update_extra_user_fields_spec.rb +++ b/spec/commands/decidim/extra_user_fields/admin/update_extra_user_fields_spec.rb @@ -18,6 +18,8 @@ module Admin let(:phone_number_pattern) { "^(\\+34)?[0-9 ]{9,12}$" } let(:phone_number_placeholder) { "+34999888777" } let(:location) { true } + let(:underage) { true } + let(:underage_limit) { 18 } # Block ExtraUserFields RspecVar # EndBlock @@ -34,6 +36,8 @@ module Admin "phone_number_pattern" => phone_number_pattern, "phone_number_placeholder" => phone_number_placeholder, "location" => location, + "underage" => underage, + "underage_limit" => underage_limit, # Block ExtraUserFields ExtraUserFields # EndBlock @@ -86,6 +90,8 @@ module Admin expect(extra_user_fields).to include("country" => { "enabled" => true }) expect(extra_user_fields).to include("phone_number" => { "enabled" => true, "pattern" => phone_number_pattern, "placeholder" => phone_number_placeholder }) expect(extra_user_fields).to include("location" => { "enabled" => true }) + expect(extra_user_fields).to include("underage" => { "enabled" => true }) + expect(extra_user_fields).to include("underage_limit" => 18) # Block ExtraUserFields InclusionSpec # EndBlock From 5005bc839d8cdfe143f8df7282ee9e7c4e067cc2 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:18:34 +0100 Subject: [PATCH 06/48] feat: update admin controller and add new controller --- .../admin/extra_user_fields_controller.rb | 15 +++++++++++---- .../extra_user_fields_controller.rb | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 app/controllers/decidim/extra_user_fields/extra_user_fields_controller.rb diff --git a/app/controllers/decidim/extra_user_fields/admin/extra_user_fields_controller.rb b/app/controllers/decidim/extra_user_fields/admin/extra_user_fields_controller.rb index fbec1ca..2216a53 100644 --- a/app/controllers/decidim/extra_user_fields/admin/extra_user_fields_controller.rb +++ b/app/controllers/decidim/extra_user_fields/admin/extra_user_fields_controller.rb @@ -38,11 +38,18 @@ def update def export_users enforce_permission_to :read, :officialization - ExportUsers.call(params[:format], current_user) do - on(:ok) do |export_data| - send_data export_data.read, type: "text/#{export_data.extension}", filename: export_data.filename("participants") - end + Decidim.traceability.perform_action!("export_users", current_organization, current_user, { format: params[:format] }) do + ExportParticipantsJob.perform_later(current_organization, current_user, params[:format]) end + + flash[:notice] = t("decidim.admin.exports.notice") + redirect_to engine_routes.officializations_path + end + + private + + def engine_routes + Decidim::Admin::Engine.routes.url_helpers end end end diff --git a/app/controllers/decidim/extra_user_fields/extra_user_fields_controller.rb b/app/controllers/decidim/extra_user_fields/extra_user_fields_controller.rb new file mode 100644 index 0000000..da85d5b --- /dev/null +++ b/app/controllers/decidim/extra_user_fields/extra_user_fields_controller.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Decidim + module ExtraUserFields + # This controller is the abstract class from which all other controllers of + # this engine inherit. + class ExtraUserFieldsController < ApplicationController + def retrieve_underage_limit + underage_limit = current_organization.extra_user_fields["underage_limit"] + if underage_limit.present? + render json: { underage_limit: underage_limit } + else + render json: { error: "Underage limit not found" }, status: :not_found + end + end + end + end +end From bfc84381e9e002ce1296975c6588588593914743 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:19:21 +0100 Subject: [PATCH 07/48] feat: update model --- .../decidim/extra_user_fields/organization_overrides.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/models/concerns/decidim/extra_user_fields/organization_overrides.rb b/app/models/concerns/decidim/extra_user_fields/organization_overrides.rb index 7784ca6..241c2ed 100644 --- a/app/models/concerns/decidim/extra_user_fields/organization_overrides.rb +++ b/app/models/concerns/decidim/extra_user_fields/organization_overrides.rb @@ -14,7 +14,7 @@ def extra_user_fields_enabled? end def at_least_one_extra_field? - extra_user_fields.reject { |key| key == "enabled" } + extra_user_fields.reject { |key| %w(enabled underage_limit).include?(key) } .map { |_, value| value["enabled"] }.any? end @@ -23,6 +23,10 @@ def activated_extra_field?(sym) extra_user_fields.dig(sym.to_s, "enabled") == true end + def age_limit? + extra_user_fields["underage_limit"].to_i + end + def extra_user_field_configuration(sym) return {} unless activated_extra_field?(sym) From 78a5eaba5978da5d2cc4596c39cbf31eb83ce4b0 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:19:59 +0100 Subject: [PATCH 08/48] feat: update forms --- .../extra_user_fields/forms_definitions.rb | 47 +++++++++++++++++++ .../admin/extra_user_fields_form.rb | 4 ++ 2 files changed, 51 insertions(+) diff --git a/app/forms/concerns/decidim/extra_user_fields/forms_definitions.rb b/app/forms/concerns/decidim/extra_user_fields/forms_definitions.rb index 0466545..356888e 100644 --- a/app/forms/concerns/decidim/extra_user_fields/forms_definitions.rb +++ b/app/forms/concerns/decidim/extra_user_fields/forms_definitions.rb @@ -19,6 +19,8 @@ module FormsDefinitions attribute :gender, String attribute :phone_number, String attribute :location, String + attribute :underage, ActiveRecord::Type::Boolean + attribute :statutory_representative_email, String # EndBlock @@ -36,6 +38,12 @@ module FormsDefinitions ) validates :location, presence: true, if: :location? + validates :underage, presence: true, if: :underage? + validates :statutory_representative_email, + presence: true, + "valid_email_2/email": { disposable: true }, + if: :underage_accepted? + validate :birth_date_under_limit # EndBlock end @@ -49,6 +57,8 @@ def map_model(model) self.gender = extended_data[:gender] self.phone_number = extended_data[:phone_number] self.location = extended_data[:location] + self.underage = extended_data[:underage] + self.statutory_representative_email = extended_data[:statutory_representative_email] # Block ExtraUserFields MapModel @@ -88,11 +98,48 @@ def location? extra_user_fields_enabled && current_organization.activated_extra_field?(:location) end + def underage? + extra_user_fields_enabled && current_organization.activated_extra_field?(:underage) + end + + def underage_accepted? + underage? && underage == "1" + end + # EndBlock def extra_user_fields_enabled @extra_user_fields_enabled ||= current_organization.extra_user_fields_enabled? end + + # Method to check if birth date is under the limit + def birth_date_under_limit + return unless date_of_birth? && underage? + + return if date_of_birth.blank? || underage.blank? || underage_limit.blank? + + age = calculate_age(date_of_birth) + + validate_age(age) + end + + def calculate_age(date_of_birth) + Time.zone.today.year - date_of_birth.year - (Time.zone.today.yday < date_of_birth.yday ? 1 : 0) + end + + def validate_age(age) + errors.add(:date_of_birth, :underage) unless underage_within_limit?(age) + underage_within_limit?(age) + end + + def underage_within_limit?(age) + (date_of_birth.present? && age < underage_limit && underage_accepted?) || (age > underage_limit && !underage_accepted?) + end + + def underage_limit + current_organization.extra_user_fields["underage_limit"] + end + end end end diff --git a/app/forms/decidim/extra_user_fields/admin/extra_user_fields_form.rb b/app/forms/decidim/extra_user_fields/admin/extra_user_fields_form.rb index 185d6f0..5354b5c 100644 --- a/app/forms/decidim/extra_user_fields/admin/extra_user_fields_form.rb +++ b/app/forms/decidim/extra_user_fields/admin/extra_user_fields_form.rb @@ -13,6 +13,8 @@ class ExtraUserFieldsForm < Decidim::Form attribute :gender, Boolean attribute :phone_number, Boolean attribute :location, Boolean + attribute :underage, Boolean + attribute :underage_limit, Integer attribute :phone_number_pattern, String translatable_attribute :phone_number_placeholder, String @@ -28,6 +30,8 @@ def map_model(model) self.gender = model.extra_user_fields.dig("gender", "enabled") self.phone_number = model.extra_user_fields.dig("phone_number", "enabled") self.location = model.extra_user_fields.dig("location", "enabled") + self.underage = model.extra_user_fields.dig("underage", "enabled") + self.underage_limit = model.extra_user_fields.fetch("underage_limit", Decidim::ExtraUserFields::Engine::DEFAULT_UNDERAGE_LIMIT) self.phone_number_pattern = model.extra_user_fields.dig("phone_number", "pattern") self.phone_number_placeholder = model.extra_user_fields.dig("phone_number", "placeholder") # Block ExtraUserFields MapModel From 152e83e7fee7be292ef2f7848d140f582c7bcc99 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:20:38 +0100 Subject: [PATCH 09/48] test: update form tests --- spec/forms/decidim/account_form_spec.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/spec/forms/decidim/account_form_spec.rb b/spec/forms/decidim/account_form_spec.rb index 1b367c0..ccfdd3b 100644 --- a/spec/forms/decidim/account_form_spec.rb +++ b/spec/forms/decidim/account_form_spec.rb @@ -3,6 +3,8 @@ require "spec_helper" module Decidim + include ActiveStorage::Blob::Analyzable + describe AccountForm do subject do described_class.new( @@ -21,7 +23,9 @@ module Decidim date_of_birth:, gender:, phone_number:, - location: + location:, + underage: underage, + statutory_representative_email: statutory_representative_email ).with_context( current_organization: organization, current_user: user @@ -38,7 +42,9 @@ module Decidim "date_of_birth" => { "enabled" => true }, "gender" => { "enabled" => true }, "phone_number" => { "enabled" => true, "pattern" => phone_number_pattern, "placeholder" => nil }, - "location" => { "enabled" => true } + "location" => { "enabled" => true }, + "underage" => { "enabled" => true }, + "underage_limit" => 18 } end let(:phone_number_pattern) { "^(\\+34)?[0-9 ]{9,12}$" } @@ -59,6 +65,8 @@ module Decidim let(:location) { "Paris" } let(:phone_number) { "0123456789" } let(:postal_code) { "75001" } + let(:underage) { "0" } + let(:statutory_representative_email) { nil } context "with correct data" do it "is valid" do @@ -75,7 +83,7 @@ module Decidim end context "with invalid phone number format" do - let(:phone_number_pattern) { "^(\\+34)?[0-1 ]{9,12}$" } + let(:phone_number) { "ABCDEFGHIJK" } it "is invalid" do expect(subject).not_to be_valid From 85b1ee5dc557618c50435fba9e725ce8c80a9e31 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:22:27 +0100 Subject: [PATCH 10/48] feat: update views and add 2 new views files --- .../extra_user_fields/_profile_form.html.erb | 5 ++++ .../_registration_form.html.erb | 25 +++++++++++++++++-- .../admin/extra_user_fields/_form.html.erb | 1 + .../fields/_underage.html.erb | 7 ++++++ .../inform.html.erb | 1 + 5 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 app/views/decidim/extra_user_fields/admin/extra_user_fields/fields/_underage.html.erb create mode 100644 app/views/decidim/extra_user_fields/statutory_representative_mailer/inform.html.erb diff --git a/app/views/decidim/extra_user_fields/_profile_form.html.erb b/app/views/decidim/extra_user_fields/_profile_form.html.erb index 4d82d2a..46473e0 100644 --- a/app/views/decidim/extra_user_fields/_profile_form.html.erb +++ b/app/views/decidim/extra_user_fields/_profile_form.html.erb @@ -24,4 +24,9 @@ <% if current_organization.activated_extra_field?(:location) %> <%= f.text_field :location %> <% end %> + + <% if current_organization.activated_extra_field?(:underage) %> + <%= f.hidden_field :underage, value: current_user.extended_data["underage"] || "0" %> + <%= f.hidden_field :statutory_representative_email, value: current_user.extended_data["statutory_representative_email"] || "" %> + <% end %> <% end %> diff --git a/app/views/decidim/extra_user_fields/_registration_form.html.erb b/app/views/decidim/extra_user_fields/_registration_form.html.erb index 1c1d85e..73567bb 100644 --- a/app/views/decidim/extra_user_fields/_registration_form.html.erb +++ b/app/views/decidim/extra_user_fields/_registration_form.html.erb @@ -1,9 +1,9 @@ <% if current_organization.extra_user_fields_enabled? %>
-

<%= t(".signup.legend") %>

+

<%= t(".signup.legend") %>

<% if current_organization.activated_extra_field?(:date_of_birth) %> - <%= f.date_field :date_of_birth %> + <%= f.date_field :date_of_birth, id: "user_date_of_birth" %> <% end %> <% if current_organization.activated_extra_field?(:gender) %> @@ -28,9 +28,30 @@ <%= f.text_field :location %> <% end %> + <% if current_organization.activated_extra_field?(:underage) %> + <% if current_organization.activated_extra_field?(:date_of_birth) %> + + <% else %> +
+ <%= f.check_box :underage, id: "underage_checkbox", label: t(".signup.underage", limit: current_organization.age_limit?) %> + +
+ <%end %> + <% end %> <%# Block ExtraUserFields SignUpFormFields %> <%# EndBlock %>
+ <%= append_javascript_pack_tag "decidim_extra_user_fields.js" %> + <%= append_stylesheet_pack_tag "decidim_extra_user_fields_css" %> <% end %> + + diff --git a/app/views/decidim/extra_user_fields/admin/extra_user_fields/_form.html.erb b/app/views/decidim/extra_user_fields/admin/extra_user_fields/_form.html.erb index 30da0e8..dc61bb0 100644 --- a/app/views/decidim/extra_user_fields/admin/extra_user_fields/_form.html.erb +++ b/app/views/decidim/extra_user_fields/admin/extra_user_fields/_form.html.erb @@ -31,6 +31,7 @@ <%= render partial: "decidim/extra_user_fields/admin/extra_user_fields/fields/gender", locals: { form: form } %> <%= render partial: "decidim/extra_user_fields/admin/extra_user_fields/fields/phone_number", locals: { form: form } %> <%= render partial: "decidim/extra_user_fields/admin/extra_user_fields/fields/location", locals: { form: form } %> + <%= render partial: "decidim/extra_user_fields/admin/extra_user_fields/fields/underage", locals: { form: form } %> diff --git a/app/views/decidim/extra_user_fields/admin/extra_user_fields/fields/_underage.html.erb b/app/views/decidim/extra_user_fields/admin/extra_user_fields/fields/_underage.html.erb new file mode 100644 index 0000000..2713630 --- /dev/null +++ b/app/views/decidim/extra_user_fields/admin/extra_user_fields/fields/_underage.html.erb @@ -0,0 +1,7 @@ +
+
+

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

+ <%= form.check_box :underage, label: t(".label") %> + <%= form.select :underage_limit, ( Decidim::ExtraUserFields::Engine::DEFAULT_UNDERAGE_OPTIONS).to_a, selected: current_organization.extra_user_fields["underage_limit"] || Decidim::ExtraUserFields::Engine::DEFAULT_UNDERAGE_LIMIT, label: t(".limit") %> +
+
diff --git a/app/views/decidim/extra_user_fields/statutory_representative_mailer/inform.html.erb b/app/views/decidim/extra_user_fields/statutory_representative_mailer/inform.html.erb new file mode 100644 index 0000000..ee6b892 --- /dev/null +++ b/app/views/decidim/extra_user_fields/statutory_representative_mailer/inform.html.erb @@ -0,0 +1 @@ +

<%== @body %>

From 0b00fd5fe242239c29fde07c317e1557497d559f Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:23:16 +0100 Subject: [PATCH 11/48] feat: update engine --- lib/decidim/extra_user_fields/engine.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/decidim/extra_user_fields/engine.rb b/lib/decidim/extra_user_fields/engine.rb index 655fb04..e6a1cb6 100644 --- a/lib/decidim/extra_user_fields/engine.rb +++ b/lib/decidim/extra_user_fields/engine.rb @@ -13,10 +13,15 @@ class Engine < ::Rails::Engine DEFAULT_GENDER_OPTIONS = [:male, :female, :other].freeze + DEFAULT_UNDERAGE_LIMIT = 18 + + DEFAULT_UNDERAGE_OPTIONS = (15..21) + routes do # Add engine routes here # resources :extra_user_fields # root to: "extra_user_fields#index" + get "underage_limit", to: "extra_user_fields#retrieve_underage_limit", as: :retrieve_underage_limit end initializer "decidim_extra_user_fields.registration_additions" do @@ -54,6 +59,12 @@ class Engine < ::Rails::Engine end end end + + initializer "decidim_extra_user_fields.mount_routes" do + Decidim::Core::Engine.routes do + mount Decidim::ExtraUserFields::Engine, at: "/extra_user_fields", as: "decidim_extra_user_fields_engine" + end + end end end end From 28fbb320bdf2f6cdddfb61179a0b7842fa55024a Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:24:35 +0100 Subject: [PATCH 12/48] feat: udpate deface file --- .../index/_export_users_dropdown.html.erb.deface | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/overrides/decidim/admin/officializations/index/_export_users_dropdown.html.erb.deface b/app/overrides/decidim/admin/officializations/index/_export_users_dropdown.html.erb.deface index fbc8047..38c25ae 100644 --- a/app/overrides/decidim/admin/officializations/index/_export_users_dropdown.html.erb.deface +++ b/app/overrides/decidim/admin/officializations/index/_export_users_dropdown.html.erb.deface @@ -1,3 +1,3 @@ - + <%= render partial: "decidim/extra_user_fields/admin/export_users/dropdown" %> From a9d32b52a690e5391320237d55da4d925876498a Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:24:57 +0100 Subject: [PATCH 13/48] feat: update serializer --- .../decidim/extra_user_fields/user_export_serializer.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/serializers/decidim/extra_user_fields/user_export_serializer.rb b/app/serializers/decidim/extra_user_fields/user_export_serializer.rb index d9b748d..ff19578 100644 --- a/app/serializers/decidim/extra_user_fields/user_export_serializer.rb +++ b/app/serializers/decidim/extra_user_fields/user_export_serializer.rb @@ -13,7 +13,7 @@ def serialize def extra_user_fields extended_data = resource.extended_data.symbolize_keys - [:gender, :country, :postal_code, :date_of_birth, :phone_number, :location].index_with do |key| + [:gender, :country, :postal_code, :date_of_birth, :phone_number, :location, :underage, :statutory_representative_email].index_with do |key| extended_data[key] end end @@ -27,6 +27,8 @@ def extra_fields :date_of_birth, :phone_number, :location, + :underage, + :statutory_representative_email # Block ExtraUserFields AddExtraField # EndBlock From 553f2d5a38663b1e23e74e91d4df513b6006df29 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:25:16 +0100 Subject: [PATCH 14/48] test: update serializer test --- .../decidim/extra_user_fields/user_export_serializer_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/serializers/decidim/extra_user_fields/user_export_serializer_spec.rb b/spec/serializers/decidim/extra_user_fields/user_export_serializer_spec.rb index 9eb39bd..2d3e6aa 100644 --- a/spec/serializers/decidim/extra_user_fields/user_export_serializer_spec.rb +++ b/spec/serializers/decidim/extra_user_fields/user_export_serializer_spec.rb @@ -15,6 +15,8 @@ country:, phone_number:, location:, + underage: underage, + statutory_representative_email: statutory_representative_email, # Block ExtraUserFields ExtraUserFields # EndBlock @@ -28,6 +30,9 @@ let(:country) { "Argentina" } let(:phone_number) { "0123456789" } let(:location) { "Cahors" } + let(:underage) { true } + let(:underage_limit) { 18 } + let(:statutory_representative_email) { "parent@example.org" } # Block ExtraUserFields RspecVar # EndBlock From 4a170da311d254295272cf887f21aa1cdfade366 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:25:56 +0100 Subject: [PATCH 15/48] feat: add mailer --- .../statutory_representative_mailer.rb | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 app/mailers/decidim/extra_user_fields/statutory_representative_mailer.rb diff --git a/app/mailers/decidim/extra_user_fields/statutory_representative_mailer.rb b/app/mailers/decidim/extra_user_fields/statutory_representative_mailer.rb new file mode 100644 index 0000000..b11df3f --- /dev/null +++ b/app/mailers/decidim/extra_user_fields/statutory_representative_mailer.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Decidim + module ExtraUserFields + class StatutoryRepresentativeMailer < ApplicationMailer + def inform(user) + return if user.email.blank? + return if user.extended_data["statutory_representative_email"].blank? + + @user = user + @statutory_representative_email = user.extended_data["statutory_representative_email"] + @organization = user.organization + + with_user(user) do + @subject = I18n.t("inform.subject", scope: "decidim.statutory_representative") + @body = I18n.t("inform.body", scope: "decidim.statutory_representative", name: user.name, nickname: user.nickname, organization: @organization.name) + + mail(from: Decidim.config.mailer_sender, to: "#{@statutory_representative_email} <#{@statutory_representative_email}>", subject: @subject) + end + end + end + end +end From ed3ce427d9728f6703cf69febcbc3c73988f7195 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:26:18 +0100 Subject: [PATCH 16/48] feat: add job --- .../admin/export_participants_job.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 app/jobs/decidim/extra_user_fields/admin/export_participants_job.rb diff --git a/app/jobs/decidim/extra_user_fields/admin/export_participants_job.rb b/app/jobs/decidim/extra_user_fields/admin/export_participants_job.rb new file mode 100644 index 0000000..337c126 --- /dev/null +++ b/app/jobs/decidim/extra_user_fields/admin/export_participants_job.rb @@ -0,0 +1,17 @@ +# frozen_string_literal = true + +module Decidim + module ExtraUserFields + module Admin + class ExportParticipantsJob < ApplicationJob + queue_as :exports + + def perform(organization, user, format) + collection = organization.users.not_deleted + export_data = Decidim::Exporters.find_exporter(format).new(collection, Decidim::ExtraUserFields::UserExportSerializer).export + ExportMailer.export(user, "participants", export_data).deliver_now + end + end + end + end +end From 199054ad043be46e48fd456a617cab148809d4d4 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:26:56 +0100 Subject: [PATCH 17/48] test: add test for job --- .../admin/export_participants_job_spec.rb | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb diff --git a/spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb b/spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb new file mode 100644 index 0000000..e4007f8 --- /dev/null +++ b/spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "spec_helper" + +module Decidim + module ExtraUserFields + module Admin + describe ExportParticipantsJob, type: :job do + let(:organization) { create(:organization, extra_user_fields: {}) } + let(:user) { create :user, :admin, :confirmed, organization: organization } + let(:format) { "CSV" } + + it "sends an email with a file attached" do + ExportParticipantsJob.perform_now(organization, user, format) + email = last_email + expect(email.subject).to include("participants") + attachment = email.attachments.first + + expect(attachment.read.length).to be_positive + expect(attachment.mime_type).to eq("application/zip") + expect(attachment.filename).to match(/^participants-[0-9]+-[0-9]+-[0-9]+-[0-9]+\.zip$/) + end + + context "when format is CSV" do + it "uses the csv exporter" do + export_data = double + expect(Decidim::Exporters::CSV).to(receive(:new).with(anything, Decidim::ExtraUserFields::UserExportSerializer)).and_return(double(export: export_data)) + expect(ExportMailer) + .to(receive(:export).with(user, "participants", export_data)) + .and_return(double(deliver_now: true)) + ExportParticipantsJob.perform_now(organization, user, format) + end + end + + context "when format is JSON" do + let(:format) { "JSON" } + + it "uses the json exporter" do + export_data = double + expect(Decidim::Exporters::JSON) + .to(receive(:new).with(anything, Decidim::ExtraUserFields::UserExportSerializer)) + .and_return(double(export: export_data)) + expect(ExportMailer) + .to(receive(:export).with(user, "participants", export_data)) + .and_return(double(deliver_now: true)) + ExportParticipantsJob.perform_now(organization, user, format) + end + end + + context "when format is excel" do + let(:format) { "Excel" } + + it "uses the excel exporter" do + export_data = double + expect(Decidim::Exporters::Excel) + .to(receive(:new).with(anything, Decidim::ExtraUserFields::UserExportSerializer)) + .and_return(double(export: export_data)) + expect(ExportMailer) + .to(receive(:export).with(user, "participants", export_data)) + .and_return(double(deliver_now: true)) + ExportParticipantsJob.perform_now(organization, user, format) + end + end + end + end + end +end From c10698f776e98c179ee0b2e40765a8f36128f3c2 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:27:38 +0100 Subject: [PATCH 18/48] feat: update spec helper file --- spec/spec_helper.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a30b234..4a64faf 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,3 +7,6 @@ Decidim::Dev.dummy_app_path = File.expand_path(File.join("spec", "decidim_dummy_app")) require "decidim/dev/test/base_spec_helper" + + + From ceb4c9f8b1c10c0892ae6c73bdeee8cb20ead4d9 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:28:05 +0100 Subject: [PATCH 19/48] test: updat system tests --- spec/system/account_spec.rb | 343 +++++++++++++++++- .../admin_manages_officializations_spec.rb | 18 +- 2 files changed, 352 insertions(+), 9 deletions(-) diff --git a/spec/system/account_spec.rb b/spec/system/account_spec.rb index 3033eaa..13f6a4d 100644 --- a/spec/system/account_spec.rb +++ b/spec/system/account_spec.rb @@ -10,7 +10,7 @@ end let(:organization) { create(:organization, extra_user_fields:) } - let(:user) { create(:user, :confirmed, organization:, password:, password_confirmation: password) } + let(:user) { create(:user, :confirmed, organization:, password:) } let(:password) { "dqCFgjfDbC7dPbrv" } # rubocop:disable Style/TrailingCommaInHashLiteral let(:extra_user_fields) do @@ -63,15 +63,31 @@ login_as user, scope: :user end + describe "navigation" do + it "shows the account form when clicking on the menu" do + visit decidim.root_path + + within_user_menu do + find("a", text: "account").click + end + + expect(page).to have_css("form.edit_user") + end + end + context "when on the account page" do before do visit decidim.account_path end + it_behaves_like "accessible page" + describe "updating personal data" do + let!(:encrypted_password) { user.encrypted_password } + before do within "form.edit_user" do - select "Castellano", from: :user_locale + select "English", from: :user_locale fill_in :user_name, with: "Nikola Tesla" fill_in :user_personal_url, with: "https://example.org" fill_in :user_about, with: "A Serbian-American inventor, electrical engineer, mechanical engineer, physicist, and futurist." @@ -82,10 +98,6 @@ fill_in :user_postal_code, with: "00000" fill_in :user_phone_number, with: "0123456789" fill_in :user_location, with: "Cahors" - # Block ExtraUserFields FillFieldSpec - - # EndBlock - find("*[type=submit]").click end end @@ -94,6 +106,43 @@ within_flash_messages do expect(page).to have_content("successfully") end + + user.reload + + within_user_menu do + find("a", text: "My public profile").click + end + + expect(page).to have_content("example.org") + expect(page).to have_content("Serbian-American") + + # The user's password should not change when they did not update it + expect(user.reload.encrypted_password).to eq(encrypted_password) + end + + context " when updating avatar" do + it "can update avatar" do + dynamically_attach_file(:user_avatar, Decidim::Dev.asset("avatar.jpg")) + + within "form.edit_user" do + find("*[type=submit]").click + end + + expect(page).to have_css(".flash.success") + end + + it "shows error when image is too big" do + find("#user_avatar_button").click + + within ".upload-modal" do + click_button "Remove" + input_element = find("input[type='file']", visible: :all) + input_element.attach_file(Decidim::Dev.asset("5000x5000.png")) + + expect(page).to have_content("File resolution is too large", count: 1) + expect(page).to have_content("Validation error!") + end + end end context "with phone number pattern blank" do @@ -164,5 +213,287 @@ it_behaves_like "does not display extra user field", "location", "Location" end + + describe "when update password" do + before do + within "form.edit_user" do + select "English", from: :user_locale + fill_in :user_name, with: "Nikola Tesla" + fill_in :user_personal_url, with: "https://example.org" + fill_in :user_about, with: "A Serbian-American inventor, electrical engineer, mechanical engineer, physicist, and futurist." + + fill_in :user_date_of_birth, with: "01/01/2000" + select "Other", from: :user_gender + select "Argentina", from: :user_country + fill_in :user_postal_code, with: "00000" + fill_in :user_phone_number, with: "0123456789" + fill_in :user_location, with: "Cahors" + find("*[type=submit]").click + end + end + + let!(:encrypted_password) { user.encrypted_password } + let(:new_password) { "decidim1234567890" } + + before do + click_button "Change password" + end + + it "toggles old and new password fields" do + within "form.edit_user" do + expect(page).to have_content("must not be too common (e.g. 123456) and must be different from your nickname and your email.") + expect(page).to have_field("user[password]", with: "", type: "password") + expect(page).to have_field("user[old_password]", with: "", type: "password") + click_button "Change password" + expect(page).not_to have_field("user[password]", with: "", type: "password") + expect(page).not_to have_field("user[old_password]", with: "", type: "password") + end + end + + it "shows fields if password is wrong" do + within "form.edit_user" do + fill_in "Password", with: new_password + fill_in "Current password", with: "wrong password12345" + find("*[type=submit]").click + end + expect(page).to have_field("user[password]", with: "decidim1234567890", type: "password") + expect(page).to have_content("is invalid") + end + + it "changes the password with correct password" do + within "form.edit_user" do + fill_in "Password", with: new_password + fill_in "Current password", with: password + find("*[type=submit]").click + end + within_flash_messages do + expect(page).to have_content("successfully") + end + expect(user.reload.encrypted_password).not_to eq(encrypted_password) + expect(page).not_to have_field("user[password]", with: "", type: "password") + expect(page).not_to have_field("user[old_password]", with: "", type: "password") + end + end + + context "when update email" do + let(:pending_email) { "foo@bar.com" } + + before do + within "form.edit_user" do + select "English", from: :user_locale + fill_in :user_name, with: "Nikola Tesla" + fill_in :user_personal_url, with: "https://example.org" + fill_in :user_about, with: "A Serbian-American inventor, electrical engineer, mechanical engineer, physicist, and futurist." + + fill_in :user_date_of_birth, with: "01/01/2000" + select "Other", from: :user_gender + select "Argentina", from: :user_country + fill_in :user_postal_code, with: "00000" + fill_in :user_phone_number, with: "0123456789" + fill_in :user_location, with: "Cahors" + find("*[type=submit]").click + end + end + + context "when typing new email" do + before do + within "form.edit_user" do + fill_in "Your email", with: pending_email + find("*[type=submit]").click + end + end + + it "toggles the current password" do + expect(page).to have_content("In order to confirm the changes to your account, please provide your current password.") + expect(find("#user_old_password")).to be_visible + expect(page).to have_content "Current password" + expect(page).not_to have_content "Password" + end + + it "renders the old password with error" do + within "form.edit_user" do + find("*[type=submit]").click + fill_in :user_old_password, with: "wrong password" + find("*[type=submit]").click + end + within ".flash.alert" do + expect(page).to have_content "There was a problem updating your account." + end + within ".old-user-password" do + expect(page).to have_content "is invalid" + end + end + end + + context "when correct old password" do + before do + within "form.edit_user" do + fill_in "Your email", with: pending_email + find("*[type=submit]").click + fill_in :user_old_password, with: password + + perform_enqueued_jobs { find("*[type=submit]").click } + end + + within_flash_messages do + expect(page).to have_content("You will receive an email to confirm your new email address") + end + end + + after do + clear_enqueued_jobs + end + + it "tells user to confirm new email" do + expect(page).to have_content("Email change verification") + expect(page).to have_selector("#user_email[disabled='disabled']") + expect(page).to have_content("We have sent an email to #{pending_email} to verify your new email address") + end + + it "resend confirmation" do + within "#email-change-pending" do + click_link "Send again" + end + expect(page).to have_content("Confirmation email resent successfully to #{pending_email}") + perform_enqueued_jobs + perform_enqueued_jobs + + visit last_email_link + expect(page).to have_content("Your email address has been successfully confirmed") + end + + it "cancels the email change" do + expect(Decidim::User.find(user.id).unconfirmed_email).to eq(pending_email) + within "#email-change-pending" do + click_link "cancel" + end + + expect(page).to have_content("Email change cancelled successfully") + expect(page).not_to have_content("Email change verification") + expect(Decidim::User.find(user.id).unconfirmed_email).to be_nil + end + end + end + + context "when on the notifications settings page" do + before do + visit decidim.notifications_settings_path + end + + it "updates the user's notifications" do + page.find("[for='newsletter_notifications']").click + + within "form.edit_user" do + find("*[type=submit]").click + end + + within_flash_messages do + expect(page).to have_content("successfully") + end + end + + context "when the user is an admin" do + let!(:user) { create(:user, :confirmed, :admin, password:) } + + before do + login_as user, scope: :user + visit decidim.notifications_settings_path + end + + it "updates the administrator's notifications" do + page.find("[for='email_on_moderations']").click + page.find("[for='user_notification_settings[close_meeting_reminder]']").click + + within "form.edit_user" do + find("*[type=submit]").click + end + + within_flash_messages do + expect(page).to have_content("successfully") + end + end + end + end + + context "when on the interests page" do + before do + visit decidim.user_interests_path + end + + it "does not find any scopes" do + expect(page).to have_content("My interests") + expect(page).to have_content("This organization does not have any scope yet") + end + + context "when scopes are defined" do + let!(:scopes) { create_list(:scope, 3, organization:) } + let!(:subscopes) { create_list(:subscope, 3, parent: scopes.first) } + + before do + visit decidim.user_interests_path + end + + it "display translated scope name" do + expect(page).to have_content("My interests") + within "label[for='user_scopes_#{scopes.first.id}_checked']" do + expect(page).to have_content(translated(scopes.first.name)) + end + end + + it "allows to choose interests" do + label_field = "label[for='user_scopes_#{scopes.first.id}_checked']" + expect(page).to have_content("My interests") + find(label_field).click + click_button "Update my interests" + + within_flash_messages do + expect(page).to have_content("Your interests have been successfully updated.") + end + end + end + end + + context "when on the delete my account page" do + before do + visit decidim.delete_account_path + end + + it "does not display the authorizations message by default" do + expect(page).not_to have_content("Some data bound to your authorization will be saved for security.") + end + + it "the user can delete their account" do + fill_in :delete_user_delete_account_delete_reason, with: "I just want to delete my account" + + click_button "Delete my account" + + click_button "Yes, I want to delete my account" + + within_flash_messages do + expect(page).to have_content("successfully") + end + + click_link("Log in", match: :first) + + within ".new_user" do + fill_in :session_user_email, with: user.email + fill_in :session_user_password, with: password + find("*[type=submit]").click + end + + expect(page).not_to have_content("Signed in successfully") + expect(page).not_to have_content(user.name) + end + + context "when the user has an authorization" do + let!(:authorization) { create(:authorization, :granted, user:) } + + it "displays the authorizations message" do + visit decidim.delete_account_path + + expect(page).to have_content("Some data bound to your authorization will be saved for security.") + end + end + end end end diff --git a/spec/system/admin_manages_officializations_spec.rb b/spec/system/admin_manages_officializations_spec.rb index 3c9f367..93a1b69 100644 --- a/spec/system/admin_manages_officializations_spec.rb +++ b/spec/system/admin_manages_officializations_spec.rb @@ -19,13 +19,25 @@ within ".layout-nav" do click_on "Participants" end - end - - it "includes export dropdown button" do within ".sidebar-menu" do click_on "Participants" end + end + it "includes export dropdown button" do expect(page).to have_content("Export") end + + context "when clicking on export csv button" do + before do + find("span.exports").click + click_on "Export CSV" + end + + it "redirects to officialization index page and display a flash message" do + expect(page).to have_title("Participants") + expect(page).to have_content("Export") + expect(page).to have_content("Your export is currently in progress. You will receive an email when it is complete") + end + end end From 59bbdb868cdfaacdafb1ed4cfaf2401d6e21c656 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:29:00 +0100 Subject: [PATCH 20/48] feat: update locales files and add new de file --- config/locales/de.yml | 82 +++++++++++++++++++++++++++++++++++++++++++ config/locales/en.yml | 22 ++++++++++++ config/locales/fr.yml | 24 +++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 config/locales/de.yml diff --git a/config/locales/de.yml b/config/locales/de.yml new file mode 100644 index 0000000..50d9c8d --- /dev/null +++ b/config/locales/de.yml @@ -0,0 +1,82 @@ +--- +de: + activemodel: + attributes: + user: + country: Land + date_of_birth: Geburtsdatum + gender: Geschlecht + location: Standort + phone_number: Telefonnummer + postal_code: Postleitzahl + errors: + models: + user: + attributes: + date_of_birth: + underage: ungültig. Wenn Sie minderjährig sind, müssen Sie die Erlaubnis der Eltern einholen + decidim: + admin: + actions: + export: Exportieren + exports: + export_as: Exportieren im Format %{export_format} + extra_user_fields: + menu: + title: Benutzerdefinierte Anmeldefelder verwalten + components: + extra_user_fields: + name: Benutzerdefinierte Anmeldefelder + extra_user_fields: + admin: + exports: + users: Teilnehmer + extra_user_fields: + fields: + country: + description: Dieses Feld enthält eine Liste von Ländern. Der Benutzer kann ein Land auswählen. + label: Das Feld Land aktivieren + date_of_birth: + description: Dieses Feld ist ein Feld für das Geburtsdatum. Der Benutzer kann ein Datum auswählen. + label: Das Feld Geburtsdatum aktivieren + gender: + description: Dieses Feld ist ein Feld für die Geschlechtsidentität. Der Benutzer kann ein Geschlecht auswählen. + label: Das Feld Geschlecht aktivieren + location: + description: Dieses Feld ermöglicht das Hinzufügen von Text. Der Benutzer kann einen Ort auswählen. + label: Das Feld Standort aktivieren + phone_number: + description: Dieses Feld ist ein Telefonnummernfeld. Der Benutzer kann eine Nummer auswählen. + label: Das Feld Telefonnummer aktivieren + postal_code: + description: Dieses Feld ist für die Postleitzahl. Der Benutzer kann eine Postleitzahl auswählen. + label: Das Postleitzahlenfeld aktivieren. + form: + callout: + help: Aktivieren Sie die Funktion für benutzerdefinierte Anmeldefelder, um zusätzliche Felder in Ihrem Anmeldeformular zu verwalten. Auch bei aktivierter Option wird das Anmeldeformular nur aktualisiert, wenn mindestens ein zusätzliches Feld aktiviert ist. + extra_user_fields: + extra_user_fields_enabled: Benutzerdefinierte Anmeldefelder aktivieren + section: Verfügbare Anmeldefelder für das Anmeldeformular + global: + title: Aktivieren / Deaktivieren von benutzerdefinierten Anmeldefeldern + index: + save: Speichern + title: Benutzerdefinierte Anmeldefelder verwalten + update: + failure: Bei der Aktualisierung ist ein Fehler aufgetreten. + success: Die Anmeldefelder wurden erfolgreich aktualisiert. + genders: + female: Frau + male: Mann + other: Divers + registration_form: + signup: + legend: Weitere Informationen + statutory_representative: + inform: + body: | + Hallo, + Sie wurden als gesetzlicher Vertreter von %{name} für die Registrierung bei %{organization} benannt. + Beste grüße, + Das %{organization} Team + subject: Sie wurden als gesetzlicher Vertreter benannt diff --git a/config/locales/en.yml b/config/locales/en.yml index d592c05..af86e18 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -9,6 +9,14 @@ en: location: Location phone_number: Phone Number postal_code: Postal code + statutory_representative_email: Representative email + underage: Underage + errors: + models: + user: + attributes: + date_of_birth: + underage: invalid. If you are underage, you must obtain parental authorization decidim: admin: actions: @@ -57,6 +65,11 @@ en: description: This field is a String field. If checked, user will have to fill in a postal code label: Enable postal code field + underage: + description: This field is a Boolean field. User will be able to check + if is underage + label: Enable parental authorization field + limit: This sets the age limit (ex. 18 years old) form: callout: help: Enable custom extra user fields functionality to be able to manage @@ -80,3 +93,12 @@ en: registration_form: signup: legend: More information + underage: I am under %{limit} years old and I agree to get a parental authorization + statutory_representative: + inform: + body: | + Hello, + You have been designated as the legal representative of %{name} for their registration with %{organization}. + Best regards, + The %{organization} Team + subject: You have been designated as the legal representative diff --git a/config/locales/fr.yml b/config/locales/fr.yml index a82b997..fd9beea 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -9,6 +9,15 @@ fr: location: Localisation phone_number: Numéro de téléphone postal_code: Code postal + statutory_representative_email: Email du représentant légal + underage: Mineur + errors: + models: + user: + attributes: + date_of_birth: + underage: invalide. Si vous êtes mineur, vous devez obtenir une autorisation + parentale decidim: admin: actions: @@ -57,6 +66,11 @@ fr: description: Ce champ est un champ code postal. L'utilisateur pourra choisir un code postal. label: Activer le champ code postal + underage: + description: Ce champ est un champ booléen. L'utilisateur pourra cocher + s'il est mineur. + label: Activer le champ d'autorisation parentale + limit: Cela définit la limite d'âge (ex. 18 ans) form: callout: help: Activez la fonctionnalité des champs d'inscription personnalisés @@ -81,3 +95,13 @@ fr: registration_form: signup: legend: Plus d'information + underage: Je suis âgé de moins de %{limit} ans et j'accepte d'obtenir une + autorisation parentale + statutory_representative: + inform: + body: | + Bonjour, + Vous avez été désigné comme représentant légal de %{name} pour son inscription à %{organization}. + Cordialement, + L'équipe de %{organization} + subject: Vous avez été désigné comme représentant légal From a641978940482bfc6f91414cd03a33a5efe25871 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 16:29:48 +0100 Subject: [PATCH 21/48] fix: update i18n task file --- config/i18n-tasks.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index ffb4faa..aa01e24 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -6,8 +6,10 @@ locales: [en] ignore_unused: - "decidim.components.extra_user_fields.name" - activemodel.attributes.user.* + - activemodel.errors.models.user.* - decidim.admin.extra_user_fields.menu.title - decidim.extra_user_fields.genders.* ignore_missing: - decidim.participatory_processes.scopes.global + - decidim.admin.exports.notice From dbbfd395e75cac35a2b1f733370665bbc4f22078 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Mon, 20 Jan 2025 17:18:14 +0100 Subject: [PATCH 22/48] style: update files with rubocop --- .../admin/update_extra_user_fields.rb | 2 - .../extra_user_fields_controller.rb | 2 +- .../extra_user_fields/forms_definitions.rb | 1 - .../user_export_serializer.rb | 2 - .../create_omniauth_registration_spec.rb | 4 +- .../decidim/create_registration_spec.rb | 8 ++-- spec/forms/decidim/account_form_spec.rb | 4 +- .../admin/export_participants_job_spec.rb | 4 +- .../user_export_serializer_spec.rb | 4 +- spec/spec_helper.rb | 3 -- spec/system/account_spec.rb | 45 +++++++++---------- 11 files changed, 35 insertions(+), 44 deletions(-) diff --git a/app/commands/decidim/extra_user_fields/admin/update_extra_user_fields.rb b/app/commands/decidim/extra_user_fields/admin/update_extra_user_fields.rb index 252649f..d2e7443 100644 --- a/app/commands/decidim/extra_user_fields/admin/update_extra_user_fields.rb +++ b/app/commands/decidim/extra_user_fields/admin/update_extra_user_fields.rb @@ -38,7 +38,6 @@ def update_extra_user_fields! ) end - # rubocop:disable Style/TrailingCommaInHashLiteral # rubocop:disable Metrics/CyclomaticComplexity def extra_user_fields { @@ -60,7 +59,6 @@ def extra_user_fields # EndBlock } end - # rubocop:enable Style/TrailingCommaInHashLiteral # rubocop:enable Metrics/CyclomaticComplexity end end diff --git a/app/controllers/decidim/extra_user_fields/extra_user_fields_controller.rb b/app/controllers/decidim/extra_user_fields/extra_user_fields_controller.rb index da85d5b..93415ef 100644 --- a/app/controllers/decidim/extra_user_fields/extra_user_fields_controller.rb +++ b/app/controllers/decidim/extra_user_fields/extra_user_fields_controller.rb @@ -8,7 +8,7 @@ class ExtraUserFieldsController < ApplicationController def retrieve_underage_limit underage_limit = current_organization.extra_user_fields["underage_limit"] if underage_limit.present? - render json: { underage_limit: underage_limit } + render json: { underage_limit: } else render json: { error: "Underage limit not found" }, status: :not_found end diff --git a/app/forms/concerns/decidim/extra_user_fields/forms_definitions.rb b/app/forms/concerns/decidim/extra_user_fields/forms_definitions.rb index 356888e..982d7ac 100644 --- a/app/forms/concerns/decidim/extra_user_fields/forms_definitions.rb +++ b/app/forms/concerns/decidim/extra_user_fields/forms_definitions.rb @@ -139,7 +139,6 @@ def underage_within_limit?(age) def underage_limit current_organization.extra_user_fields["underage_limit"] end - end end end diff --git a/app/serializers/decidim/extra_user_fields/user_export_serializer.rb b/app/serializers/decidim/extra_user_fields/user_export_serializer.rb index ff19578..6e9c444 100644 --- a/app/serializers/decidim/extra_user_fields/user_export_serializer.rb +++ b/app/serializers/decidim/extra_user_fields/user_export_serializer.rb @@ -18,7 +18,6 @@ def extra_user_fields end end - # rubocop:disable Style/TrailingCommaInArrayLiteral def extra_fields [ :gender, @@ -34,7 +33,6 @@ def extra_fields # EndBlock ] end - # rubocop:enable Style/TrailingCommaInArrayLiteral end end end diff --git a/spec/commands/decidim/create_omniauth_registration_spec.rb b/spec/commands/decidim/create_omniauth_registration_spec.rb index bd8fbde..a87436a 100644 --- a/spec/commands/decidim/create_omniauth_registration_spec.rb +++ b/spec/commands/decidim/create_omniauth_registration_spec.rb @@ -28,8 +28,8 @@ module Comments location:, phone_number:, postal_code:, - underage: underage, - statutory_representative_email: statutory_representative_email + underage:, + statutory_representative_email: } end diff --git a/spec/commands/decidim/create_registration_spec.rb b/spec/commands/decidim/create_registration_spec.rb index e734d88..080fde6 100644 --- a/spec/commands/decidim/create_registration_spec.rb +++ b/spec/commands/decidim/create_registration_spec.rb @@ -31,8 +31,8 @@ module Comments location:, phone_number:, postal_code:, - underage: underage, - statutory_representative_email: statutory_representative_email + underage:, + statutory_representative_email: } end @@ -125,8 +125,8 @@ module Comments location:, phone_number:, postal_code:, - underage: underage, - statutory_representative_email: statutory_representative_email + underage:, + statutory_representative_email: } ).and_call_original diff --git a/spec/forms/decidim/account_form_spec.rb b/spec/forms/decidim/account_form_spec.rb index ccfdd3b..ad76c2d 100644 --- a/spec/forms/decidim/account_form_spec.rb +++ b/spec/forms/decidim/account_form_spec.rb @@ -24,8 +24,8 @@ module Decidim gender:, phone_number:, location:, - underage: underage, - statutory_representative_email: statutory_representative_email + underage:, + statutory_representative_email: ).with_context( current_organization: organization, current_user: user diff --git a/spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb b/spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb index e4007f8..9b8963e 100644 --- a/spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb +++ b/spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb @@ -5,9 +5,9 @@ module Decidim module ExtraUserFields module Admin - describe ExportParticipantsJob, type: :job do + describe ExportParticipantsJob do let(:organization) { create(:organization, extra_user_fields: {}) } - let(:user) { create :user, :admin, :confirmed, organization: organization } + let(:user) { create(:user, :admin, :confirmed, organization:) } let(:format) { "CSV" } it "sends an email with a file attached" do diff --git a/spec/serializers/decidim/extra_user_fields/user_export_serializer_spec.rb b/spec/serializers/decidim/extra_user_fields/user_export_serializer_spec.rb index 2d3e6aa..f1aa167 100644 --- a/spec/serializers/decidim/extra_user_fields/user_export_serializer_spec.rb +++ b/spec/serializers/decidim/extra_user_fields/user_export_serializer_spec.rb @@ -15,8 +15,8 @@ country:, phone_number:, location:, - underage: underage, - statutory_representative_email: statutory_representative_email, + underage:, + statutory_representative_email:, # Block ExtraUserFields ExtraUserFields # EndBlock diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4a64faf..a30b234 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,6 +7,3 @@ Decidim::Dev.dummy_app_path = File.expand_path(File.join("spec", "decidim_dummy_app")) require "decidim/dev/test/base_spec_helper" - - - diff --git a/spec/system/account_spec.rb b/spec/system/account_spec.rb index 13f6a4d..aa59d0f 100644 --- a/spec/system/account_spec.rb +++ b/spec/system/account_spec.rb @@ -120,7 +120,7 @@ expect(user.reload.encrypted_password).to eq(encrypted_password) end - context " when updating avatar" do + context "when updating avatar" do it "can update avatar" do dynamically_attach_file(:user_avatar, Decidim::Dev.asset("avatar.jpg")) @@ -135,7 +135,7 @@ find("#user_avatar_button").click within ".upload-modal" do - click_button "Remove" + click_on "Remove" input_element = find("input[type='file']", visible: :all) input_element.attach_file(Decidim::Dev.asset("5000x5000.png")) @@ -230,23 +230,20 @@ fill_in :user_location, with: "Cahors" find("*[type=submit]").click end + click_on "Change password" end let!(:encrypted_password) { user.encrypted_password } let(:new_password) { "decidim1234567890" } - before do - click_button "Change password" - end - it "toggles old and new password fields" do within "form.edit_user" do expect(page).to have_content("must not be too common (e.g. 123456) and must be different from your nickname and your email.") expect(page).to have_field("user[password]", with: "", type: "password") expect(page).to have_field("user[old_password]", with: "", type: "password") - click_button "Change password" - expect(page).not_to have_field("user[password]", with: "", type: "password") - expect(page).not_to have_field("user[old_password]", with: "", type: "password") + click_on "Change password" + expect(page).to have_no_field("user[password]", with: "", type: "password") + expect(page).to have_no_field("user[old_password]", with: "", type: "password") end end @@ -270,8 +267,8 @@ expect(page).to have_content("successfully") end expect(user.reload.encrypted_password).not_to eq(encrypted_password) - expect(page).not_to have_field("user[password]", with: "", type: "password") - expect(page).not_to have_field("user[old_password]", with: "", type: "password") + expect(page).to have_no_field("user[password]", with: "", type: "password") + expect(page).to have_no_field("user[old_password]", with: "", type: "password") end end @@ -307,7 +304,7 @@ expect(page).to have_content("In order to confirm the changes to your account, please provide your current password.") expect(find("#user_old_password")).to be_visible expect(page).to have_content "Current password" - expect(page).not_to have_content "Password" + expect(page).to have_no_content "Password" end it "renders the old password with error" do @@ -346,13 +343,13 @@ it "tells user to confirm new email" do expect(page).to have_content("Email change verification") - expect(page).to have_selector("#user_email[disabled='disabled']") + expect(page).to have_css("#user_email[disabled='disabled']") expect(page).to have_content("We have sent an email to #{pending_email} to verify your new email address") end it "resend confirmation" do within "#email-change-pending" do - click_link "Send again" + click_link_or_button "Send again" end expect(page).to have_content("Confirmation email resent successfully to #{pending_email}") perform_enqueued_jobs @@ -365,11 +362,11 @@ it "cancels the email change" do expect(Decidim::User.find(user.id).unconfirmed_email).to eq(pending_email) within "#email-change-pending" do - click_link "cancel" + click_link_or_button "cancel" end expect(page).to have_content("Email change cancelled successfully") - expect(page).not_to have_content("Email change verification") + expect(page).to have_no_content("Email change verification") expect(Decidim::User.find(user.id).unconfirmed_email).to be_nil end end @@ -444,7 +441,7 @@ label_field = "label[for='user_scopes_#{scopes.first.id}_checked']" expect(page).to have_content("My interests") find(label_field).click - click_button "Update my interests" + click_on "Update my interests" within_flash_messages do expect(page).to have_content("Your interests have been successfully updated.") @@ -459,21 +456,23 @@ end it "does not display the authorizations message by default" do - expect(page).not_to have_content("Some data bound to your authorization will be saved for security.") + expect(page).to have_no_content("Some data bound to your authorization will be saved for security.") end it "the user can delete their account" do fill_in :delete_user_delete_account_delete_reason, with: "I just want to delete my account" - click_button "Delete my account" + within ".form__wrapper-block" do + click_on "Delete my account" + end - click_button "Yes, I want to delete my account" + click_on "Yes, I want to delete my account" within_flash_messages do expect(page).to have_content("successfully") end - click_link("Log in", match: :first) + click_link_or_button("Log in", match: :first) within ".new_user" do fill_in :session_user_email, with: user.email @@ -481,8 +480,8 @@ find("*[type=submit]").click end - expect(page).not_to have_content("Signed in successfully") - expect(page).not_to have_content(user.name) + expect(page).to have_no_content("Signed in successfully") + expect(page).to have_no_content(user.name) end context "when the user has an authorization" do From bd7352a67d66aa908fdc3a4870a1ce23422ac490 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 21 Jan 2025 10:51:26 +0100 Subject: [PATCH 23/48] test: update accont system test --- spec/system/account_spec.rb | 74 +++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/spec/system/account_spec.rb b/spec/system/account_spec.rb index aa59d0f..5c66f68 100644 --- a/spec/system/account_spec.rb +++ b/spec/system/account_spec.rb @@ -335,6 +335,7 @@ within_flash_messages do expect(page).to have_content("You will receive an email to confirm your new email address") end + # 2 emails generated (confirmation + update) end after do @@ -355,6 +356,8 @@ perform_enqueued_jobs perform_enqueued_jobs + # the emails include 1 confirmation + 1 update emails added to the 2 previous emails + expect(emails.count).to eq(4) visit last_email_link expect(page).to have_content("Your email address has been successfully confirmed") end @@ -495,4 +498,75 @@ end end end + + context "when on the notifications page in a PWA browser" do + let(:organization) { create(:organization, host: "pwa.lvh.me") } + let(:user) { create(:user, :confirmed, password:, organization:) } + let(:password) { "dqCFgjfDbC7dPbrv" } + let(:vapid_keys) do + { + enabled: true, + public_key: "BKmjw_A8tJCcZNQ72uG8QW15XHQnrGJjHjsmoUILUUFXJ1VNhOnJLc3ywR3eZKibX4HSqhB1hAzZFj__3VqzcPQ=", + private_key: "TF_MRbSSs_4BE1jVfOsILSJemND8cRMpiznWHgdsro0=" + } + end + + context "when VAPID keys are set" do + before do + Rails.application.secrets[:vapid] = vapid_keys + driven_by(:pwa_chrome) + switch_to_host(organization.host) + login_as user, scope: :user + visit decidim.notifications_settings_path + end + + context "when on the account page" do + it "enables push notifications if supported browser" do + sleep 2 + page.find("[for='allow_push_notifications']").click + + # Wait for the browser to be subscribed + sleep 5 + + within "form.edit_user" do + find("*[type=submit]").click + end + + within_flash_messages do + expect(page).to have_content("successfully") + end + + find(:css, "#allow_push_notifications", visible: false).execute_script("this.checked = true") + end + end + end + + context "when VAPID is disabled" do + before do + Rails.application.secrets[:vapid] = { enabled: false } + driven_by(:pwa_chrome) + switch_to_host(organization.host) + login_as user, scope: :user + visit decidim.notifications_settings_path + end + + it "does not show the push notifications switch" do + expect(page).to have_no_selector(".push-notifications") + end + end + + context "when VAPID keys are not set" do + before do + Rails.application.secrets.delete(:vapid) + driven_by(:pwa_chrome) + switch_to_host(organization.host) + login_as user, scope: :user + visit decidim.notifications_settings_path + end + + it "does not show the push notifications switch" do + expect(page).to have_no_selector(".push-notifications") + end + end + end end From b122ecd6180c05a4fbf8878f13dd7fe78af70791 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 21 Jan 2025 14:38:12 +0100 Subject: [PATCH 24/48] ci: update actions in ci --- .github/workflows/ci_tests.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 5a16bc4..83180d3 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -10,7 +10,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 1 - uses: actions/setup-node@master @@ -48,19 +48,19 @@ jobs: if: "github.ref != 'refs/heads/develop'" env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - - uses: actions/checkout@v2.0.0 + - uses: actions/checkout@v3 with: fetch-depth: 1 - uses: ruby/setup-ruby@v1 with: bundler-cache: true - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} - name: Get npm cache directory path id: npm-cache-dir-path run: echo "::set-output name=dir::$(npm get cache)-extra_user_fields" - - uses: actions/cache@v2 + - uses: actions/cache@v3 id: npm-cache with: path: ${{ steps.npm-cache-dir-path.outputs.dir }} @@ -77,8 +77,8 @@ jobs: working-directory: ./spec/decidim_dummy_app/ - run: bundle exec rspec --exclude-pattern "spec/system/**/*_spec.rb" name: RSpec - - uses: codecov/codecov-action@v1 - - uses: actions/upload-artifact@v2 + - uses: codecov/codecov-action@v3 + - uses: actions/upload-artifact@v3 if: always() with: name: screenshots @@ -108,19 +108,19 @@ jobs: if: "github.ref != 'refs/heads/develop'" env: GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - - uses: actions/checkout@v2.0.0 + - uses: actions/checkout@v3 with: fetch-depth: 1 - uses: ruby/setup-ruby@v1 with: bundler-cache: true - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} - name: Get npm cache directory path id: npm-cache-dir-path run: echo "::set-output name=dir::$(npm get cache)-extra_user_fields" - - uses: actions/cache@v2 + - uses: actions/cache@v3 id: npm-cache with: path: ${{ steps.npm-cache-dir-path.outputs.dir }} @@ -137,8 +137,8 @@ jobs: working-directory: ./spec/decidim_dummy_app/ - run: bundle exec rspec spec/system name: RSpec - - uses: codecov/codecov-action@v1 - - uses: actions/upload-artifact@v2 + - uses: codecov/codecov-action@v3 + - uses: actions/upload-artifact@v3 if: always() with: name: screenshots From 0486481e5002a3c1ff6d209b636eb8c3e2b51230 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 21 Jan 2025 15:30:14 +0100 Subject: [PATCH 25/48] fix: add options to selenium driver --- spec/spec_helper.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a30b234..8e5b69d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -7,3 +7,20 @@ Decidim::Dev.dummy_app_path = File.expand_path(File.join("spec", "decidim_dummy_app")) require "decidim/dev/test/base_spec_helper" + +Capybara.register_driver :headless_chrome do |app| + options = Selenium::WebDriver::Chrome::Options.new + options.args << "--headless=new" + options.args << "--no-sandbox" + options.args << if ENV["BIG_SCREEN_SIZE"].present? + "--window-size=1920,3000" + else + "--window-size=1920,1080" + end + options.args << "--ignore-certificate-errors" if ENV["TEST_SSL"] + Capybara::Selenium::Driver.new( + app, + browser: :chrome, + options: + ) +end From 145f7bbf90c2ba51e8803d415c01773c22e9ea24 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 21 Jan 2025 15:47:56 +0100 Subject: [PATCH 26/48] ci: add chrome version and dependencies --- .github/workflows/ci_tests.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 83180d3..1c24bbb 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -5,6 +5,7 @@ env: CI: "true" RUBY_VERSION: 3.1.1 NODE_VERSION: 18.17.1 + CHROME_VERSION: 126.0.6478.182 jobs: lint: @@ -113,7 +114,14 @@ jobs: fetch-depth: 1 - uses: ruby/setup-ruby@v1 with: + ruby-version: ${{ env.RUBY_VERSION }} bundler-cache: true + - run: | + sudo apt install imagemagick + wget --no-verbose -O /tmp/chrome.deb https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${{env.CHROME_VERSION}}-1_amd64.deb + sudo dpkg -i /tmp/chrome.deb + rm /tmp/chrome.deb + name: Install Chrome version ${{ env.CHROME_VERSION }} - uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} From 418ef9b453c8b6dbab1799ecc68e251ba9aef78a Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 21 Jan 2025 15:51:01 +0100 Subject: [PATCH 27/48] ci: add new package --- .github/workflows/ci_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 1c24bbb..e4bdfce 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -117,7 +117,7 @@ jobs: ruby-version: ${{ env.RUBY_VERSION }} bundler-cache: true - run: | - sudo apt install imagemagick + sudo apt install libu2f-udev imagemagick wget --no-verbose -O /tmp/chrome.deb https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${{env.CHROME_VERSION}}-1_amd64.deb sudo dpkg -i /tmp/chrome.deb rm /tmp/chrome.deb From 662a1ca91cf0b07ed355818bd637bc3bb1af3bea Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 21 Jan 2025 16:07:07 +0100 Subject: [PATCH 28/48] fix: add new options to selenium driver --- spec/spec_helper.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8e5b69d..3379a53 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -10,8 +10,10 @@ Capybara.register_driver :headless_chrome do |app| options = Selenium::WebDriver::Chrome::Options.new - options.args << "--headless=new" + options.args << "--headless" options.args << "--no-sandbox" + options.args << "--disable-gpu" + options.args << "--disable-dev-shm-usage" options.args << if ENV["BIG_SCREEN_SIZE"].present? "--window-size=1920,3000" else From ebc783d19cc451773cc03a1094e4e71702b2aaad Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 21 Jan 2025 16:15:06 +0100 Subject: [PATCH 29/48] ci: add chrome-driver version --- .github/workflows/ci_tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index e4bdfce..532474c 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -122,6 +122,8 @@ jobs: sudo dpkg -i /tmp/chrome.deb rm /tmp/chrome.deb name: Install Chrome version ${{ env.CHROME_VERSION }} + with: + chromedriver-version: ${{ env.CHROME_VERSION }} - uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} From 845ae9d92715ac4c8db5dce9607046f9d945ba1f Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 21 Jan 2025 16:25:45 +0100 Subject: [PATCH 30/48] ci: try updating ci again to fix error --- .github/workflows/ci_tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 532474c..d1bc4b6 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -121,6 +121,7 @@ jobs: wget --no-verbose -O /tmp/chrome.deb https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${{env.CHROME_VERSION}}-1_amd64.deb sudo dpkg -i /tmp/chrome.deb rm /tmp/chrome.deb + - uses: nanasess/setup-chromedriver@v2 name: Install Chrome version ${{ env.CHROME_VERSION }} with: chromedriver-version: ${{ env.CHROME_VERSION }} @@ -129,7 +130,7 @@ jobs: node-version: ${{ env.NODE_VERSION }} - name: Get npm cache directory path id: npm-cache-dir-path - run: echo "::set-output name=dir::$(npm get cache)-extra_user_fields" + run: echo "dir=$(npm get cache)--extra_user_fields" >> $GITHUB_OUTPUT - uses: actions/cache@v3 id: npm-cache with: From fe9f22bb74fe96724b4ef53aced1a5bee6708222 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 21 Jan 2025 17:00:41 +0100 Subject: [PATCH 31/48] fix: add option to webdriver and update ci --- .github/workflows/ci_tests.yml | 2 ++ spec/spec_helper.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index d1bc4b6..6e7b494 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -143,6 +143,8 @@ jobs: - run: mkdir -p ./spec/decidim_dummy_app/tmp/screenshots name: Create the screenshots folder - uses: nanasess/setup-chromedriver@v2 + with: + chromedriver-version: ${{ env.CHROME_VERSION }} - run: RAILS_ENV=test bundle exec rails assets:precompile name: Precompile assets working-directory: ./spec/decidim_dummy_app/ diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 3379a53..ff76ebd 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -14,6 +14,7 @@ options.args << "--no-sandbox" options.args << "--disable-gpu" options.args << "--disable-dev-shm-usage" + options.args << "--remote-debugging-pipe" options.args << if ENV["BIG_SCREEN_SIZE"].present? "--window-size=1920,3000" else From 3e40d1e4d2d381e093c694c1287760473e095baa Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 21 Jan 2025 17:25:29 +0100 Subject: [PATCH 32/48] fix: update gemfile to fix CreateList error --- Gemfile | 6 +++++- Gemfile.lock | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index c73393d..7b2375c 100644 --- a/Gemfile +++ b/Gemfile @@ -15,7 +15,6 @@ gem "puma", ">= 4.3" group :development, :test do gem "byebug", "~> 11.0", platform: :mri - gem "decidim-dev", DECIDIM_VERSION end @@ -28,3 +27,8 @@ group :development do gem "spring-watcher-listen", "~> 2.0" gem "web-console", "~> 3.5" end + +group :test do + gem 'rubocop-factory_bot', '!= 2.26.0', require: false + gem 'rubocop-rspec_rails', '!= 2.29.0', require: false +end diff --git a/Gemfile.lock b/Gemfile.lock index 10e135b..50b339b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -671,7 +671,7 @@ GEM parser (>= 3.3.1.0) rubocop-capybara (2.21.0) rubocop (~> 1.41) - rubocop-factory_bot (2.26.0) + rubocop-factory_bot (2.25.1) rubocop (~> 1.41) rubocop-faker (1.1.0) faker (>= 2.12.0) @@ -686,7 +686,7 @@ GEM rubocop-capybara (~> 2.17) rubocop-factory_bot (~> 2.22) rubocop-rspec_rails (~> 2.28) - rubocop-rspec_rails (2.29.0) + rubocop-rspec_rails (2.28.3) rubocop (~> 1.40) ruby-progressbar (1.13.0) ruby-vips (2.2.1) @@ -810,7 +810,9 @@ DEPENDENCIES letter_opener_web (~> 1.3) listen (~> 3.1) puma (>= 4.3) + rubocop-factory_bot (!= 2.26.0) rubocop-faker + rubocop-rspec_rails (!= 2.29.0) spring (~> 2.0) spring-watcher-listen (~> 2.0) web-console (~> 3.5) From 0d9eb6a5faf36f5f6ceb3009a11b8e986826f9f3 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Tue, 21 Jan 2025 17:27:54 +0100 Subject: [PATCH 33/48] style: use double quotes in gemfile --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 7b2375c..3c5b45d 100644 --- a/Gemfile +++ b/Gemfile @@ -29,6 +29,6 @@ group :development do end group :test do - gem 'rubocop-factory_bot', '!= 2.26.0', require: false - gem 'rubocop-rspec_rails', '!= 2.29.0', require: false + gem "rubocop-factory_bot", "!= 2.26.0", require: false + gem "rubocop-rspec_rails", "!= 2.29.0", require: false end From 3265e16bbd0d162ab8e756a9c7efbe39316cd1fc Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 10:16:26 +0100 Subject: [PATCH 34/48] style: update rubocop.yml file --- .rubocop.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.rubocop.yml b/.rubocop.yml index b901a13..b77d8ce 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -18,3 +18,7 @@ AllCops: RSpec/FilePath: Exclude: - "spec/serializers/user_export_serializer_spec.rb" + +Style/FrozenStringLiteralComment: + Exclude: + - "spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb" From 106618d07f543b655de43dd8d7f997f59e635fa1 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 10:17:39 +0100 Subject: [PATCH 35/48] fix: update options for selenium webdriver --- spec/spec_helper.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ff76ebd..e7e7fa4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -10,9 +10,8 @@ Capybara.register_driver :headless_chrome do |app| options = Selenium::WebDriver::Chrome::Options.new - options.args << "--headless" options.args << "--no-sandbox" - options.args << "--disable-gpu" + options.args << "--headless" options.args << "--disable-dev-shm-usage" options.args << "--remote-debugging-pipe" options.args << if ENV["BIG_SCREEN_SIZE"].present? From bcb7e295ff3a58561e3dd60062b639e353d34745 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 10:28:26 +0100 Subject: [PATCH 36/48] style: update spec file and rubocop.yml file --- .rubocop.yml | 4 ---- .../extra_user_fields/admin/export_participants_job_spec.rb | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index b77d8ce..b901a13 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -18,7 +18,3 @@ AllCops: RSpec/FilePath: Exclude: - "spec/serializers/user_export_serializer_spec.rb" - -Style/FrozenStringLiteralComment: - Exclude: - - "spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb" diff --git a/spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb b/spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb index 9b8963e..360facb 100644 --- a/spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb +++ b/spec/jobs/decidim/extra_user_fields/admin/export_participants_job_spec.rb @@ -24,7 +24,8 @@ module Admin context "when format is CSV" do it "uses the csv exporter" do export_data = double - expect(Decidim::Exporters::CSV).to(receive(:new).with(anything, Decidim::ExtraUserFields::UserExportSerializer)).and_return(double(export: export_data)) + expect(Decidim::Exporters::CSV).to(receive(:new).with(anything, + Decidim::ExtraUserFields::UserExportSerializer)).and_return(double(export: export_data)) expect(ExportMailer) .to(receive(:export).with(user, "participants", export_data)) .and_return(double(deliver_now: true)) From 77fb7782c092df77130dd7b28d1f3e28aefc9cb1 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 11:22:50 +0100 Subject: [PATCH 37/48] ci: update ci file to try fixing error --- .github/workflows/ci_tests.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 6e7b494..fbbfb68 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -5,7 +5,6 @@ env: CI: "true" RUBY_VERSION: 3.1.1 NODE_VERSION: 18.17.1 - CHROME_VERSION: 126.0.6478.182 jobs: lint: @@ -116,15 +115,12 @@ jobs: with: ruby-version: ${{ env.RUBY_VERSION }} bundler-cache: true - - run: | - sudo apt install libu2f-udev imagemagick - wget --no-verbose -O /tmp/chrome.deb https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${{env.CHROME_VERSION}}-1_amd64.deb - sudo dpkg -i /tmp/chrome.deb - rm /tmp/chrome.deb - uses: nanasess/setup-chromedriver@v2 name: Install Chrome version ${{ env.CHROME_VERSION }} - with: - chromedriver-version: ${{ env.CHROME_VERSION }} + - run: | + export DISPLAY=:99 + chromedriver --url-base=/wd/hub & + sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional - uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} From 08a5094ff4c862cefbb0e73837745ca3dce28841 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 11:26:38 +0100 Subject: [PATCH 38/48] ci: update in ci file --- .github/workflows/ci_tests.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index fbbfb68..de309c9 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -116,7 +116,6 @@ jobs: ruby-version: ${{ env.RUBY_VERSION }} bundler-cache: true - uses: nanasess/setup-chromedriver@v2 - name: Install Chrome version ${{ env.CHROME_VERSION }} - run: | export DISPLAY=:99 chromedriver --url-base=/wd/hub & @@ -139,8 +138,10 @@ jobs: - run: mkdir -p ./spec/decidim_dummy_app/tmp/screenshots name: Create the screenshots folder - uses: nanasess/setup-chromedriver@v2 - with: - chromedriver-version: ${{ env.CHROME_VERSION }} + - run: | + export DISPLAY=:99 + chromedriver --url-base=/wd/hub & + sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional - run: RAILS_ENV=test bundle exec rails assets:precompile name: Precompile assets working-directory: ./spec/decidim_dummy_app/ From e1171725e4f0320159403c08076f41782612d8d8 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 11:53:13 +0100 Subject: [PATCH 39/48] ci: another update of ci file --- .github/workflows/ci_tests.yml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index de309c9..1d03f32 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -5,6 +5,7 @@ env: CI: "true" RUBY_VERSION: 3.1.1 NODE_VERSION: 18.17.1 + CHROME_VERSION: 126.0.6478.182 jobs: lint: @@ -115,11 +116,18 @@ jobs: with: ruby-version: ${{ env.RUBY_VERSION }} bundler-cache: true + - run: | + sudo apt install libu2f-udev imagemagick + wget --no-verbose -O /tmp/chrome.deb https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${{env.CHROME_VERSION}}-1_amd64.deb + sudo dpkg -i /tmp/chrome.deb + rm /tmp/chrome.deb + name: Install Chrome version ${{ env.CHROME_VERSION }} - uses: nanasess/setup-chromedriver@v2 + with: + chromedriver-version: ${{ env.CHROME_VERSION }} - run: | export DISPLAY=:99 - chromedriver --url-base=/wd/hub & - sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional + chromedriver --url-base=/wd/hub - uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} @@ -138,10 +146,11 @@ jobs: - run: mkdir -p ./spec/decidim_dummy_app/tmp/screenshots name: Create the screenshots folder - uses: nanasess/setup-chromedriver@v2 + with: + chromedriver-version: ${{ env.CHROME_VERSION }} - run: | export DISPLAY=:99 - chromedriver --url-base=/wd/hub & - sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional + chromedriver --url-base=/wd/hub - run: RAILS_ENV=test bundle exec rails assets:precompile name: Precompile assets working-directory: ./spec/decidim_dummy_app/ From e84f1def177ce4e636e7a42e205d5ffc8b2bc876 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 11:54:12 +0100 Subject: [PATCH 40/48] test: another update of options for webdriver --- spec/spec_helper.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e7e7fa4..8e5b69d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -10,10 +10,8 @@ Capybara.register_driver :headless_chrome do |app| options = Selenium::WebDriver::Chrome::Options.new + options.args << "--headless=new" options.args << "--no-sandbox" - options.args << "--headless" - options.args << "--disable-dev-shm-usage" - options.args << "--remote-debugging-pipe" options.args << if ENV["BIG_SCREEN_SIZE"].present? "--window-size=1920,3000" else From d3b563a42c3f860825a452b38e771fc2f601e1e5 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 12:11:50 +0100 Subject: [PATCH 41/48] ci: add specific chrome version again --- .github/workflows/ci_tests.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 1d03f32..f43d528 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -125,9 +125,6 @@ jobs: - uses: nanasess/setup-chromedriver@v2 with: chromedriver-version: ${{ env.CHROME_VERSION }} - - run: | - export DISPLAY=:99 - chromedriver --url-base=/wd/hub - uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} @@ -148,9 +145,6 @@ jobs: - uses: nanasess/setup-chromedriver@v2 with: chromedriver-version: ${{ env.CHROME_VERSION }} - - run: | - export DISPLAY=:99 - chromedriver --url-base=/wd/hub - run: RAILS_ENV=test bundle exec rails assets:precompile name: Precompile assets working-directory: ./spec/decidim_dummy_app/ From 215cf4ee20eee70a7ec49dce09e612a08ddb8ac1 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 12:25:46 +0100 Subject: [PATCH 42/48] ci: update again --- .github/workflows/ci_tests.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index f43d528..68781c2 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -122,9 +122,6 @@ jobs: sudo dpkg -i /tmp/chrome.deb rm /tmp/chrome.deb name: Install Chrome version ${{ env.CHROME_VERSION }} - - uses: nanasess/setup-chromedriver@v2 - with: - chromedriver-version: ${{ env.CHROME_VERSION }} - uses: actions/setup-node@v3 with: node-version: ${{ env.NODE_VERSION }} From 962b0fc7552664f2a5748c4cd23e62f1282f6da0 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 15:55:58 +0100 Subject: [PATCH 43/48] test: remove webdriver options --- spec/spec_helper.rb | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8e5b69d..a73f5d2 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -8,19 +8,3 @@ require "decidim/dev/test/base_spec_helper" -Capybara.register_driver :headless_chrome do |app| - options = Selenium::WebDriver::Chrome::Options.new - options.args << "--headless=new" - options.args << "--no-sandbox" - options.args << if ENV["BIG_SCREEN_SIZE"].present? - "--window-size=1920,3000" - else - "--window-size=1920,1080" - end - options.args << "--ignore-certificate-errors" if ENV["TEST_SSL"] - Capybara::Selenium::Driver.new( - app, - browser: :chrome, - options: - ) -end From fbea2e0c866ebc8fd4e2fea03bbddddc0de1e3a7 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 15:57:30 +0100 Subject: [PATCH 44/48] ci:implement ci similar to decidim/decidim --- .github/workflows/build_app.yml | 66 +++++++++++++++ .github/workflows/ci_tests.yml | 145 ++++---------------------------- .github/workflows/test_app.yml | 99 ++++++++++++++++++++++ 3 files changed, 182 insertions(+), 128 deletions(-) create mode 100644 .github/workflows/build_app.yml create mode 100644 .github/workflows/test_app.yml diff --git a/.github/workflows/build_app.yml b/.github/workflows/build_app.yml new file mode 100644 index 0000000..35e54a5 --- /dev/null +++ b/.github/workflows/build_app.yml @@ -0,0 +1,66 @@ +on: + workflow_call: + inputs: + ruby_version: + description: 'Ruby Version' + default: "3.1.1" + type: string + required: false + node_version: + description: 'Node version' + default: '18.17.1' + required: false + type: string +jobs: + build_app: + name: Build app + runs-on: ubuntu-22.04 + if: "!startsWith(github.head_ref, 'chore/l10n')" + timeout-minutes: 60 + env: + DATABASE_USERNAME: postgres + DATABASE_PASSWORD: postgres + DATABASE_HOST: localhost + RUBYOPT: '-W:no-deprecated' + services: + postgres: + image: postgres:14 + ports: ["5432:5432"] + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + env: + POSTGRES_PASSWORD: postgres + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 1 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ inputs.ruby_version }} + bundler-cache: true + - uses: actions/setup-node@v3 + with: + node-version: ${{ inputs.node_version }} + cache: 'npm' + cache-dependency-path: ./package-lock.json + - uses: actions/cache@v3 + id: app-cache + with: + path: ./spec/decidim_dummy_app/ + key: app-${{ github.sha }} + restore-keys: app-${{ github.sha }} + - run: bundle exec rake test_app + name: Create test app + shell: "bash" + - run: mkdir -p ./spec/decidim_dummy_app/tmp/screenshots + name: Create the screenshots folder + shell: "bash" + - run: RAILS_ENV=test bundle exec rails assets:precompile + name: Precompile assets + working-directory: ./spec/decidim_dummy_app/ + shell: "bash" + env: + NODE_ENV: "test" diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 68781c2..f3842d2 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -5,11 +5,21 @@ env: CI: "true" RUBY_VERSION: 3.1.1 NODE_VERSION: 18.17.1 - CHROME_VERSION: 126.0.6478.182 + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true jobs: + build_app: + uses: ./.github/workflows/build_app.yml + secrets: inherit + name: Build test application + lint: + name: Lint code runs-on: ubuntu-latest + timeout-minutes: 60 steps: - uses: actions/checkout@v3 with: @@ -25,132 +35,11 @@ jobs: name: Lint Ruby files - run: bundle exec erblint app/**/*.erb name: Lint ERB files + tests: name: Tests - runs-on: ubuntu-latest - timeout-minutes: 30 - services: - postgres: - image: postgres:11 - ports: ["5432:5432"] - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - env: - POSTGRES_PASSWORD: postgres - env: - DATABASE_USERNAME: postgres - DATABASE_PASSWORD: postgres - DATABASE_HOST: localhost - steps: - - uses: rokroskar/workflow-run-cleanup-action@v0.3.0 - if: "github.ref != 'refs/heads/develop'" - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - - uses: actions/checkout@v3 - with: - fetch-depth: 1 - - uses: ruby/setup-ruby@v1 - with: - bundler-cache: true - - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Get npm cache directory path - id: npm-cache-dir-path - run: echo "::set-output name=dir::$(npm get cache)-extra_user_fields" - - uses: actions/cache@v3 - id: npm-cache - with: - path: ${{ steps.npm-cache-dir-path.outputs.dir }} - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm- - - run: bundle exec rake test_app - name: Create test app - - run: mkdir -p ./spec/decidim_dummy_app/tmp/screenshots - name: Create the screenshots folder - - uses: nanasess/setup-chromedriver@v2 - - run: RAILS_ENV=test bundle exec rails assets:precompile - name: Precompile assets - working-directory: ./spec/decidim_dummy_app/ - - run: bundle exec rspec --exclude-pattern "spec/system/**/*_spec.rb" - name: RSpec - - uses: codecov/codecov-action@v3 - - uses: actions/upload-artifact@v3 - if: always() - with: - name: screenshots - path: ./spec/decidim_dummy_app/tmp/screenshots - if-no-files-found: ignore - system-tests: - name: System tests - runs-on: ubuntu-latest - timeout-minutes: 30 - services: - postgres: - image: postgres:11 - ports: ["5432:5432"] - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - env: - POSTGRES_PASSWORD: postgres - env: - DATABASE_USERNAME: postgres - DATABASE_PASSWORD: postgres - DATABASE_HOST: localhost - steps: - - uses: rokroskar/workflow-run-cleanup-action@v0.3.0 - if: "github.ref != 'refs/heads/develop'" - env: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - - uses: actions/checkout@v3 - with: - fetch-depth: 1 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ${{ env.RUBY_VERSION }} - bundler-cache: true - - run: | - sudo apt install libu2f-udev imagemagick - wget --no-verbose -O /tmp/chrome.deb https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${{env.CHROME_VERSION}}-1_amd64.deb - sudo dpkg -i /tmp/chrome.deb - rm /tmp/chrome.deb - name: Install Chrome version ${{ env.CHROME_VERSION }} - - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - - name: Get npm cache directory path - id: npm-cache-dir-path - run: echo "dir=$(npm get cache)--extra_user_fields" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 - id: npm-cache - with: - path: ${{ steps.npm-cache-dir-path.outputs.dir }} - key: npm-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - npm- - - run: bundle exec rake test_app - name: Create test app - - run: mkdir -p ./spec/decidim_dummy_app/tmp/screenshots - name: Create the screenshots folder - - uses: nanasess/setup-chromedriver@v2 - with: - chromedriver-version: ${{ env.CHROME_VERSION }} - - run: RAILS_ENV=test bundle exec rails assets:precompile - name: Precompile assets - working-directory: ./spec/decidim_dummy_app/ - - run: bundle exec rspec spec/system - name: RSpec - - uses: codecov/codecov-action@v3 - - uses: actions/upload-artifact@v3 - if: always() - with: - name: screenshots - path: ./spec/decidim_dummy_app/tmp/screenshots - if-no-files-found: ignore + needs: build_app. + uses: ./.github/workflows/test_app.yml + with: + test_command: "bundle exec rspec --pattern './spec/**/*_spec.rb'" + secrets: inherit diff --git a/.github/workflows/test_app.yml b/.github/workflows/test_app.yml new file mode 100644 index 0000000..5dcfa0d --- /dev/null +++ b/.github/workflows/test_app.yml @@ -0,0 +1,99 @@ +on: + workflow_call: + inputs: + ruby_version: + description: 'Ruby Version' + default: "3.1.1" + required: false + type: string + test_command: + description: 'The testing command to be ran' + required: true + type: string + chrome_version: + description: 'Chrome & Chromedriver version' + required: false + default: "126.0.6478.182" + type: string + +jobs: + build_app: + name: Test app + runs-on: ubuntu-22.04 + if: "!startsWith(github.head_ref, 'chore/l10n')" + timeout-minutes: 60 + env: + DATABASE_USERNAME: postgres + DATABASE_PASSWORD: postgres + DATABASE_HOST: localhost + RUBYOPT: '-W:no-deprecated' + services: + validator: + image: ghcr.io/validator/validator:latest + ports: ["8888:8888"] + postgres: + image: postgres:14 + ports: ["5432:5432"] + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + env: + POSTGRES_PASSWORD: postgres + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 1 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ inputs.ruby_version }} + bundler-cache: true + - run: | + sudo apt update + sudo apt install libu2f-udev + wget --no-verbose -O /tmp/chrome.deb https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_${{inputs.chrome_version}}-1_amd64.deb + sudo dpkg -i /tmp/chrome.deb + rm /tmp/chrome.deb + - uses: nanasess/setup-chromedriver@v2 + name: Install Chrome version ${{inputs.chrome_version}} + with: + chromedriver-version: ${{inputs.chrome_version}} + - uses: actions/cache@v3 + id: app-cache + with: + path: ./spec/decidim_dummy_app/ + key: app-${{ github.sha }} + restore-keys: app-${{ github.sha }} + - run: | + bundle install + bundle exec rake db:create db:schema:load + name: Install gems and create db + shell: "bash" + working-directory: ./spec/decidim_dummy_app/ + - run: | + sudo Xvfb -ac $DISPLAY -screen 0 1920x1084x24 > /dev/null 2>&1 & + ${{ inputs.test_command }} + name: RSpec + working-directory: ./ + env: + VALIDATOR_HTML_URI: http://localhost:8888/ + RUBY_VERSION: ${{ inputs.ruby_version }} + DECIDIM_MODULE: ${{ inputs.working-directory }} + DISPLAY: ":99" + CI: "true" + SIMPLECOV: "true" + SHAKAPACKER_RUNTIME_COMPILE: "false" + NODE_ENV: "test" + - uses: codecov/codecov-action@v3 + name: Upload coverage + with: + name: ${{ inputs.working-directory }} + flags: ${{ inputs.working-directory }} + - uses: actions/upload-artifact@v3 + if: always() + with: + name: screenshots + path: ./spec/decidim_dummy_app/tmp/screenshots + if-no-files-found: ignore + overwrite: true From e6e9501fbb1b4628220d7e0a0d46ee6c968c6139 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 16:03:08 +0100 Subject: [PATCH 45/48] ci: update ci --- .github/workflows/ci_tests.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index f3842d2..01affb1 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -1,5 +1,16 @@ name: "[CI] ExtraUserFields" -on: "push" +on: + push: + branches: + - develop + - release/* + - "*-stable" + pull_request: + branches-ignore: + - "chore/l10n*" + paths: + - "*" + - ".github/**" env: CI: "true" @@ -38,7 +49,7 @@ jobs: tests: name: Tests - needs: build_app. + needs: build_app uses: ./.github/workflows/test_app.yml with: test_command: "bundle exec rspec --pattern './spec/**/*_spec.rb'" From d2ff8a279a360a771d8c0d3dcb02a30572eaa2d6 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 16:19:30 +0100 Subject: [PATCH 46/48] fix: add package-lock.json --- package-lock.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..e83bb48 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "decidim-module-extra_user_fields", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} From 2d3cd3a059c9fb78dab1a26093e2ee5963fd6fe7 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 16:41:16 +0100 Subject: [PATCH 47/48] ci: fix test.yml --- .github/workflows/test_app.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test_app.yml b/.github/workflows/test_app.yml index 5dcfa0d..6489b0a 100644 --- a/.github/workflows/test_app.yml +++ b/.github/workflows/test_app.yml @@ -65,12 +65,10 @@ jobs: path: ./spec/decidim_dummy_app/ key: app-${{ github.sha }} restore-keys: app-${{ github.sha }} - - run: | - bundle install - bundle exec rake db:create db:schema:load - name: Install gems and create db - shell: "bash" - working-directory: ./spec/decidim_dummy_app/ + - run: bundle exec rake parallel:create parallel:load_schema + name: Parallel tests + shell: "bash" + working-directory: ./spec/decidim_dummy_app/ - run: | sudo Xvfb -ac $DISPLAY -screen 0 1920x1084x24 > /dev/null 2>&1 & ${{ inputs.test_command }} From f634c0becda9a61622d83cc30ec9fdf7e877ffa8 Mon Sep 17 00:00:00 2001 From: stephanie rousset Date: Wed, 22 Jan 2025 16:53:59 +0100 Subject: [PATCH 48/48] ci: fix in test.yml --- .github/workflows/test_app.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test_app.yml b/.github/workflows/test_app.yml index 6489b0a..f75fb10 100644 --- a/.github/workflows/test_app.yml +++ b/.github/workflows/test_app.yml @@ -65,8 +65,8 @@ jobs: path: ./spec/decidim_dummy_app/ key: app-${{ github.sha }} restore-keys: app-${{ github.sha }} - - run: bundle exec rake parallel:create parallel:load_schema - name: Parallel tests + - run: bundle exec rails db:create db:schema:load + name: Install gems and create db shell: "bash" working-directory: ./spec/decidim_dummy_app/ - run: |