commit
a829810406
39 changed files with 255 additions and 82 deletions
|
@ -79,7 +79,7 @@ class Admin::ProceduresController < AdminController
|
||||||
end
|
end
|
||||||
|
|
||||||
def transfer
|
def transfer
|
||||||
admin = Administrateur.find_by(email: params[:email_admin].downcase)
|
admin = Administrateur.by_email(params[:email_admin].downcase)
|
||||||
|
|
||||||
if admin.nil?
|
if admin.nil?
|
||||||
render '/admin/procedures/transfer', formats: 'js', status: 404
|
render '/admin/procedures/transfer', formats: 'js', status: 404
|
||||||
|
|
|
@ -22,11 +22,7 @@ module Manager
|
||||||
def delete
|
def delete
|
||||||
administrateur = Administrateur.find(params[:id])
|
administrateur = Administrateur.find(params[:id])
|
||||||
|
|
||||||
if !administrateur.can_be_deleted?
|
administrateur.delete_and_transfer_services
|
||||||
fail "Impossible de supprimer cet administrateur car il a des dossiers ou des procédures"
|
|
||||||
end
|
|
||||||
administrateur.dossiers.each(&:delete_and_keep_track)
|
|
||||||
administrateur.destroy
|
|
||||||
|
|
||||||
logger.info("L'administrateur #{administrateur.id} est supprimé par #{current_administration.id}")
|
logger.info("L'administrateur #{administrateur.id} est supprimé par #{current_administration.id}")
|
||||||
flash[:notice] = "L'administrateur #{administrateur.id} est supprimé"
|
flash[:notice] = "L'administrateur #{administrateur.id} est supprimé"
|
||||||
|
|
|
@ -48,9 +48,9 @@ module Manager
|
||||||
end
|
end
|
||||||
|
|
||||||
def pending_demandes
|
def pending_demandes
|
||||||
already_approved_emails = Administrateur
|
already_approved_emails = Administrateur.eager(:user)
|
||||||
.where(email: demandes.map { |d| d[:email] })
|
.where(users: { email: demandes.map { |d| d[:email] } })
|
||||||
.pluck(:email)
|
.map(&:email)
|
||||||
|
|
||||||
demandes.reject { |demande| already_approved_emails.include?(demande[:email]) }
|
demandes.reject { |demande| already_approved_emails.include?(demande[:email]) }
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,5 +6,19 @@ module Manager
|
||||||
flash[:notice] = "Instructeur réinvité."
|
flash[:notice] = "Instructeur réinvité."
|
||||||
redirect_to manager_instructeur_path(instructeur)
|
redirect_to manager_instructeur_path(instructeur)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete
|
||||||
|
instructeur = Instructeur.find(params[:id])
|
||||||
|
|
||||||
|
if !instructeur.can_be_deleted?
|
||||||
|
fail "Impossible de supprimer cet instructeur car il est administrateur ou il est le seul instructeur sur une démarche"
|
||||||
|
end
|
||||||
|
instructeur.destroy!
|
||||||
|
|
||||||
|
logger.info("L'instructeur #{instructeur.id} est supprimé par #{current_administration.id}")
|
||||||
|
flash[:notice] = "L'instructeur #{instructeur.id} est supprimé"
|
||||||
|
|
||||||
|
redirect_to manager_instructeurs_path
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,7 +29,7 @@ module Manager
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_administrateur
|
def add_administrateur
|
||||||
administrateur = Administrateur.find_by(email: params[:email])
|
administrateur = Administrateur.by_email(params[:email])
|
||||||
if administrateur
|
if administrateur
|
||||||
procedure.administrateurs << administrateur
|
procedure.administrateurs << administrateur
|
||||||
flash[:notice] = "L'administrateur \"#{params[:email]}\" est ajouté à la démarche."
|
flash[:notice] = "L'administrateur \"#{params[:email]}\" est ajouté à la démarche."
|
||||||
|
|
|
@ -37,7 +37,7 @@ module Manager
|
||||||
def delete
|
def delete
|
||||||
user = User.find(params[:id])
|
user = User.find(params[:id])
|
||||||
if !user.can_be_deleted?
|
if !user.can_be_deleted?
|
||||||
fail "Impossible de supprimer cet utilisateur car il a des dossiers en instruction"
|
fail "Impossible de supprimer cet utilisateur. Il a des dossiers en instruction ou il est administrateur."
|
||||||
end
|
end
|
||||||
user.delete_and_keep_track_dossiers(current_administration)
|
user.delete_and_keep_track_dossiers(current_administration)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ module NewAdministrateur
|
||||||
email = params.require(:administrateur)[:email]&.strip&.downcase
|
email = params.require(:administrateur)[:email]&.strip&.downcase
|
||||||
|
|
||||||
# Find the admin
|
# Find the admin
|
||||||
administrateur = Administrateur.find_by(email: email)
|
administrateur = Administrateur.by_email(email)
|
||||||
if administrateur.nil?
|
if administrateur.nil?
|
||||||
flash.alert = "L’administrateur « #{email} » n’existe pas. Invitez-le à demander un compte administrateur à l’addresse <a href=#{new_demande_url}>#{new_demande_url}</a>."
|
flash.alert = "L’administrateur « #{email} » n’existe pas. Invitez-le à demander un compte administrateur à l’addresse <a href=#{new_demande_url}>#{new_demande_url}</a>."
|
||||||
return
|
return
|
||||||
|
|
|
@ -11,7 +11,7 @@ class Users::PasswordsController < Devise::PasswordsController
|
||||||
def create
|
def create
|
||||||
# Check the credentials associated to the mail to generate a correct reset link
|
# Check the credentials associated to the mail to generate a correct reset link
|
||||||
email = params[:user][:email]
|
email = params[:user][:email]
|
||||||
if Administrateur.find_by(email: email)
|
if Administrateur.by_email(email)
|
||||||
@devise_mapping = Devise.mappings[:administrateur]
|
@devise_mapping = Devise.mappings[:administrateur]
|
||||||
params[:administrateur] = params[:user]
|
params[:administrateur] = params[:user]
|
||||||
# uncomment to check password complexity for Instructeur
|
# uncomment to check password complexity for Instructeur
|
||||||
|
@ -56,7 +56,7 @@ class Users::PasswordsController < Devise::PasswordsController
|
||||||
|
|
||||||
def try_to_authenticate_administrateur
|
def try_to_authenticate_administrateur
|
||||||
if user_signed_in?
|
if user_signed_in?
|
||||||
administrateur = Administrateur.find_by(email: current_user.email)
|
administrateur = Administrateur.by_email(current_user.email)
|
||||||
|
|
||||||
if administrateur
|
if administrateur
|
||||||
sign_in(administrateur.user)
|
sign_in(administrateur.user)
|
||||||
|
|
|
@ -52,6 +52,7 @@ const baseOptions = {
|
||||||
|
|
||||||
const baseAjaxOptions = {
|
const baseAjaxOptions = {
|
||||||
delay: 250,
|
delay: 250,
|
||||||
|
timeout: 10 * 1000, // 10 sec
|
||||||
cache: true,
|
cache: true,
|
||||||
data({ term: nom }) {
|
data({ term: nom }) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -86,5 +86,5 @@ class RemotePoller {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const attachementPoller = new RemotePoller({ interval: 2000, maxChecks: 5 });
|
const attachementPoller = new RemotePoller({ interval: 3000, maxChecks: 5 });
|
||||||
const exportPoller = new RemotePoller({ interval: 4000, maxChecks: 10 });
|
const exportPoller = new RemotePoller({ interval: 6000, maxChecks: 10 });
|
||||||
|
|
|
@ -3,11 +3,6 @@ class ApplicationMailer < ActionMailer::Base
|
||||||
default from: "demarches-simplifiees.fr <#{CONTACT_EMAIL}>"
|
default from: "demarches-simplifiees.fr <#{CONTACT_EMAIL}>"
|
||||||
layout 'mailer'
|
layout 'mailer'
|
||||||
|
|
||||||
# Don’t retry to send a message if the server rejects the recipient address
|
|
||||||
rescue_from Net::SMTPSyntaxError do |_error|
|
|
||||||
message.perform_deliveries = false
|
|
||||||
end
|
|
||||||
|
|
||||||
# Attach the procedure logo to the email (if any).
|
# Attach the procedure logo to the email (if any).
|
||||||
# Returns the attachment url.
|
# Returns the attachment url.
|
||||||
def attach_logo(procedure)
|
def attach_logo(procedure)
|
||||||
|
|
|
@ -4,11 +4,6 @@ class DeviseUserMailer < Devise::Mailer
|
||||||
include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
|
include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url`
|
||||||
layout 'mailers/layout'
|
layout 'mailers/layout'
|
||||||
|
|
||||||
# Don’t retry to send a message if the server rejects the recipient address
|
|
||||||
rescue_from Net::SMTPSyntaxError do |_error|
|
|
||||||
message.perform_deliveries = false
|
|
||||||
end
|
|
||||||
|
|
||||||
def template_paths
|
def template_paths
|
||||||
['devise_mailer']
|
['devise_mailer']
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,21 +1,27 @@
|
||||||
class Administrateur < ApplicationRecord
|
class Administrateur < ApplicationRecord
|
||||||
self.ignored_columns = ['features', 'encrypted_password', 'reset_password_token', 'reset_password_sent_at', 'remember_created_at', 'sign_in_count', 'current_sign_in_at', 'last_sign_in_at', 'current_sign_in_ip', 'last_sign_in_ip', 'failed_attempts', 'unlock_token', 'locked_at']
|
self.ignored_columns = ['email', 'features', 'encrypted_password', 'reset_password_token', 'reset_password_sent_at', 'remember_created_at', 'sign_in_count', 'current_sign_in_at', 'last_sign_in_at', 'current_sign_in_ip', 'last_sign_in_ip', 'failed_attempts', 'unlock_token', 'locked_at']
|
||||||
include EmailSanitizableConcern
|
|
||||||
include ActiveRecord::SecureToken
|
include ActiveRecord::SecureToken
|
||||||
|
|
||||||
has_and_belongs_to_many :instructeurs
|
has_and_belongs_to_many :instructeurs
|
||||||
has_many :administrateurs_procedures
|
has_many :administrateurs_procedures
|
||||||
has_many :procedures, through: :administrateurs_procedures
|
has_many :procedures, through: :administrateurs_procedures
|
||||||
has_many :services
|
has_many :services
|
||||||
has_many :dossiers, -> { state_not_brouillon }, through: :procedures
|
|
||||||
|
|
||||||
has_one :user, dependent: :nullify
|
has_one :user, dependent: :nullify
|
||||||
|
|
||||||
before_validation -> { sanitize_email(:email) }
|
default_scope { eager_load(:user) }
|
||||||
|
|
||||||
scope :inactive, -> { joins(:user).where(users: { last_sign_in_at: nil }) }
|
scope :inactive, -> { joins(:user).where(users: { last_sign_in_at: nil }) }
|
||||||
scope :with_publiees_ou_closes, -> { joins(:procedures).where(procedures: { aasm_state: [:publiee, :close, :depubliee] }) }
|
scope :with_publiees_ou_closes, -> { joins(:procedures).where(procedures: { aasm_state: [:publiee, :close, :depubliee] }) }
|
||||||
|
|
||||||
|
def self.by_email(email)
|
||||||
|
Administrateur.find_by(users: { email: email })
|
||||||
|
end
|
||||||
|
|
||||||
|
def email
|
||||||
|
user.email
|
||||||
|
end
|
||||||
|
|
||||||
# validate :password_complexity, if: Proc.new { |a| Devise.password_length.include?(a.password.try(:size)) }
|
# validate :password_complexity, if: Proc.new { |a| Devise.password_length.include?(a.password.try(:size)) }
|
||||||
|
|
||||||
def password_complexity
|
def password_complexity
|
||||||
|
@ -68,6 +74,18 @@ class Administrateur < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_be_deleted?
|
def can_be_deleted?
|
||||||
dossiers.state_instruction_commencee.none? && procedures.all? { |p| p.administrateurs.count > 1 }
|
procedures.all? { |p| p.administrateurs.count > 1 }
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_and_transfer_services
|
||||||
|
if !can_be_deleted?
|
||||||
|
fail "Impossible de supprimer cet administrateur car il a des démarches où il est le seul administrateur"
|
||||||
|
end
|
||||||
|
|
||||||
|
procedures.each do |procedure|
|
||||||
|
next_administrateur = procedure.administrateurs.where.not(id: self.id).first
|
||||||
|
procedure.service.update(administrateur: next_administrateur)
|
||||||
|
end
|
||||||
|
destroy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -381,7 +381,7 @@ class Dossier < ApplicationRecord
|
||||||
update(hidden_at: deleted_dossier.deleted_at)
|
update(hidden_at: deleted_dossier.deleted_at)
|
||||||
|
|
||||||
if en_construction?
|
if en_construction?
|
||||||
administration_emails = followers_instructeurs.present? ? followers_instructeurs.map(&:email) : procedure.administrateurs.pluck(:email)
|
administration_emails = followers_instructeurs.present? ? followers_instructeurs.map(&:email) : procedure.administrateurs.map(&:email)
|
||||||
administration_emails.each do |email|
|
administration_emails.each do |email|
|
||||||
DossierMailer.notify_deletion_to_administration(deleted_dossier, email).deliver_later
|
DossierMailer.notify_deletion_to_administration(deleted_dossier, email).deliver_later
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,9 +17,9 @@ class Instructeur < ApplicationRecord
|
||||||
has_many :previously_followed_dossiers, -> { distinct }, through: :previous_follows, source: :dossier
|
has_many :previously_followed_dossiers, -> { distinct }, through: :previous_follows, source: :dossier
|
||||||
has_many :avis
|
has_many :avis
|
||||||
has_many :dossiers_from_avis, through: :avis, source: :dossier
|
has_many :dossiers_from_avis, through: :avis, source: :dossier
|
||||||
has_many :trusted_device_tokens
|
has_many :trusted_device_tokens, dependent: :destroy
|
||||||
|
|
||||||
has_one :user
|
has_one :user, dependent: :nullify
|
||||||
|
|
||||||
default_scope { eager_load(:user) }
|
default_scope { eager_load(:user) }
|
||||||
|
|
||||||
|
@ -176,6 +176,10 @@ class Instructeur < ApplicationRecord
|
||||||
trusted_device_token&.token_young?
|
trusted_device_token&.token_young?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def can_be_deleted?
|
||||||
|
user.administrateur.nil? && procedures.all? { |p| p.defaut_groupe_instructeur.instructeurs.count > 1 }
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def annotations_hash(demande, annotations_privees, avis, messagerie)
|
def annotations_hash(demande, annotations_privees, avis, messagerie)
|
||||||
|
|
|
@ -82,7 +82,7 @@ class User < ApplicationRecord
|
||||||
user = User.create_or_promote_to_instructeur(email, password)
|
user = User.create_or_promote_to_instructeur(email, password)
|
||||||
|
|
||||||
if user.valid? && user.administrateur_id.nil?
|
if user.valid? && user.administrateur_id.nil?
|
||||||
user.create_administrateur!(email: email)
|
user.create_administrateur!
|
||||||
end
|
end
|
||||||
|
|
||||||
user
|
user
|
||||||
|
@ -97,7 +97,7 @@ class User < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_be_deleted?
|
def can_be_deleted?
|
||||||
dossiers.state_instruction_commencee.empty?
|
administrateur.nil? && instructeur.nil? && dossiers.state_instruction_commencee.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_and_keep_track_dossiers(administration)
|
def delete_and_keep_track_dossiers(administration)
|
||||||
|
@ -105,12 +105,11 @@ class User < ApplicationRecord
|
||||||
raise "Cannot delete this user because instruction has started for some dossiers"
|
raise "Cannot delete this user because instruction has started for some dossiers"
|
||||||
end
|
end
|
||||||
|
|
||||||
if can_be_deleted?
|
dossiers.each do |dossier|
|
||||||
dossiers.each do |dossier|
|
dossier.delete_and_keep_track(administration)
|
||||||
dossier.delete_and_keep_track(administration)
|
|
||||||
end
|
|
||||||
destroy
|
|
||||||
end
|
end
|
||||||
|
dossiers.with_hidden.destroy_all
|
||||||
|
destroy!
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -119,7 +119,7 @@ class AdministrateurUsageStatisticsService
|
||||||
end
|
end
|
||||||
|
|
||||||
def nb_instructeurs_by_administrateur_id
|
def nb_instructeurs_by_administrateur_id
|
||||||
@nb_instructeurs_by_administrateur_id ||= with_default(0, Administrateur.joins(:instructeurs).group(:administrateur_id).count)
|
@nb_instructeurs_by_administrateur_id ||= with_default(0, Administrateur.joins(:instructeurs).group('administrateurs.id').count)
|
||||||
end
|
end
|
||||||
|
|
||||||
def nb_dossiers_by_administrateur_id_and_procedure_id_and_synthetic_state
|
def nb_dossiers_by_administrateur_id_and_procedure_id_and_synthetic_state
|
||||||
|
|
|
@ -56,4 +56,4 @@
|
||||||
%td.flex
|
%td.flex
|
||||||
= link_to('Consulter', apercu_procedure_path(id: procedure.id), target: "_blank", rel: "noopener", class: 'button small')
|
= link_to('Consulter', apercu_procedure_path(id: procedure.id), target: "_blank", rel: "noopener", class: 'button small')
|
||||||
= link_to('Cloner', admin_procedure_clone_path(procedure.id, from_new_from_existing: true), 'data-method' => :put, class: 'button small primary')
|
= link_to('Cloner', admin_procedure_clone_path(procedure.id, from_new_from_existing: true), 'data-method' => :put, class: 'button small primary')
|
||||||
= link_to('Contacter', "mailto:#{procedure.administrateurs.pluck(:email) * ","}", class: 'button small')
|
= link_to('Contacter', "mailto:#{procedure.administrateurs.map(&:email) * ","}", class: 'button small')
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
- if @reset_password_token.present?
|
- if @reset_password_token.present?
|
||||||
%p
|
%p
|
||||||
%b
|
%b
|
||||||
Pour l’activer, cliquez sur le lien suivant :
|
Pour l’activer, cliquez sur le lien suivant :
|
||||||
= link_to(admin_activate_url(token: @reset_password_token), admin_activate_url(token: @reset_password_token))
|
= link_to(admin_activate_url(token: @reset_password_token), admin_activate_url(token: @reset_password_token))
|
||||||
- else
|
- else
|
||||||
%p
|
%p
|
||||||
Pour vous connecter, cliquez sur le lien suivant :
|
Pour vous connecter, cliquez sur le lien suivant :
|
||||||
= link_to(new_user_session_url, new_user_session_url)
|
= link_to(new_user_session_url, new_user_session_url)
|
||||||
|
|
||||||
%p
|
%p
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
Bonjour,
|
Bonjour,
|
||||||
|
|
||||||
%p
|
%p
|
||||||
Pour activer votre compte sur demarches-simplifiees.fr, veuillez cliquer sur le lien suivant :
|
Pour activer votre compte sur demarches-simplifiees.fr, veuillez cliquer sur le lien suivant :
|
||||||
= link_to(confirmation_url(@user, confirmation_token: @token), confirmation_url(@user, confirmation_token: @token))
|
= link_to(confirmation_url(@user, confirmation_token: @token), confirmation_url(@user, confirmation_token: @token))
|
||||||
|
|
||||||
- else
|
- else
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
Bonjour,
|
Bonjour,
|
||||||
|
|
||||||
%p
|
%p
|
||||||
Pour confirmer votre changement d'adresse email, veuillez cliquer sur le lien suivant :
|
Pour confirmer votre changement d'adresse email, veuillez cliquer sur le lien suivant :
|
||||||
= link_to(confirmation_url(@user, confirmation_token: @token), confirmation_url(@user, confirmation_token: @token))
|
= link_to(confirmation_url(@user, confirmation_token: @token), confirmation_url(@user, confirmation_token: @token))
|
||||||
|
|
||||||
= render partial: "layouts/mailers/signature"
|
= render partial: "layouts/mailers/signature"
|
||||||
|
|
|
@ -7,4 +7,4 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= render_flash(timeout: 7000) %>
|
<%= render_flash(timeout: 20000) %>
|
||||||
|
|
|
@ -36,7 +36,7 @@ as well as a link to its edit page.
|
||||||
<% if page.resource.invitation_expired? %>
|
<% if page.resource.invitation_expired? %>
|
||||||
<%= link_to "renvoyer l'invitation", reinvite_manager_administrateur_path(page.resource), method: :post, class: "button" %>
|
<%= link_to "renvoyer l'invitation", reinvite_manager_administrateur_path(page.resource), method: :post, class: "button" %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= button_to "supprimer", delete_manager_administrateur_path(page.resource), method: :delete, disabled: !page.resource.can_be_deleted?, class: "button", data: { confirm: "Confirmez-vous la suppression de l'administrateur ?" }, title: page.resource.can_be_deleted? ? "Supprimer" : "Cet administrateur a des dossiers ou des procédures dont il est le seul admin et ne peut être supprimé" %>
|
<%= button_to "supprimer", delete_manager_administrateur_path(page.resource), method: :delete, disabled: !page.resource.can_be_deleted?, class: "button", data: { confirm: "Confirmez-vous la suppression de l'administrateur ?" }, title: page.resource.can_be_deleted? ? "Supprimer" : "Cet administrateur a des démarches dont il est le seul admin et ne peut être supprimé" %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</header>
|
</header>
|
||||||
|
|
|
@ -34,7 +34,10 @@ as well as a link to its edit page.
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<%= link_to 'Réinviter', reinvite_manager_instructeur_path(instructeur), method: :post, class: 'button' %>
|
<%= link_to 'Réinviter', reinvite_manager_instructeur_path(instructeur), method: :post, class: 'button' %>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
<%= button_to "Supprimer", delete_manager_instructeur_path(page.resource), method: :delete, disabled: !page.resource.can_be_deleted?, class: "button", data: { confirm: "Confirmez-vous la suppression de l'instructeur ?" }, title: page.resource.can_be_deleted? ? "Supprimer" : "Cet instructeur est administrateur ou a des démarches dont il est le seul instructeur et ne peut être supprimé" %>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section class="main-content__body">
|
<section class="main-content__body">
|
||||||
|
|
|
@ -28,7 +28,7 @@ as well as a link to its edit page.
|
||||||
<%= button_to "modifier", edit_manager_user_path(page.resource), method: :get, class: "button" %>
|
<%= button_to "modifier", edit_manager_user_path(page.resource), method: :get, class: "button" %>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<%= button_to "supprimer", delete_manager_user_path(page.resource), method: :delete, disabled: !page.resource.can_be_deleted?, class: "button", data: { confirm: "Confirmez-vous la suppression de l'utilisateur ?" }, title: page.resource.can_be_deleted? ? "Supprimer" : "Cet utilisateur a des dossiers dont l'instruction a commencé et ne peut être supprimé" %>
|
<%= button_to "supprimer", delete_manager_user_path(page.resource), method: :delete, disabled: !page.resource.can_be_deleted?, class: "button", data: { confirm: "Confirmez-vous la suppression de l'utilisateur ?" }, title: page.resource.can_be_deleted? ? "Supprimer" : "Cet utilisateur ne peut être supprimé. Il a des dossiers dont l'instruction a commencé ou il est administrateur ou instructeur" %>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<% if !user.confirmed? %>
|
<% if !user.confirmed? %>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
= form_for procedure.administrateurs.new,
|
= form_for procedure.administrateurs.new(user: User.new),
|
||||||
url: { controller: 'procedure_administrateurs' },
|
url: { controller: 'procedure_administrateurs' },
|
||||||
html: { class: 'form', id: "procedure-#{procedure.id}-new_administrateur" } ,
|
html: { class: 'form', id: "procedure-#{procedure.id}-new_administrateur" } ,
|
||||||
remote: true do |f|
|
remote: true do |f|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
%th= 'Enregistré le'
|
%th= 'Enregistré le'
|
||||||
%th= 'État'
|
%th= 'État'
|
||||||
%tbody{ id: "procedure-#{@procedure.id}-administrateurs" }
|
%tbody{ id: "procedure-#{@procedure.id}-administrateurs" }
|
||||||
= render partial: 'administrateur', collection: @procedure.administrateurs.order(:email)
|
= render partial: 'administrateur', collection: @procedure.administrateurs.order('users.email')
|
||||||
%tfoot
|
%tfoot
|
||||||
%tr
|
%tr
|
||||||
%th{ colspan: 4 }
|
%th{ colspan: 4 }
|
||||||
|
|
|
@ -32,6 +32,7 @@ Rails.application.routes.draw do
|
||||||
|
|
||||||
resources :instructeurs, only: [:index, :show] do
|
resources :instructeurs, only: [:index, :show] do
|
||||||
post 'reinvite', on: :member
|
post 'reinvite', on: :member
|
||||||
|
delete 'delete', on: :member
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :dossiers, only: [:show]
|
resources :dossiers, only: [:show]
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
class RemoveUniqueConstraintOnAdministrateurEmails < ActiveRecord::Migration[5.2]
|
||||||
|
def up
|
||||||
|
# Drop the index entirely
|
||||||
|
remove_index :administrateurs, :email
|
||||||
|
# Add the index again, without the unicity constraint
|
||||||
|
add_index :administrateurs, :email
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_index :administrateurs, :email
|
||||||
|
add_index :administrateurs, :email, unique: true
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2020_01_14_113700) do
|
ActiveRecord::Schema.define(version: 2020_01_30_165328) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -53,7 +53,7 @@ ActiveRecord::Schema.define(version: 2020_01_14_113700) do
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.boolean "active", default: false
|
t.boolean "active", default: false
|
||||||
t.string "encrypted_token"
|
t.string "encrypted_token"
|
||||||
t.index ["email"], name: "index_administrateurs_on_email", unique: true
|
t.index ["email"], name: "index_administrateurs_on_email"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "administrateurs_instructeurs", id: false, force: :cascade do |t|
|
create_table "administrateurs_instructeurs", id: false, force: :cascade do |t|
|
||||||
|
|
17
spec/controllers/manager/instructeurs_controller_spec.rb
Normal file
17
spec/controllers/manager/instructeurs_controller_spec.rb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
describe Manager::InstructeursController, type: :controller do
|
||||||
|
let(:administration) { create(:administration) }
|
||||||
|
|
||||||
|
describe '#delete' do
|
||||||
|
let!(:instructeur) { create(:instructeur) }
|
||||||
|
|
||||||
|
before { sign_in administration }
|
||||||
|
|
||||||
|
subject { delete :delete, params: { id: instructeur.id } }
|
||||||
|
|
||||||
|
it 'deletes the instructeur' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(Instructeur.find_by(id: instructeur.id)).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,9 +1,8 @@
|
||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
sequence(:administrateur_email) { |n| "admin#{n}@admin.com" }
|
sequence(:administrateur_email) { |n| "admin#{n}@admin.com" }
|
||||||
factory :administrateur do
|
factory :administrateur do
|
||||||
email { generate(:administrateur_email) }
|
|
||||||
|
|
||||||
transient do
|
transient do
|
||||||
|
email { generate(:administrateur_email) }
|
||||||
password { 'mon chien aime les bananes' }
|
password { 'mon chien aime les bananes' }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ require 'spec_helper'
|
||||||
feature 'As an administrateur', js: true do
|
feature 'As an administrateur', js: true do
|
||||||
let(:administration) { create(:administration) }
|
let(:administration) { create(:administration) }
|
||||||
let(:admin_email) { 'new_admin@gouv.fr' }
|
let(:admin_email) { 'new_admin@gouv.fr' }
|
||||||
let(:new_admin) { Administrateur.find_by(email: admin_email) }
|
let(:new_admin) { Administrateur.by_email(admin_email) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
perform_enqueued_jobs do
|
perform_enqueued_jobs do
|
||||||
|
|
|
@ -59,4 +59,18 @@ feature 'Administrateurs can edit procedures', js: true do
|
||||||
expect(page).to have_field('procedure_libelle', with: 'Ma petite démarche')
|
expect(page).to have_field('procedure_libelle', with: 'Ma petite démarche')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario 'the administrator can add another administrator' do
|
||||||
|
another_administrateur = create(:administrateur)
|
||||||
|
visit admin_procedure_path(procedure)
|
||||||
|
click_on 'Administrateurs'
|
||||||
|
|
||||||
|
fill_in('administrateur_email', with: another_administrateur.email)
|
||||||
|
|
||||||
|
click_on 'Ajouter comme administrateur'
|
||||||
|
|
||||||
|
within('.alert-success') do
|
||||||
|
expect(page).to have_content(another_administrateur.email)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,16 +3,6 @@ RSpec.describe ApplicationMailer, type: :mailer do
|
||||||
let(:dossier) { create(:dossier, procedure: build(:simple_procedure)) }
|
let(:dossier) { create(:dossier, procedure: build(:simple_procedure)) }
|
||||||
subject { DossierMailer.notify_new_draft(dossier) }
|
subject { DossierMailer.notify_new_draft(dossier) }
|
||||||
|
|
||||||
describe 'invalid emails are not sent' do
|
|
||||||
before do
|
|
||||||
allow_any_instance_of(DossierMailer)
|
|
||||||
.to receive(:notify_new_draft)
|
|
||||||
.and_raise(Net::SMTPSyntaxError)
|
|
||||||
end
|
|
||||||
|
|
||||||
it { expect(subject.message).to be_an_instance_of(ActionMailer::Base::NullMail) }
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'valid emails are sent' do
|
describe 'valid emails are sent' do
|
||||||
it { expect(subject.message).not_to be_an_instance_of(ActionMailer::Base::NullMail) }
|
it { expect(subject.message).not_to be_an_instance_of(ActionMailer::Base::NullMail) }
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,6 +41,6 @@ class AdministrationMailerPreview < ActionMailer::Preview
|
||||||
end
|
end
|
||||||
|
|
||||||
def administrateur
|
def administrateur
|
||||||
Administrateur.new(id: 111, email: "chef.de.service@administration.gouv.fr")
|
Administrateur.new(id: 111, user: User.new(email: "chef.de.service@administration.gouv.fr"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,13 +24,6 @@ describe Administrateur, type: :model do
|
||||||
describe "#can_be_deleted?" do
|
describe "#can_be_deleted?" do
|
||||||
subject { administrateur.can_be_deleted? }
|
subject { administrateur.can_be_deleted? }
|
||||||
|
|
||||||
context 'when the administrateur has a dossier in instruction' do
|
|
||||||
let!(:dossier) { create(:dossier, :en_instruction) }
|
|
||||||
let(:administrateur) { dossier.procedure.administrateurs.first }
|
|
||||||
|
|
||||||
it { is_expected.to be false }
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when the administrateur's procedures have other administrateurs" do
|
context "when the administrateur's procedures have other administrateurs" do
|
||||||
let!(:administrateur) { create(:administrateur) }
|
let!(:administrateur) { create(:administrateur) }
|
||||||
let!(:autre_administrateur) { create(:administrateur) }
|
let!(:autre_administrateur) { create(:administrateur) }
|
||||||
|
@ -39,6 +32,13 @@ describe Administrateur, type: :model do
|
||||||
it { is_expected.to be true }
|
it { is_expected.to be true }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when the administrateur has a procedure where they is the only admin" do
|
||||||
|
let!(:administrateur) { create(:administrateur) }
|
||||||
|
let!(:procedure) { create(:procedure, administrateurs: [administrateur]) }
|
||||||
|
|
||||||
|
it { is_expected.to be false }
|
||||||
|
end
|
||||||
|
|
||||||
context "when the administrateur has no procedure" do
|
context "when the administrateur has no procedure" do
|
||||||
let!(:administrateur) { create(:administrateur) }
|
let!(:administrateur) { create(:administrateur) }
|
||||||
|
|
||||||
|
@ -46,6 +46,21 @@ describe Administrateur, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#delete_and_transfer_services' do
|
||||||
|
let!(:administrateur) { create(:administrateur) }
|
||||||
|
let!(:autre_administrateur) { create(:administrateur) }
|
||||||
|
let!(:procedure) { create(:procedure, :with_service, administrateurs: [administrateur, autre_administrateur]) }
|
||||||
|
let(:service) { procedure.service }
|
||||||
|
|
||||||
|
it "delete and transfer services to other admin" do
|
||||||
|
service.update(administrateur: administrateur)
|
||||||
|
administrateur.delete_and_transfer_services
|
||||||
|
|
||||||
|
expect(Administrateur.find_by(id: administrateur.id)).to be_nil
|
||||||
|
expect(service.reload.administrateur).to eq(autre_administrateur)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# describe '#password_complexity' do
|
# describe '#password_complexity' do
|
||||||
# let(:email) { 'mail@beta.gouv.fr' }
|
# let(:email) { 'mail@beta.gouv.fr' }
|
||||||
# let(:passwords) { ['pass', '12pass23', 'démarches ', 'démarches-simple', 'démarches-simplifiées-pwd'] }
|
# let(:passwords) { ['pass', '12pass23', 'démarches ', 'démarches-simple', 'démarches-simplifiées-pwd'] }
|
||||||
|
|
|
@ -114,6 +114,29 @@ describe TagsSubstitutionConcern, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the procedure has a type de champ with apostrophes' do
|
||||||
|
let(:types_de_champ) do
|
||||||
|
[
|
||||||
|
create(:type_de_champ, libelle: "Intitulé de l'‘«\"évènement\"»’")
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'and they are used in the template' do
|
||||||
|
let(:template) { "--Intitulé de l'‘«\"évènement\"»’--" }
|
||||||
|
|
||||||
|
context 'and their value in the dossier are not nil' do
|
||||||
|
before do
|
||||||
|
dossier.champs
|
||||||
|
.filter { |champ| champ.libelle == "Intitulé de l'‘«\"évènement\"»’" }
|
||||||
|
.first
|
||||||
|
.update(value: 'ceci est mon évènement')
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to eq('ceci est mon évènement') }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when the procedure has a type de champ repetition' do
|
context 'when the procedure has a type de champ repetition' do
|
||||||
let(:template) { '--Répétition--' }
|
let(:template) { '--Répétition--' }
|
||||||
let(:types_de_champ) do
|
let(:types_de_champ) do
|
||||||
|
|
|
@ -424,9 +424,40 @@ describe Instructeur, type: :model do
|
||||||
it { expect(instructeur_a.procedures.all.to_ary).to eq([procedure_a]) }
|
it { expect(instructeur_a.procedures.all.to_ary).to eq([procedure_a]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#can_be_deleted?" do
|
||||||
|
subject { instructeur.can_be_deleted? }
|
||||||
|
|
||||||
|
context 'when the instructeur is an administrateur' do
|
||||||
|
let!(:administrateur) { create(:administrateur) }
|
||||||
|
let(:instructeur) { administrateur.instructeur }
|
||||||
|
|
||||||
|
it { is_expected.to be false }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the instructeur's procedures have other instructeurs" do
|
||||||
|
let(:instructeur_not_admin) { create(:instructeur) }
|
||||||
|
let(:autre_instructeur) { create(:instructeur) }
|
||||||
|
|
||||||
|
it "can be deleted" do
|
||||||
|
assign(procedure, instructeur_assigne: instructeur_not_admin)
|
||||||
|
assign(procedure, instructeur_assigne: autre_instructeur)
|
||||||
|
expect(autre_instructeur.can_be_deleted?).to be_truthy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the instructeur's procedures is the only one" do
|
||||||
|
let(:instructeur_not_admin) { create :instructeur }
|
||||||
|
let(:autre_procedure) { create :procedure }
|
||||||
|
it "can be deleted" do
|
||||||
|
assign(autre_procedure, instructeur_assigne: instructeur_not_admin)
|
||||||
|
expect(instructeur_not_admin.can_be_deleted?).to be_falsy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def assign(procedure_to_assign)
|
def assign(procedure_to_assign, instructeur_assigne: instructeur)
|
||||||
create :assign_to, instructeur: instructeur, procedure: procedure_to_assign, groupe_instructeur: procedure_to_assign.defaut_groupe_instructeur
|
create :assign_to, instructeur: instructeur_assigne, procedure: procedure_to_assign, groupe_instructeur: procedure_to_assign.defaut_groupe_instructeur
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -224,6 +224,24 @@ describe User, type: :model do
|
||||||
context 'when the user has no dossier in instruction' do
|
context 'when the user has no dossier in instruction' do
|
||||||
it { is_expected.to be true }
|
it { is_expected.to be true }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the user is an administrateur' do
|
||||||
|
it 'cannot be deleted' do
|
||||||
|
administrateur = create(:administrateur)
|
||||||
|
user = administrateur.user
|
||||||
|
|
||||||
|
expect(user.can_be_deleted?).to be_falsy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the user is an instructeur' do
|
||||||
|
it 'cannot be deleted' do
|
||||||
|
instructeur = create(:instructeur)
|
||||||
|
user = instructeur.user
|
||||||
|
|
||||||
|
expect(user.can_be_deleted?).to be_falsy
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#delete_and_keep_track_dossiers' do
|
describe '#delete_and_keep_track_dossiers' do
|
||||||
|
@ -241,12 +259,39 @@ describe User, type: :model do
|
||||||
let!(:dossier_en_construction) { create(:dossier, :en_construction, user: user) }
|
let!(:dossier_en_construction) { create(:dossier, :en_construction, user: user) }
|
||||||
let!(:dossier_brouillon) { create(:dossier, user: user) }
|
let!(:dossier_brouillon) { create(:dossier, user: user) }
|
||||||
|
|
||||||
it "keep track of dossiers and delete user" do
|
context 'without a hidden dossier' do
|
||||||
user.delete_and_keep_track_dossiers(administration)
|
it "keep track of dossiers and delete user" do
|
||||||
|
user.delete_and_keep_track_dossiers(administration)
|
||||||
|
|
||||||
expect(DeletedDossier.find_by(dossier_id: dossier_en_construction)).to be_present
|
expect(DeletedDossier.find_by(dossier_id: dossier_en_construction)).to be_present
|
||||||
expect(DeletedDossier.find_by(dossier_id: dossier_brouillon)).to be_present
|
expect(DeletedDossier.find_by(dossier_id: dossier_brouillon)).to be_present
|
||||||
expect(User.find_by(id: user.id)).to be_nil
|
expect(User.find_by(id: user.id)).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a hidden dossier' do
|
||||||
|
let!(:dossier_cache) do
|
||||||
|
create(:dossier, :en_construction, user: user)
|
||||||
|
end
|
||||||
|
let!(:dossier_from_another_user) do
|
||||||
|
create(:dossier, :en_construction, user: create(:user))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "keep track of dossiers and delete user" do
|
||||||
|
dossier_cache.delete_and_keep_track(administration)
|
||||||
|
user.delete_and_keep_track_dossiers(administration)
|
||||||
|
|
||||||
|
expect(DeletedDossier.find_by(dossier_id: dossier_en_construction)).to be_present
|
||||||
|
expect(DeletedDossier.find_by(dossier_id: dossier_brouillon)).to be_present
|
||||||
|
expect(User.find_by(id: user.id)).to be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't destroy dossiers of another user" do
|
||||||
|
dossier_cache.delete_and_keep_track(administration)
|
||||||
|
user.delete_and_keep_track_dossiers(administration)
|
||||||
|
|
||||||
|
expect(Dossier.find_by(id: dossier_from_another_user.id)).to be_present
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue