Merge pull request #4188 from betagouv/dev

2019-08-12-01
This commit is contained in:
LeSim 2019-08-12 15:26:20 +02:00 committed by GitHub
commit 796d5b8cd6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
242 changed files with 2006 additions and 1752 deletions

View file

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View file

@ -312,8 +312,8 @@
}
.explication {
margin-bottom: 2 * $default-padding;
padding: $default-padding;
margin-bottom: $default-padding;
padding: $default-padding / 2;
background-color: $light-grey;
p:not(:last-child) {

View file

@ -2,33 +2,39 @@
@import "constants";
$strength-bg: #EEEEEE;
$weak-strength-color: $lighter-red;
$medium-strength-color: $orange;
$strong-strength-color: $green;
$strength-color-0: $lighter-red;
$strength-color-1: #FF5000;
$strength-color-2: $orange;
$strength-color-3: #FFD000;
$strength-color-4: $green;
.password-strength {
margin-top: -24px;
width: 100%;
min-height: 22px;
height: 12px;
background: $strength-bg;
display: block;
margin-bottom: $default-spacer;
text-align: center;
border-radius: 8px;
&.strength-0 {
background: linear-gradient(to right, $strength-color-0 00%, $strength-bg 20%);
}
&.strength-1 {
background: linear-gradient(to right, $weak-strength-color 0%, $weak-strength-color 25%, $strength-bg 25%, $strength-bg 100%);
background: linear-gradient(to right, $strength-color-1 20%, $strength-bg 40%);
}
&.strength-2 {
background: linear-gradient(to right, $medium-strength-color 0%, $medium-strength-color 50%, $strength-bg 50%, $strength-bg 100%);
background: linear-gradient(to right, $strength-color-2 40%, $strength-bg 60%);
}
&.strength-3 {
background: linear-gradient(to right, $medium-strength-color 0%, $medium-strength-color 75%, $strength-bg 75%, $strength-bg 100%);
background: linear-gradient(to right, $strength-color-3 60%, $strength-bg 80%);
}
&.strength-4 {
background: $strong-strength-color;
color: #FFFFFF;
background: $strength-color-4;
}
}

View file

@ -0,0 +1,54 @@
class Admin::AssignsController < AdminController
include SmartListing::Helper::ControllerExtensions
helper SmartListing::Helper
before_action :retrieve_procedure
ASSIGN = 'assign'
NOT_ASSIGN = 'not_assign'
def show
assign_scope = @procedure.instructeurs
@instructeurs_assign = smart_listing_create :instructeurs_assign,
assign_scope,
partial: "admin/assigns/list_assign",
array: true
not_assign_scope = current_administrateur.instructeurs.where.not(id: assign_scope.ids)
if params[:filter]
not_assign_scope = not_assign_scope.where("email LIKE ?", "%#{params[:filter]}%")
end
@instructeurs_not_assign = smart_listing_create :instructeurs_not_assign,
not_assign_scope,
partial: "admin/assigns/list_not_assign",
array: true
@instructeur ||= Instructeur.new
end
def update
instructeur = Instructeur.find(params[:instructeur_id])
procedure = Procedure.find(params[:procedure_id])
to = params[:to]
case to
when ASSIGN
if instructeur.assign_to_procedure(procedure)
flash.notice = "L'instructeur a bien été affecté"
else
flash.alert = "L'instructeur a déjà été affecté"
end
when NOT_ASSIGN
if instructeur.remove_from_procedure(procedure)
flash.notice = "L'instructeur a bien été désaffecté"
else
flash.alert = "L'instructeur a déjà été désaffecté"
end
end
redirect_to admin_procedure_assigns_path, procedure_id: params[:procedure_id]
end
end

View file

@ -1,72 +0,0 @@
class Admin::GestionnairesController < AdminController
include SmartListing::Helper::ControllerExtensions
helper SmartListing::Helper
def index
@gestionnaires = smart_listing_create :gestionnaires,
current_administrateur.gestionnaires,
partial: "admin/gestionnaires/list",
array: true
@gestionnaire ||= Gestionnaire.new
end
def create
email = params[:gestionnaire][:email].downcase
@gestionnaire = Gestionnaire.find_by(email: email)
procedure_id = params[:procedure_id]
if @gestionnaire.nil?
invite_gestionnaire(params[:gestionnaire][:email])
else
assign_gestionnaire!
end
if procedure_id.present?
redirect_to admin_procedure_instructeurs_path(procedure_id: procedure_id)
else
redirect_to admin_gestionnaires_path
end
end
def destroy
Gestionnaire.find(params[:id]).administrateurs.delete current_administrateur
redirect_to admin_gestionnaires_path
end
private
def invite_gestionnaire(email)
password = SecureRandom.hex
@gestionnaire = Gestionnaire.create(
email: email,
password: password,
password_confirmation: password,
administrateurs: [current_administrateur]
)
if @gestionnaire.errors.messages.empty?
@gestionnaire.invite!
if User.exists?(email: @gestionnaire.email)
GestionnaireMailer.user_to_gestionnaire(@gestionnaire.email).deliver_later
else
User.create(email: email, password: password, confirmed_at: Time.zone.now)
end
flash.notice = 'Instructeur ajouté'
else
flash.alert = @gestionnaire.errors.full_messages
end
end
def assign_gestionnaire!
if current_administrateur.gestionnaires.include?(@gestionnaire)
flash.alert = 'Instructeur déjà ajouté'
else
@gestionnaire.administrateurs.push current_administrateur
flash.notice = 'Instructeur ajouté'
# TODO Mailer no assign_to
end
end
end

View file

@ -2,53 +2,71 @@ class Admin::InstructeursController < AdminController
include SmartListing::Helper::ControllerExtensions
helper SmartListing::Helper
before_action :retrieve_procedure
ASSIGN = 'assign'
NOT_ASSIGN = 'not_assign'
def show
assign_scope = @procedure.gestionnaires
@instructeurs_assign = smart_listing_create :instructeurs_assign,
assign_scope,
partial: "admin/instructeurs/list_assign",
def index
@instructeurs = smart_listing_create :instructeurs,
current_administrateur.instructeurs,
partial: "admin/instructeurs/list",
array: true
not_assign_scope = current_administrateur.gestionnaires.where.not(id: assign_scope.ids)
if params[:filter]
not_assign_scope = not_assign_scope.where("email LIKE ?", "%#{params[:filter]}%")
end
@instructeurs_not_assign = smart_listing_create :instructeurs_not_assign,
not_assign_scope,
partial: "admin/instructeurs/list_not_assign",
array: true
@gestionnaire ||= Gestionnaire.new
@instructeur ||= Instructeur.new
end
def update
gestionnaire = Gestionnaire.find(params[:instructeur_id])
procedure = Procedure.find(params[:procedure_id])
to = params[:to]
def create
email = params[:instructeur][:email].downcase
@instructeur = Instructeur.find_by(email: email)
procedure_id = params[:procedure_id]
case to
when ASSIGN
if gestionnaire.assign_to_procedure(procedure)
flash.notice = "L'instructeur a bien été affecté"
else
flash.alert = "L'instructeur a déjà été affecté"
end
when NOT_ASSIGN
if gestionnaire.remove_from_procedure(procedure)
flash.notice = "L'instructeur a bien été désaffecté"
else
flash.alert = "L'instructeur a déjà été désaffecté"
end
if @instructeur.nil?
invite_instructeur(params[:instructeur][:email])
else
assign_instructeur!
end
redirect_to admin_procedure_instructeurs_path, procedure_id: params[:procedure_id]
if procedure_id.present?
redirect_to admin_procedure_assigns_path(procedure_id: procedure_id)
else
redirect_to admin_instructeurs_path
end
end
def destroy
Instructeur.find(params[:id]).administrateurs.delete current_administrateur
redirect_to admin_instructeurs_path
end
private
def invite_instructeur(email)
password = SecureRandom.hex
@instructeur = Instructeur.create(
email: email,
password: password,
password_confirmation: password,
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
flash.notice = 'Instructeur ajouté'
else
flash.alert = @instructeur.errors.full_messages
end
end
def assign_instructeur!
if current_administrateur.instructeurs.include?(@instructeur)
flash.alert = 'Instructeur déjà ajouté'
else
@instructeur.administrateurs.push current_administrateur
flash.notice = 'Instructeur ajouté'
# TODO Mailer no assign_to
end
end
end

View file

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

View file

@ -1,10 +1,9 @@
require 'zxcvbn'
class Administrateurs::ActivateController < ApplicationController
include TrustedDeviceConcern
def new
@administrateur = Administrateur.find_inactive_by_token(params[:token])
@token = params[:token]
@administrateur = Administrateur.find_inactive_by_token(@token)
if @administrateur
# the administrateur activates its account from an email
@ -25,7 +24,7 @@ class Administrateurs::ActivateController < ApplicationController
if administrateur && administrateur.errors.empty?
sign_in(administrateur, scope: :administrateur)
try_to_authenticate(User, administrateur.email, password)
try_to_authenticate(Gestionnaire, administrateur.email, password)
try_to_authenticate(Instructeur, administrateur.email, password)
flash.notice = "Mot de passe enregistré"
redirect_to admin_procedures_path
else
@ -34,10 +33,6 @@ class Administrateurs::ActivateController < ApplicationController
end
end
def test_password_strength
@score = Zxcvbn.test(params[:administrateur][:password], [], ZXCVBN_DICTIONNARIES).score
end
private
def update_administrateur_params

View file

@ -0,0 +1,69 @@
class Administrateurs::PasswordsController < Devise::PasswordsController
after_action :try_to_authenticate_user, only: [:update]
after_action :try_to_authenticate_instructeur, only: [:update]
# GET /resource/password/new
# def new
# super
# end
# POST /resource/password
# def create
# super
# end
# GET /resource/password/edit?reset_password_token=abcdef
# def edit
# super
# end
# PUT /resource/password
# def update
# # params[:user][:password_confirmation] = params[:user][:password]
# super
# end
# protected
# def after_resetting_password_path_for(resource)
# super(resource)
# end
# The path used after sending reset password instructions
# def after_sending_reset_password_instructions_path_for(resource_name)
# super(resource_name)
# end
def try_to_authenticate_user
if administrateur_signed_in?
user = User.find_by(email: current_administrateur.email)
if user
sign_in user
end
end
end
def try_to_authenticate_instructeur
if administrateur_signed_in?
instructeur = Instructeur.find_by(email: current_administrateur.email)
if instructeur
sign_in instructeur
end
end
end
def test_strength
@score, @words, @length = ZxcvbnService.new(password_params[:password]).complexity
@min_length = PASSWORD_MIN_LENGTH
@min_complexity = PASSWORD_COMPLEXITY_FOR_ADMIN
render 'shared/password/test_strength'
end
private
def password_params
params.require(:administrateur).permit(:reset_password_token, :password)
end
end

View file

@ -47,7 +47,7 @@ class ApplicationController < ActionController::Base
def pundit_user
{
administrateur: current_administrateur,
gestionnaire: current_gestionnaire,
instructeur: current_instructeur,
user: current_user
}.compact
end
@ -55,8 +55,8 @@ class ApplicationController < ActionController::Base
protected
def authenticate_logged_user!
if gestionnaire_signed_in?
authenticate_gestionnaire!
if instructeur_signed_in?
authenticate_instructeur!
elsif administrateur_signed_in?
authenticate_administrateur!
else
@ -64,8 +64,8 @@ class ApplicationController < ActionController::Base
end
end
def authenticate_gestionnaire!
if gestionnaire_signed_in?
def authenticate_instructeur!
if instructeur_signed_in?
super
else
redirect_to new_user_session_path
@ -88,7 +88,7 @@ class ApplicationController < ActionController::Base
def set_current_roles
Current.administrateur = current_administrateur
Current.gestionnaire = current_gestionnaire
Current.instructeur = current_instructeur
end
def set_active_storage_host
@ -108,7 +108,7 @@ class ApplicationController < ActionController::Base
def logged_users
@logged_users ||= [
current_user,
current_gestionnaire,
current_instructeur,
current_administrateur,
current_administration
].compact
@ -162,14 +162,14 @@ class ApplicationController < ActionController::Base
elsif api_request
render json: { error: MAINTENANCE_MESSAGE }.to_json, status: :service_unavailable
else
[:user, :gestionnaire, :administrateur].each { |role| sign_out(role) }
[:user, :instructeur, :administrateur].each { |role| sign_out(role) }
flash[:alert] = MAINTENANCE_MESSAGE
redirect_to root_path
end
end
def redirect_if_untrusted
if gestionnaire_signed_in? &&
if instructeur_signed_in? &&
sensitive_path &&
Flipflop.enable_email_login_token? &&
!IPService.ip_trusted?(request.headers['X-Forwarded-For']) &&
@ -179,8 +179,8 @@ class ApplicationController < ActionController::Base
# after the device is trusted
store_location_for(:user, request.fullpath)
send_login_token_or_bufferize(current_gestionnaire)
redirect_to link_sent_path(email: current_gestionnaire.email)
send_login_token_or_bufferize(current_instructeur)
redirect_to link_sent_path(email: current_instructeur.email)
end
end
@ -238,7 +238,7 @@ class ApplicationController < ActionController::Base
DS_CREATED_AT: current_administrateur&.created_at,
DS_ACTIVE: current_administrateur&.active,
DS_ID: current_administrateur&.id,
DS_GESTIONNAIRE_ID: current_gestionnaire&.id,
DS_GESTIONNAIRE_ID: current_instructeur&.id,
DS_ROLES: logged_user_roles
}
}
@ -266,7 +266,7 @@ class ApplicationController < ActionController::Base
def current_email
current_user&.email ||
current_gestionnaire&.email ||
current_instructeur&.email ||
current_administrateur&.email
end
end

View file

@ -17,7 +17,7 @@ module CreateAvisConcern
{
email: email,
introduction: create_avis_params[:introduction],
claimant: current_gestionnaire,
claimant: current_instructeur,
dossier: dossier,
confidentiel: confidentiel
}

View file

@ -40,8 +40,8 @@ class FranceConnect::ParticulierController < ApplicationController
sign_out :user
end
if gestionnaire_signed_in?
sign_out :gestionnaire
if instructeur_signed_in?
sign_out :instructeur
end
if administrateur_signed_in?

View file

@ -1,50 +0,0 @@
class Gestionnaires::ActivateController < ApplicationController
include TrustedDeviceConcern
def new
@gestionnaire = Gestionnaire.with_reset_password_token(params[:token])
if @gestionnaire
# the gestionnaire 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_gestionnaire_params[:password]
gestionnaire = Gestionnaire.reset_password_by_token({
password: password,
password_confirmation: password,
reset_password_token: create_gestionnaire_params[:reset_password_token]
})
if gestionnaire && gestionnaire.errors.empty?
sign_in(gestionnaire, scope: :gestionnaire)
try_to_authenticate(User, gestionnaire.email, password)
try_to_authenticate(Administrateur, gestionnaire.email, password)
flash.notice = "Mot de passe enregistré"
redirect_to gestionnaire_procedures_path
else
flash.alert = gestionnaire.errors.full_messages
redirect_to gestionnaire_activate_path(token: create_gestionnaire_params[:reset_password_token])
end
end
private
def create_gestionnaire_params
params.require(:gestionnaire).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

@ -1,9 +0,0 @@
module Gestionnaires
class GestionnaireController < ApplicationController
before_action :authenticate_gestionnaire!
def nav_bar_profile
:gestionnaire
end
end
end

View file

@ -1,12 +0,0 @@
module Gestionnaires
class RechercheController < GestionnaireController
def index
@search_terms = params[:q]
@dossiers = DossierSearchService.matching_dossiers_for_gestionnaire(@search_terms, current_gestionnaire)
@followed_dossiers_id = current_gestionnaire
.followed_dossiers
.where(procedure_id: @dossiers.pluck(:procedure_id))
.pluck(:id)
end
end
end

View file

@ -0,0 +1,50 @@
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

@ -1,19 +1,19 @@
module Gestionnaires
class AvisController < GestionnaireController
module Instructeurs
class AvisController < InstructeurController
include CreateAvisConcern
before_action :authenticate_gestionnaire!, except: [:sign_up, :create_gestionnaire]
before_action :authenticate_instructeur!, except: [:sign_up, :create_instructeur]
before_action :redirect_if_no_sign_up_needed, only: [:sign_up]
before_action :check_avis_exists_and_email_belongs_to_avis, only: [:sign_up, :create_gestionnaire]
before_action :check_avis_exists_and_email_belongs_to_avis, only: [:sign_up, :create_instructeur]
before_action :set_avis_and_dossier, only: [:show, :instruction, :messagerie, :create_commentaire, :update]
A_DONNER_STATUS = 'a-donner'
DONNES_STATUS = 'donnes'
def index
gestionnaire_avis = current_gestionnaire.avis.includes(dossier: [:procedure, :user])
@avis_a_donner = gestionnaire_avis.without_answer
@avis_donnes = gestionnaire_avis.with_answer
instructeur_avis = current_instructeur.avis.includes(dossier: [:procedure, :user])
@avis_a_donner = instructeur_avis.without_answer
@avis_donnes = instructeur_avis.with_answer
@statut = params[:statut].presence || A_DONNER_STATUS
@ -37,7 +37,7 @@ module Gestionnaires
def update
if @avis.update(avis_params)
flash.notice = 'Votre réponse est enregistrée.'
redirect_to instruction_gestionnaire_avis_path(@avis)
redirect_to instruction_instructeur_avis_path(@avis)
else
flash.now.alert = @avis.errors.full_messages
@new_avis = Avis.new
@ -50,11 +50,11 @@ module Gestionnaires
end
def create_commentaire
@commentaire = CommentaireService.build(current_gestionnaire, avis.dossier, commentaire_params)
@commentaire = CommentaireService.build(current_instructeur, avis.dossier, commentaire_params)
if @commentaire.save
flash.notice = "Message envoyé"
redirect_to messagerie_gestionnaire_avis_path(avis)
redirect_to messagerie_instructeur_avis_path(avis)
else
flash.alert = @commentaire.errors.full_messages
render :messagerie
@ -65,7 +65,7 @@ module Gestionnaires
@new_avis = create_avis_from_params(avis.dossier, avis.confidentiel)
if @new_avis.nil?
redirect_to instruction_gestionnaire_avis_path(avis)
redirect_to instruction_instructeur_avis_path(avis)
else
set_avis_and_dossier
render :instruction
@ -79,26 +79,26 @@ module Gestionnaires
render
end
def create_gestionnaire
def create_instructeur
email = params[:email]
password = params['gestionnaire']['password']
password = params['instructeur']['password']
gestionnaire = Gestionnaire.new(email: email, password: password)
instructeur = Instructeur.new(email: email, password: password)
if gestionnaire.save
if instructeur.save
user = User.find_by(email: email)
if user.blank?
user = User.create(email: email, password: password, confirmed_at: Time.zone.now)
end
sign_in(user)
sign_in(gestionnaire, scope: :gestionnaire)
sign_in(instructeur, scope: :instructeur)
Avis.link_avis_to_gestionnaire(gestionnaire)
redirect_to url_for(gestionnaire_avis_index_path)
Avis.link_avis_to_instructeur(instructeur)
redirect_to url_for(instructeur_avis_index_path)
else
flash[:alert] = gestionnaire.errors.full_messages
redirect_to url_for(sign_up_gestionnaire_avis_path(params[:id], email))
flash[:alert] = instructeur.errors.full_messages
redirect_to url_for(sign_up_instructeur_avis_path(params[:id], email))
end
end
@ -112,14 +112,14 @@ module Gestionnaires
def redirect_if_no_sign_up_needed
avis = Avis.find(params[:id])
if current_gestionnaire.present?
# a gestionnaire is authenticated ... lets see if it can view the dossier
if current_instructeur.present?
# a instructeur is authenticated ... lets see if it can view the dossier
redirect_to gestionnaire_avis_url(avis)
elsif avis.gestionnaire&.email == params[:email]
# the avis gestionnaire has already signed up and it sould sign in
redirect_to instructeur_avis_url(avis)
elsif avis.instructeur&.email == params[:email]
# the avis instructeur has already signed up and it sould sign in
redirect_to new_gestionnaire_session_url
redirect_to new_instructeur_session_url
end
end
@ -130,7 +130,7 @@ module Gestionnaires
end
def avis
current_gestionnaire.avis.includes(dossier: [:avis, :commentaires]).find(params[:id])
current_instructeur.avis.includes(dossier: [:avis, :commentaires]).find(params[:id])
end
def avis_params

View file

@ -1,4 +1,4 @@
module Gestionnaires
module Instructeurs
class DossiersController < ProceduresController
include ActionView::Helpers::NumberHelper
include ActionView::Helpers::TextHelper
@ -22,72 +22,72 @@ module Gestionnaires
end
def show
@demande_seen_at = current_gestionnaire.follows.find_by(dossier: dossier)&.demande_seen_at
@demande_seen_at = current_instructeur.follows.find_by(dossier: dossier)&.demande_seen_at
end
def messagerie
@commentaire = Commentaire.new
@messagerie_seen_at = current_gestionnaire.follows.find_by(dossier: dossier)&.messagerie_seen_at
@messagerie_seen_at = current_instructeur.follows.find_by(dossier: dossier)&.messagerie_seen_at
end
def annotations_privees
@annotations_privees_seen_at = current_gestionnaire.follows.find_by(dossier: dossier)&.annotations_privees_seen_at
@annotations_privees_seen_at = current_instructeur.follows.find_by(dossier: dossier)&.annotations_privees_seen_at
end
def avis
@avis_seen_at = current_gestionnaire.follows.find_by(dossier: dossier)&.avis_seen_at
@avis_seen_at = current_instructeur.follows.find_by(dossier: dossier)&.avis_seen_at
@avis = Avis.new
end
def personnes_impliquees
@following_instructeurs_emails = dossier.followers_gestionnaires.pluck(:email)
previous_followers = dossier.previous_followers_gestionnaires - dossier.followers_gestionnaires
@following_instructeurs_emails = dossier.followers_instructeurs.pluck(:email)
previous_followers = dossier.previous_followers_instructeurs - dossier.followers_instructeurs
@previous_following_instructeurs_emails = previous_followers.pluck(:email)
@avis_emails = dossier.avis.includes(:gestionnaire).map(&:email_to_display)
@avis_emails = dossier.avis.includes(:instructeur).map(&:email_to_display)
@invites_emails = dossier.invites.map(&:email)
@potential_recipients = procedure.gestionnaires.reject { |g| g == current_gestionnaire }
@potential_recipients = procedure.instructeurs.reject { |g| g == current_instructeur }
end
def send_to_instructeurs
recipients = Gestionnaire.find(params[:recipients])
recipients = Instructeur.find(params[:recipients])
recipients.each do |recipient|
GestionnaireMailer.send_dossier(current_gestionnaire, dossier, recipient).deliver_later
InstructeurMailer.send_dossier(current_instructeur, dossier, recipient).deliver_later
end
flash.notice = "Dossier envoyé"
redirect_to(personnes_impliquees_gestionnaire_dossier_path(procedure, dossier))
redirect_to(personnes_impliquees_instructeur_dossier_path(procedure, dossier))
end
def follow
current_gestionnaire.follow(dossier)
current_instructeur.follow(dossier)
flash.notice = 'Dossier suivi'
redirect_back(fallback_location: gestionnaire_procedures_url)
redirect_back(fallback_location: instructeur_procedures_url)
end
def unfollow
current_gestionnaire.unfollow(dossier)
current_instructeur.unfollow(dossier)
flash.notice = "Vous ne suivez plus le dossier nº #{dossier.id}"
redirect_back(fallback_location: gestionnaire_procedures_url)
redirect_back(fallback_location: instructeur_procedures_url)
end
def archive
dossier.update(archived: true)
current_gestionnaire.unfollow(dossier)
redirect_back(fallback_location: gestionnaire_procedures_url)
current_instructeur.unfollow(dossier)
redirect_back(fallback_location: instructeur_procedures_url)
end
def unarchive
dossier.update(archived: false)
redirect_back(fallback_location: gestionnaire_procedures_url)
redirect_back(fallback_location: instructeur_procedures_url)
end
def passer_en_instruction
if dossier.en_instruction?
flash.notice = 'Le dossier est déjà en instruction.'
else
dossier.passer_en_instruction!(current_gestionnaire)
dossier.passer_en_instruction!(current_instructeur)
flash.notice = 'Dossier passé en instruction.'
end
@ -98,7 +98,7 @@ module Gestionnaires
if dossier.en_construction?
flash.notice = 'Le dossier est déjà en construction.'
else
dossier.repasser_en_construction!(current_gestionnaire)
dossier.repasser_en_construction!(current_instructeur)
flash.notice = 'Dossier repassé en construction.'
end
@ -113,7 +113,7 @@ module Gestionnaires
flash.notice = 'Il nest pas possible de repasser un dossier accepté en instruction.'
else
flash.notice = "Le dossier #{dossier.id} a été repassé en instruction."
dossier.repasser_en_instruction!(current_gestionnaire)
dossier.repasser_en_instruction!(current_instructeur)
end
end
@ -129,13 +129,13 @@ module Gestionnaires
else
case params[:process_action]
when "refuser"
dossier.refuser!(current_gestionnaire, motivation, justificatif)
dossier.refuser!(current_instructeur, motivation, justificatif)
flash.notice = "Dossier considéré comme refusé."
when "classer_sans_suite"
dossier.classer_sans_suite!(current_gestionnaire, motivation, justificatif)
dossier.classer_sans_suite!(current_instructeur, motivation, justificatif)
flash.notice = "Dossier considéré comme sans suite."
when "accepter"
dossier.accepter!(current_gestionnaire, motivation, justificatif)
dossier.accepter!(current_instructeur, motivation, justificatif)
flash.notice = "Dossier traité avec succès."
end
end
@ -144,12 +144,12 @@ module Gestionnaires
end
def create_commentaire
@commentaire = CommentaireService.build(current_gestionnaire, dossier, commentaire_params)
@commentaire = CommentaireService.build(current_instructeur, dossier, commentaire_params)
if @commentaire.save
current_gestionnaire.follow(dossier)
current_instructeur.follow(dossier)
flash.notice = "Message envoyé"
redirect_to messagerie_gestionnaire_dossier_path(procedure, dossier)
redirect_to messagerie_instructeur_dossier_path(procedure, dossier)
else
flash.alert = @commentaire.errors.full_messages
render :messagerie
@ -160,18 +160,18 @@ module Gestionnaires
@avis = create_avis_from_params(dossier)
if @avis.nil?
redirect_to avis_gestionnaire_dossier_path(procedure, dossier)
redirect_to avis_instructeur_dossier_path(procedure, dossier)
else
@avis_seen_at = current_gestionnaire.follows.find_by(dossier: dossier)&.avis_seen_at
@avis_seen_at = current_instructeur.follows.find_by(dossier: dossier)&.avis_seen_at
render :avis
end
end
def update_annotations
dossier = current_gestionnaire.dossiers.includes(champs_private: :type_de_champ).find(params[:dossier_id])
dossier = current_instructeur.dossiers.includes(champs_private: :type_de_champ).find(params[:dossier_id])
dossier.update(champs_private_params)
dossier.modifier_annotations!(current_gestionnaire)
redirect_to annotations_privees_gestionnaire_dossier_path(procedure, dossier)
dossier.modifier_annotations!(current_instructeur)
redirect_to annotations_privees_instructeur_dossier_path(procedure, dossier)
end
def print
@ -190,7 +190,7 @@ module Gestionnaires
private
def dossier
@dossier ||= current_gestionnaire.dossiers.find(params[:dossier_id])
@dossier ||= current_instructeur.dossiers.find(params[:dossier_id])
end
def commentaire_params
@ -205,19 +205,19 @@ module Gestionnaires
end
def mark_demande_as_read
current_gestionnaire.mark_tab_as_seen(dossier, :demande)
current_instructeur.mark_tab_as_seen(dossier, :demande)
end
def mark_messagerie_as_read
current_gestionnaire.mark_tab_as_seen(dossier, :messagerie)
current_instructeur.mark_tab_as_seen(dossier, :messagerie)
end
def mark_avis_as_read
current_gestionnaire.mark_tab_as_seen(dossier, :avis)
current_instructeur.mark_tab_as_seen(dossier, :avis)
end
def mark_annotations_privees_as_read
current_gestionnaire.mark_tab_as_seen(dossier, :annotations_privees)
current_instructeur.mark_tab_as_seen(dossier, :annotations_privees)
end
end
end

View file

@ -0,0 +1,9 @@
module Instructeurs
class InstructeurController < ApplicationController
before_action :authenticate_instructeur!
def nav_bar_profile
:instructeur
end
end
end

View file

@ -1,4 +1,4 @@
class Gestionnaires::PasswordsController < Devise::PasswordsController
class Instructeurs::PasswordsController < Devise::PasswordsController
after_action :try_to_authenticate_user, only: [:update]
after_action :try_to_authenticate_administrateur, only: [:update]
@ -34,8 +34,8 @@ class Gestionnaires::PasswordsController < Devise::PasswordsController
# end
def try_to_authenticate_user
if gestionnaire_signed_in?
user = User.find_by(email: current_gestionnaire.email)
if instructeur_signed_in?
user = User.find_by(email: current_instructeur.email)
if user
sign_in user
@ -44,8 +44,8 @@ class Gestionnaires::PasswordsController < Devise::PasswordsController
end
def try_to_authenticate_administrateur
if gestionnaire_signed_in?
administrateur = Administrateur.find_by(email: current_gestionnaire.email)
if instructeur_signed_in?
administrateur = Administrateur.find_by(email: current_instructeur.email)
if administrateur
sign_in administrateur

View file

@ -1,20 +1,20 @@
module Gestionnaires
class ProceduresController < GestionnaireController
module Instructeurs
class ProceduresController < InstructeurController
before_action :ensure_ownership!, except: [:index]
before_action :redirect_to_avis_if_needed, only: [:index]
ITEMS_PER_PAGE = 25
def index
@procedures = current_gestionnaire.visible_procedures.order(archived_at: :desc, published_at: :desc, created_at: :desc)
@procedures = current_instructeur.visible_procedures.order(archived_at: :desc, published_at: :desc, created_at: :desc)
dossiers = current_gestionnaire.dossiers
dossiers = current_instructeur.dossiers
@dossiers_count_per_procedure = dossiers.all_state.group(:procedure_id).reorder(nil).count
@dossiers_a_suivre_count_per_procedure = dossiers.without_followers.en_cours.group(:procedure_id).reorder(nil).count
@dossiers_archived_count_per_procedure = dossiers.archived.group(:procedure_id).count
@dossiers_termines_count_per_procedure = dossiers.termine.group(:procedure_id).reorder(nil).count
@followed_dossiers_count_per_procedure = current_gestionnaire
@followed_dossiers_count_per_procedure = current_instructeur
.followed_dossiers
.en_cours
.where(procedure: @procedures)
@ -39,13 +39,13 @@ module Gestionnaires
.without_followers
.en_cours
@followed_dossiers = current_gestionnaire
@followed_dossiers = current_instructeur
.followed_dossiers
.includes(:user)
.where(procedure: @procedure)
.en_cours
@followed_dossiers_id = current_gestionnaire
@followed_dossiers_id = current_instructeur
.followed_dossiers
.where(procedure: @procedure)
.pluck(:id)
@ -69,7 +69,7 @@ module Gestionnaires
@archived_dossiers
end
sorted_ids = procedure_presentation.sorted_ids(@dossiers, current_gestionnaire)
sorted_ids = procedure_presentation.sorted_ids(@dossiers, current_instructeur)
if @current_filters.count > 0
filtered_ids = procedure_presentation.filtered_ids(@dossiers, statut)
@ -112,7 +112,7 @@ module Gestionnaires
procedure_presentation.update(sort: Procedure.default_sort)
end
redirect_back(fallback_location: gestionnaire_procedure_url(procedure))
redirect_back(fallback_location: instructeur_procedure_url(procedure))
end
def update_sort
@ -134,7 +134,7 @@ module Gestionnaires
procedure_presentation.update(sort: sort)
redirect_back(fallback_location: gestionnaire_procedure_url(procedure))
redirect_back(fallback_location: instructeur_procedure_url(procedure))
end
def add_filter
@ -153,7 +153,7 @@ module Gestionnaires
procedure_presentation.update(filters: filters)
end
redirect_back(fallback_location: gestionnaire_procedure_url(procedure))
redirect_back(fallback_location: instructeur_procedure_url(procedure))
end
def remove_filter
@ -164,7 +164,7 @@ module Gestionnaires
procedure_presentation.update(filters: filters)
redirect_back(fallback_location: gestionnaire_procedure_url(procedure))
redirect_back(fallback_location: instructeur_procedure_url(procedure))
end
def download_dossiers
@ -195,7 +195,7 @@ module Gestionnaires
assign_to.update!(email_notifications_enabled: params[:assign_to][:email_notifications_enabled])
flash.notice = 'Vos notifications sont enregistrées.'
redirect_to gestionnaire_procedure_path(procedure)
redirect_to instructeur_procedure_path(procedure)
end
private
@ -209,7 +209,7 @@ module Gestionnaires
end
def assign_to
current_gestionnaire.assign_to.find_by(procedure: procedure)
current_instructeur.assign_to.find_by(procedure: procedure)
end
def statut
@ -221,15 +221,15 @@ module Gestionnaires
end
def ensure_ownership!
if !procedure.gestionnaires.include?(current_gestionnaire)
if !procedure.instructeurs.include?(current_instructeur)
flash[:alert] = "Vous n'avez pas accès à cette démarche"
redirect_to root_path
end
end
def redirect_to_avis_if_needed
if current_gestionnaire.visible_procedures.count == 0 && current_gestionnaire.avis.count > 0
redirect_to gestionnaire_avis_index_path
if current_instructeur.visible_procedures.count == 0 && current_instructeur.avis.count > 0
redirect_to instructeur_avis_index_path
end
end
@ -238,7 +238,7 @@ module Gestionnaires
end
def get_procedure_presentation
procedure_presentation, errors = current_gestionnaire.procedure_presentation_and_errors_for_procedure_id(params[:procedure_id])
procedure_presentation, errors = current_instructeur.procedure_presentation_and_errors_for_procedure_id(params[:procedure_id])
if errors.present?
flash[:alert] = "Votre affichage a dû être réinitialisé en raison du problème suivant : " + errors.full_messages.join(', ')
end

View file

@ -0,0 +1,12 @@
module Instructeurs
class RechercheController < InstructeurController
def index
@search_terms = params[:q]
@dossiers = DossierSearchService.matching_dossiers_for_instructeur(@search_terms, current_instructeur)
@followed_dossiers_id = current_instructeur
.followed_dossiers
.where(procedure_id: @dossiers.pluck(:procedure_id))
.pluck(:id)
end
end
end

View file

@ -1,4 +1,4 @@
class Gestionnaires::SessionsController < Sessions::SessionsController
class Instructeurs::SessionsController < Sessions::SessionsController
def new
redirect_to new_user_session_path
end

View file

@ -1,24 +0,0 @@
module Manager
class GestionnairesController < Manager::ApplicationController
def reinvite
gestionnaire = Gestionnaire.find(params[:id])
gestionnaire.invite!
flash[:notice] = "Instructeur réinvité."
redirect_to manager_gestionnaire_path(gestionnaire)
end
def enable_feature
gestionnaire = Gestionnaire.find(params[:id])
params[:features].each do |key, enable|
if enable
gestionnaire.enable_feature(key.to_sym)
else
gestionnaire.disable_feature(key.to_sym)
end
end
head :ok
end
end
end

View file

@ -0,0 +1,24 @@
module Manager
class InstructeursController < Manager::ApplicationController
def reinvite
instructeur = Instructeur.find(params[:id])
instructeur.invite!
flash[:notice] = "Instructeur réinvité."
redirect_to manager_instructeur_path(instructeur)
end
def enable_feature
instructeur = Instructeur.find(params[:id])
params[:features].each do |key, enable|
if enable
instructeur.enable_feature(key.to_sym)
else
instructeur.disable_feature(key.to_sym)
end
end
head :ok
end
end
end

View file

@ -2,8 +2,8 @@ class RootController < ApplicationController
def index
if administrateur_signed_in?
return redirect_to admin_procedures_path
elsif gestionnaire_signed_in?
return redirect_to gestionnaire_procedures_path
elsif instructeur_signed_in?
return redirect_to instructeur_procedures_path
elsif user_signed_in?
return redirect_to dossiers_path
elsif administration_signed_in?

View file

@ -8,8 +8,8 @@ class Sessions::SessionsController < Devise::SessionsController
sign_out :user
end
if gestionnaire_signed_in?
sign_out :gestionnaire
if instructeur_signed_in?
sign_out :instructeur
end
if administrateur_signed_in?

View file

@ -223,6 +223,10 @@ module Users
dossier = Dossier.create!(procedure: procedure, user: current_user, state: Dossier.states.fetch(:brouillon))
if dossier.procedure.for_individual
if current_user.france_connect_information.present?
dossier.update_with_france_connect(current_user.france_connect_information)
end
redirect_to identite_dossier_path(dossier)
else
redirect_to siret_dossier_path(id: dossier.id)

View file

@ -1,5 +1,5 @@
class Users::PasswordsController < Devise::PasswordsController
after_action :try_to_authenticate_gestionnaire, only: [:update]
after_action :try_to_authenticate_instructeur, only: [:update]
after_action :try_to_authenticate_administrateur, only: [:update]
# GET /resource/password/new
@ -8,9 +8,19 @@ class Users::PasswordsController < Devise::PasswordsController
# end
# POST /resource/password
# def create
# super
# end
def create
# Check the credentials associated to the mail to generate a correct reset link
email = params[:user][:email]
if Administrateur.find_by(email: email)
@devise_mapping = Devise.mappings[:administrateur]
params[:administrateur] = params[:user]
# uncomment to check password complexity for Instructeur
# elsif Instructeur.find_by(email: email)
# @devise_mapping = Devise.mappings[:instructeur]
# params[:instructeur] = params[:user]
end
super
end
# GET /resource/password/edit?reset_password_token=abcdef
# def edit
@ -19,6 +29,7 @@ class Users::PasswordsController < Devise::PasswordsController
# PUT /resource/password
# def update
# # params[:user][:password_confirmation] = params[:user][:password]
# super
# end
@ -33,12 +44,12 @@ class Users::PasswordsController < Devise::PasswordsController
# super(resource_name)
# end
def try_to_authenticate_gestionnaire
def try_to_authenticate_instructeur
if user_signed_in?
gestionnaire = Gestionnaire.find_by(email: current_user.email)
instructeur = Instructeur.find_by(email: current_user.email)
if gestionnaire
sign_in gestionnaire
if instructeur
sign_in instructeur
end
end
end
@ -52,4 +63,15 @@ class Users::PasswordsController < Devise::PasswordsController
end
end
end
def test_strength
@score, @words, @length = ZxcvbnService.new(password_params[:password]).complexity
@min_length = PASSWORD_MIN_LENGTH
@min_complexity = PASSWORD_COMPLEXITY_FOR_USER
render 'shared/password/test_strength'
end
def password_params
params.require(:user).permit(:reset_password_token, :password)
end
end

View file

@ -17,7 +17,7 @@ class Users::SessionsController < Sessions::SessionsController
remember_me = params[:user][:remember_me] == '1'
if resource_locked?(try_to_authenticate(User, remember_me)) ||
resource_locked?(try_to_authenticate(Gestionnaire, remember_me)) ||
resource_locked?(try_to_authenticate(Instructeur, remember_me)) ||
resource_locked?(try_to_authenticate(Administrateur, remember_me))
flash.alert = 'Votre compte est verrouillé.'
new
@ -28,7 +28,7 @@ class Users::SessionsController < Sessions::SessionsController
current_user.update(loged_in_with_france_connect: nil)
end
if gestionnaire_signed_in? || user_signed_in?
if instructeur_signed_in? || user_signed_in?
set_flash_message :notice, :signed_in
redirect_to after_sign_in_path_for(:user)
else
@ -44,8 +44,8 @@ class Users::SessionsController < Sessions::SessionsController
# DELETE /resource/sign_out
def destroy
if gestionnaire_signed_in?
sign_out :gestionnaire
if instructeur_signed_in?
sign_out :instructeur
end
if administrateur_signed_in?
@ -74,8 +74,8 @@ class Users::SessionsController < Sessions::SessionsController
end
def sign_in_by_link
gestionnaire = Gestionnaire.find(params[:id])
trusted_device_token = gestionnaire
instructeur = Instructeur.find(params[:id])
trusted_device_token = instructeur
.trusted_device_tokens
.find_by(token: params[:jeton])
@ -89,7 +89,7 @@ class Users::SessionsController < Sessions::SessionsController
# redirect to procedure'url if stored by store_location_for(:user) in dossiers_controller
# redirect to root_path otherwise
if gestionnaire_signed_in?
if instructeur_signed_in?
redirect_to after_sign_in_path_for(:user)
else
redirect_to new_user_session_path
@ -97,8 +97,8 @@ class Users::SessionsController < Sessions::SessionsController
else
flash[:alert] = 'Votre lien est invalide ou expiré, un nouveau vient de vous être envoyé.'
send_login_token_or_bufferize(gestionnaire)
redirect_to link_sent_path(email: gestionnaire.email)
send_login_token_or_bufferize(instructeur)
redirect_to link_sent_path(email: instructeur.email)
end
end

View file

@ -4,7 +4,7 @@ class WebhookController < ActionController::Base
def helpscout
email = params[:customer][:email].downcase
user = User.find_by(email: email)
gestionnaire = Gestionnaire.find_by(email: email)
instructeur = Instructeur.find_by(email: email)
administrateur = Administrateur.find_by(email: email)
html = []
@ -13,9 +13,9 @@ class WebhookController < ActionController::Base
html << link_to_manager(user, url)
end
if gestionnaire
url = manager_gestionnaire_url(gestionnaire)
html << link_to_manager(gestionnaire, url)
if instructeur
url = manager_instructeur_url(instructeur)
html << link_to_manager(instructeur, url)
end
if administrateur

View file

@ -1,6 +1,6 @@
require "administrate/base_dashboard"
class GestionnaireDashboard < Administrate::BaseDashboard
class InstructeurDashboard < Administrate::BaseDashboard
# ATTRIBUTE_TYPES
# a hash that describes the type of each of the model's fields.
#
@ -48,7 +48,7 @@ class GestionnaireDashboard < Administrate::BaseDashboard
# Overwrite this method to customize how users are displayed
# across all pages of the admin dashboard.
#
def display_resource(gestionnaire)
gestionnaire.email
def display_resource(instructeur)
instructeur.email
end
end

View file

@ -12,7 +12,7 @@ class ProcedureDashboard < Administrate::BaseDashboard
types_de_champ_private: TypesDeChampCollectionField,
path: ProcedureLinkField,
dossiers: Field::HasMany,
gestionnaires: Field::HasMany,
instructeurs: Field::HasMany,
administrateurs: Field::HasMany,
id: Field::Number.with_options(searchable: true),
libelle: Field::String,
@ -73,7 +73,7 @@ class ProcedureDashboard < Administrate::BaseDashboard
:types_de_champ_private,
:for_individual,
:auto_archive_on,
:gestionnaires,
:instructeurs,
:initiated_mail_template,
:received_mail_template,
:closed_mail_template,

View file

@ -86,7 +86,7 @@ module ApplicationHelper
def current_email
current_user&.email ||
current_gestionnaire&.email ||
current_instructeur&.email ||
current_administrateur&.email
end
@ -104,8 +104,8 @@ module ApplicationHelper
def root_path_for_profile(nav_bar_profile)
case nav_bar_profile
when :gestionnaire
gestionnaire_procedures_path
when :instructeur
instructeur_procedures_path
when :user
dossiers_path
else

View file

@ -1,12 +1,12 @@
module DossierLinkHelper
def dossier_linked_path(user, dossier)
if user.is_a?(Gestionnaire)
if dossier.procedure.gestionnaires.include?(user)
gestionnaire_dossier_path(dossier.procedure, dossier)
if user.is_a?(Instructeur)
if dossier.procedure.instructeurs.include?(user)
instructeur_dossier_path(dossier.procedure, dossier)
else
avis = dossier.avis.find_by(gestionnaire: user)
avis = dossier.avis.find_by(instructeur: user)
if avis.present?
gestionnaire_avis_path(avis)
instructeur_avis_path(avis)
end
end
elsif user.owns_or_invite?(dossier)

View file

@ -55,7 +55,7 @@ module ProcedureHelper
end
def procedure_dossiers_download_path(procedure, format:, version:)
download_dossiers_gestionnaire_procedure_path(format: format,
download_dossiers_instructeur_procedure_path(format: format,
procedure_id: procedure.id,
tables: [:etablissements],
version: version)

View file

@ -2,8 +2,8 @@ module TableauDeBordHelper
def tableau_de_bord_helper_path
if current_administrateur.present?
admin_procedures_path
elsif current_gestionnaire.present?
gestionnaire_procedures_path
elsif current_instructeur.present?
instructeur_procedures_path
else
dossiers_path
end

View file

@ -1,7 +0,0 @@
class GestionnaireEmailNotificationJob < ApplicationJob
queue_as :cron
def perform(*args)
NotificationService.send_gestionnaire_email_notification
end
end

View file

@ -0,0 +1,7 @@
class InstructeurEmailNotificationJob < ApplicationJob
queue_as :cron
def perform(*args)
NotificationService.send_instructeur_email_notification
end
end

View file

@ -4,10 +4,10 @@ class WeeklyOverviewJob < ApplicationJob
def perform(*args)
# Feature flipped to avoid mails in staging due to unprocessed dossier
if Rails.application.config.ds_weekly_overview
Gestionnaire.all
.map { |gestionnaire| [gestionnaire, gestionnaire.last_week_overview] }
Instructeur.all
.map { |instructeur| [instructeur, instructeur.last_week_overview] }
.reject { |_, overview| overview.nil? }
.each { |gestionnaire, _| GestionnaireMailer.last_week_overview(gestionnaire).deliver_later }
.each { |instructeur, _| InstructeurMailer.last_week_overview(instructeur).deliver_later }
end
end
end

View file

@ -10,7 +10,7 @@ module Flipflop::Strategies
def enabled?(feature)
find_current_administrateur&.feature_enabled?(feature) ||
find_current_gestionnaire&.feature_enabled?(feature)
find_current_instructeur&.feature_enabled?(feature)
end
private
@ -22,10 +22,10 @@ module Flipflop::Strategies
end
end
def find_current_gestionnaire
gestionnaire_id = Current.gestionnaire&.id
if gestionnaire_id
Gestionnaire.find_by(id: gestionnaire_id)
def find_current_instructeur
instructeur_id = Current.instructeur&.id
if instructeur_id
Instructeur.find_by(id: instructeur_id)
end
end
end

View file

@ -4,7 +4,7 @@ class AvisMailer < ApplicationMailer
def avis_invitation(avis)
@avis = avis
email = @avis.gestionnaire&.email || @avis.email
email = @avis.instructeur&.email || @avis.email
subject = "Donnez votre avis sur le dossier nº #{@avis.dossier.id} (#{@avis.dossier.procedure.libelle})"
mail(to: email, subject: subject)

View file

@ -1,28 +1,28 @@
# Preview all emails at http://localhost:3000/rails/mailers/gestionnaire_mailer
class GestionnaireMailer < ApplicationMailer
# Preview all emails at http://localhost:3000/rails/mailers/instructeur_mailer
class InstructeurMailer < ApplicationMailer
layout 'mailers/layout'
def invite_gestionnaire(gestionnaire, reset_password_token)
def invite_instructeur(instructeur, reset_password_token)
@reset_password_token = reset_password_token
@gestionnaire = gestionnaire
@instructeur = instructeur
subject = "Activez votre compte instructeur"
mail(to: gestionnaire.email,
mail(to: instructeur.email,
subject: subject,
reply_to: CONTACT_EMAIL)
end
def user_to_gestionnaire(email)
def user_to_instructeur(email)
@email = email
subject = "Vous avez été nommé instructeur"
mail(to: @email, subject: subject)
end
def last_week_overview(gestionnaire)
email = gestionnaire.email
def last_week_overview(instructeur)
email = instructeur.email
@subject = 'Votre activité hebdomadaire'
@overview = gestionnaire.last_week_overview
@overview = instructeur.last_week_overview
if @overview.present?
headers['X-mailjet-campaign'] = 'last_week_overview'
@ -38,18 +38,18 @@ class GestionnaireMailer < ApplicationMailer
mail(to: recipient.email, subject: subject)
end
def send_login_token(gestionnaire, login_token)
@gestionnaire_id = gestionnaire.id
def send_login_token(instructeur, login_token)
@instructeur_id = instructeur.id
@login_token = login_token
subject = "Connexion sécurisée à demarches-simplifiees.fr"
mail(to: gestionnaire.email, subject: subject)
mail(to: instructeur.email, subject: subject)
end
def send_notifications(gestionnaire, data)
def send_notifications(instructeur, data)
@data = data
subject = "Vous avez du nouveau sur vos démarches"
mail(to: gestionnaire.email, subject: subject)
mail(to: instructeur.email, subject: subject)
end
end

View file

@ -6,7 +6,7 @@ class Administrateur < ApplicationRecord
devise :database_authenticatable, :registerable, :async,
:recoverable, :rememberable, :trackable, :validatable, :lockable
has_and_belongs_to_many :gestionnaires
has_and_belongs_to_many :instructeurs
has_many :administrateurs_procedures
has_many :procedures, through: :administrateurs_procedures
has_many :services
@ -20,11 +20,8 @@ class Administrateur < ApplicationRecord
validate :password_complexity, if: Proc.new { |a| Devise.password_length.include?(a.password.try(:size)) }
def password_complexity
if password.present?
score = Zxcvbn.test(password, [], ZXCVBN_DICTIONNARIES).score
if score < 4
errors.add(:password, :not_strength)
end
if password.present? && ZxcvbnService.new(password).score < PASSWORD_COMPLEXITY_FOR_ADMIN
errors.add(:password, :not_strong)
end
end
@ -120,8 +117,8 @@ class Administrateur < ApplicationRecord
procedure.administrateurs.include?(self)
end
def gestionnaire
Gestionnaire.find_by(email: email)
def instructeur
Instructeur.find_by(email: email)
end
def can_be_deleted?

View file

@ -26,7 +26,7 @@ class Administration < ApplicationRecord
confirmed_at: Time.zone.now
})
Gestionnaire.create({
Instructeur.create({
email: email,
password: password
})

View file

@ -1,6 +1,6 @@
class AssignTo < ApplicationRecord
belongs_to :procedure
belongs_to :gestionnaire
belongs_to :instructeur
has_one :procedure_presentation, dependent: :destroy
scope :with_email_notifications, -> { where(email_notifications_enabled: true) }

View file

@ -2,8 +2,8 @@ class Avis < ApplicationRecord
include EmailSanitizableConcern
belongs_to :dossier, inverse_of: :avis, touch: true
belongs_to :gestionnaire
belongs_to :claimant, class_name: 'Gestionnaire'
belongs_to :instructeur
belongs_to :claimant, class_name: 'Instructeur'
has_one_attached :piece_justificative_file
@ -11,8 +11,8 @@ class Avis < ApplicationRecord
validates :claimant, presence: true
before_validation -> { sanitize_email(:email) }
before_create :try_to_assign_gestionnaire
after_create :notify_gestionnaire
before_create :try_to_assign_instructeur
after_create :notify_instructeur
default_scope { joins(:dossier) }
scope :with_answer, -> { where.not(answer: nil) }
@ -26,11 +26,11 @@ class Avis < ApplicationRecord
attr_accessor :emails
def email_to_display
gestionnaire&.email || email
instructeur&.email || email
end
def self.link_avis_to_gestionnaire(gestionnaire)
Avis.where(email: gestionnaire.email).update_all(email: nil, gestionnaire_id: gestionnaire.id)
def self.link_avis_to_instructeur(instructeur)
Avis.where(email: instructeur.email).update_all(email: nil, instructeur_id: instructeur.id)
end
def self.avis_exists_and_email_belongs_to_avis?(avis_id, email)
@ -49,14 +49,14 @@ class Avis < ApplicationRecord
private
def notify_gestionnaire
def notify_instructeur
AvisMailer.avis_invitation(self).deliver_later
end
def try_to_assign_gestionnaire
gestionnaire = Gestionnaire.find_by(email: email)
if gestionnaire
self.gestionnaire = gestionnaire
def try_to_assign_instructeur
instructeur = Instructeur.find_by(email: email)
if instructeur
self.instructeur = instructeur
self.email = nil
end
end

View file

@ -2,7 +2,7 @@ class Commentaire < ApplicationRecord
belongs_to :dossier, inverse_of: :commentaires, touch: true
belongs_to :user
belongs_to :gestionnaire
belongs_to :instructeur
mount_uploader :file, CommentaireFileUploader
validate :messagerie_available?, on: :create
@ -19,8 +19,8 @@ class Commentaire < ApplicationRecord
def email
if user
user.email
elsif gestionnaire
gestionnaire.email
elsif instructeur
instructeur.email
else
read_attribute(:email)
end
@ -31,8 +31,8 @@ class Commentaire < ApplicationRecord
end
def redacted_email
if gestionnaire.present?
gestionnaire.email.split('@').first
if instructeur.present?
instructeur.email.split('@').first
else
email
end
@ -40,7 +40,7 @@ class Commentaire < ApplicationRecord
def sent_by_system?
[CONTACT_EMAIL, OLD_CONTACT_EMAIL].include?(email) &&
user.nil? && gestionnaire.nil?
user.nil? && instructeur.nil?
end
def sent_by?(someone)
@ -70,7 +70,7 @@ class Commentaire < ApplicationRecord
# of an automated notification email we sent to a user, so do nothing.
# - If a user or an invited user posted a commentaire, do nothing,
# the notification system will properly
# - Otherwise, a gestionnaire posted a commentaire, we need to notify the user
# - Otherwise, a instructeur posted a commentaire, we need to notify the user
if !email.in?([CONTACT_EMAIL, dossier_user_email, *invited_users_emails])
notify_user
end

View file

@ -17,10 +17,10 @@ module TrustedDeviceConcern
(Time.zone.now - TRUSTED_DEVICE_PERIOD) < trusted_device_cookie_created_at
end
def send_login_token_or_bufferize(gestionnaire)
if !gestionnaire.young_login_token?
login_token = gestionnaire.create_trusted_device_token
GestionnaireMailer.send_login_token(gestionnaire, login_token).deliver_later
def send_login_token_or_bufferize(instructeur)
if !instructeur.young_login_token?
login_token = instructeur.create_trusted_device_token
InstructeurMailer.send_login_token(instructeur, login_token).deliver_later
end
end

View file

@ -1,3 +1,3 @@
class Current < ActiveSupport::CurrentAttributes
attribute :gestionnaire, :administrateur
attribute :instructeur, :administrateur
end

View file

@ -29,8 +29,8 @@ class Dossier < ApplicationRecord
has_many :invites, dependent: :destroy
has_many :follows, -> { active }, inverse_of: :dossier
has_many :previous_follows, -> { inactive }, class_name: 'Follow', inverse_of: :dossier
has_many :followers_gestionnaires, through: :follows, source: :gestionnaire
has_many :previous_followers_gestionnaires, -> { distinct }, through: :previous_follows, source: :gestionnaire
has_many :followers_instructeurs, through: :follows, source: :instructeur
has_many :previous_followers_instructeurs, -> { distinct }, through: :previous_follows, source: :instructeur
has_many :avis, inverse_of: :dossier, dependent: :destroy
has_many :dossier_operation_logs, dependent: :destroy
@ -114,7 +114,7 @@ class Dossier < ApplicationRecord
.includes(
:user,
:individual,
:followers_gestionnaires,
:followers_instructeurs,
:avis,
etablissement: :champ,
champs: {
@ -129,7 +129,7 @@ class Dossier < ApplicationRecord
}
scope :en_cours, -> { not_archived.state_en_construction_ou_instruction }
scope :without_followers, -> { left_outer_joins(:follows).where(follows: { id: nil }) }
scope :followed_by, -> (gestionnaire) { joins(:follows).where(follows: { gestionnaire: gestionnaire }) }
scope :followed_by, -> (instructeur) { joins(:follows).where(follows: { instructeur: instructeur }) }
scope :with_champs, -> { includes(champs: :type_de_champ) }
scope :nearing_end_of_retention, -> (duration = '1 month') { joins(:procedure).where("en_instruction_at + (duree_conservation_dossiers_dans_ds * interval '1 month') - now() < interval ?", duration) }
scope :since, -> (since) { where('dossiers.en_construction_at >= ?', since) }
@ -273,14 +273,14 @@ class Dossier < ApplicationRecord
parts.join
end
def avis_for(gestionnaire)
if gestionnaire.dossiers.include?(self)
def avis_for(instructeur)
if instructeur.dossiers.include?(self)
avis.order(created_at: :asc)
else
avis
.where(confidentiel: false)
.or(avis.where(claimant: gestionnaire))
.or(avis.where(gestionnaire: gestionnaire))
.or(avis.where(claimant: instructeur))
.or(avis.where(instructeur: instructeur))
.order(created_at: :asc)
end
end
@ -335,7 +335,7 @@ class Dossier < ApplicationRecord
update(hidden_at: deleted_dossier.deleted_at)
if en_construction?
administration_emails = followers_gestionnaires.present? ? followers_gestionnaires.pluck(:email) : procedure.administrateurs.pluck(:email)
administration_emails = followers_instructeurs.present? ? followers_instructeurs.pluck(:email) : procedure.administrateurs.pluck(:email)
administration_emails.each do |email|
DossierMailer.notify_deletion_to_administration(deleted_dossier, email).deliver_later
end
@ -345,34 +345,34 @@ class Dossier < ApplicationRecord
log_dossier_operation(author, :supprimer, self)
end
def after_passer_en_instruction(gestionnaire)
gestionnaire.follow(self)
def after_passer_en_instruction(instructeur)
instructeur.follow(self)
log_dossier_operation(gestionnaire, :passer_en_instruction)
log_dossier_operation(instructeur, :passer_en_instruction)
end
def after_passer_automatiquement_en_instruction
log_automatic_dossier_operation(:passer_en_instruction)
end
def after_repasser_en_construction(gestionnaire)
def after_repasser_en_construction(instructeur)
self.en_instruction_at = nil
save!
log_dossier_operation(gestionnaire, :repasser_en_construction)
log_dossier_operation(instructeur, :repasser_en_construction)
end
def after_repasser_en_instruction(gestionnaire)
def after_repasser_en_instruction(instructeur)
self.processed_at = nil
self.motivation = nil
attestation&.destroy
save!
DossierMailer.notify_revert_to_instruction(self).deliver_later
log_dossier_operation(gestionnaire, :repasser_en_instruction)
log_dossier_operation(instructeur, :repasser_en_instruction)
end
def after_accepter(gestionnaire, motivation, justificatif = nil)
def after_accepter(instructeur, motivation, justificatif = nil)
self.motivation = motivation
if justificatif
@ -385,7 +385,7 @@ class Dossier < ApplicationRecord
save!
NotificationMailer.send_closed_notification(self).deliver_later
log_dossier_operation(gestionnaire, :accepter, self)
log_dossier_operation(instructeur, :accepter, self)
end
def after_accepter_automatiquement
@ -400,7 +400,7 @@ class Dossier < ApplicationRecord
log_automatic_dossier_operation(:accepter, self)
end
def after_refuser(gestionnaire, motivation, justificatif = nil)
def after_refuser(instructeur, motivation, justificatif = nil)
self.motivation = motivation
if justificatif
@ -409,10 +409,10 @@ class Dossier < ApplicationRecord
save!
NotificationMailer.send_refused_notification(self).deliver_later
log_dossier_operation(gestionnaire, :refuser, self)
log_dossier_operation(instructeur, :refuser, self)
end
def after_classer_sans_suite(gestionnaire, motivation, justificatif = nil)
def after_classer_sans_suite(instructeur, motivation, justificatif = nil)
self.motivation = motivation
if justificatif
@ -421,7 +421,7 @@ class Dossier < ApplicationRecord
save!
NotificationMailer.send_without_continuation_notification(self).deliver_later
log_dossier_operation(gestionnaire, :classer_sans_suite, self)
log_dossier_operation(instructeur, :classer_sans_suite, self)
end
def check_mandatory_champs
@ -432,9 +432,9 @@ class Dossier < ApplicationRecord
end
end
def modifier_annotations!(gestionnaire)
def modifier_annotations!(instructeur)
champs_private.select(&:value_previously_changed?).each do |champ|
log_dossier_operation(gestionnaire, :modifier_annotation, champ)
log_dossier_operation(instructeur, :modifier_annotation, champ)
end
end
@ -457,7 +457,7 @@ class Dossier < ApplicationRecord
['Passé en instruction le', :en_instruction_at],
['Traité le', :processed_at],
['Motivation de la décision', :motivation],
['Instructeurs', followers_gestionnaires.map(&:email).join(' ')]
['Instructeurs', followers_instructeurs.map(&:email).join(' ')]
] + champs_for_export + annotations_for_export
end
@ -477,6 +477,10 @@ class Dossier < ApplicationRecord
!PiecesJustificativesService.liste_pieces_justificatives(self).empty? && PiecesJustificativesService.pieces_justificatives_total_size(self) < Dossier::TAILLE_MAX_ZIP
end
def update_with_france_connect(fc_information)
self.individual = Individual.create_from_france_connect(fc_information)
end
private
def log_dossier_operation(author, operation, subject = nil)

View file

@ -1,8 +1,8 @@
class Follow < ApplicationRecord
belongs_to :gestionnaire
belongs_to :instructeur
belongs_to :dossier
validates :gestionnaire_id, uniqueness: { scope: [:dossier_id, :unfollowed_at] }
validates :instructeur_id, uniqueness: { scope: [:dossier_id, :unfollowed_at] }
before_create :set_default_date

View file

@ -5,4 +5,15 @@ class Individual < ApplicationRecord
validates :gender, presence: true, allow_nil: false, on: :update
validates :nom, presence: true, allow_blank: false, allow_nil: false, on: :update
validates :prenom, presence: true, allow_blank: false, allow_nil: false, on: :update
GENDER_MALE = 'M.'
GENDER_FEMALE = 'Mme'
def self.create_from_france_connect(fc_information)
create(
nom: fc_information.family_name,
prenom: fc_information.given_name,
gender: fc_information.gender == 'female' ? GENDER_FEMALE : GENDER_MALE
)
end
end

View file

@ -1,4 +1,4 @@
class Gestionnaire < ApplicationRecord
class Instructeur < ApplicationRecord
include CredentialsSyncableConcern
include EmailSanitizableConcern
@ -12,12 +12,12 @@ class Gestionnaire < ApplicationRecord
has_many :assign_to, dependent: :destroy
has_many :procedures, through: :assign_to
has_many :assign_to_with_email_notifications, -> { with_email_notifications }, class_name: 'AssignTo', inverse_of: :gestionnaire
has_many :assign_to_with_email_notifications, -> { with_email_notifications }, class_name: 'AssignTo', inverse_of: :instructeur
has_many :procedures_with_email_notifications, through: :assign_to_with_email_notifications, source: :procedure
has_many :dossiers, -> { state_not_brouillon }, through: :procedures
has_many :follows, -> { active }, inverse_of: :gestionnaire
has_many :previous_follows, -> { inactive }, class_name: 'Follow', inverse_of: :gestionnaire
has_many :follows, -> { active }, inverse_of: :instructeur
has_many :previous_follows, -> { inactive }, class_name: 'Follow', inverse_of: :instructeur
has_many :followed_dossiers, through: :follows, source: :dossier
has_many :previously_followed_dossiers, -> { distinct }, through: :previous_follows, source: :dossier
has_many :avis
@ -37,7 +37,7 @@ class Gestionnaire < ApplicationRecord
# Database uniqueness constraint
rescue ActiveRecord::RecordInvalid => e
# ActiveRecord validation
raise unless e.record.errors.details.dig(:gestionnaire_id, 0, :error) == :taken
raise unless e.record.errors.details.dig(:instructeur_id, 0, :error) == :taken
end
end
@ -90,7 +90,7 @@ class Gestionnaire < ApplicationRecord
def notifications_for_dossier(dossier)
follow = Follow
.includes(dossier: [:champs, :avis, :commentaires])
.find_by(gestionnaire: self, dossier: dossier)
.find_by(instructeur: self, dossier: dossier)
if follow.present?
demande = follow.dossier.champs.updated_since?(follow.demande_seen_at).any?
@ -175,13 +175,13 @@ class Gestionnaire < ApplicationRecord
def mark_tab_as_seen(dossier, tab)
attributes = {}
attributes["#{tab}_seen_at"] = Time.zone.now
Follow.where(gestionnaire: self, dossier: dossier).update_all(attributes)
Follow.where(instructeur: self, dossier: dossier).update_all(attributes)
end
def invite!
reset_password_token = set_reset_password_token
GestionnaireMailer.invite_gestionnaire(self, reset_password_token).deliver_later
InstructeurMailer.invite_instructeur(self, reset_password_token).deliver_later
end
def feature_enabled?(feature)

View file

@ -17,7 +17,7 @@ class Procedure < ApplicationRecord
has_many :assign_to, dependent: :destroy
has_many :administrateurs_procedures
has_many :administrateurs, through: :administrateurs_procedures, after_remove: -> (procedure, _admin) { procedure.validate! }
has_many :gestionnaires, through: :assign_to
has_many :instructeurs, through: :assign_to
has_one :initiated_mail, class_name: "Mails::InitiatedMail", dependent: :destroy
has_one :received_mail, class_name: "Mails::ReceivedMail", dependent: :destroy
@ -243,7 +243,7 @@ class Procedure < ApplicationRecord
procedure.service = self.service.clone_and_assign_to_administrateur(admin)
end
admin.gestionnaire.assign_to_procedure(procedure)
admin.instructeur.assign_to_procedure(procedure)
procedure
end
@ -402,7 +402,7 @@ class Procedure < ApplicationRecord
result << :service
end
if gestionnaires.empty?
if instructeurs.empty?
result << :instructeurs
end

View file

@ -19,7 +19,7 @@ class ProcedurePresentation < ApplicationRecord
field_hash('En construction le', 'self', 'en_construction_at'),
field_hash('Mis à jour le', 'self', 'updated_at'),
field_hash('Demandeur', 'user', 'email'),
field_hash('Email instructeur', 'followers_gestionnaires', 'email')
field_hash('Email instructeur', 'followers_instructeurs', 'email')
]
if procedure.for_individual
@ -73,13 +73,13 @@ class ProcedurePresentation < ApplicationRecord
displayed_fields.map { |field| get_value(dossier, field['table'], field['column']) }
end
def sorted_ids(dossiers, gestionnaire)
def sorted_ids(dossiers, instructeur)
dossiers.each { |dossier| assert_matching_procedure(dossier) }
table, column, order = sort.values_at('table', 'column', 'order')
case table
when 'notifications'
dossiers_id_with_notification = gestionnaire.dossiers_id_with_notifications(dossiers)
dossiers_id_with_notification = instructeur.dossiers_id_with_notifications(dossiers)
if order == 'desc'
return dossiers_id_with_notification +
(dossiers.order('dossiers.updated_at desc').ids - dossiers_id_with_notification)
@ -93,7 +93,7 @@ class ProcedurePresentation < ApplicationRecord
.where("champs.type_de_champ_id = #{column.to_i}")
.order("champs.value #{order}")
.pluck(:id)
when 'self', 'user', 'individual', 'etablissement', 'followers_gestionnaires'
when 'self', 'user', 'individual', 'etablissement', 'followers_instructeurs'
return (table == 'self' ? dossiers : dossiers.includes(table))
.order("#{self.class.sanitized_column(table, column)} #{order}")
.pluck(:id)
@ -129,7 +129,7 @@ class ProcedurePresentation < ApplicationRecord
.includes(table)
.filter_ilike(table, column, values)
end
when 'user', 'individual', 'followers_gestionnaires'
when 'user', 'individual', 'followers_instructeurs'
dossiers
.includes(table)
.filter_ilike(table, column, values)
@ -202,7 +202,7 @@ class ProcedurePresentation < ApplicationRecord
dossier.send(column)&.strftime('%d/%m/%Y')
when 'user', 'individual', 'etablissement'
dossier.send(table)&.send(column)
when 'followers_gestionnaires'
when 'followers_instructeurs'
dossier.send(table)&.map { |g| g.send(column) }&.join(', ')
when 'type_de_champ'
dossier.champs.find { |c| c.type_de_champ_id == column.to_i }.value

View file

@ -2,7 +2,7 @@ class TrustedDeviceToken < ApplicationRecord
LOGIN_TOKEN_VALIDITY = 1.week
LOGIN_TOKEN_YOUTH = 15.minutes
belongs_to :gestionnaire
belongs_to :instructeur
has_secure_token
def token_valid?

View file

@ -35,11 +35,11 @@ class ApplicationPolicy
end
class Scope
attr_reader :user, :gestionnaire, :administrateur, :scope
attr_reader :user, :instructeur, :administrateur, :scope
def initialize(account, scope)
@user = account[:user]
@gestionnaire = account[:gestionnaire]
@instructeur = account[:instructeur]
@administrateur = account[:administrateur]
@scope = scope
end

View file

@ -94,7 +94,7 @@ class DossierSerializer < ActiveModel::Serializer
end
def instructeurs
object.followers_gestionnaires.pluck(:email)
object.followers_instructeurs.pluck(:email)
end
def created_at

View file

@ -5,7 +5,7 @@ class OperationAuthorSerializer < ActiveModel::Serializer
case object
when User
"Usager##{object.id}"
when Gestionnaire
when Instructeur
"Instructeur##{object.id}"
when Administrateur
"Administrateur##{object.id}"

View file

@ -120,7 +120,7 @@ class AdministrateurUsageStatisticsService
end
def nb_instructeurs_by_administrateur_id
@nb_instructeurs_by_administrateur_id ||= with_default(0, Administrateur.joins(:gestionnaires).group(:administrateur_id).count)
@nb_instructeurs_by_administrateur_id ||= with_default(0, Administrateur.joins(:instructeurs).group(:administrateur_id).count)
end
def nb_dossiers_by_administrateur_id_and_procedure_id_and_synthetic_state

View file

@ -4,8 +4,8 @@ class CommentaireService
case sender
when User
params[:user] = sender
when Gestionnaire
params[:gestionnaire] = sender
when Instructeur
params[:instructeur] = sender
end
build_with_email(sender.email, dossier, params)

View file

@ -1,22 +1,22 @@
class DossierSearchService
def self.matching_dossiers_for_gestionnaire(search_terms, gestionnaire)
dossier_by_exact_id_for_gestionnaire(search_terms, gestionnaire)
.presence || dossier_by_full_text_for_gestionnaire(search_terms, gestionnaire)
def self.matching_dossiers_for_instructeur(search_terms, instructeur)
dossier_by_exact_id_for_instructeur(search_terms, instructeur)
.presence || dossier_by_full_text_for_instructeur(search_terms, instructeur)
end
private
def self.dossier_by_exact_id_for_gestionnaire(search_terms, gestionnaire)
def self.dossier_by_exact_id_for_instructeur(search_terms, instructeur)
id = search_terms.to_i
if id != 0 && id_compatible?(id) # Sometimes gestionnaire is searching dossiers with a big number (ex: SIRET), ActiveRecord can't deal with them and throws ActiveModel::RangeError. id_compatible? prevents this.
dossiers_by_id(id, gestionnaire)
if id != 0 && id_compatible?(id) # Sometimes instructeur is searching dossiers with a big number (ex: SIRET), ActiveRecord can't deal with them and throws ActiveModel::RangeError. id_compatible? prevents this.
dossiers_by_id(id, instructeur)
else
Dossier.none
end
end
def self.dossiers_by_id(id, gestionnaire)
(gestionnaire.dossiers.where(id: id) + gestionnaire.dossiers_from_avis.where(id: id)).uniq
def self.dossiers_by_id(id, instructeur)
(instructeur.dossiers.where(id: id) + instructeur.dossiers_from_avis.where(id: id)).uniq
end
def self.id_compatible?(number)
@ -26,11 +26,11 @@ class DossierSearchService
false
end
def self.dossier_by_full_text_for_gestionnaire(search_terms, gestionnaire)
def self.dossier_by_full_text_for_instructeur(search_terms, instructeur)
ts_vector = "to_tsvector('french', search_terms || private_search_terms)"
ts_query = "to_tsquery('french', #{Dossier.connection.quote(to_tsquery(search_terms))})"
gestionnaire
instructeur
.dossiers
.state_not_brouillon
.where("#{ts_vector} @@ #{ts_query}")

View file

@ -1,19 +1,19 @@
class NotificationService
class << self
def send_gestionnaire_email_notification
Gestionnaire
def send_instructeur_email_notification
Instructeur
.includes(assign_to: { procedure: :dossiers })
.where(assign_tos: { email_notifications_enabled: true })
.find_in_batches { |gestionnaires| send_batch_of_gestionnaires_email_notification(gestionnaires) }
.find_in_batches { |instructeurs| send_batch_of_instructeurs_email_notification(instructeurs) }
end
private
def send_batch_of_gestionnaires_email_notification(gestionnaires)
gestionnaires
.map { |gestionnaire| [gestionnaire, gestionnaire.email_notification_data] }
.reject { |(_gestionnaire, data)| data.empty? }
.each { |(gestionnaire, data)| GestionnaireMailer.send_notifications(gestionnaire, data).deliver_later }
def send_batch_of_instructeurs_email_notification(instructeurs)
instructeurs
.map { |instructeur| [instructeur, instructeur.email_notification_data] }
.reject { |(_instructeur, data)| data.empty? }
.each { |(instructeur, data)| InstructeurMailer.send_notifications(instructeur, data).deliver_later }
end
end
end

View file

@ -167,7 +167,7 @@ class ProcedureExportService
when :individual_gender
dossier.individual&.gender
when :emails_instructeurs
dossier.followers_gestionnaires.map(&:email).join(' ')
dossier.followers_instructeurs.map(&:email).join(' ')
else
dossier.read_attribute(key)
end

View file

@ -4,8 +4,8 @@ class SwitchDeviseProfileService
end
def multiple_devise_profile_connect?
user_signed_in? && gestionnaire_signed_in? ||
gestionnaire_signed_in? && administrateur_signed_in? ||
user_signed_in? && instructeur_signed_in? ||
instructeur_signed_in? && administrateur_signed_in? ||
user_signed_in? && administrateur_signed_in?
end
@ -15,8 +15,8 @@ class SwitchDeviseProfileService
@warden.authenticate(:scope => :user).present?
end
def gestionnaire_signed_in?
@warden.authenticate(:scope => :gestionnaire).present?
def instructeur_signed_in?
@warden.authenticate(:scope => :instructeur).present?
end
def administrateur_signed_in?

View file

@ -14,9 +14,9 @@ class SyncCredentialsService
end
end
if @klass != Gestionnaire
gestionnaire = Gestionnaire.find_by(email: @email_before_last_save)
if gestionnaire && !gestionnaire.update_columns(email: @email, encrypted_password: @encrypted_password)
if @klass != Instructeur
instructeur = Instructeur.find_by(email: @email_before_last_save)
if instructeur && !instructeur.update_columns(email: @email, encrypted_password: @encrypted_password)
return false
end
end

View file

@ -0,0 +1,23 @@
class ZxcvbnService
def initialize(password)
@password = password
end
def complexity
wxcvbn = compute_zxcvbn
score = wxcvbn.score
length = @password.blank? ? 0 : @password.length
vulnerabilities = wxcvbn.match_sequence.map { |m| m.matched_word.nil? ? m.token : m.matched_word }.select { |s| s.length > 2 }.join(', ')
[score, vulnerabilities, length]
end
def score
compute_zxcvbn.score
end
private
def compute_zxcvbn
Zxcvbn.test(@password, [], ZXCVBN_DICTIONNARIES)
end
end

View file

@ -1,7 +1,7 @@
.row{ style: 'height: 34px;' }
- if smart_listing.present?
%table.table#liste-gestionnaire
%table.table#liste-instructeur
%thead
%th Enlever
%th#email{ style: 'text-align: right;' } Email
@ -9,7 +9,7 @@
- @instructeurs_assign.each do |instructeur|
%tr
%td.col-md-1.col-lg-1.col-sm-1.col-xs-1.col-sm-1.col-xs-1.center
= link_to "#{admin_procedure_instructeurs_path(procedure_id: @procedure.id, instructeur_id: instructeur.id, to: Admin::InstructeursController::NOT_ASSIGN)}", class: "btn btn-primary", 'data-method' => 'put' do
= link_to "#{admin_procedure_assigns_path(procedure_id: @procedure.id, instructeur_id: instructeur.id, to: Admin::AssignsController::NOT_ASSIGN)}", class: "btn btn-primary", 'data-method' => 'put' do
.fa.fa-arrow-left
%td{ style: 'padding-top: 11px; font-size: 15px; text-align: right;' }= instructeur.email

View file

@ -7,7 +7,7 @@
- if smart_listing.present?
%table.table#liste-gestionnaire
%table.table#liste-instructeur
%thead
%th#email Email
%th Ajouter
@ -16,7 +16,7 @@
%tr
%td.col-xs-11{ style: 'padding-top: 11px; font-size: 15px;' }= instructeur.email
%td.center
= link_to "#{admin_procedure_instructeurs_path(procedure_id: @procedure.id, instructeur_id: instructeur.id, to: Admin::InstructeursController::ASSIGN)}", class: "btn btn-success gestionnaire-affectation", 'data-method' => 'put' do
= link_to "#{admin_procedure_assigns_path(procedure_id: @procedure.id, instructeur_id: instructeur.id, to: Admin::AssignsController::ASSIGN)}", class: "btn btn-success instructeur-affectation", 'data-method' => 'put' do
.fa.fa-arrow-right

View file

@ -9,15 +9,15 @@
%h3
= t('dynamics.admin.procedure.onglet_instructeurs.add.title')
#procedure_new.section.section-label
= form_for @gestionnaire, url: { controller: 'admin/gestionnaires', action: :create } do |f|
= form_for @instructeur, url: { controller: 'admin/instructeurs', action: :create } do |f|
.row
.col-xs-5
= hidden_field_tag :procedure_id, params[:procedure_id]
= render partial: 'admin/gestionnaires/informations', locals: { f: f }
= render partial: 'admin/instructeurs/informations', locals: { f: f }
.col-xs-2
%br
%br
= f.submit 'Valider', class: 'btn btn-info', style: 'float: left;', id: 'add-gestionnaire-email'
= f.submit 'Valider', class: 'btn btn-info', style: 'float: left;', id: 'add-instructeur-email'
.col-xs-6
%h3.text-success Affectés
= smart_listing_render :instructeurs_assign

View file

@ -1 +0,0 @@
<%= smart_listing_update :gestionnaires %>

View file

@ -1,17 +1,17 @@
- if smart_listing.present?
%table.table#liste-gestionnaire
%table.table#liste-instructeur
%thead
%th#libelle= smart_listing.sortable 'Email', 'email'
%th
- @gestionnaires.each do |gestionnaire|
- @instructeurs.each do |instructeur|
%tr
%td{ style: 'padding-top: 11px; font-size: 15px;' }= gestionnaire.email
%td{ style: 'padding-top: 11px; font-size: 15px;' }= instructeur.email
%td{ style: 'text-align: right;' }
.delete.btn.btn-sm.fa.fa-trash
.confirm
= link_to 'Valider', admin_gestionnaire_path(id: gestionnaire.id), { method: :delete, class: 'btn btn-sm btn-success' }
= link_to 'Valider', admin_instructeur_path(id: instructeur.id), { method: :delete, class: 'btn btn-sm btn-success' }
.cancel.btn.btn-sm.btn-danger.fa.fa-minus{ style: 'top: 0;' }
= smart_listing.paginate

View file

@ -12,13 +12,13 @@
.row
.col-xs-4
= smart_listing_render :gestionnaires
= smart_listing_render :instructeurs
.col-xs-1
&nbsp;
.col-xs-6
%h3 Ajouter un instructeur
#procedure_new.section.section-label
= form_for @gestionnaire, url: { controller: 'admin/gestionnaires', action: :create } do |f|
= form_for @instructeur, url: { controller: 'admin/instructeurs', action: :create } do |f|
.row
.col-xs-5
= render partial: 'informations', locals: { f: f }

View file

@ -0,0 +1 @@
<%= smart_listing_update :instructeurs %>

View file

@ -5,9 +5,9 @@
= render partial: '/admin/procedures/modal_transfer'
- if @procedure.brouillon?
- if @procedure.gestionnaires.empty? || @procedure.service.nil?
- if @procedure.instructeurs.empty? || @procedure.service.nil?
- missing_elements = []
- if @procedure.gestionnaires.empty?
- if @procedure.instructeurs.empty?
- missing_elements << 'des instructeurs'
- if @procedure.service.nil?
- missing_elements << 'un service'
@ -59,7 +59,7 @@
%br
Attention, diffusez toujours le <strong>lien complet</strong> affiché ci-dessus, et non pas un lien générique vers demarches-simplifiees.fr. Ne dites pas non plus aux usagers de se rendre sur le site générique demarches-simplifiees.fr, donnez-leur toujours le lien complet.
- elsif @procedure.brouillon_avec_lien?
- if @procedure.gestionnaires.present? && @procedure.service.present?
- if @procedure.instructeurs.present? && @procedure.service.present?
%p
Cette démarche est actuellement <strong>en test</strong>,
pour y accéder vous pouvez utiliser le lien :
@ -106,9 +106,9 @@
- else
.alert.alert-info
Pour pouvoir tester cette démarche, vous devez dabord lui affecter
- if @procedure.gestionnaires.empty?
= link_to("des instructeurs", admin_procedure_instructeurs_path(@procedure))
- if @procedure.gestionnaires.empty? && @procedure.service.nil?
- if @procedure.instructeurs.empty?
= link_to("des instructeurs", admin_procedure_assigns_path(@procedure))
- if @procedure.instructeurs.empty? && @procedure.service.nil?
et
- if @procedure.service.nil?
= link_to("un service", services_path(procedure_id: @procedure))
@ -122,7 +122,7 @@
- if @procedure.missing_steps.include?(:instructeurs)
%p.alert.alert-danger
Vous devez affecter des instructeurs avant de pouvoir publier votre démarche.
= link_to 'Cliquez ici.', admin_procedure_instructeurs_path(@procedure)
= link_to 'Cliquez ici.', admin_procedure_assigns_path(@procedure)
%p.alert.alert-info
Cette démarche na pas encore de lien, et nest pas accessible par le public.

View file

@ -1,5 +0,0 @@
#strength-bar.password-strength{ class: "strength-#{score}" }
- if score < 4
Mot de passe pas assez complexe
- else
Mot de passe suffisamment complexe

View file

@ -10,20 +10,13 @@
%h1
Choix du mot de passe
= f.hidden_field :reset_password_token, value: @token
= f.label :email, "Email"
= f.text_field :email, disabled: true
= f.label :password do
Mot de passe
= f.password_field :password, placeholder: 'Mot de passe', data: { remote: true, url: admin_activate_test_password_strength_path }
= render partial: 'shared/password/edit_password', locals: { form: f, controller: 'administrateurs/passwords' }
#strength-bar.password-strength
&nbsp;
.explication
%strong Aide :
Une courte phrase peut être un mot de passe très sécurisé.
= f.hidden_field :reset_password_token, value: params[:token]
= f.submit 'Continuer', class: 'button large primary expand', id: "submit-password", data: { disable_with: "Envoi..." }

View file

@ -1 +0,0 @@
<%= render_to_element('#strength-bar', partial: 'password_strength', outer: true, locals: { score: @score }) %>

View file

@ -0,0 +1,6 @@
- content_for(:title, 'Changement de mot de passe')
- content_for :footer do
= render partial: 'root/footer'
= render 'shared/password/edit', test_password_strength: administrateurs_password_test_strength_path

View file

@ -1,5 +1,5 @@
- content_for(:title, 'Invitation à donner votre avis')
- avis_link = @avis.gestionnaire.present? ? gestionnaire_avis_url(@avis) : sign_up_gestionnaire_avis_url(@avis.id, @avis.email)
- avis_link = @avis.instructeur.present? ? instructeur_avis_url(@avis) : sign_up_instructeur_avis_url(@avis.id, @avis.email)
- content_for(:footer) do
Merci de ne pas répondre à cet email. Donnez votre avis
@ -23,7 +23,7 @@
%p{ style: "padding: 8px; color: #333333; background-color: #EEEEEE; font-size: 14px;" }
= @avis.introduction
- if @avis.gestionnaire.present?
- if @avis.instructeur.present?
%p
= link_to "Connectez-vous pour donner votre avis", avis_link
- else

View file

@ -1,6 +1,6 @@
:ruby
url = if field.resource.class.name == 'Gestionnaire'
enable_feature_manager_gestionnaire_path(field.resource.id)
url = if field.resource.class.name == 'Instructeur'
enable_feature_manager_instructeur_path(field.resource.id)
else
enable_feature_manager_administrateur_path(field.resource.id)
end

View file

@ -1,3 +0,0 @@
= link_to "/gestionnaires/sign_out", method: :delete do
%span.fa.fa-sign-out
Se déconnecter

View file

@ -1,10 +0,0 @@
.sub-header
.container
%ul.breadcrumbs
%li= link_to('Avis', gestionnaire_avis_index_path)
%li= "#{dossier.procedure.libelle}, dossier nº #{dossier.id}"
%ul.tabs
= dynamic_tab_item('Demande', gestionnaire_avis_path(avis))
= dynamic_tab_item('Avis', instruction_gestionnaire_avis_path(avis), notification: avis.answer.blank?)
= dynamic_tab_item('Messagerie', messagerie_gestionnaire_avis_path(avis))

View file

@ -1,15 +0,0 @@
- content_for(:title, "Personnes impliquées · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
= render partial: "header", locals: { dossier: @dossier }
.personnes-impliquees.container
= render partial: 'gestionnaires/dossiers/envoyer_dossier_block', locals: { dossier: @dossier, potential_recipients: @potential_recipients }
= render partial: 'gestionnaires/dossiers/personnes_impliquees_block', locals: { emails_collection: @following_instructeurs_emails, title: "Instructeurs qui suivent actuellement le dossier", blank: "Aucun instructeur ne suit ce dossier" }
- if @previous_following_instructeurs_emails.present?
= render partial: 'gestionnaires/dossiers/personnes_impliquees_block', locals: { emails_collection: @previous_following_instructeurs_emails, title: "Instructeurs ayant précédemment suivi le dossier", blank: " " }
= render partial: 'gestionnaires/dossiers/personnes_impliquees_block', locals: { emails_collection: @avis_emails, title: "Personnes à qui un avis a été demandé", blank: "Aucun avis n'a été demandé" }
= render partial: 'gestionnaires/dossiers/personnes_impliquees_block', locals: { emails_collection: @invites_emails, title: "Personnes invitées à consulter ce dossier", blank: "Aucune personne n'a été invitée à consulter ce dossier" }

View file

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

View file

@ -10,7 +10,7 @@
%h2{ style: 'font-size: 16px; font-weight: 300; margin: 25px 0 5px;' }
#{procedure_overview.procedure.libelle}
= link_to 'voir', gestionnaire_procedure_url(procedure_overview.procedure), style: 'color: #0069CC; font-size: 14px;'
= link_to 'voir', instructeur_procedure_url(procedure_overview.procedure), style: 'color: #0069CC; font-size: 14px;'
%table{ cellpadding: '0', cellspacing: '0', style: 'width: 100%; padding-bottom: 20px;' }
%tbody
@ -30,7 +30,7 @@
- if procedure_overview.old_dossiers_en_construction.count < 6
\:
- old_dossiers_en_construction = procedure_overview.old_dossiers_en_construction.map do |old_dossier|
- link_to "nº #{old_dossier.id}", gestionnaire_dossier_url(procedure_overview.procedure, old_dossier), style: 'color: #0069CC;'
- link_to "nº #{old_dossier.id}", instructeur_dossier_url(procedure_overview.procedure, old_dossier), style: 'color: #0069CC;'
- end.join(', ')
= sanitize(old_dossiers_en_construction, attributes: %w(href style))
@ -44,7 +44,7 @@
- if procedure_overview.old_dossiers_en_instruction.count < 6
\:
- old_dossiers_en_instruction = procedure_overview.old_dossiers_en_instruction.map do |old_dossier|
- link_to "nº #{old_dossier.id}", gestionnaire_dossier_url(procedure_overview.procedure, old_dossier), style: 'color: #0069CC;'
- link_to "nº #{old_dossier.id}", instructeur_dossier_url(procedure_overview.procedure, old_dossier), style: 'color: #0069CC;'
- end.join(', ')
= sanitize(old_dossiers_en_instruction, attributes: %w(href style))

View file

@ -3,6 +3,6 @@
%p
= "#{@sender.email} vous a envoyé le dossier nº #{@dossier.id}, cliquez sur le lien ci-dessous pour y accéder :"
= link_to(gestionnaire_dossier_url(@dossier.procedure, @dossier), gestionnaire_dossier_url(@dossier.procedure, @dossier))
= link_to(instructeur_dossier_url(@dossier.procedure, @dossier), instructeur_dossier_url(@dossier.procedure, @dossier))
= render partial: "layouts/mailers/signature"

View file

@ -3,7 +3,7 @@
%p
Veuillez cliquer sur le lien suivant pour vous connecter sur le site demarches-simplifiees.fr : 
= link_to(sign_in_by_link_url(@gestionnaire_id, jeton: @login_token), sign_in_by_link_url(@gestionnaire_id, jeton: @login_token))
= link_to(sign_in_by_link_url(@instructeur_id, jeton: @login_token), sign_in_by_link_url(@instructeur_id, jeton: @login_token))
%p
Ce lien est

View file

@ -0,0 +1,3 @@
= link_to "/instructeurs/sign_out", method: :delete do
%span.fa.fa-sign-out
Se déconnecter

View file

@ -1,7 +1,7 @@
.container
= form_for @gestionnaire, url: { controller: 'gestionnaires/activate', action: :create }, html: { class: "form" } do |f|
= form_for @instructeur, url: { controller: 'instructeurs/activate', action: :create }, html: { class: "form" } do |f|
%br
%h1= @gestionnaire.email
%h1= @instructeur.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'

View file

@ -0,0 +1,10 @@
.sub-header
.container
%ul.breadcrumbs
%li= link_to('Avis', instructeur_avis_index_path)
%li= "#{dossier.procedure.libelle}, dossier nº #{dossier.id}"
%ul.tabs
= dynamic_tab_item('Demande', instructeur_avis_path(avis))
= dynamic_tab_item('Avis', instruction_instructeur_avis_path(avis), notification: avis.answer.blank?)
= dynamic_tab_item('Messagerie', messagerie_instructeur_avis_path(avis))

View file

@ -1,4 +1,4 @@
- avis_statut = (@statut == Gestionnaires::AvisController::A_DONNER_STATUS) ? 'à donner' : 'rendus'
- avis_statut = (@statut == Instructeurs::AvisController::A_DONNER_STATUS) ? 'à donner' : 'rendus'
- content_for(:title, "Avis #{avis_statut}")
.sub-header
@ -7,14 +7,14 @@
%h1.tab-title Avis
%ul.tabs
= tab_item('avis à donner',
gestionnaire_avis_index_path(statut: Gestionnaires::AvisController::A_DONNER_STATUS),
active: @statut == Gestionnaires::AvisController::A_DONNER_STATUS,
instructeur_avis_index_path(statut: Instructeurs::AvisController::A_DONNER_STATUS),
active: @statut == Instructeurs::AvisController::A_DONNER_STATUS,
badge: @avis_a_donner.count,
notification: @avis_a_donner.any?)
= tab_item("avis #{'donné'.pluralize(@avis_donnes.count)}",
gestionnaire_avis_index_path(statut: Gestionnaires::AvisController::DONNES_STATUS),
active: @statut == Gestionnaires::AvisController::DONNES_STATUS,
instructeur_avis_index_path(statut: Instructeurs::AvisController::DONNES_STATUS),
active: @statut == Instructeurs::AvisController::DONNES_STATUS,
badge: @avis_donnes.count)
.container
@ -29,11 +29,11 @@
- @avis.each do |avis|
%tr
%td.number-col
= link_to(gestionnaire_avis_path(avis), class: 'cell-link') do
= link_to(instructeur_avis_path(avis), class: 'cell-link') do
%span.icon.folder
#{avis.dossier.id}
%td= link_to(avis.dossier.user.email, gestionnaire_avis_path(avis), class: 'cell-link')
%td= link_to(avis.dossier.procedure.libelle, gestionnaire_avis_path(avis), class: 'cell-link')
%td= link_to(avis.dossier.user.email, instructeur_avis_path(avis), class: 'cell-link')
%td= link_to(avis.dossier.procedure.libelle, instructeur_avis_path(avis), class: 'cell-link')
= paginate(@avis)
- else
%h2.empty-text Aucun avis

View file

@ -11,7 +11,7 @@
%span.date Demande d'avis envoyée le #{l(@avis.created_at, format: '%d/%m/%y')}
%p.introduction= @avis.introduction
= form_for @avis, url: gestionnaire_avis_path(@avis), html: { class: 'form' } do |f|
= form_for @avis, url: instructeur_avis_path(@avis), html: { class: 'form' } do |f|
= f.text_area :answer, rows: 3, placeholder: 'Votre avis', required: true
= render partial: "shared/attachment/update", locals: { attachment: @avis.piece_justificative_file.attachment, user_can_destroy: true, form: f }
@ -28,7 +28,7 @@
= f.submit 'Envoyer votre avis', class: 'button send'
- if !@dossier.termine?
= render partial: "gestionnaires/shared/avis/form", locals: { url: avis_gestionnaire_avis_path(@avis), must_be_confidentiel: @avis.confidentiel?, avis: @new_avis }
= render partial: "instructeurs/shared/avis/form", locals: { url: avis_instructeur_avis_path(@avis), must_be_confidentiel: @avis.confidentiel?, avis: @new_avis }
- if @dossier.avis_for(current_gestionnaire).present?
= render partial: 'gestionnaires/shared/avis/list', locals: { avis: @dossier.avis_for(current_gestionnaire), avis_seen_at: nil }
- if @dossier.avis_for(current_instructeur).present?
= render partial: 'instructeurs/shared/avis/list', locals: { avis: @dossier.avis_for(current_instructeur), avis_seen_at: nil }

Some files were not shown because too many files have changed in this diff Show more