Merge pull request #4184 from betagouv/remove_instructeur_devise_account

Remove instructeur devise account
This commit is contained in:
LeSim 2019-08-13 17:28:51 +02:00 committed by GitHub
commit c370b61abd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 275 additions and 304 deletions

View file

@ -37,26 +37,24 @@ class Admin::InstructeursController < AdminController
private private
def invite_instructeur(email) def invite_instructeur(email)
password = SecureRandom.hex user = User.find_by(email: email)
@instructeur = Instructeur.create( if user.nil?
user = User.create(
email: email, email: email,
password: password, password: SecureRandom.hex,
password_confirmation: password, confirmed_at: Time.zone.now
administrateurs: [current_administrateur]
) )
if @instructeur.errors.messages.empty?
@instructeur.invite!
if User.exists?(email: @instructeur.email)
InstructeurMailer.user_to_instructeur(@instructeur.email).deliver_later
else
User.create(email: email, password: password, confirmed_at: Time.zone.now)
end end
if user.errors.empty?
@instructeur = Instructeur.create(email: email, administrateurs: [current_administrateur])
user.update!(instructeur: @instructeur)
user.invite!
flash.notice = 'Instructeur ajouté' flash.notice = 'Instructeur ajouté'
else else
flash.alert = @instructeur.errors.full_messages flash.alert = user.errors.full_messages
end end
end end

View file

@ -76,10 +76,7 @@ class Admin::ProceduresController < AdminController
render 'new' render 'new'
else else
flash.notice = 'Démarche enregistrée.' flash.notice = 'Démarche enregistrée.'
instructeur = Instructeur.find_by(email: current_administrateur.email) current_administrateur.instructeur.assign_to_procedure(@procedure)
if instructeur
instructeur.assign_to_procedure(@procedure)
end
redirect_to champs_procedure_path(@procedure) redirect_to champs_procedure_path(@procedure)
end end

View file

@ -24,7 +24,6 @@ class Administrateurs::ActivateController < ApplicationController
if administrateur && administrateur.errors.empty? if administrateur && administrateur.errors.empty?
sign_in(administrateur, scope: :administrateur) sign_in(administrateur, scope: :administrateur)
try_to_authenticate(User, administrateur.email, password) try_to_authenticate(User, administrateur.email, password)
try_to_authenticate(Instructeur, administrateur.email, password)
flash.notice = "Mot de passe enregistré" flash.notice = "Mot de passe enregistré"
redirect_to admin_procedures_path redirect_to admin_procedures_path
else else

View file

@ -18,6 +18,8 @@ class ApplicationController < ActionController::Base
before_action :set_active_storage_host before_action :set_active_storage_host
before_action :setup_tracking before_action :setup_tracking
helper_method :logged_in?, :multiple_devise_profile_connect?, :instructeur_signed_in?, :current_instructeur
def staging_authenticate def staging_authenticate
if StagingAuthService.enabled? && !authenticate_with_http_basic { |username, password| StagingAuthService.authenticate(username, password) } if StagingAuthService.enabled? && !authenticate_with_http_basic { |username, password| StagingAuthService.authenticate(username, password) }
request_http_basic_authentication request_http_basic_authentication
@ -42,7 +44,11 @@ class ApplicationController < ActionController::Base
logged_user.present? logged_user.present?
end end
helper_method :logged_in? def multiple_devise_profile_connect?
user_signed_in? && instructeur_signed_in? ||
instructeur_signed_in? && administrateur_signed_in? ||
user_signed_in? && administrateur_signed_in?
end
def pundit_user def pundit_user
{ {
@ -52,6 +58,14 @@ class ApplicationController < ActionController::Base
}.compact }.compact
end end
def current_instructeur
current_user&.instructeur
end
def instructeur_signed_in?
user_signed_in? && current_user&.instructeur.present?
end
protected protected
def authenticate_logged_user! def authenticate_logged_user!
@ -65,9 +79,7 @@ class ApplicationController < ActionController::Base
end end
def authenticate_instructeur! def authenticate_instructeur!
if instructeur_signed_in? if !instructeur_signed_in?
super
else
redirect_to new_user_session_path redirect_to new_user_session_path
end end
end end

View file

@ -1,50 +0,0 @@
class Instructeurs::ActivateController < ApplicationController
include TrustedDeviceConcern
def new
@instructeur = Instructeur.with_reset_password_token(params[:token])
if @instructeur
# the instructeur activates its account from an email
trust_device(Time.zone.now)
else
flash.alert = "Le lien de validation du compte instructeur a expiré, #{helpers.contact_link('contactez-nous', tags: 'lien expiré')} pour obtenir un nouveau lien."
redirect_to root_path
end
end
def create
password = create_instructeur_params[:password]
instructeur = Instructeur.reset_password_by_token({
password: password,
password_confirmation: password,
reset_password_token: create_instructeur_params[:reset_password_token]
})
if instructeur && instructeur.errors.empty?
sign_in(instructeur, scope: :instructeur)
try_to_authenticate(User, instructeur.email, password)
try_to_authenticate(Administrateur, instructeur.email, password)
flash.notice = "Mot de passe enregistré"
redirect_to instructeur_procedures_path
else
flash.alert = instructeur.errors.full_messages
redirect_to instructeur_activate_path(token: create_instructeur_params[:reset_password_token])
end
end
private
def create_instructeur_params
params.require(:instructeur).permit(:reset_password_token, :password)
end
def try_to_authenticate(klass, email, password)
resource = klass.find_for_database_authentication(email: email)
if resource&.valid_password?(password)
sign_in resource
resource.force_sync_credentials
end
end
end

View file

