commit
d3f8ba2516
15 changed files with 380 additions and 37 deletions
|
@ -47,12 +47,12 @@ module Manager
|
|||
end
|
||||
|
||||
def add_administrateur
|
||||
administrateur = Administrateur.by_email(params[:email])
|
||||
administrateur = Administrateur.by_email(current_super_admin.email)
|
||||
if administrateur
|
||||
procedure.administrateurs << administrateur
|
||||
flash[:notice] = "L'administrateur \"#{params[:email]}\" est ajouté à la démarche."
|
||||
AdministrateursProcedure.create(procedure: procedure, administrateur: administrateur, manager: true)
|
||||
flash[:notice] = "L’administrateur \"#{administrateur.email}\" est ajouté à la démarche pour la journée."
|
||||
else
|
||||
flash[:alert] = "L'administrateur \"#{params[:email]}\" est introuvable."
|
||||
flash[:alert] = "Vous n’êtes pas connecté en tant qu’administrateur."
|
||||
end
|
||||
redirect_to manager_procedure_path(procedure)
|
||||
end
|
||||
|
|
|
@ -2,14 +2,37 @@ module Manager
|
|||
class UsersController < Manager::ApplicationController
|
||||
def update
|
||||
user = User.find(params[:id])
|
||||
new_email = params[:user][:email]
|
||||
user.skip_reconfirmation!
|
||||
user.update(email: new_email)
|
||||
if (user.valid?)
|
||||
flash[:notice] = "L'email a été modifié en « #{new_email} » sans notification ni validation par email."
|
||||
preexisting_user = User.find_by(email: targeted_email)
|
||||
|
||||
if user.administrateur.present?
|
||||
flash[:error] = "« #{targeted_email} » est un administrateur. On ne sait pas encore faire."
|
||||
elsif preexisting_user.nil?
|
||||
user.skip_reconfirmation!
|
||||
user.update(email: targeted_email)
|
||||
|
||||
if (user.valid?)
|
||||
flash[:notice] = "L'email a été modifié en « #{targeted_email} » sans notification ni validation par email."
|
||||
else
|
||||
flash[:error] = user.errors.full_messages.to_sentence
|
||||
end
|
||||
else
|
||||
flash[:error] = "« #{new_email} » n’est pas une adresse valide."
|
||||
user.dossiers.update_all(user_id: preexisting_user.id)
|
||||
|
||||
if preexisting_user.instructeur.nil?
|
||||
user.instructeur&.update(user: preexisting_user)
|
||||
else
|
||||
preexisting_user.instructeur.merge(user.instructeur)
|
||||
end
|
||||
|
||||
if preexisting_user.expert.nil?
|
||||
user.expert&.update(user: preexisting_user)
|
||||
else
|
||||
preexisting_user.expert.merge(user.expert)
|
||||
end
|
||||
|
||||
flash[:notice] = "Le compte « #{targeted_email} » a absorbé le compte « #{user.email} »."
|
||||
end
|
||||
|
||||
redirect_to edit_manager_user_path(user)
|
||||
end
|
||||
|
||||
|
@ -72,5 +95,11 @@ module Manager
|
|||
end
|
||||
redirect_to emails_manager_user_path(@user)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def targeted_email
|
||||
params[:user][:email]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
class Cron::PurgeManagerAdministrateurSessionsJob < Cron::CronJob
|
||||
self.schedule_expression = "every day at 3 am"
|
||||
|
||||
def perform
|
||||
AdministrateursProcedure.where(manager: true).destroy_all
|
||||
end
|
||||
end
|
13
app/models/administrateurs_instructeur.rb
Normal file
13
app/models/administrateurs_instructeur.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: administrateurs_instructeurs
|
||||
#
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# administrateur_id :integer
|
||||
# instructeur_id :integer
|
||||
#
|
||||
class AdministrateursInstructeur < ApplicationRecord
|
||||
belongs_to :administrateur
|
||||
belongs_to :instructeur
|
||||
end
|
|
@ -2,6 +2,7 @@
|
|||
#
|
||||
# Table name: administrateurs_procedures
|
||||
#
|
||||
# manager :boolean
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
# administrateur_id :bigint not null
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
class Expert < ApplicationRecord
|
||||
has_one :user
|
||||
has_many :experts_procedures
|
||||
has_many :procedures, through: :experts_procedures
|
||||
has_many :avis, through: :experts_procedures
|
||||
has_many :dossiers, through: :avis
|
||||
has_many :commentaires
|
||||
|
||||
default_scope { eager_load(:user) }
|
||||
|
||||
|
@ -34,4 +36,24 @@ class Expert < ApplicationRecord
|
|||
@avis_summary = { unanswered: result.unanswered, total: result.total }
|
||||
end
|
||||
end
|
||||
|
||||
def merge(old_expert)
|
||||
procedure_with_new, procedure_without_new = old_expert
|
||||
.procedures
|
||||
.partition { |p| p.experts.exists?(id) }
|
||||
|
||||
ExpertsProcedure
|
||||
.where(expert_id: old_expert.id, procedure: procedure_without_new)
|
||||
.update_all(expert_id: id)
|
||||
|
||||
ExpertsProcedure
|
||||
.where(expert_id: old_expert.id, procedure: procedure_with_new)
|
||||
.destroy_all
|
||||
|
||||
old_expert.commentaires.update_all(expert_id: id)
|
||||
|
||||
Avis
|
||||
.where(claimant_id: old_expert.id, claimant_type: Expert.name)
|
||||
.update_all(claimant_id: id)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,8 @@
|
|||
# updated_at :datetime
|
||||
#
|
||||
class Instructeur < ApplicationRecord
|
||||
has_and_belongs_to_many :administrateurs
|
||||
has_many :administrateurs_instructeurs
|
||||
has_many :administrateurs, through: :administrateurs_instructeurs
|
||||
|
||||
has_many :assign_to, dependent: :destroy
|
||||
has_many :groupe_instructeurs, through: :assign_to
|
||||
|
@ -19,6 +20,7 @@ class Instructeur < ApplicationRecord
|
|||
has_many :assign_to_with_email_notifications, -> { with_email_notifications }, class_name: 'AssignTo', inverse_of: :instructeur
|
||||
has_many :groupe_instructeur_with_email_notifications, through: :assign_to_with_email_notifications, source: :groupe_instructeur
|
||||
|
||||
has_many :commentaires
|
||||
has_many :dossiers, -> { state_not_brouillon }, through: :groupe_instructeurs
|
||||
has_many :follows, -> { active }, inverse_of: :instructeur
|
||||
has_many :previous_follows, -> { inactive }, class_name: 'Follow', inverse_of: :instructeur
|
||||
|
@ -249,6 +251,34 @@ class Instructeur < ApplicationRecord
|
|||
Dossier.connection.select_all(sanitized_query).first
|
||||
end
|
||||
|
||||
def merge(old_instructeur)
|
||||
old_instructeur
|
||||
.assign_to
|
||||
.where.not(groupe_instructeur_id: assign_to.pluck(:groupe_instructeur_id))
|
||||
.update_all(instructeur_id: id)
|
||||
|
||||
old_instructeur
|
||||
.follows
|
||||
.where.not(dossier_id: follows.pluck(:dossier_id))
|
||||
.update_all(instructeur_id: id)
|
||||
|
||||
admin_with_new_instructeur, admin_without_new_instructeur = old_instructeur
|
||||
.administrateurs
|
||||
.partition { |admin| admin.instructeurs.exists?(id) }
|
||||
|
||||
admin_without_new_instructeur.each do |admin|
|
||||
admin.instructeurs << self
|
||||
admin.instructeurs.delete(old_instructeur)
|
||||
end
|
||||
|
||||
admin_with_new_instructeur.each do |admin|
|
||||
admin.instructeurs.delete(old_instructeur)
|
||||
end
|
||||
|
||||
old_instructeur.commentaires.update_all(instructeur_id: id)
|
||||
old_instructeur.bulk_messages.update_all(instructeur_id: id)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def annotations_hash(demande, annotations_privees, avis, messagerie)
|
||||
|
|
|
@ -64,9 +64,12 @@ as well as a link to its edit page.
|
|||
<dd class="attribute-data attribute-data--<%=attribute.html_class%>">
|
||||
<%= render_field attribute, page: page %>
|
||||
<% if attribute.name == 'administrateurs' %>
|
||||
<%= form_tag(add_administrateur_manager_procedure_path(procedure), style: 'margin-top: 1rem;') do %>
|
||||
<%= email_field_tag(:email, '', placeholder: 'Email', autocapitalize: 'off', autocorrect: 'off', spellcheck: 'false', style: 'margin-bottom: 1rem;width:24rem;') %>
|
||||
<button>Ajouter un administrateur</button>
|
||||
<% if procedure.administrateurs.find { |admin| admin.email == current_super_admin.email } %>
|
||||
<p style="margin-top: 20px;">Vous êtes déjà administrateur sur cette démarche</p>
|
||||
<% else %>
|
||||
<%= form_tag(add_administrateur_manager_procedure_path(procedure), style: 'margin-top: 1rem;') do %>
|
||||
<button>Devenir administrateur (pour la journée)</button>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</dd>
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddManagerToAdministrateursProcedures < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
add_column :administrateurs_procedures, :manager, :boolean
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2021_10_01_143403) do
|
||||
ActiveRecord::Schema.define(version: 2021_10_06_164955) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -76,6 +76,7 @@ ActiveRecord::Schema.define(version: 2021_10_01_143403) do
|
|||
t.bigint "procedure_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.boolean "manager"
|
||||
t.index ["administrateur_id", "procedure_id"], name: "index_unique_admin_proc_couple", unique: true
|
||||
t.index ["administrateur_id"], name: "index_administrateurs_procedures_on_administrateur_id"
|
||||
t.index ["procedure_id"], name: "index_administrateurs_procedures_on_procedure_id"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
xdescribe Manager::InstructeursController, type: :controller do
|
||||
describe Manager::InstructeursController, type: :controller do
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
xdescribe Manager::ProceduresController, type: :controller do
|
||||
describe Manager::ProceduresController, type: :controller do
|
||||
let(:super_admin) { create :super_admin }
|
||||
|
||||
before { sign_in super_admin }
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
xdescribe Manager::UsersController, type: :controller do
|
||||
describe Manager::UsersController, type: :controller do
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
|
||||
before { sign_in super_admin }
|
||||
|
||||
describe '#show' do
|
||||
render_views
|
||||
|
||||
|
@ -8,7 +10,6 @@ xdescribe Manager::UsersController, type: :controller do
|
|||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
sign_in(super_admin)
|
||||
get :show, params: { id: user.id }
|
||||
end
|
||||
|
||||
|
@ -16,39 +17,119 @@ xdescribe Manager::UsersController, type: :controller do
|
|||
end
|
||||
|
||||
describe '#update' do
|
||||
let!(:user) { create(:user, email: 'ancien.email@domaine.fr') }
|
||||
let(:user) { create(:user, email: 'ancien.email@domaine.fr') }
|
||||
|
||||
before {
|
||||
sign_in super_admin
|
||||
}
|
||||
subject { patch :update, params: { id: user.id, user: { email: nouvel_email } } }
|
||||
|
||||
describe 'with a valid email' do
|
||||
let(:nouvel_email) { 'nouvel.email@domaine.fr' }
|
||||
context 'when the targeted email does not exist' do
|
||||
describe 'with a valid email' do
|
||||
let(:nouvel_email) { 'nouvel.email@domaine.fr' }
|
||||
|
||||
it 'updates the user email' do
|
||||
subject
|
||||
it 'updates the user email' do
|
||||
subject
|
||||
|
||||
expect(User.find_by(id: user.id).email).to eq(nouvel_email)
|
||||
expect(User.find_by(id: user.id).email).to eq(nouvel_email)
|
||||
end
|
||||
|
||||
context 'and the user is an administrateur' do
|
||||
let(:user) { create(:administrateur).user }
|
||||
|
||||
it 'rejects the modification' do
|
||||
subject
|
||||
|
||||
expect(flash[:error]).to match("« nouvel.email@domaine.fr » est un administrateur. On ne sait pas encore faire.")
|
||||
expect(user.reload.email).not_to eq(nouvel_email)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with an invalid email' do
|
||||
let(:nouvel_email) { 'plop' }
|
||||
|
||||
it 'does not update the user email' do
|
||||
subject
|
||||
|
||||
expect(User.find_by(id: user.id).email).not_to eq(nouvel_email)
|
||||
expect(flash[:error]).to match("Courriel invalide")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with an invalid email' do
|
||||
let(:nouvel_email) { 'plop' }
|
||||
context 'when the targeted email exists' do
|
||||
let(:preexisting_user) { create(:user, email: 'email.existant@domaine.fr') }
|
||||
let(:nouvel_email) { preexisting_user.email }
|
||||
|
||||
it 'does not update the user email' do
|
||||
subject
|
||||
context 'and the old account has a dossier' do
|
||||
let!(:dossier) { create(:dossier, user: user) }
|
||||
|
||||
expect(User.find_by(id: user.id).email).not_to eq(nouvel_email)
|
||||
expect(flash[:error]).to match("« #{nouvel_email} » n'est pas une adresse valide.")
|
||||
it 'transfers the dossier' do
|
||||
subject
|
||||
|
||||
expect(preexisting_user.dossiers).to match([dossier])
|
||||
end
|
||||
end
|
||||
|
||||
context 'and the old account belongs to an instructeur and expert' do
|
||||
let!(:instructeur) { create(:instructeur, user: user) }
|
||||
let!(:expert) { create(:expert, user: user) }
|
||||
|
||||
it 'transfers instructeur account' do
|
||||
subject
|
||||
preexisting_user.reload
|
||||
|
||||
expect(preexisting_user.instructeur).to match(instructeur)
|
||||
expect(preexisting_user.expert).to match(expert)
|
||||
expect(flash[:notice]).to match("Le compte « email.existant@domaine.fr » a absorbé le compte « ancien.email@domaine.fr ».")
|
||||
end
|
||||
|
||||
context 'and the preexisting account owns an instructeur and expert as well' do
|
||||
let!(:preexisting_instructeur) { create(:instructeur, user: preexisting_user) }
|
||||
let!(:preexisting_expert) { create(:expert, user: preexisting_user) }
|
||||
|
||||
context 'and the source instructeur has some procedures and dossiers' do
|
||||
let!(:procedure) { create(:procedure, instructeurs: [instructeur]) }
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:administrateur) { create(:administrateur) }
|
||||
let!(:commentaire) { create(:commentaire, instructeur: instructeur, dossier: dossier) }
|
||||
let!(:bulk_message) { BulkMessage.create!(instructeur: instructeur, body: 'body', sent_at: Time.zone.now) }
|
||||
|
||||
before do
|
||||
user.instructeur.followed_dossiers << dossier
|
||||
user.instructeur.administrateurs << administrateur
|
||||
end
|
||||
|
||||
it 'transferts all the stuff' do
|
||||
subject
|
||||
preexisting_user.reload
|
||||
|
||||
expect(procedure.instructeurs).to match([preexisting_user.instructeur])
|
||||
expect(preexisting_user.instructeur.followed_dossiers).to match([dossier])
|
||||
expect(preexisting_user.instructeur.administrateurs).to match([administrateur])
|
||||
expect(preexisting_user.instructeur.commentaires).to match([commentaire])
|
||||
expect(preexisting_user.instructeur.bulk_messages).to match([bulk_message])
|
||||
end
|
||||
end
|
||||
|
||||
context 'and the source expert has some avis and commentaires' do
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:experts_procedure) { create(:experts_procedure, expert: user.expert, procedure: dossier.procedure) }
|
||||
let!(:avis) { create(:avis, dossier: dossier, claimant: create(:instructeur), experts_procedure: experts_procedure) }
|
||||
let!(:commentaire) { create(:commentaire, expert: expert, dossier: dossier) }
|
||||
|
||||
it 'transfers the avis' do
|
||||
subject
|
||||
|
||||
expect(preexisting_user.expert.avis).to match([avis])
|
||||
expect(preexisting_user.expert.commentaires).to match([commentaire])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete' do
|
||||
let!(:user) { create(:user) }
|
||||
|
||||
before { sign_in super_admin }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
subject { delete :delete, params: { id: user.id } }
|
||||
|
||||
|
|
|
@ -12,4 +12,67 @@ RSpec.describe Expert, type: :model do
|
|||
it { expect(ExpertsProcedure.where(expert: expert, procedure: procedure).count).to eq(1) }
|
||||
it { expect(ExpertsProcedure.where(expert: expert, procedure: procedure).first.allow_decision_access).to be_falsy }
|
||||
end
|
||||
|
||||
describe '#merge' do
|
||||
let(:old_expert) { create(:expert) }
|
||||
let(:new_expert) { create(:expert) }
|
||||
|
||||
subject { new_expert.merge(old_expert) }
|
||||
|
||||
context 'when an old expert access a procedure' do
|
||||
let(:procedure) { create(:procedure) }
|
||||
|
||||
before do
|
||||
procedure.experts << old_expert
|
||||
subject
|
||||
end
|
||||
|
||||
it 'transfers the access to the new expert' do
|
||||
expect(procedure.reload.experts). to match_array(new_expert)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when both expert access a procedure' do
|
||||
let(:procedure) { create(:procedure) }
|
||||
|
||||
before do
|
||||
procedure.experts << old_expert
|
||||
procedure.experts << new_expert
|
||||
subject
|
||||
end
|
||||
|
||||
it 'removes the old one' do
|
||||
expect(procedure.reload.experts). to match_array(new_expert)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an old expert has a commentaire' do
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:commentaire) { CommentaireService.build(old_expert, dossier, body: "Mon commentaire") }
|
||||
|
||||
before do
|
||||
commentaire.save
|
||||
subject
|
||||
end
|
||||
|
||||
it 'transfers the commentaire to the new expert' do
|
||||
expect(new_expert.reload.commentaires).to match_array(commentaire)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an old expert claims for an avis' do
|
||||
let!(:avis) { create(:avis, dossier: create(:dossier), claimant: old_expert) }
|
||||
|
||||
before do
|
||||
subject
|
||||
end
|
||||
|
||||
it 'transfers the claim to the new expert' do
|
||||
avis_claimed_by_new_expert = Avis
|
||||
.where(claimant_id: new_expert.id, claimant_type: Expert.name)
|
||||
|
||||
expect(avis_claimed_by_new_expert).to match_array(avis)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -737,6 +737,94 @@ describe Instructeur, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#merge' do
|
||||
let(:old_instructeur) { create(:instructeur) }
|
||||
let(:new_instructeur) { create(:instructeur) }
|
||||
|
||||
subject { new_instructeur.merge(old_instructeur) }
|
||||
|
||||
context 'when an procedure is assigned to the old instructeur' do
|
||||
let(:procedure) { create(:procedure) }
|
||||
|
||||
before do
|
||||
procedure.defaut_groupe_instructeur.instructeurs << old_instructeur
|
||||
subject
|
||||
end
|
||||
|
||||
it 'transfers the assignment' do
|
||||
expect(new_instructeur.procedures).to match_array(procedure)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when both instructeurs are assigned to the same procedure' do
|
||||
let(:procedure) { create(:procedure) }
|
||||
|
||||
before do
|
||||
procedure.defaut_groupe_instructeur.instructeurs << old_instructeur
|
||||
procedure.defaut_groupe_instructeur.instructeurs << new_instructeur
|
||||
subject
|
||||
end
|
||||
|
||||
it 'keeps the assignment' do
|
||||
expect(new_instructeur.procedures).to match_array(procedure)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a dossier is followed by an old instructeur' do
|
||||
let(:dossier) { create(:dossier) }
|
||||
|
||||
before do
|
||||
old_instructeur.followed_dossiers << dossier
|
||||
subject
|
||||
end
|
||||
|
||||
it 'transfers the dossier' do
|
||||
expect(new_instructeur.followed_dossiers).to match_array(dossier)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when both instructeurs follow the same dossier' do
|
||||
let(:dossier) { create(:dossier) }
|
||||
|
||||
before do
|
||||
old_instructeur.followed_dossiers << dossier
|
||||
new_instructeur.followed_dossiers << dossier
|
||||
subject
|
||||
end
|
||||
|
||||
it 'does not change anything' do
|
||||
expect(new_instructeur.followed_dossiers.pluck(:id)).to match_array(dossier.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the old instructeur is on on admin list' do
|
||||
let(:administrateur) { create(:administrateur) }
|
||||
|
||||
before do
|
||||
administrateur.instructeurs << old_instructeur
|
||||
subject
|
||||
end
|
||||
|
||||
it 'is replaced by the new one' do
|
||||
expect(administrateur.reload.instructeurs).to match_array(new_instructeur)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when both are on the same admin list' do
|
||||
let(:administrateur) { create(:administrateur) }
|
||||
|
||||
before do
|
||||
administrateur.instructeurs << old_instructeur
|
||||
administrateur.instructeurs << new_instructeur
|
||||
subject
|
||||
end
|
||||
|
||||
it 'removes the old one' do
|
||||
expect(administrateur.reload.instructeurs).to match_array(new_instructeur)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assign(procedure_to_assign, instructeur_assigne: instructeur)
|
||||
|
|
Loading…
Reference in a new issue