diff --git a/app/admin/user.rb b/app/admin/user.rb index f34aed6ce..0322c8eed 100644 --- a/app/admin/user.rb +++ b/app/admin/user.rb @@ -5,6 +5,14 @@ link_to I18n.t("active_admin.users.upload_from_csv"), action: "upload_csv" end + action_item :confirm, only: :show do + unless user.confirmed? + link_to I18n.t("active_admin.users.confirm_user"), + confirm_admin_user_path(user), + method: :put + end + end + collection_action :upload_csv do render "admin/csv/upload_csv" end @@ -16,6 +24,15 @@ redirect_to action: :index end + member_action :confirm, method: :put do + resource.skip_confirmation! + if resource.save + redirect_to admin_user_path(resource), notice: I18n.t("active_admin.users.confirmed_notice") + else + redirect_to admin_user_path(resource), alert: resource.errors.full_messages.to_sentence + end + end + scope :all scope :without_memberships @@ -32,6 +49,7 @@ column :posts do |u| u.posts.count end + column :confirmed_at column :created_at actions end @@ -53,6 +71,9 @@ f.input :postcode f.input :gender, as: :select, collection: User::GENDERS f.input :locale, as: :select, collection: I18n.available_locales + f.input :password, required: false, input_html: { autocomplete: "new-password" } + f.input :password_confirmation, required: false, input_html: { autocomplete: "new-password" } + f.input :confirm_immediately, as: :boolean if f.object.new_record? end f.inputs "Memberships" do f.has_many :members, allow_destroy: true do |m| @@ -91,6 +112,22 @@ end end - permit_params :username, :email, :phone, :postcode, :gender, :locale, + permit_params :username, :email, :phone, :postcode, :gender, :locale, :confirm_immediately, + :password, :password_confirmation, members_attributes: [:id, :organization_id, :active, :manager, :_destroy] + + controller do + def create_resource(obj) + obj.skip_confirmation! if obj.confirm_immediately + super + end + + def update_resource(obj, attributes) + if attributes.first[:password].blank? + attributes.first.delete(:password) + attributes.first.delete(:password_confirmation) + end + super + end + end end diff --git a/app/models/user.rb b/app/models/user.rb index d503083a5..379062855 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -22,6 +22,7 @@ class User < ApplicationRecord attr_accessor :empty_email attr_accessor :from_signup + attribute :confirm_immediately, :boolean has_one_attached :avatar diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 6a2c68683..e693a0260 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -2,6 +2,8 @@ ca: active_admin: users: organization: Banc de temps + confirm_user: Confirmar usuari + confirmed_notice: Usuari confirmat correctament upload_csv: Fitxer upload_from_csv: Importar CSV activerecord: @@ -70,6 +72,7 @@ ca: registration_date: Data d'alta registration_number: Codi d'usuari superadmin: SuperAdministrador del Sistema + confirm_immediately: Confirmar immediatament unconfirmed_email: Correu sense confirmar updated_at: Actualitzat username: Nom diff --git a/config/locales/en.yml b/config/locales/en.yml index 1d26d73fd..551b88838 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2,6 +2,8 @@ en: active_admin: users: organization: Time bank + confirm_user: Confirm user + confirmed_notice: User confirmed successfully upload_csv: File upload_from_csv: Upload CSV activerecord: @@ -70,6 +72,7 @@ en: registration_date: Registration date registration_number: User code superadmin: System Administrator + confirm_immediately: Confirm immediately unconfirmed_email: Unconfirmed Email updated_at: Updated username: Name diff --git a/config/locales/es.yml b/config/locales/es.yml index 3490a28de..14fb665b1 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -2,6 +2,8 @@ es: active_admin: users: organization: Banco de tiempo + confirm_user: Confirmar usuario + confirmed_notice: Usuario confirmado correctamente upload_csv: Fichero upload_from_csv: Importar CSV activerecord: @@ -70,6 +72,7 @@ es: registration_date: Fecha de alta registration_number: Código de usuario superadmin: Administrador de sistema + confirm_immediately: Confirmar inmediatamente unconfirmed_email: Correo sin confirmar updated_at: Actualizado username: Nombre diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 506b3398f..cf2922a9f 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -2,6 +2,8 @@ eu: active_admin: users: organization: Denbora Bankua + confirm_user: Erabiltzailea baieztatu + confirmed_notice: Erabiltzailea berretsita upload_csv: Fitxategia upload_from_csv: Igo CSVa activerecord: @@ -70,6 +72,7 @@ eu: registration_date: Erregistratze-da registration_number: Erabiltzaile kodea superadmin: Sistema administratzailea + confirm_immediately: Berehala baieztatu unconfirmed_email: Baieztatu gabeko eposta updated_at: Eguneratua username: Izena diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 9e9bf3459..8a5779b7f 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -2,6 +2,8 @@ fr: active_admin: users: organization: Banque de temps + confirm_user: "Confirmer l'utilisateur" + confirmed_notice: "Utilisateur confirmé avec succès" upload_csv: Fichier upload_from_csv: Uploader un CSV activerecord: @@ -70,6 +72,7 @@ fr: registration_date: Date d'inscription registration_number: Numéro d'inscription superadmin: Administrateur système + confirm_immediately: Confirmer immédiatement unconfirmed_email: Adresse email non-confirmée updated_at: Mis·e à jour le username: Nom diff --git a/config/locales/gl.yml b/config/locales/gl.yml index e5affa6b3..776de46c1 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -2,6 +2,8 @@ gl: active_admin: users: organization: Banco de tempo + confirm_user: Confirmar usuario + confirmed_notice: Usuario confirmado correctamente upload_csv: Ficheiro upload_from_csv: Importar CSV activerecord: @@ -70,6 +72,7 @@ gl: registration_date: Data de rexistro registration_number: Código de persoa usuaria superadmin: Persoa dministradora do sistema + confirm_immediately: Confirmar inmediatamente unconfirmed_email: Correo electrónico non confirmado updated_at: Actualizado username: Nome diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 9494d415f..3f06c06d9 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -2,6 +2,8 @@ ja: active_admin: users: organization: タイムバンク + confirm_user: ユーザーを確認 + confirmed_notice: ユーザーが確認されました upload_csv: ファイル upload_from_csv: CSVをインポート activerecord: @@ -70,6 +72,7 @@ ja: registration_date: 登録日 registration_number: ユーザー番号 superadmin: システム管理者 + confirm_immediately: すぐに確認する unconfirmed_email: 未確認メールアドレス updated_at: 更新 username: 名前 diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index c575806ba..5da85f8f9 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -2,6 +2,8 @@ pt-BR: active_admin: users: organization: Banco de Tempo + confirm_user: Confirmar usuário + confirmed_notice: Usuário confirmado com sucesso upload_csv: Arquivo upload_from_csv: Importar CSV activerecord: @@ -70,6 +72,7 @@ pt-BR: registration_date: Data de ingresso registration_number: Código do usuário superadmin: Administrador do sistema + confirm_immediately: Confirmar imediatamente unconfirmed_email: E-mail sem confirmação updated_at: Atualizado username: Nome diff --git a/spec/admin/users_controller_spec.rb b/spec/admin/users_controller_spec.rb new file mode 100644 index 000000000..0dfad21ca --- /dev/null +++ b/spec/admin/users_controller_spec.rb @@ -0,0 +1,79 @@ +RSpec.describe Admin::UsersController, type: :controller do + let(:organization) { Fabricate(:organization) } + let(:member) { Fabricate(:member, organization: organization) } + let(:user) { member.user } + + before do + login(user) + allow(controller).to receive(:authenticate_superuser!).and_return(true) + end + + describe "PUT #confirm" do + context "when the user is unconfirmed" do + let(:unconfirmed_user) { Fabricate(:user, confirmed_at: nil) } + + it "confirms the user and redirects with notice" do + put :confirm, params: { id: unconfirmed_user.id } + + expect(unconfirmed_user.reload.confirmed?).to be true + expect(response).to redirect_to(admin_user_path(unconfirmed_user)) + expect(flash[:notice]).to eq(I18n.t("active_admin.users.confirmed_notice")) + end + end + + context "when the user is already confirmed" do + it "re-confirms and redirects with notice" do + put :confirm, params: { id: user.id } + + expect(response).to redirect_to(admin_user_path(user)) + expect(flash[:notice]).to eq(I18n.t("active_admin.users.confirmed_notice")) + end + end + end + + describe "POST #create" do + let(:valid_params) do + { username: "newuser", email: "new@example.com", locale: "en" } + end + + context "with confirm_immediately checked" do + it "creates a confirmed user" do + post :create, params: { user: valid_params.merge(confirm_immediately: "1") } + + created_user = User.find_by(email: "new@example.com") + expect(created_user).to be_confirmed + end + end + + context "without confirm_immediately checked" do + it "creates an unconfirmed user" do + post :create, params: { user: valid_params.merge(confirm_immediately: "0") } + + created_user = User.find_by(email: "new@example.com") + expect(created_user).not_to be_confirmed + end + end + end + + describe "PUT #update" do + context "when password is blank" do + it "does not change the existing password" do + original_encrypted = user.encrypted_password + + put :update, params: { id: user.id, user: { password: "", password_confirmation: "" } } + + expect(user.reload.encrypted_password).to eq(original_encrypted) + end + end + + context "when password is provided" do + it "updates the password" do + original_encrypted = user.encrypted_password + + put :update, params: { id: user.id, user: { password: "newpassword123", password_confirmation: "newpassword123" } } + + expect(user.reload.encrypted_password).not_to eq(original_encrypted) + end + end + end +end