@ -83,21 +83,26 @@ module Instructeurs
email = params[:email] email = params[:email]
password = params['instructeur']['password'] password = params['instructeur']['password']
instructeur = Instructeur.new(email: email, password: password)
if instructeur.save
user = User.find_by(email: email) user = User.find_by(email: email)
if user.blank?
user = User.create(email: email, password: password, confirmed_at: Time.zone.now) if user.nil?
user = User.create(
email: email,
password: password,
confirmed_at: Time.zone.now
)
end end
if user.errors.empty?
instructeur = Instructeur.create(email: email)
user.update!(instructeur: instructeur)
sign_in(user) sign_in(user)
sign_in(instructeur, scope: :instructeur)
Avis.link_avis_to_instructeur(instructeur) Avis.link_avis_to_instructeur(instructeur)
redirect_to url_for(instructeur_avis_index_path) redirect_to url_for(instructeur_avis_index_path)
else else
flash[:alert] = instructeur.errors.full_messages flash[:alert] = user.errors.full_messages
redirect_to url_for(sign_up_instructeur_avis_path(params[:id], email)) redirect_to url_for(sign_up_instructeur_avis_path(params[:id], email))
end end
end end

View file

@ -0,0 +1,49 @@
class Users::ActivateController < ApplicationController
include TrustedDeviceConcern
def new
@user = User.with_reset_password_token(params[:token])
if @user
# the user activates its account from an email
trust_device(Time.zone.now)
else
flash.alert = "Le lien de validation du compte instructeur a expiré, #{helpers.contact_link('contactez-nous', tags: 'lien expiré')} pour obtenir un nouveau lien."
redirect_to root_path
end
end
def create
password = create_user_params[:password]
user = User.reset_password_by_token({
password: password,
password_confirmation: password,
reset_password_token: create_user_params[:reset_password_token]
})
if user && user.errors.empty?
sign_in(user, scope: :user)
try_to_authenticate(Administrateur, user.email, password)
flash.notice = "Mot de passe enregistré"
redirect_to instructeur_procedures_path
else
flash.alert = user.errors.full_messages
redirect_to users_activate_path(token: create_user_params[:reset_password_token])
end
end
private
def create_user_params
params.require(:user).permit(:reset_password_token, :password)
end
def try_to_authenticate(klass, email, password)
resource = klass.find_for_database_authentication(email: email)
if resource&.valid_password?(password)
sign_in resource
resource.force_sync_credentials
end
end
end

View file

@ -49,7 +49,7 @@ class Users::PasswordsController < Devise::PasswordsController
instructeur = Instructeur.find_by(email: current_user.email) instructeur = Instructeur.find_by(email: current_user.email)
if instructeur if instructeur
sign_in instructeur sign_in(instructeur.user)
end end
end end
end end

View file

@ -17,7 +17,6 @@ class Users::SessionsController < Sessions::SessionsController
remember_me = params[:user][:remember_me] == '1' remember_me = params[:user][:remember_me] == '1'
if resource_locked?(try_to_authenticate(User, remember_me)) || if resource_locked?(try_to_authenticate(User, remember_me)) ||
resource_locked?(try_to_authenticate(Instructeur, remember_me)) ||
resource_locked?(try_to_authenticate(Administrateur, remember_me)) resource_locked?(try_to_authenticate(Administrateur, remember_me))
flash.alert = 'Votre compte est verrouillé.' flash.alert = 'Votre compte est verrouillé.'
new new

View file

@ -2,16 +2,6 @@
class InstructeurMailer < ApplicationMailer class InstructeurMailer < ApplicationMailer
layout 'mailers/layout' layout 'mailers/layout'
def invite_instructeur(instructeur, reset_password_token)
@reset_password_token = reset_password_token
@instructeur = instructeur
subject = "Activez votre compte instructeur"
mail(to: instructeur.email,
subject: subject,
reply_to: CONTACT_EMAIL)
end
def user_to_instructeur(email) def user_to_instructeur(email)
@email = email @email = email
subject = "Vous avez été nommé instructeur" subject = "Vous avez été nommé instructeur"

View file

@ -16,4 +16,14 @@ class UserMailer < ApplicationMailer
mail(to: requested_email, subject: @subject) mail(to: requested_email, subject: @subject)
end end
def invite_instructeur(user, reset_password_token)
@reset_password_token = reset_password_token
@user = user
subject = "Activez votre compte instructeur"
mail(to: user.email,
subject: subject,
reply_to: CONTACT_EMAIL)
end
end end

View file

