diff --git a/app/models/jubla/wizards/register_new_user_wizard.rb b/app/models/jubla/wizards/register_new_user_wizard.rb new file mode 100644 index 0000000..c8c08a4 --- /dev/null +++ b/app/models/jubla/wizards/register_new_user_wizard.rb @@ -0,0 +1,22 @@ +module Jubla::Wizards::RegisterNewUserWizard + extend ActiveSupport::Concern + PHONE_NUMBER_LABEL = "Privat" + + prepended do + # attribute :address_care_of, :string + # attribute :street, :string + # attribute :housenumber, :string + + # attribute :postbox, :string + # attribute :zip_code, :string + # attribute :town, :string + # attribute :country, :string + + # attribute :phone_number, :string + # attribute :email, :string + + # validates :email, presence: true + end + + delegate :person_attributes, to: :new_user_form +end diff --git a/app/models/jubla/wizards/steps/new_user_form.rb b/app/models/jubla/wizards/steps/new_user_form.rb new file mode 100644 index 0000000..f6aa4da --- /dev/null +++ b/app/models/jubla/wizards/steps/new_user_form.rb @@ -0,0 +1,61 @@ +module Jubla::Wizards::Steps::NewUserForm + extend ActiveSupport::Concern + PHONE_NUMBER_LABEL = "Privat" + + prepended do + attribute :address_care_of, :string + attribute :street, :string + attribute :housenumber, :string + + attribute :postbox, :string + attribute :zip_code, :string + attribute :town, :string + attribute :country, :string + + attribute :phone_number, :string + attribute :email, :string + + validates :email, presence: true + + validate :assert_valid_phone_number + end + + def initialize(...) + super + + if current_user + self.id = current_user.id + self.gender ||= current_user.gender + self.first_name ||= current_user.first_name + self.last_name ||= current_user.last_name + self.birthday ||= current_user.birthday + self.email ||= current_user.email + self.address_care_of ||= current_user.address_care_of + self.street ||= current_user.street + self.housenumber ||= current_user.housenumber + self.postbox ||= current_user.postbox + self.zip_code ||= current_user.zip_code + self.town ||= current_user.town + self.country ||= current_user.country + self.phone_number ||= current_user.phone_numbers.find_by(label: PHONE_NUMBER_LABEL)&.number + else + self.country ||= Settings.addresses.imported_countries.to_a.first + end + end + + def person_attributes + attributes.compact.symbolize_keys.except(:phone_number).then do |attrs| + next attrs if phone_number.blank? + + attrs.merge(phone_numbers_attributes: [{label: PHONE_NUMBER_LABEL, number: phone_number, public: false}.compact]) + end + end + + private + + def assert_valid_phone_number + if phone_number.present? && PhoneNumber.new(number: phone_number).tap(&:valid?).errors.key?(:number) + errors.add(:phone_number, :invalid) + end + end +end diff --git a/app/views/wizards/steps/_new_user_form.html.haml b/app/views/wizards/steps/_new_user_form.html.haml new file mode 100644 index 0000000..acceb19 --- /dev/null +++ b/app/views/wizards/steps/_new_user_form.html.haml @@ -0,0 +1,19 @@ +-# Copyright (c) 2025, Jungwacht Blauring Schweiz. This file is part of +-# hitobito_sac_cas and licensed under the Aformero General Public License version 3 +-# or later. See the COPYING file at the top-level directory or at +-# https://github.com/hitobito/hitobito_sac_cas. + += c.fields_for do |ff| + = ff.labeled_input_fields :first_name, :last_name + - if f.object.new_user_form.support_company? + = ff.labeled_input_fields :company_name + = ff.labeled_boolean_field :company + = render 'contactable/address_fields', f: ff + = ff.labeled_input_field :phone_number, placeholder: t('global.phone_placeholder') + + = ff.labeled_input_field :email, help_inline: t('people.email_field.used_as_login'), class: 'd-inline' + + - if f.object.steps.one? + = render 'groups/self_registration/adult_consent_field', f: ff + = field_set_tag(nil, class: 'privacy-policy-fields') do + = render('people/privacy_policy_acceptance_field', f: ff, policy_finder: f.object.policy_finder) diff --git a/config/locales/views.de.yml b/config/locales/views.de.yml index b0be848..7593cb1 100644 --- a/config/locales/views.de.yml +++ b/config/locales/views.de.yml @@ -4,6 +4,12 @@ # https://github.com/hitobito/hitobito_jubla. de: + global: + phone_placeholder: +41 77 123 45 67 + activemodel: + attributes: + wizards/steps/new_user_form: + phone_number: Telefon (Privat) census_evaluation/federation: export_enqueued: "Export wird im Hintergrund gestartet und nach Fertigstellung heruntergeladen." census_evaluation/state: diff --git a/lib/hitobito_jubla/wagon.rb b/lib/hitobito_jubla/wagon.rb index 346ec52..3ca3c20 100644 --- a/lib/hitobito_jubla/wagon.rb +++ b/lib/hitobito_jubla/wagon.rb @@ -114,6 +114,11 @@ class Wagon < Rails::Engine ### helpers EventParticipationsHelper.prepend Jubla::EventParticipationsHelper + ### wizards + Wizards::RegisterNewUserWizard.prepend Jubla::Wizards::RegisterNewUserWizard + Wizards::Steps::NewUserForm.prepend Jubla::Wizards::Steps::NewUserForm + Wizards::Steps::NewUserForm.support_company = false + # add more active_for urls to main navigation admin = NavigationHelper::MAIN.find { |opts| opts[:label] == :admin } admin[:active_for] << "event_camp_kinds" diff --git a/spec/models/wizards/register_new_user_wizard_spec.rb b/spec/models/wizards/register_new_user_wizard_spec.rb new file mode 100644 index 0000000..cd5c0bd --- /dev/null +++ b/spec/models/wizards/register_new_user_wizard_spec.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +# Copyright (c) 2024, Schweizer Alpen-Club. This file is part of hitobito and licensed under the +# Affero General Public License version 3 or later. See the COPYING file at the top-level directory +# or at https://github.com/hitobito/hitobito. + +require "spec_helper" + +describe Wizards::RegisterNewUserWizard do + let(:params) { {} } + let(:role_type) { Group::Flock::External } + let(:group) { groups(:thun) } + + subject(:wizard) do + described_class.new(group: group, **params).tap { |w| w.step_at(0) } + end + + subject(:new_user_form) { wizard.new_user_form } + + context "with self_wizard_role_type on group" do + before { group.update!(self_registration_role_type: role_type) } + + describe "validations" do + it "is invalid if attributes are not present" do + expect(wizard).not_to be_valid + expect(new_user_form.errors).to have(3).item + expect(new_user_form.errors[:first_name][0]).to eq "muss ausgefüllt werden" + expect(new_user_form.errors[:last_name][0]).to eq "muss ausgefüllt werden" + expect(new_user_form.errors[:email][0]).to eq "muss ausgefüllt werden" + end + + it "is valid if required attributes are present" do + params[:new_user_form] = {first_name: "test", last_name: "test", email: "tester@example.com"} + expect(wizard).to be_valid + end + + it "is invalid if phone number is invalid" do + params[:new_user_form] = {first_name: "test", last_name: "test", email: "tester@example.com", phone_number: "1234"} + expect(wizard).not_to be_valid + expect(new_user_form.errors).to have(1).item + expect(new_user_form.errors[:phone_number][0]).to eq "ist nicht gültig" + end + end + + describe "#save!" do + let(:person) { Person.find_by(first_name: "test") } + + it "updates all person fields" do + params[:new_user_form] = { + first_name: "test", + last_name: "dummy", + address_care_of: "", + street: "Bergstrasse", + housenumber: "41", + postbox: "3", + zip_code: "3000", + town: "Bern", + email: "test@example.com", + privacy_policy_accepted: true + } + freeze_time + wizard.save! + expect(person.privacy_policy_accepted_at).to eq Time.zone.now + expect(person.last_name).to eq "dummy" + expect(person.street).to eq "Bergstrasse" + expect(person.housenumber).to eq "41" + expect(person.postbox).to eq "3" + expect(person.zip_code).to eq "3000" + expect(person.town).to eq "Bern" + expect(person.email).to eq "test@example.com" + end + + it "sets non-public phone number with correct label" do + params[:new_user_form] = { + first_name: "test", + last_name: "dummy", + phone_number: "0781234567", + email: "test@example.com", + privacy_policy_accepted: true + } + wizard.save! + expect(person.phone_numbers).to have(1).item + number = person.phone_numbers.first + expect(number.label).to eq "Privat" + expect(number.number).to eq "+41 78 123 45 67" + expect(number.public).to eq false + end + end + end +end