diff --git a/app/controllers/administrateurs/activate_controller.rb b/app/controllers/administrateurs/activate_controller.rb new file mode 100644 index 000000000..396d31df6 --- /dev/null +++ b/app/controllers/administrateurs/activate_controller.rb @@ -0,0 +1,34 @@ +class Administrateurs::ActivateController < ApplicationController + layout "new_application" + + def new + @administrateur = Administrateur.find_inactive_by_token(params[:token]) + + if !@administrateur + flash.alert = "Le lien de validation d'administrateur a expiré, contactez-nous à contact@tps.apientreprise.fr pour obtenir un nouveau lien." + redirect_to root_path + end + end + + def create + administrateur = Administrateur.reset_password( + update_administrateur_params[:reset_password_token], + update_administrateur_params[:password] + ) + + if administrateur && administrateur.errors.empty? + sign_in(administrateur, scope: :administrateur) + flash.notice = "Mot de passe enregistré" + redirect_to admin_procedures_path + else + flash.alert = administrateur.errors.full_messages + redirect_to admin_activate_path(token: update_administrateur_params[:reset_password_token]) + end + end + + private + + def update_administrateur_params + params.require(:administrateur).permit(:reset_password_token, :password) + end +end diff --git a/app/controllers/administrations_controller.rb b/app/controllers/administrations_controller.rb index f182fc0a7..f600ecfd5 100644 --- a/app/controllers/administrations_controller.rb +++ b/app/controllers/administrations_controller.rb @@ -14,21 +14,26 @@ class AdministrationsController < ApplicationController end def create - admin = Administrateur.new create_administrateur_params + administrateur = current_administration.invite_admin(create_administrateur_params[:email]) - if admin.save + if administrateur.errors.empty? flash.notice = "Administrateur créé" - AdministrationMailer.new_admin_email(admin, current_administration).deliver_now! else - flash.alert = admin.errors.full_messages + flash.alert = administrateur.errors.full_messages end redirect_to administrations_path end + def update + Administrateur.find_inactive_by_id(params[:id]).invite! + + redirect_to administrations_path + end + private def create_administrateur_params - params.require(:administrateur).permit(:email, :password) + params.require(:administrateur).permit(:email) end end diff --git a/app/mailers/administration_mailer.rb b/app/mailers/administration_mailer.rb index 0bafaec32..bcc0839eb 100644 --- a/app/mailers/administration_mailer.rb +++ b/app/mailers/administration_mailer.rb @@ -9,6 +9,13 @@ class AdministrationMailer < ApplicationMailer subject: "Création d'un compte Admin TPS") end + def invite_admin(admin, reset_password_token) + @reset_password_token = reset_password_token + mail(to: admin.email, + subject: "TPS - Activez votre compte administrateur", + reply_to: "equipe@tps.apientreprise.fr") + end + def dubious_procedures(procedures_and_type_de_champs) @procedures_and_type_de_champs = procedures_and_type_de_champs mail(to: 'equipe@tps.apientreprise.fr', diff --git a/app/models/administrateur.rb b/app/models/administrateur.rb index d23ce1cf4..18ad7e7ae 100644 --- a/app/models/administrateur.rb +++ b/app/models/administrateur.rb @@ -9,6 +9,16 @@ class Administrateur < ActiveRecord::Base include CredentialsSyncableConcern + scope :inactive, -> { where(active: false) } + + def self.find_inactive_by_token(reset_password_token) + self.inactive.with_reset_password_token(reset_password_token) + end + + def self.find_inactive_by_id(id) + self.inactive.find(id) + end + def ensure_api_token if api_token.nil? self.api_token = generate_api_token @@ -19,6 +29,46 @@ class Administrateur < ActiveRecord::Base update_attributes(api_token: generate_api_token) end + def registration_state + if active? + 'Actif' + elsif reset_password_period_valid? + 'En attente' + else + 'Expiré' + end + end + + def invite! + if active? + raise "Impossible d'inviter un utilisateur déjà actif !" + end + + reset_password_token = set_reset_password_token + + AdministrationMailer.invite_admin(self, reset_password_token).deliver_now! + + reset_password_token + end + + def invitation_expired? + !active && !reset_password_period_valid? + end + + def self.reset_password(reset_password_token, password) + administrateur = self.reset_password_by_token({ + password: password, + password_confirmation: password, + reset_password_token: reset_password_token + }) + + if administrateur && administrateur.errors.empty? + administrateur.update_column(:active, true) + end + + administrateur + end + private def generate_api_token diff --git a/app/models/administration.rb b/app/models/administration.rb index f19ea8226..a2e3b56fa 100644 --- a/app/models/administration.rb +++ b/app/models/administration.rb @@ -6,4 +6,19 @@ class Administration < ActiveRecord::Base def self.from_omniauth(params) find_by(email: params["info"]["email"]) end + + def invite_admin(email) + administrateur = Administrateur.new({ + email: email, + active: false + }) + administrateur.password = administrateur.password_confirmation = SecureRandom.hex + + if administrateur.save + AdministrationMailer.new_admin_email(administrateur, self).deliver_now! + administrateur.invite! + end + + administrateur + end end diff --git a/app/views/administrateurs/activate/new.html.haml b/app/views/administrateurs/activate/new.html.haml new file mode 100644 index 000000000..256159867 --- /dev/null +++ b/app/views/administrateurs/activate/new.html.haml @@ -0,0 +1,8 @@ +.container + = form_for @administrateur, url: { controller: 'administrateurs/activate', action: :create }, html: { class: "form" } do |f| + %br + %h1 + = @administrateur.email + = f.password_field :password, placeholder: 'Mot de passe' + = f.hidden_field :reset_password_token, value: params[:token] + = f.submit 'Définir le mot de passe', class: 'button large primary expand' diff --git a/app/views/administration_mailer/invite_admin.html.haml b/app/views/administration_mailer/invite_admin.html.haml new file mode 100644 index 000000000..6693ae419 --- /dev/null +++ b/app/views/administration_mailer/invite_admin.html.haml @@ -0,0 +1,16 @@ +- content_for(:title, 'Activation du compte administrateur') + +Bonjour, +%br +%br +L'équipe TPS vous invite à activer votre compte administrateur sur TPS. +%br +%br +Pour le faire, merci de cliquer sur le lien suivant : += link_to admin_activate_url(token: @reset_password_token), admin_activate_url(token: @reset_password_token) +%br +%br +Bonne journée, +%br +%br +L'équipe Téléprocédures Simplifiées diff --git a/app/views/administrations/_list.html.haml b/app/views/administrations/_list.html.haml index c5559f651..e17abfa15 100644 --- a/app/views/administrations/_list.html.haml +++ b/app/views/administrations/_list.html.haml @@ -4,6 +4,7 @@ %thead %th.col-xs-4= smart_listing.sortable 'Email', :email %th.col-xs-4= smart_listing.sortable 'Date de dernière connexion', :last_sign_in_at + %th.col-xs-2 État %th.col-xs-2 Procédure active %th.col-xs-2 Dossier en cours @@ -17,6 +18,11 @@ ( = admin.last_sign_in_at.localtime.strftime('%d/%m/%Y') ) + %td + - if admin.invitation_expired? + = link_to admin.registration_state, administration_path(admin), remote: true, method: :patch + - else + = admin.registration_state %td = admin.procedures.publiees.count %td diff --git a/app/views/administrations/index.html.haml b/app/views/administrations/index.html.haml index 869242426..730a7b487 100644 --- a/app/views/administrations/index.html.haml +++ b/app/views/administrations/index.html.haml @@ -3,7 +3,6 @@ = form_for @admin, url: { controller: 'administrations', action: :create } do |f| .form-group.form-inline.text-center = f.text_field :email, placeholder: :email, class: 'form-control' - = f.text_field :password, placeholder: :password, class: 'form-control' = f.submit 'Créer un administrateur', class: 'btn btn-success', id: 'submit_new_administrateur' diff --git a/config/routes.rb b/config/routes.rb index 6f58fe1b3..e28361914 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -55,8 +55,7 @@ Rails.application.routes.draw do get 'administrations/sign_in' => 'administrations/sessions#new' delete 'administrations/sign_out' => 'administrations/sessions#destroy' authenticate :administration do - resources :administrations, only: [:index, :create] - namespace :administrations do + resources :administrations, only: [:index, :create, :update] do match "/delayed_job" => DelayedJobWeb, :anchor => false, :via => [:get, :post] end end @@ -111,6 +110,8 @@ Rails.application.routes.draw do end namespace :admin do + get 'activate' => '/administrateurs/activate#new' + patch 'activate' => '/administrateurs/activate#create' get 'sign_in' => '/administrateurs/sessions#new' get 'procedures/archived' => 'procedures#archived' get 'procedures/draft' => 'procedures#draft' diff --git a/db/migrate/20180104150513_add_active_to_administrateurs.rb b/db/migrate/20180104150513_add_active_to_administrateurs.rb new file mode 100644 index 000000000..5de20b1f3 --- /dev/null +++ b/db/migrate/20180104150513_add_active_to_administrateurs.rb @@ -0,0 +1,5 @@ +class AddActiveToAdministrateurs < ActiveRecord::Migration[5.0] + def change + add_column :administrateurs, :active, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 08f4ec561..ab3be6bdd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -17,12 +17,12 @@ ActiveRecord::Schema.define(version: 20180111153308) do enable_extension "unaccent" create_table "administrateurs", force: :cascade do |t| - t.string "email", default: "", null: false - t.string "encrypted_password", default: "", null: false + t.string "email", default: "", null: false + t.string "encrypted_password", default: "", null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0, null: false + t.integer "sign_in_count", default: 0, null: false t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" t.string "current_sign_in_ip" @@ -30,6 +30,7 @@ ActiveRecord::Schema.define(version: 20180111153308) do t.datetime "created_at" t.datetime "updated_at" t.string "api_token" + t.boolean "active", default: false t.index ["email"], name: "index_administrateurs_on_email", unique: true, using: :btree t.index ["reset_password_token"], name: "index_administrateurs_on_reset_password_token", unique: true, using: :btree end diff --git a/lib/tasks/2018_01_11_add_active_state_to_administrators.rake b/lib/tasks/2018_01_11_add_active_state_to_administrators.rake new file mode 100644 index 000000000..7de822e6c --- /dev/null +++ b/lib/tasks/2018_01_11_add_active_state_to_administrators.rake @@ -0,0 +1,7 @@ +namespace :'2018_01_11_add_active_state_to_administrators' do + task set: :environment do + Administrateur.find_each do |administrateur| + administrateur.update_column(:active, true) + end + end +end diff --git a/spec/controllers/administrations_controller_spec.rb b/spec/controllers/administrations_controller_spec.rb index 48b2ba8dc..1ce833d1b 100644 --- a/spec/controllers/administrations_controller_spec.rb +++ b/spec/controllers/administrations_controller_spec.rb @@ -27,7 +27,7 @@ describe AdministrationsController, type: :controller do sign_in administration end - subject { post :create, administrateur: {email: email, password: password} } + subject { post :create, administrateur: {email: email } } context 'when email and password are correct' do it 'add new administrateur in database' do @@ -37,6 +37,8 @@ describe AdministrationsController, type: :controller do it 'alert new mail are send' do expect(AdministrationMailer).to receive(:new_admin_email).and_return(AdministrationMailer) expect(AdministrationMailer).to receive(:deliver_now!) + expect(AdministrationMailer).to receive(:invite_admin).and_return(AdministrationMailer) + expect(AdministrationMailer).to receive(:deliver_now!) subject end end diff --git a/spec/models/administrateur_spec.rb b/spec/models/administrateur_spec.rb index 65cc16f5f..6fb94c9fc 100644 --- a/spec/models/administrateur_spec.rb +++ b/spec/models/administrateur_spec.rb @@ -50,4 +50,20 @@ describe Administrateur, type: :model do expect(gestionnaire.valid_password?('super secret')).to be(true) end end + + describe '#find_inactive_by_token' do + let(:administrateur) { create(:administration).invite_admin('paul@tps.fr') } + let(:reset_password_token) { administrateur.invite! } + + it { expect(Administrateur.find_inactive_by_token(reset_password_token)).not_to be_nil } + end + + describe '#reset_password' do + let(:administrateur) { create(:administration).invite_admin('paul@tps.fr') } + let(:reset_password_token) { administrateur.invite! } + + it { expect(Administrateur.reset_password(reset_password_token, '12345678').errors).to be_empty } + it { expect(Administrateur.reset_password('123', '12345678').errors).not_to be_empty } + it { expect(Administrateur.reset_password(reset_password_token, '').errors).not_to be_empty } + end end diff --git a/spec/models/administration_spec.rb b/spec/models/administration_spec.rb new file mode 100644 index 000000000..9f8e0463e --- /dev/null +++ b/spec/models/administration_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe Administration, type: :model do + describe '#invite_admin' do + let(:administration) { create :administration } + let(:valid_email) { 'paul@tps.fr' } + subject { administration.invite_admin(valid_email) } + + it { + expect(subject.errors).to be_empty + expect(subject).to be_persisted + expect(administration.invite_admin(valid_email).errors).not_to be_empty + } + it { expect(administration.invite_admin(nil).errors).not_to be_empty } + it { expect(administration.invite_admin('toto').errors).not_to be_empty } + end +end