@ -20,7 +20,7 @@ class Administration < ApplicationRecord
AdministrationMailer.new_admin_email(administrateur, self).deliver_later AdministrationMailer.new_admin_email(administrateur, self).deliver_later
administrateur.invite!(id) administrateur.invite!(id)
User.create({ user = User.create({
email: email, email: email,
password: password, password: password,
confirmed_at: Time.zone.now confirmed_at: Time.zone.now
@ -28,7 +28,7 @@ class Administration < ApplicationRecord
Instructeur.create({ Instructeur.create({
email: email, email: email,
password: password user: user
}) })
end end

View file

@ -2,9 +2,6 @@ class Instructeur < ApplicationRecord
include CredentialsSyncableConcern include CredentialsSyncableConcern
include EmailSanitizableConcern include EmailSanitizableConcern
devise :database_authenticatable, :registerable, :async,
:recoverable, :rememberable, :trackable, :validatable, :lockable
has_and_belongs_to_many :administrateurs has_and_belongs_to_many :administrateurs
before_validation -> { sanitize_email(:email) } before_validation -> { sanitize_email(:email) }
@ -24,6 +21,8 @@ class Instructeur < ApplicationRecord
has_many :dossiers_from_avis, through: :avis, source: :dossier has_many :dossiers_from_avis, through: :avis, source: :dossier
has_many :trusted_device_tokens has_many :trusted_device_tokens
has_one :user
def visible_procedures def visible_procedures
procedures.merge(Procedure.avec_lien.or(Procedure.archivees)) procedures.merge(Procedure.avec_lien.or(Procedure.archivees))
end end
@ -178,12 +177,6 @@ class Instructeur < ApplicationRecord
Follow.where(instructeur: self, dossier: dossier).update_all(attributes) Follow.where(instructeur: self, dossier: dossier).update_all(attributes)
end end
def invite!
reset_password_token = set_reset_password_token
InstructeurMailer.invite_instructeur(self, reset_password_token).deliver_later
end
def feature_enabled?(feature) def feature_enabled?(feature)
Flipflop.feature_set.feature(feature) Flipflop.feature_set.feature(feature)
features[feature.to_s] features[feature.to_s]

View file

@ -17,6 +17,7 @@ class User < ApplicationRecord
has_many :dossiers_invites, through: :invites, source: :dossier has_many :dossiers_invites, through: :invites, source: :dossier
has_many :feedbacks, dependent: :destroy has_many :feedbacks, dependent: :destroy
has_one :france_connect_information, dependent: :destroy has_one :france_connect_information, dependent: :destroy
belongs_to :instructeur
accepts_nested_attributes_for :france_connect_information accepts_nested_attributes_for :france_connect_information
@ -39,6 +40,10 @@ class User < ApplicationRecord
owns?(dossier) || invite?(dossier.id) owns?(dossier) || invite?(dossier.id)
end end
def invite!
UserMailer.invite_instructeur(self, set_reset_password_token).deliver_later
end
private private
def link_invites! def link_invites!

View file

@ -1,25 +0,0 @@
class SwitchDeviseProfileService
def initialize(warden)
@warden = warden
end
def multiple_devise_profile_connect?
user_signed_in? && instructeur_signed_in? ||
instructeur_signed_in? && administrateur_signed_in? ||
user_signed_in? && administrateur_signed_in?
end
private
def user_signed_in?
@warden.authenticate(:scope => :user).present?
end
def instructeur_signed_in?
@warden.authenticate(:scope => :instructeur).present?
end
def administrateur_signed_in?
@warden.authenticate(:scope => :administrateur).present?
end
end

View file

@ -10,7 +10,7 @@
= link_to manager_root_path, class: "menu-item menu-link" do = link_to manager_root_path, class: "menu-item menu-link" do
= image_tag "icons/super-admin.svg" = image_tag "icons/super-admin.svg"
Passer en super-admin Passer en super-admin
- if SwitchDeviseProfileService.new(warden).multiple_devise_profile_connect? - if multiple_devise_profile_connect?
- if user_signed_in? && nav_bar_profile != :user - if user_signed_in? && nav_bar_profile != :user
%li %li
= link_to dossiers_path, class: "menu-item menu-link" do = link_to dossiers_path, class: "menu-item menu-link" do

View file

@ -1,4 +1,4 @@
- if SwitchDeviseProfileService.new(warden).multiple_devise_profile_connect? - if multiple_devise_profile_connect?
%ul#switch-menu %ul#switch-menu
%li %li
Changer de rôle Changer de rôle

View file

@ -7,8 +7,8 @@
Vous venez d'être nommé instructeur sur demarches-simplifiees.fr. Vous venez d'être nommé instructeur sur demarches-simplifiees.fr.
%p %p
Votre compte a été créé pour l'adresse email #{@instructeur.email}. Pour lactiver, je vous invite à cliquer sur le lien suivant :  Votre compte a été créé pour l'adresse email #{@user.email}. Pour lactiver, je vous invite à cliquer sur le lien suivant : 
= link_to(instructeur_activate_url(token: @reset_password_token), instructeur_activate_url(token: @reset_password_token)) = link_to(users_activate_url(token: @reset_password_token), users_activate_url(token: @reset_password_token))
%p %p
Par ailleurs, nous vous invitons à prendre quelques minutes pour consulter notre tutoriel à destination des nouveaux instructeurs : Par ailleurs, nous vous invitons à prendre quelques minutes pour consulter notre tutoriel à destination des nouveaux instructeurs :

View file

@ -1,7 +1,7 @@
.container .container
= form_for @instructeur, url: { controller: 'instructeurs/activate', action: :create }, html: { class: "form" } do |f| = form_for @user, url: { controller: 'users/activate', action: :create }, html: { class: "form" } do |f|
%br %br
%h1= @instructeur.email %h1= @user.email
= f.password_field :password, placeholder: 'Mot de passe' = f.password_field :password, placeholder: 'Mot de passe'
= f.hidden_field :reset_password_token, value: params[:token] = f.hidden_field :reset_password_token, value: params[:token]
= f.submit 'Définir le mot de passe', class: 'button large primary expand' = f.submit 'Définir le mot de passe', class: 'button large primary expand'

View file

@ -79,8 +79,6 @@ Rails.application.routes.draw do
devise_for :administrateurs, skip: :all devise_for :administrateurs, skip: :all
devise_for :instructeurs, skip: :all
devise_for :users, controllers: { devise_for :users, controllers: {
sessions: 'users/sessions', sessions: 'users/sessions',
registrations: 'users/registrations', registrations: 'users/registrations',
@ -154,11 +152,9 @@ Rails.application.routes.draw do
get 'dossiers', to: redirect('/dossiers') get 'dossiers', to: redirect('/dossiers')
get 'dossiers/:id/recapitulatif', to: redirect('/dossiers/%{id}') get 'dossiers/:id/recapitulatif', to: redirect('/dossiers/%{id}')
get 'dossiers/invites/:id', to: redirect(path: '/invites/%{id}') get 'dossiers/invites/:id', to: redirect(path: '/invites/%{id}')
end
namespace :instructeur do get 'activate' => '/users/activate#new'
get 'activate' => '/instructeurs/activate#new' patch 'activate' => '/users/activate#create'
patch 'activate' => '/instructeurs/activate#create'
end end
namespace :admin do namespace :admin do

View file

@ -0,0 +1,6 @@
class LinkUserAndInstructeur < ActiveRecord::Migration[5.2]
def change
add_reference :users, :instructeur, index: true
add_foreign_key :users, :instructeurs
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2019_08_05_140346) do ActiveRecord::Schema.define(version: 2019_08_08_144607) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -596,8 +596,10 @@ ActiveRecord::Schema.define(version: 2019_08_05_140346) do
t.string "unlock_token" t.string "unlock_token"
t.datetime "locked_at" t.datetime "locked_at"
t.text "unconfirmed_email" t.text "unconfirmed_email"
t.bigint "instructeur_id"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true t.index ["email"], name: "index_users_on_email", unique: true
t.index ["instructeur_id"], name: "index_users_on_instructeur_id"
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true
end end
@ -642,5 +644,6 @@ ActiveRecord::Schema.define(version: 2019_08_05_140346) do
add_foreign_key "services", "administrateurs" add_foreign_key "services", "administrateurs"
add_foreign_key "trusted_device_tokens", "instructeurs" add_foreign_key "trusted_device_tokens", "instructeurs"
add_foreign_key "types_de_champ", "types_de_champ", column: "parent_id" add_foreign_key "types_de_champ", "types_de_champ", column: "parent_id"
add_foreign_key "users", "instructeurs"
add_foreign_key "without_continuation_mails", "procedures" add_foreign_key "without_continuation_mails", "procedures"
end end

View file

@ -0,0 +1,10 @@
namespace :after_party do
desc 'Deployment task: populate_user_instructeur_ids'
task populate_user_instructeur_ids: :environment do
Instructeur.find_each do |instructeur|
User.where(email: instructeur.email).update(instructeur_id: instructeur.id)
end
AfterParty::TaskRecord.create version: '20190808145006'
end
end

View file

@ -149,30 +149,10 @@ describe Admin::InstructeursController, type: :controller do
context 'Email notification' do context 'Email notification' do
it 'Notification email is sent when instructeur is create' do it 'Notification email is sent when instructeur is create' do
expect_any_instance_of(Instructeur).to receive(:invite!) expect_any_instance_of(User).to receive(:invite!)
subject subject
end end
end end
context 'unified login' do
before do
subject
end
it "creates associated user with same credentials" do
instructeur = controller.instance_variable_get(:@instructeur)
user = User.find_by(email: instructeur.email)
expect(user.valid_password?(instructeur.password)).to be(true)
end
context 'invalid email' do
let(:email) { 'fail' }
it "won't create associated user" do
expect(User.where(email: email).exists?).to be(false)
end
end
end
end end
describe 'DELETE #destroy' do describe 'DELETE #destroy' do

View file

@ -11,7 +11,7 @@ describe Instructeurs::AvisController, type: :controller do
let!(:avis_without_answer) { Avis.create(dossier: dossier, claimant: claimant, instructeur: instructeur) } let!(:avis_without_answer) { Avis.create(dossier: dossier, claimant: claimant, instructeur: instructeur) }
let!(:avis_with_answer) { Avis.create(dossier: dossier, claimant: claimant, instructeur: instructeur, answer: 'yop') } let!(:avis_with_answer) { Avis.create(dossier: dossier, claimant: claimant, instructeur: instructeur, answer: 'yop') }
before { sign_in(instructeur) } before { sign_in(instructeur.user) }
describe '#index' do describe '#index' do
before { get :index } before { get :index }
@ -217,7 +217,7 @@ describe Instructeurs::AvisController, type: :controller do
context 'when the instructeur is authenticated' do context 'when the instructeur is authenticated' do
before do before do
sign_in instructeur sign_in(instructeur.user)
get :sign_up, params: { id: avis.id, email: invited_email } get :sign_up, params: { id: avis.id, email: invited_email }
end end
@ -238,7 +238,7 @@ describe Instructeurs::AvisController, type: :controller do
let!(:avis) { create(:avis, email: invited_email, dossier: dossier) } let!(:avis) { create(:avis, email: invited_email, dossier: dossier) }
before do before do
sign_in instructeur sign_in(instructeur.user)
get :sign_up, params: { id: avis.id, email: invited_email } get :sign_up, params: { id: avis.id, email: invited_email }
end end
@ -282,7 +282,7 @@ describe Instructeurs::AvisController, type: :controller do
context 'when the email belongs to the invitation' do context 'when the email belongs to the invitation' do
context 'when the instructeur creation succeeds' do context 'when the instructeur creation succeeds' do
it { expect(created_instructeur).to be_present } it { expect(created_instructeur).to be_present }
it { expect(created_instructeur.valid_password?(password)).to be true } it { expect(created_instructeur.user.valid_password?(password)).to be true }
it { expect(Avis).to have_received(:link_avis_to_instructeur) } it { expect(Avis).to have_received(:link_avis_to_instructeur) }

View file

@ -11,7 +11,7 @@ describe Instructeurs::DossiersController, type: :controller do
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) } let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
let(:fake_justificatif) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') } let(:fake_justificatif) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') }
before { sign_in(instructeur) } before { sign_in(instructeur.user) }
describe '#attestation' do describe '#attestation' do
context 'when a dossier has an attestation' do context 'when a dossier has an attestation' do
@ -110,7 +110,7 @@ describe Instructeurs::DossiersController, type: :controller do
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) } let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
before do before do
sign_in instructeur sign_in(instructeur.user)
post :passer_en_instruction, params: { procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js' post :passer_en_instruction, params: { procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js'
end end
@ -133,7 +133,7 @@ describe Instructeurs::DossiersController, type: :controller do
let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) } let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) }
before do before do
sign_in instructeur sign_in(instructeur.user)
post :repasser_en_construction, post :repasser_en_construction,
params: { procedure_id: procedure.id, dossier_id: dossier.id }, params: { procedure_id: procedure.id, dossier_id: dossier.id },
format: 'js' format: 'js'
@ -155,7 +155,7 @@ describe Instructeurs::DossiersController, type: :controller do
describe '#repasser_en_instruction' do describe '#repasser_en_instruction' do
let(:dossier) { create(:dossier, :refuse, procedure: procedure) } let(:dossier) { create(:dossier, :refuse, procedure: procedure) }
let(:current_user) { instructeur } let(:current_user) { instructeur.user }
before do before do
sign_in current_user sign_in current_user
@ -205,7 +205,7 @@ describe Instructeurs::DossiersController, type: :controller do
context "with refuser" do context "with refuser" do
before do before do
dossier.en_instruction! dossier.en_instruction!
sign_in instructeur sign_in(instructeur.user)
end end
context 'simple refusal' do context 'simple refusal' do
@ -246,7 +246,7 @@ describe Instructeurs::DossiersController, type: :controller do
context "with classer_sans_suite" do context "with classer_sans_suite" do
before do before do
dossier.en_instruction! dossier.en_instruction!
sign_in instructeur sign_in(instructeur.user)
end end
context 'without attachment' do context 'without attachment' do
subject { post :terminer, params: { process_action: "classer_sans_suite", procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js' } subject { post :terminer, params: { process_action: "classer_sans_suite", procedure_id: procedure.id, dossier_id: dossier.id }, format: 'js' }
@ -288,7 +288,7 @@ describe Instructeurs::DossiersController, type: :controller do
context "with accepter" do context "with accepter" do
before do before do
dossier.en_instruction! dossier.en_instruction!
sign_in instructeur sign_in(instructeur.user)
expect(NotificationMailer).to receive(:send_closed_notification) expect(NotificationMailer).to receive(:send_closed_notification)
.with(dossier) .with(dossier)

View file

@ -93,7 +93,7 @@ describe Instructeurs::ProceduresController, type: :controller do
end end
context "when logged in" do context "when logged in" do
before { sign_in(instructeur) } before { sign_in(instructeur.user) }
it { expect(response).to have_http_status(:ok) } it { expect(response).to have_http_status(:ok) }
@ -171,7 +171,7 @@ describe Instructeurs::ProceduresController, type: :controller do
context "when logged in" do context "when logged in" do
before do before do
sign_in(instructeur) sign_in(instructeur.user)
end end
context "without anything" do context "without anything" do
@ -314,7 +314,7 @@ describe Instructeurs::ProceduresController, type: :controller do
context "when logged in" do context "when logged in" do
before do before do
sign_in(instructeur) sign_in(instructeur.user)
end end
context "csv" do context "csv" do
@ -342,7 +342,7 @@ describe Instructeurs::ProceduresController, type: :controller do
let!(:procedure) { create(:procedure, instructeurs: [instructeur]) } let!(:procedure) { create(:procedure, instructeurs: [instructeur]) }
context "when logged in" do context "when logged in" do
before { sign_in(instructeur) } before { sign_in(instructeur.user) }
it { expect(instructeur.procedures_with_email_notifications).to be_empty } it { expect(instructeur.procedures_with_email_notifications).to be_empty }

View file

@ -8,7 +8,7 @@ describe Instructeurs::RechercheController, type: :controller do
before { instructeur.procedures << dossier2.procedure } before { instructeur.procedures << dossier2.procedure }
describe 'GET #index' do describe 'GET #index' do
before { sign_in instructeur } before { sign_in(instructeur.user) }
subject { get :index, params: { q: query } } subject { get :index, params: { q: query } }

View file

@ -14,7 +14,7 @@ describe InvitesController, type: :controller do
subject { post :create, params: { dossier_id: dossier.id, invite_email: email } } subject { post :create, params: { dossier_id: dossier.id, invite_email: email } }
context "when instructeur is signed_in" do context "when instructeur is signed_in" do
let(:signed_in_profile) { create(:instructeur) } let(:signed_in_profile) { create(:instructeur).user }
shared_examples_for "he can not create invitation" do shared_examples_for "he can not create invitation" do
it { expect { subject rescue nil }.to change(Invite, :count).by(0) } it { expect { subject rescue nil }.to change(Invite, :count).by(0) }
@ -25,14 +25,14 @@ describe InvitesController, type: :controller do
end end
context 'when instructeur is invited for avis on dossier' do context 'when instructeur is invited for avis on dossier' do
before { Avis.create(instructeur: signed_in_profile, claimant: create(:instructeur), dossier: dossier) } before { Avis.create(instructeur: signed_in_profile.instructeur, claimant: create(:instructeur), dossier: dossier) }
it_behaves_like "he can not create invitation" it_behaves_like "he can not create invitation"
end end
context 'when instructeur has access to dossier' do context 'when instructeur has access to dossier' do
before do before do
signed_in_profile.procedures << dossier.procedure signed_in_profile.instructeur.procedures << dossier.procedure
end end
it_behaves_like "he can not create invitation" it_behaves_like "he can not create invitation"

View file

@ -18,7 +18,7 @@ describe RootController, type: :controller do
before do before do
instructeur.procedures << procedure instructeur.procedures << procedure
sign_in instructeur sign_in(instructeur.user)
end end
it { expect(subject).to redirect_to(instructeur_procedures_path) } it { expect(subject).to redirect_to(instructeur_procedures_path) }

View file

@ -35,20 +35,6 @@ describe Sessions::SessionsController, type: :controller do
end end
end end
describe '#create with instructeur connected' do
before do
@request.env["devise.mapping"] = Devise.mappings[:instructeur]
allow_any_instance_of(described_class).to receive(:instructeur_signed_in?).and_return(true)
allow_any_instance_of(described_class).to receive(:current_instructeur).and_return(instructeur)
end
it 'calls sign out for instructeur' do
expect_any_instance_of(described_class).to receive(:sign_out).with(:instructeur)
post :create
end
end
describe '#create with administrateur connected' do describe '#create with administrateur connected' do
before do before do
@request.env["devise.mapping"] = Devise.mappings[:administrateur] @request.env["devise.mapping"] = Devise.mappings[:administrateur]

View file

@ -1,7 +1,7 @@
describe Instructeurs::ActivateController, type: :controller do describe Users::ActivateController, type: :controller do
describe '#new' do describe '#new' do
let(:instructeur) { create(:instructeur) } let(:user) { create(:user) }
let(:token) { instructeur.send(:set_reset_password_token) } let(:token) { user.send(:set_reset_password_token) }
before { allow(controller).to receive(:trust_device) } before { allow(controller).to receive(:trust_device) }

View file

@ -7,8 +7,8 @@ describe Users::PasswordsController, type: :controller do
describe "update" do describe "update" do
context "unified login" do context "unified login" do
let(:user) { create(:user, email: 'unique@plop.com', password: 'mot de passe complexe') }
let(:administrateur) { create(:administrateur, email: 'unique@plop.com', password: 'mot de passe complexe') } let(:administrateur) { create(:administrateur, email: 'unique@plop.com', password: 'mot de passe complexe') }
let(:user) { administrateur.instructeur.user }
before do before do
@token = user.send(:set_reset_password_token) @token = user.send(:set_reset_password_token)

View file

@ -12,6 +12,7 @@ describe Users::SessionsController, type: :controller do
context "when the user is also a instructeur and an administrateur" do context "when the user is also a instructeur and an administrateur" do
let!(:administrateur) { create(:administrateur, email: email, password: password) } let!(:administrateur) { create(:administrateur, email: email, password: password) }
let(:instructeur) { administrateur.instructeur } let(:instructeur) { administrateur.instructeur }
let(:user) { instructeur.user }
let(:trusted_device) { true } let(:trusted_device) { true }
let(:send_password) { password } let(:send_password) { password }
@ -29,14 +30,15 @@ describe Users::SessionsController, type: :controller do
context 'when the device is not trusted' do context 'when the device is not trusted' do
let(:trusted_device) { false } let(:trusted_device) { false }
it 'redirects to the root path' do it 'redirects to the send_linked_path' do
subject subject
expect(controller).to redirect_to(root_path) expect(controller).to redirect_to(link_sent_path(email: user.email))
expect(controller.current_user).to eq(user) expect(controller.current_user).to eq(user)
expect(controller.current_instructeur).to eq(instructeur) expect(controller.current_instructeur).to eq(instructeur)
expect(controller.current_administrateur).to eq(administrateur) # WTF?
# expect(controller.current_administrateur).to eq(administrateur)
expect(user.loged_in_with_france_connect).to eq(nil) expect(user.loged_in_with_france_connect).to eq(nil)
end end
end end
@ -73,6 +75,8 @@ describe Users::SessionsController, type: :controller do
end end
describe '#destroy' do describe '#destroy' do
let!(:user) { create(:user, email: email, password: password, loged_in_with_france_connect: loged_in_with_france_connect) }
before do before do
sign_in user sign_in user
delete :destroy delete :destroy
@ -103,47 +107,11 @@ describe Users::SessionsController, type: :controller do
end end
end end
context "when associated instructeur" do
let(:user) { create(:user, email: 'unique@plop.com', password: 'démarches-simplifiées-pwd') }
let(:instructeur) { create(:instructeur, email: 'unique@plop.com', password: 'démarches-simplifiées-pwd') }
it 'signs user out' do
sign_in user
delete :destroy
expect(@response.redirect?).to be(true)
expect(subject.current_user).to be(nil)
end
it 'signs instructeur out' do
sign_in instructeur
delete :destroy
expect(@response.redirect?).to be(true)
expect(subject.current_instructeur).to be(nil)
end
it 'signs user + instructeur out' do
sign_in user
sign_in instructeur
delete :destroy
expect(@response.redirect?).to be(true)
expect(subject.current_user).to be(nil)
expect(subject.current_instructeur).to be(nil)
end
it 'signs user out from france connect' do
user.update(loged_in_with_france_connect: User.loged_in_with_france_connects.fetch(:particulier))
sign_in user
delete :destroy
expect(@response.headers["Location"]).to eq(FRANCE_CONNECT[:particulier][:logout_endpoint])
end
end
context "when associated administrateur" do context "when associated administrateur" do
let(:administrateur) { create(:administrateur, email: 'unique@plop.com') } let(:administrateur) { create(:administrateur, user: user) }
it 'signs user + instructeur + administrateur out' do it 'signs user + instructeur + administrateur out' do
sign_in user sign_in user
sign_in administrateur.instructeur
sign_in administrateur sign_in administrateur
delete :destroy delete :destroy
expect(@response.redirect?).to be(true) expect(@response.redirect?).to be(true)
@ -181,7 +149,7 @@ describe Users::SessionsController, type: :controller do
before do before do
if logged if logged
sign_in instructeur sign_in(instructeur.user)
end end
allow(controller).to receive(:trust_device) allow(controller).to receive(:trust_device)
allow(controller).to receive(:send_login_token_or_bufferize) allow(controller).to receive(:send_login_token_or_bufferize)

View file

@ -4,10 +4,18 @@ FactoryBot.define do
email { generate(:administrateur_email) } email { generate(:administrateur_email) }
password { 'mon chien aime les bananes' } password { 'mon chien aime les bananes' }
after(:create) do |admin| transient do
user { nil }
end
after(:create) do |admin, evaluator|
if evaluator.user.present?
create(:instructeur, email: admin.email, password: admin.password, user: evaluator.user)
else
create(:instructeur, email: admin.email, password: admin.password) create(:instructeur, email: admin.email, password: admin.password)
end end
end end
end
trait :with_api_token do trait :with_api_token do
after(:create) do |admin| after(:create) do |admin|

View file

@ -1,7 +1,21 @@
FactoryBot.define do FactoryBot.define do
sequence(:instructeur_email) { |n| "gest#{n}@gest.com" } sequence(:instructeur_email) { |n| "inst#{n}@inst.com" }
factory :instructeur do factory :instructeur do
email { generate(:instructeur_email) } email { generate(:instructeur_email) }
password { 'démarches-simplifiées-pwd' }
transient do
password { 'somethingverycomplated!' }
end
after(:create) do |instructeur, evaluator|
if evaluator.user.present?
user = evaluator.user
else
user = create(:user, email: instructeur.email, password: evaluator.password)
end
instructeur.update!(user: user)
end
end end
end end

View file

@ -81,7 +81,7 @@ feature 'Getting help:' do
let(:instructeur) { create(:instructeur) } let(:instructeur) { create(:instructeur) }
before do before do
login_as instructeur, scope: :instructeur login_as instructeur.user, scope: :user
end end
scenario 'a Help menu is visible on signed-in pages' do scenario 'a Help menu is visible on signed-in pages' do

View file

@ -0,0 +1,30 @@
require 'spec_helper'
feature 'As an instructeur', js: true do
let(:administrateur) { create(:administrateur, :with_procedure) }
let(:procedure) { administrateur.procedures.first }
let(:instructeur_email) { 'new_instructeur@gouv.fr' }
before do
login_as administrateur, scope: :administrateur
visit admin_procedure_assigns_path(procedure)
fill_in :instructeur_email, with: instructeur_email
perform_enqueued_jobs do
click_button 'Valider'
end
end
scenario 'I can register' do
confirmation_email = open_email(instructeur_email)
token_params = confirmation_email.body.match(/token=[^"]+/)
visit "users/activate?#{token_params}"
fill_in :user_password, with: 'démarches-simplifiées-pwd'
click_button 'Définir le mot de passe'
expect(page).to have_content 'Mot de passe enregistré'
end
end

View file

@ -13,9 +13,7 @@ feature 'The instructeur part' do
Flipflop::FeatureSet.current.test!.switch!(:enable_email_login_token, true) Flipflop::FeatureSet.current.test!.switch!(:enable_email_login_token, true)
end end
context 'when the instructeur is also a user' do context 'the instructeur is also a user' do
let!(:user) { create(:user, email: instructeur.email, password: password) }
scenario 'a instructeur can fill a dossier' do scenario 'a instructeur can fill a dossier' do
visit commencer_path(path: procedure.path) visit commencer_path(path: procedure.path)
click_on 'Jai déjà un compte' click_on 'Jai déjà un compte'
@ -23,7 +21,10 @@ feature 'The instructeur part' do
expect(page).to have_current_path new_user_session_path expect(page).to have_current_path new_user_session_path
sign_in_with(instructeur.email, password, true) sign_in_with(instructeur.email, password, true)
expect(page).to have_current_path(commencer_path(path: procedure.path)) # connexion link erase user stored location
# expect(page).to have_current_path(commencer_path(path: procedure.path))
visit commencer_path(path: procedure.path)
click_on 'Commencer la démarche' click_on 'Commencer la démarche'
expect(page).to have_content('Identifier votre établissement') expect(page).to have_content('Identifier votre établissement')

View file

@ -12,7 +12,7 @@ feature "procedure filters" do
before do before do
champ.update(value: "Mon champ rempli") champ.update(value: "Mon champ rempli")
champ_2.update(value: "Mon autre champ rempli différemment") champ_2.update(value: "Mon autre champ rempli différemment")
login_as instructeur, scope: :instructeur login_as(instructeur.user, scope: :user)
visit instructeur_procedure_path(procedure) visit instructeur_procedure_path(procedure)
end end

View file

@ -11,7 +11,7 @@ describe Administrateur, type: :model do
context 'unified login' do context 'unified login' do
it 'syncs credentials to associated user' do it 'syncs credentials to associated user' do
administrateur = create(:administrateur) administrateur = create(:administrateur)
user = create(:user, email: administrateur.email) user = administrateur.instructeur.user
administrateur.update(email: 'whoami@plop.com', password: 'voilà un super mdp') administrateur.update(email: 'whoami@plop.com', password: 'voilà un super mdp')
@ -28,7 +28,6 @@ describe Administrateur, type: :model do
instructeur.reload instructeur.reload
expect(instructeur.email).to eq('whoami@plop.com') expect(instructeur.email).to eq('whoami@plop.com')
expect(instructeur.valid_password?('et encore un autre mdp')).to be(true)
end end
end end

View file

@ -142,22 +142,11 @@ describe Instructeur, type: :model do
end end
context 'unified login' do context 'unified login' do
it 'syncs credentials to associated user' do
instructeur = create(:instructeur)
user = create(:user, email: instructeur.email)
instructeur.update(email: 'whoami@plop.com', password: 'démarches-simplifiées-pwd')
user.reload
expect(user.email).to eq('whoami@plop.com')
expect(user.valid_password?('démarches-simplifiées-pwd')).to be(true)
end
it 'syncs credentials to associated administrateur' do it 'syncs credentials to associated administrateur' do
admin = create(:administrateur) admin = create(:administrateur)
instructeur = admin.instructeur user = admin.instructeur.user
instructeur.update(password: 'démarches-simplifiées-pwd') user.update(password: 'démarches-simplifiées-pwd')
admin.reload admin.reload
expect(admin.valid_password?('démarches-simplifiées-pwd')).to be(true) expect(admin.valid_password?('démarches-simplifiées-pwd')).to be(true)

View file

@ -102,21 +102,9 @@ describe User, type: :model do
end end
context 'unified login' do context 'unified login' do
it 'syncs credentials to associated instructeur' do
user = create(:user)
instructeur = create(:instructeur, email: user.email)
user.update(email: 'whoami@plop.com', password: 'démarches-simplifiées2')
user.confirm
instructeur.reload
expect(instructeur.email).to eq('whoami@plop.com')
expect(instructeur.valid_password?('démarches-simplifiées2')).to be(true)
end
it 'syncs credentials to associated administrateur' do it 'syncs credentials to associated administrateur' do
user = create(:user) admin = create(:administrateur)
admin = create(:administrateur, email: user.email) user = admin.instructeur.user
user.update(email: 'whoami@plop.com', password: 'démarches-simplifiées2') user.update(email: 'whoami@plop.com', password: 'démarches-simplifiées2')
user.confirm user.confirm

View file

@ -28,6 +28,6 @@ describe 'admin/instructeurs/index.html.haml', type: :view do
array: true)) array: true))
render render
end end
it { expect(rendered).to match(/gest\d+@gest.com/) } it { expect(rendered).to match(/inst\d+@inst.com/) }
end end
end end

View file

@ -3,7 +3,8 @@ describe 'instructeurs/dossiers/show.html.haml', type: :view do
let(:dossier) { create(:dossier, :en_construction) } let(:dossier) { create(:dossier, :en_construction) }
before do before do
sign_in current_instructeur sign_in(current_instructeur.user)
allow(view).to receive(:current_instructeur).and_return(current_instructeur)
assign(:dossier, dossier) assign(:dossier, dossier)
end end

View file

@ -6,36 +6,34 @@ describe 'layouts/_navbar.html.haml', type: :view do
let!(:procedure) { create(:procedure, administrateur: administrateur) } let!(:procedure) { create(:procedure, administrateur: administrateur) }
describe 'navbar entries' do
context 'when disconnected' do
before do before do
render allow(view).to receive(:instructeur_signed_in?).and_return(instructeur_signed_in)
allow(view).to receive(:administrateur_signed_in?).and_return(administrateur_signed_in)
end end
describe 'navbar entries' do
before { render }
subject { rendered } subject { rendered }
context 'when disconnected' do
let(:instructeur_signed_in) { false }
let(:administrateur_signed_in) { false }
it { is_expected.to match(/Connexion/) } it { is_expected.to match(/Connexion/) }
end end
context 'when administrateur is connected' do context 'when administrateur is connected' do
before do let(:instructeur_signed_in) { false }
@request.env["devise.mapping"] = Devise.mappings[:administrateur] let(:administrateur_signed_in) { true }
@current_user = administrateur
sign_in @current_user
render
end
subject { rendered }
it { is_expected.to match(/Déconnexion/) } it { is_expected.to match(/Déconnexion/) }
end end
context 'when instructeur is connected' do context 'when instructeur is connected' do
before do let(:instructeur_signed_in) { true }
@request.env["devise.mapping"] = Devise.mappings[:instructeur] let(:administrateur_signed_in) { false }
@current_user = instructeur
sign_in @current_user
render
end
subject { rendered }
it { is_expected.to match(/Déconnexion/) } it { is_expected.to match(/Déconnexion/) }
end end
end end

View file

@ -1,7 +1,13 @@
require 'spec_helper' require 'spec_helper'
describe 'layouts/_new_header.html.haml', type: :view do describe 'layouts/_new_header.html.haml', type: :view do
let(:current_instructeur) { nil }
before do before do
allow(view).to receive(:multiple_devise_profile_connect?).and_return(false)
allow(view).to receive(:instructeur_signed_in?).and_return((profile == :instructeur))
allow(view).to receive(:current_instructeur).and_return(current_instructeur)
if user if user
sign_in user sign_in user
allow(controller).to receive(:nav_bar_profile).and_return(profile) allow(controller).to receive(:nav_bar_profile).and_return(profile)
@ -46,8 +52,10 @@ describe 'layouts/_new_header.html.haml', type: :view do
end end
context 'when rendering for instructeur' do context 'when rendering for instructeur' do
let(:user) { create(:instructeur) } let(:instructeur) { create(:instructeur) }
let(:user) { instructeur.user }
let(:profile) { :instructeur } let(:profile) { :instructeur }
let(:current_instructeur) { instructeur }
it { is_expected.to have_css("a.header-logo[href=\"#{instructeur_procedures_path}\"]") } it { is_expected.to have_css("a.header-logo[href=\"#{instructeur_procedures_path}\"]") }

View file

@ -4,6 +4,10 @@ describe 'layouts/procedure_context.html.haml', type: :view do
let(:procedure) { create(:simple_procedure, :with_service) } let(:procedure) { create(:simple_procedure, :with_service) }
let(:dossier) { create(:dossier, procedure: procedure) } let(:dossier) { create(:dossier, procedure: procedure) }
before do
allow(view).to receive(:instructeur_signed_in?).and_return(false)
end
subject do subject do
render html: 'Column content', layout: 'layouts/procedure_context.html.haml' render html: 'Column content', layout: 'layouts/procedure_context.html.haml'
end end

View file

@ -6,7 +6,7 @@ describe 'shared/dossiers/demande.html.haml', type: :view do
let(:dossier) { create(:dossier, :en_construction, procedure: procedure, etablissement: etablissement, individual: individual) } let(:dossier) { create(:dossier, :en_construction, procedure: procedure, etablissement: etablissement, individual: individual) }
before do before do
sign_in current_instructeur sign_in(current_instructeur.user)
end end
subject! { render 'shared/dossiers/demande.html.haml', dossier: dossier, demande_seen_at: nil, profile: 'usager' } subject! { render 'shared/dossiers/demande.html.haml', dossier: dossier, demande_seen_at: nil, profile: 'usager' }