Merge pull request #5315 from betagouv/dev

2020-06-29-01
This commit is contained in:
Kara Diaby 2020-06-29 15:50:28 +02:00 committed by GitHub
commit d23b2026c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 339 additions and 345 deletions

View file

@ -109,6 +109,7 @@ group :development do
end end
group :development, :test do group :development, :test do
gem 'axe-matchers' # accessibility rspec matchers
gem 'byebug' # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' # Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'graphql-schema_comparator' gem 'graphql-schema_comparator'
gem 'mina', git: 'https://github.com/mina-deploy/mina.git', require: false # Deploy gem 'mina', git: 'https://github.com/mina-deploy/mina.git', require: false # Deploy

View file

@ -97,6 +97,13 @@ GEM
attr_required (1.0.1) attr_required (1.0.1)
autoprefixer-rails (9.7.4) autoprefixer-rails (9.7.4)
execjs execjs
axe-matchers (2.6.1)
dumb_delegator (~> 0.8)
virtus (~> 1.0)
axiom-types (0.1.1)
descendants_tracker (~> 0.0.4)
ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1)
axlsx_styler (1.0.0) axlsx_styler (1.0.0)
activesupport (>= 3.1) activesupport (>= 3.1)
caxlsx (>= 2.0.2) caxlsx (>= 2.0.2)
@ -146,6 +153,8 @@ GEM
chunky_png (1.3.11) chunky_png (1.3.11)
clamav-client (3.1.0) clamav-client (3.1.0)
coderay (1.1.2) coderay (1.1.2)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
coffee-rails (4.2.2) coffee-rails (4.2.2)
coffee-script (>= 2.2.0) coffee-script (>= 2.2.0)
railties (>= 4.0.0) railties (>= 4.0.0)
@ -179,6 +188,8 @@ GEM
delayed_job (> 2.0.3) delayed_job (> 2.0.3)
rack-protection (>= 1.5.5) rack-protection (>= 1.5.5)
sinatra (>= 1.4.4) sinatra (>= 1.4.4)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devise (4.7.1) devise (4.7.1)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
@ -198,9 +209,11 @@ GEM
dotenv (= 2.7.5) dotenv (= 2.7.5)
railties (>= 3.2, < 6.1) railties (>= 3.2, < 6.1)
dry-inflector (0.2.0) dry-inflector (0.2.0)
dumb_delegator (0.8.1)
em-websocket (0.5.1) em-websocket (0.5.1)
eventmachine (>= 0.12.9) eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0) http_parser.rb (~> 0.6.0)
equalizer (0.0.11)
erubi (1.9.0) erubi (1.9.0)
erubis (2.7.0) erubis (2.7.0)
et-orbi (1.2.4) et-orbi (1.2.4)
@ -319,6 +332,7 @@ GEM
httpclient (2.8.3) httpclient (2.8.3)
i18n (1.8.3) i18n (1.8.3)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
ipaddress (0.8.3) ipaddress (0.8.3)
jaro_winkler (1.5.4) jaro_winkler (1.5.4)
jquery-rails (4.3.5) jquery-rails (4.3.5)
@ -678,6 +692,11 @@ GEM
activemodel (>= 3.0.0) activemodel (>= 3.0.0)
addressable addressable
vcr (4.0.0) vcr (4.0.0)
virtus (1.0.5)
axiom-types (~> 0.1)
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
warden (1.2.8) warden (1.2.8)
rack (>= 2.0.6) rack (>= 2.0.6)
web-console (3.7.0) web-console (3.7.0)
@ -728,6 +747,7 @@ DEPENDENCIES
administrate administrate
after_party after_party
anchored anchored
axe-matchers
bcrypt bcrypt
bootstrap-sass (>= 3.4.1) bootstrap-sass (>= 3.4.1)
bootstrap-wysihtml5-rails (~> 0.3.3.8) bootstrap-wysihtml5-rails (~> 0.3.3.8)

View file

@ -16,3 +16,17 @@ $new-p-margin-bottom: 3 * $default-space;
.new-p { .new-p {
margin-bottom: $new-p-margin-bottom; margin-bottom: $new-p-margin-bottom;
} }
// A class to make elements only accessible to screen-readers
.sr-only {
position: absolute;
width: 1px;
height: 1px;
opacity: 0;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: none;
}

View file

@ -67,6 +67,7 @@
.label { .label {
width: 110px; width: 110px;
text-align: center; text-align: center;
margin: 0 4px;
} }
} }

View file

@ -1,53 +0,0 @@
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.defaut_groupe_instructeur.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].present?
filter = params[:filter].downcase.strip
not_assign_scope = not_assign_scope.where('users.email LIKE ?', "%#{filter}%")
end
@instructeurs_not_assign = smart_listing_create :instructeurs_not_assign,
not_assign_scope,
partial: "admin/assigns/list_not_assign",
array: true
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

@ -13,6 +13,7 @@ class Admin::InstructeursController < AdminController
email = params[:instructeur][:email].downcase email = params[:instructeur][:email].downcase
@instructeur = Instructeur.by_email(email) @instructeur = Instructeur.by_email(email)
procedure_id = params[:procedure_id] procedure_id = params[:procedure_id]
procedure = Procedure.find_by(id: procedure_id)
if @instructeur.nil? if @instructeur.nil?
invite_instructeur(email) invite_instructeur(email)
@ -21,7 +22,7 @@ class Admin::InstructeursController < AdminController
end end
if procedure_id.present? if procedure_id.present?
redirect_to admin_procedure_assigns_path(procedure_id: procedure_id) redirect_to procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur)
else else
redirect_to admin_instructeurs_path redirect_to admin_instructeurs_path
end end

View file

@ -100,16 +100,27 @@ module NewAdministrateur
create_instructeur(instructeur_email) create_instructeur(instructeur_email)
end end
groupe_instructeur.instructeurs << instructeurs if procedure.routee?
groupe_instructeur.instructeurs << instructeurs
GroupeInstructeurMailer GroupeInstructeurMailer
.add_instructeurs(groupe_instructeur, instructeurs, current_user.email) .add_instructeurs(groupe_instructeur, instructeurs, current_user.email)
.deliver_later .deliver_later
flash[:notice] = t('.assignment', flash[:notice] = t('.assignment',
count: email_to_adds.count, count: email_to_adds.count,
value: email_to_adds.join(', '), value: email_to_adds.join(', '),
groupe: groupe_instructeur.label) groupe: groupe_instructeur.label)
else
if instructeurs.present?
instructeurs.each do |instructeur|
instructeur.assign_to_procedure(procedure)
end
flash[:notice] = "Les instructeurs ont bien été affectés à la démarche"
end
end
end end
redirect_to procedure_groupe_instructeur_path(procedure, groupe_instructeur) redirect_to procedure_groupe_instructeur_path(procedure, groupe_instructeur)
@ -120,14 +131,23 @@ module NewAdministrateur
flash[:alert] = "Suppression impossible : il doit y avoir au moins un instructeur dans le groupe" flash[:alert] = "Suppression impossible : il doit y avoir au moins un instructeur dans le groupe"
else else
@instructeur = Instructeur.find(instructeur_id) if procedure.routee?
groupe_instructeur.instructeurs.destroy(@instructeur) @instructeur = Instructeur.find(instructeur_id)
flash[:notice] = "Linstructeur « #{@instructeur.email} » a été retiré du groupe." groupe_instructeur.instructeurs.destroy(@instructeur)
GroupeInstructeurMailer flash[:notice] = "Linstructeur « #{@instructeur.email} » a été retiré du groupe."
.remove_instructeur(groupe_instructeur, @instructeur, current_user.email) GroupeInstructeurMailer
.deliver_later .remove_instructeur(groupe_instructeur, @instructeur, current_user.email)
end .deliver_later
else
instructeur = Instructeur.find(instructeur_id)
if instructeur.remove_from_procedure(procedure)
flash[:notice] = "L'instructeur a bien été désaffecté de la démarche"
else
flash[:alert] = "Suppression impossible : il doit y avoir au moins un instructeur dans le groupe"
end
end
end
redirect_to procedure_groupe_instructeur_path(procedure, groupe_instructeur) redirect_to procedure_groupe_instructeur_path(procedure, groupe_instructeur)
end end

View file

@ -1177,7 +1177,7 @@ enum TypeDeChamp {
dossier_link dossier_link
""" """
Menu déroulant Choix parmi une liste
""" """
drop_down_list drop_down_list
@ -1212,7 +1212,7 @@ enum TypeDeChamp {
linked_drop_down_list linked_drop_down_list
""" """
Menu déroulant à choix multiples Choix multiples
""" """
multiple_drop_down_list multiple_drop_down_list
@ -1317,4 +1317,4 @@ type ValidationError {
A description of the error A description of the error
""" """
message: String! message: String!
} }

View file

@ -40,4 +40,7 @@ if (enabled) {
'session:event', 'session:event',
[[['PAGE_VIEW', { URL: window.location.pathname }]]] [[['PAGE_VIEW', { URL: window.location.pathname }]]]
]); ]);
// Prevent Crisp to log warnings about Sentry overriding document.addEventListener
window.$crisp.push(['safe', true]);
} }

View file

@ -2,15 +2,6 @@
class AdministrationMailer < ApplicationMailer class AdministrationMailer < ApplicationMailer
layout 'mailers/layout' layout 'mailers/layout'
def new_admin_email(admin, administration)
@admin = admin
@administration = administration
subject = "Création d'un compte admininistrateur"
mail(to: TECH_EMAIL,
subject: subject)
end
def invite_admin(admin, reset_password_token, administration_id) def invite_admin(admin, reset_password_token, administration_id)
@reset_password_token = reset_password_token @reset_password_token = reset_password_token
@admin = admin @admin = admin

View file

@ -11,7 +11,6 @@ class Administration < ApplicationRecord
user = User.create_or_promote_to_administrateur(email, SecureRandom.hex) user = User.create_or_promote_to_administrateur(email, SecureRandom.hex)
if user.valid? if user.valid?
AdministrationMailer.new_admin_email(user.administrateur, self).deliver_later
user.invite_administrateur!(id) user.invite_administrateur!(id)
end end

View file

@ -1,20 +0,0 @@
.row{ style: 'height: 34px;' }
- if smart_listing.present?
%table.table#liste-instructeur
%thead
%th Enlever
%th#email{ style: 'text-align: right;' } Email
- @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_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
= smart_listing.paginate
= smart_listing.pagination_per_page_links
- else
%h4.center
Aucun d'affecté

View file

@ -1,27 +0,0 @@
= smart_listing_controls_for(:instructeurs_not_assign, { class: "form-inline text-right" }) do
.form-group.filter.input-append
= text_field_tag :filter, '', class: "search form-control",
placeholder: "Recherche...", autocomplete: :off
%button.btn.btn-primary{ type: :submit }
%span.fa.fa-search
- if smart_listing.present?
%table.table#liste-instructeur
%thead
%th#email Email
%th Ajouter
- @instructeurs_not_assign.each do |instructeur|
%tr
%td.col-xs-11{ style: 'padding-top: 11px; font-size: 15px;' }= instructeur.email
%td.center
= 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
= smart_listing.paginate
= smart_listing.pagination_per_page_links
- else
%h4.center
Aucun de disponible

View file

@ -1,23 +0,0 @@
.row.white-back
#instructeur_form
.row
.col-xs-6
%h3.text-info Disponibles
= smart_listing_render :instructeurs_not_assign
%br
%h3
= t('dynamics.admin.procedure.onglet_instructeurs.add.title')
#procedure_new.section.section-label
= form_with url: { controller: 'admin/instructeurs', action: :create } do
.row
.col-xs-5
= hidden_field_tag :procedure_id, params[:procedure_id]
= render partial: 'admin/instructeurs/informations'
.col-xs-2
%br
%br
= submit_tag 'Ajouter', 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,3 +0,0 @@
<%= smart_listing_update :instructeurs_not_assign %>
<%= smart_listing_update :instructeurs_assign %>

View file

@ -1,4 +1,4 @@
.form-group .form-group
%h4 %p.notice
= 'Email *' = 'Email *'
= text_field_tag 'instructeur[email]', nil, class: 'form-control', placeholder: 'laura.azema@exemple.gouv.fr' = text_field_tag 'instructeur[email]', nil, class: 'form-control', placeholder: 'ex : laura.azema@exemple.gouv.fr'

View file

@ -107,7 +107,7 @@
.alert.alert-info .alert.alert-info
Pour pouvoir tester cette démarche, vous devez dabord lui affecter Pour pouvoir tester cette démarche, vous devez dabord lui affecter
- if @procedure.missing_instructeurs? - if @procedure.missing_instructeurs?
= link_to("des instructeurs", admin_procedure_assigns_path(@procedure)) = link_to("des instructeurs", procedure_groupe_instructeur_path(@procedure, @procedure.defaut_groupe_instructeur))
- if @procedure.missing_instructeurs? && @procedure.service.nil? - if @procedure.missing_instructeurs? && @procedure.service.nil?
et et
- if @procedure.service.nil? - if @procedure.service.nil?
@ -122,7 +122,7 @@
- if @procedure.missing_steps.include?(:instructeurs) - if @procedure.missing_steps.include?(:instructeurs)
%p.alert.alert-danger %p.alert.alert-danger
Vous devez affecter des instructeurs avant de pouvoir publier votre démarche. Vous devez affecter des instructeurs avant de pouvoir publier votre démarche.
= link_to 'Cliquez ici.', admin_procedure_assigns_path(@procedure) = link_to 'Cliquez ici.', procedure_groupe_instructeur_path(@procedure, @procedure.defaut_groupe_instructeur)
%p.alert.alert-info %p.alert.alert-info
Cette démarche na pas encore de lien, et nest pas accessible par le public. Cette démarche na pas encore de lien, et nest pas accessible par le public.

View file

@ -31,7 +31,7 @@
Administrateurs Administrateurs
- if !feature_enabled?(:administrateur_routage) - if !feature_enabled?(:administrateur_routage)
%a#onglet-instructeurs{ href: url_for(admin_procedure_assigns_path(@procedure)) } %a#onglet-instructeurs{ href: url_for(procedure_groupe_instructeur_path(@procedure, @procedure.defaut_groupe_instructeur)) }
.procedure-list-element{ class: ('active' if active == 'Instructeurs') } .procedure-list-element{ class: ('active' if active == 'Instructeurs') }
Instructeurs Instructeurs
- if @procedure.missing_steps.include?(:instructeurs) - if @procedure.missing_steps.include?(:instructeurs)

View file

@ -0,0 +1,9 @@
%h1 Groupe « #{@groupe_instructeur.label} »
.card.mt-2
= form_for @groupe_instructeur,
url: procedure_groupe_instructeur_path(@procedure, @groupe_instructeur),
html: { class: 'form' } do |f|
= f.label :label, 'Nom du groupe'
= f.text_field :label, placeholder: 'Ville de Bordeaux', required: true
= f.submit 'Renommer', class: 'button primary send'

View file

@ -1,20 +1,20 @@
= render partial: 'new_administrateur/breadcrumbs',
locals: { steps: [link_to('Démarches', admin_procedures_path), - if feature_enabled?(:administrateur_routage)
link_to(@procedure.libelle, admin_procedure_path(@procedure)), = render partial: 'new_administrateur/breadcrumbs',
link_to('Groupes dinstructeurs', procedure_groupe_instructeurs_path(@procedure)), locals: { steps: [link_to('Démarches', admin_procedures_path),
@groupe_instructeur.label] } link_to(@procedure.libelle, admin_procedure_path(@procedure)),
link_to('Groupes dinstructeurs', procedure_groupe_instructeurs_path(@procedure)),
@groupe_instructeur.label] }
- else
= render partial: 'new_administrateur/breadcrumbs',
locals: { steps: [link_to('Démarches', admin_procedures_path),
link_to(@procedure.libelle, admin_procedure_path(@procedure)),
'Instructeurs'] }
.container.groupe-instructeur .container.groupe-instructeur
%h1 Groupe « #{@groupe_instructeur.label} »
.card.mt-2 - if feature_enabled?(:administrateur_routage)
= form_for @groupe_instructeur, = render partial: 'new_administrateur/groups_header'
url: procedure_groupe_instructeur_path(@procedure, @groupe_instructeur),
html: { class: 'form' } do |f|
= f.label :label, 'Nom du groupe'
= f.text_field :label, placeholder: 'Ville de Bordeaux', required: true
= f.submit 'Renommer', class: 'button primary send'
.card .card
.card-title Affectation des instructeurs .card-title Affectation des instructeurs
@ -23,6 +23,8 @@
html: { class: 'form' } do |f| html: { class: 'form' } do |f|
.instructeur-wrapper .instructeur-wrapper
- if !@procedure.routee?
%p.notice Entrez les adresses email des instructeurs que vous souhaitez affecter à cette démarche
= select_tag :emails, = select_tag :emails,
options_for_select(@available_instructeur_emails), options_for_select(@available_instructeur_emails),
multiple: true, multiple: true,
@ -43,7 +45,7 @@
%td.actions= button_to 'retirer', %td.actions= button_to 'retirer',
{ action: :remove_instructeur }, { action: :remove_instructeur },
{ method: :delete, { method: :delete,
data: { confirm: "Êtes-vous sûr de vouloir retirer linstructeur « #{instructeur.email} » du groupe  « #{@groupe_instructeur.label} » ?" }, data: { confirm: feature_enabled?(:administrateur_routage) ? "Êtes-vous sûr de vouloir retirer linstructeur « #{instructeur.email} » du groupe  « #{@groupe_instructeur.label} » ?" : "Êtes-vous sûr de vouloir retirer linstructeur « #{instructeur.email} » de la démarche ?" },
params: { instructeur: { id: instructeur.id }}, params: { instructeur: { id: instructeur.id }},
class: 'button' } class: 'button' }

View file

@ -18,7 +18,7 @@
= render partial: "shared/attachment/show", locals: { attachment: attachment, user_can_upload: true } = render partial: "shared/attachment/show", locals: { attachment: attachment, user_can_upload: true }
- if user_can_destroy - if user_can_destroy
.attachment-action .attachment-action
= link_to 'Supprimer', attachment_url(attachment.id, { signed_id: attachment.blob.signed_id }), remote: true, method: :delete, class: 'button small danger' = link_to 'Supprimer', attachment_url(attachment.id, { signed_id: attachment.blob.signed_id }), remote: true, method: :delete, class: 'button small danger', data: { disable: true }
.attachment-action .attachment-action
= button_tag 'Remplacer', type: 'button', class: 'button small', data: { 'toggle-target': ".attachment-input-#{attachment_id}" } = button_tag 'Remplacer', type: 'button', class: 'button small', data: { 'toggle-target': ".attachment-input-#{attachment_id}" }

View file

@ -29,36 +29,31 @@
%table.table.dossiers-table.hoverable %table.table.dossiers-table.hoverable
%thead %thead
%tr %tr
%th.notification-col
%th.number-col Nº dossier %th.number-col Nº dossier
%th Démarche %th Démarche
- if @dossiers.count > 1 - if @dossiers.count > 1
%th Demandeur %th Demandeur
%th.status-col Statut %th.status-col Statut
%th.updated-at-col Mis à jour %th.updated-at-col Mis à jour
%th %th.sr-only Actions
%tbody %tbody
- @dossiers.each do |dossier| - @dossiers.each do |dossier|
%tr{ data: { 'dossier-id': dossier.id } } %tr{ data: { 'dossier-id': dossier.id } }
%td.folder-col
= link_to(url_for_dossier(dossier), class: 'cell-link') do
%span.icon.folder
%td.number-col %td.number-col
= link_to(url_for_dossier(dossier), class: 'cell-link') do = link_to(url_for_dossier(dossier), class: 'cell-link', tabindex: -1) do
%span.icon.folder
= dossier.id = dossier.id
%td %td
= link_to(url_for_dossier(dossier), class: 'cell-link') do = link_to(url_for_dossier(dossier), class: 'cell-link') do
= procedure_libelle(dossier.procedure) = procedure_libelle(dossier.procedure)
- if @dossiers.count > 1 - if @dossiers.count > 1
%td.number-col %td.cell-link
= demandeur_dossier(dossier) = demandeur_dossier(dossier)
%td.status-col %td.status-col
= link_to(url_for_dossier(dossier), class: 'cell-link') do = status_badge(dossier.state)
= status_badge(dossier.state) %td.updated-at-col.cell-link
%td.updated-at-col = try_format_date(dossier.updated_at)
= link_to(url_for_dossier(dossier), class: 'cell-link') do %td.action-col
= try_format_date(dossier.updated_at)
%td.action-col.action-col
= render partial: 'dossier_actions', locals: { dossier: dossier } = render partial: 'dossier_actions', locals: { dossier: dossier }
= paginate(@dossiers) = paginate(@dossiers)

5
bors.toml Normal file
View file

@ -0,0 +1,5 @@
status = [
"ci/circleci: build",
"ci/circleci: test",
"ci/circleci: lint"
]

View file

@ -18,8 +18,8 @@ fr:
phone: 'Téléphone' phone: 'Téléphone'
address: 'Adresse' address: 'Adresse'
yes_no: 'Oui/Non' yes_no: 'Oui/Non'
drop_down_list: 'Menu déroulant' drop_down_list: 'Choix parmi une liste'
multiple_drop_down_list: 'Menu déroulant à choix multiples' multiple_drop_down_list: 'Choix multiples'
linked_drop_down_list: 'Deux menus déroulants liés' linked_drop_down_list: 'Deux menus déroulants liés'
pays: 'Pays' pays: 'Pays'
regions: 'Régions' regions: 'Régions'

View file

@ -202,8 +202,6 @@ Rails.application.routes.draw do
post 'transfer' => 'procedures#transfer', as: :transfer post 'transfer' => 'procedures#transfer', as: :transfer
put 'clone' => 'procedures#clone', as: :clone put 'clone' => 'procedures#clone', as: :clone
resource :assigns, only: [:show, :update], path: 'instructeurs'
resource :attestation_template, only: [:edit, :update, :create] resource :attestation_template, only: [:edit, :update, :create]
post 'attestation_template/disactivate' => 'attestation_templates#disactivate' post 'attestation_template/disactivate' => 'attestation_templates#disactivate'

View file

@ -1,62 +0,0 @@
describe Admin::AssignsController, type: :controller do
let(:admin) { create(:administrateur) }
before do
sign_in(admin.user)
end
describe 'GET #show' do
let(:procedure) { create :procedure, administrateur: admin, instructeurs: [instructeur_assigned_1, instructeur_assigned_2] }
let!(:instructeur_assigned_1) { create :instructeur, email: 'instructeur_1@ministere_a.gouv.fr', administrateurs: [admin] }
let!(:instructeur_assigned_2) { create :instructeur, email: 'instructeur_2@ministere_b.gouv.fr', administrateurs: [admin] }
let!(:instructeur_not_assigned_1) { create :instructeur, email: 'instructeur_3@ministere_a.gouv.fr', administrateurs: [admin] }
let!(:instructeur_not_assigned_2) { create :instructeur, email: 'instructeur_4@ministere_b.gouv.fr', administrateurs: [admin] }
let(:filter) { nil }
subject! { get :show, params: { procedure_id: procedure.id, filter: filter } }
it { expect(response.status).to eq(200) }
it 'sets the assigned and not assigned instructeurs' do
expect(assigns(:instructeurs_assign)).to match_array([instructeur_assigned_1, instructeur_assigned_2])
expect(assigns(:instructeurs_not_assign)).to match_array([instructeur_not_assigned_1, instructeur_not_assigned_2])
end
context 'with a search filter' do
let(:filter) { '@ministere_a.gouv.fr' }
it 'filters the unassigned instructeurs' do
expect(assigns(:instructeurs_not_assign)).to match_array([instructeur_not_assigned_1])
end
it 'does not filter the assigned instructeurs' do
expect(assigns(:instructeurs_assign)).to match_array([instructeur_assigned_1, instructeur_assigned_2])
end
context 'when the filter has spaces or a mixed case' do
let(:filter) { ' @ministere_A.gouv.fr ' }
it 'trims spaces and ignores the case' do
expect(assigns(:instructeurs_not_assign)).to match_array([instructeur_not_assigned_1])
end
end
end
end
describe 'PUT #update' do
let(:procedure) { create :procedure, administrateur: admin }
let(:instructeur) { create :instructeur, administrateurs: [admin] }
subject { put :update, params: { instructeur_id: instructeur.id, procedure_id: procedure.id, to: 'assign' } }
it { expect(subject).to redirect_to admin_procedure_assigns_path(procedure_id: procedure.id) }
context 'when assignement is valid' do
before do
subject
end
it { expect(flash[:notice]).to be_present }
end
end
end

View file

@ -42,9 +42,8 @@ describe Admin::InstructeursController, type: :controller do
context 'when procedure_id params is not null' do context 'when procedure_id params is not null' do
let(:procedure) { create :procedure } let(:procedure) { create :procedure }
let(:procedure_id) { procedure.id } let(:procedure_id) { procedure.id }
it { expect(response.status).to eq(302) } it { expect(response.status).to eq(302) }
it { expect(response).to redirect_to admin_procedure_assigns_path(procedure_id: procedure_id) } it { expect(response).to redirect_to procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur) }
end end
describe 'Instructeur attributs in database' do describe 'Instructeur attributs in database' do

View file

@ -36,8 +36,6 @@ describe Manager::AdministrateursController, type: :controller do
end end
it 'alert new mail are send' do it 'alert new mail are send' do
expect(AdministrationMailer).to receive(:new_admin_email).and_return(AdministrationMailer)
expect(AdministrationMailer).to receive(:deliver_later)
expect(AdministrationMailer).to receive(:invite_admin).and_return(AdministrationMailer) expect(AdministrationMailer).to receive(:invite_admin).and_return(AdministrationMailer)
expect(AdministrationMailer).to receive(:deliver_later) expect(AdministrationMailer).to receive(:deliver_later)
subject subject

View file

@ -31,6 +31,22 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do
it { expect(response).to have_http_status(:ok) } it { expect(response).to have_http_status(:ok) }
end end
context 'when the routage is not activated on the procedure' do
let(:procedure) { create :procedure, administrateur: admin, instructeurs: [instructeur_assigned_1, instructeur_assigned_2] }
let!(:instructeur_assigned_1) { create :instructeur, email: 'instructeur_1@ministere_a.gouv.fr', administrateurs: [admin] }
let!(:instructeur_assigned_2) { create :instructeur, email: 'instructeur_2@ministere_b.gouv.fr', administrateurs: [admin] }
let!(:instructeur_not_assigned_1) { create :instructeur, email: 'instructeur_3@ministere_a.gouv.fr', administrateurs: [admin] }
let!(:instructeur_not_assigned_2) { create :instructeur, email: 'instructeur_4@ministere_b.gouv.fr', administrateurs: [admin] }
subject! { get :show, params: { procedure_id: procedure.id, id: gi_1_1.id } }
it { expect(response.status).to eq(200) }
it 'sets the assigned and not assigned instructeurs' do
expect(assigns(:instructeurs)).to match_array([instructeur_assigned_1, instructeur_assigned_2])
expect(assigns(:available_instructeur_emails)).to match_array(['instructeur_3@ministere_a.gouv.fr', 'instructeur_4@ministere_b.gouv.fr'])
end
end
end end
describe '#create' do describe '#create' do
@ -189,10 +205,40 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do
end end
end end
describe '#add_instructeur_procedure_non_routee' do
let(:procedure) { create :procedure, administrateur: admin }
let(:emails) { ['instructeur_3@ministere_a.gouv.fr', 'instructeur_4@ministere_b.gouv.fr'] }
subject { post :add_instructeur, params: { emails: emails, procedure_id: procedure.id, id: gi_1_1.id } }
context 'when all emails are valid' do
let(:emails) { ['test@b.gouv.fr', 'test2@b.gouv.fr'] }
it { expect(response.status).to eq(200) }
it { expect(subject.request.flash[:alert]).to be_nil }
it { expect(subject.request.flash[:notice]).to be_present }
it { expect(subject).to redirect_to procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur) }
end
context 'when there is at least one bad email' do
let(:emails) { ['badmail', 'instructeur2@gmail.com'] }
it { expect(response.status).to eq(200) }
it { expect(subject.request.flash[:alert]).to be_present }
it { expect(subject.request.flash[:notice]).to be_present }
it { expect(subject).to redirect_to procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur) }
end
context 'when the admin wants to assign an instructor who is already assigned on this procedure' do
let(:emails) { ['instructeur_1@ministere_a.gouv.fr'] }
it { expect(subject.request.flash[:alert]).to be_present }
it { expect(subject).to redirect_to procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur) }
end
end
describe '#add_instructeur' do describe '#add_instructeur' do
let!(:instructeur) { create(:instructeur) } let!(:instructeur) { create(:instructeur) }
let(:gi_1_2) { procedure.groupe_instructeurs.create(label: 'groupe instructeur 2') }
before do before do
gi_1_1.instructeurs << instructeur gi_1_2.instructeurs << instructeur
allow(GroupeInstructeurMailer).to receive(:add_instructeurs) allow(GroupeInstructeurMailer).to receive(:add_instructeurs)
.and_return(double(deliver_later: true)) .and_return(double(deliver_later: true))
@ -200,7 +246,7 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do
post :add_instructeur, post :add_instructeur,
params: { params: {
procedure_id: procedure.id, procedure_id: procedure.id,
id: gi_1_1.id, id: gi_1_2.id,
emails: new_instructeur_emails emails: new_instructeur_emails
} }
end end
@ -208,12 +254,13 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do
context 'of a news instructeurs' do context 'of a news instructeurs' do
let(:new_instructeur_emails) { ['new_i1@mail.com', 'new_i2@mail.com'] } let(:new_instructeur_emails) { ['new_i1@mail.com', 'new_i2@mail.com'] }
it { expect(gi_1_1.instructeurs.pluck(:email)).to include(*new_instructeur_emails) } it { expect(gi_1_2.instructeurs.pluck(:email)).to include(*new_instructeur_emails) }
it { expect(flash.notice).to be_present } it { expect(flash.notice).to be_present }
it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, gi_1_1)) } it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, gi_1_2)) }
it { expect(procedure.routee?).to be_truthy }
it "calls GroupeInstructeurMailer with the right groupe and instructeurs" do it "calls GroupeInstructeurMailer with the right groupe and instructeurs" do
expect(GroupeInstructeurMailer).to have_received(:add_instructeurs).with( expect(GroupeInstructeurMailer).to have_received(:add_instructeurs).with(
gi_1_1, gi_1_2,
satisfy { |instructeurs| instructeurs.all? { |i| new_instructeur_emails.include?(i.email) } }, satisfy { |instructeurs| instructeurs.all? { |i| new_instructeur_emails.include?(i.email) } },
admin.email admin.email
) )
@ -223,20 +270,20 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do
context 'of an instructeur already in the group' do context 'of an instructeur already in the group' do
let(:new_instructeur_emails) { [instructeur.email] } let(:new_instructeur_emails) { [instructeur.email] }
it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur)) } it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, gi_1_2)) }
end end
context 'of badly formed email' do context 'of badly formed email' do
let(:new_instructeur_emails) { ['badly_formed_email'] } let(:new_instructeur_emails) { ['badly_formed_email'] }
it { expect(flash.alert).to be_present } it { expect(flash.alert).to be_present }
it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur)) } it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, gi_1_2)) }
end end
context 'of an empty string' do context 'of an empty string' do
let(:new_instructeur_emails) { '' } let(:new_instructeur_emails) { '' }
it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, procedure.defaut_groupe_instructeur)) } it { expect(response).to redirect_to(procedure_groupe_instructeur_path(procedure, gi_1_2)) }
end end
end end
@ -275,6 +322,33 @@ describe NewAdministrateur::GroupeInstructeursController, type: :controller do
end end
end end
describe '#remove_instructeur_procedure_non_routee' do
let(:procedure) { create :procedure, administrateur: admin, instructeurs: [instructeur_assigned_1, instructeur_assigned_2] }
let!(:instructeur_assigned_1) { create :instructeur, email: 'instructeur_1@ministere_a.gouv.fr', administrateurs: [admin] }
let!(:instructeur_assigned_2) { create :instructeur, email: 'instructeur_2@ministere_b.gouv.fr', administrateurs: [admin] }
let!(:instructeur_assigned_3) { create :instructeur, email: 'instructeur_3@ministere_a.gouv.fr', administrateurs: [admin] }
subject! { get :show, params: { procedure_id: procedure.id, id: gi_1_1.id } }
it 'sets the assigned instructeurs' do
expect(assigns(:instructeurs)).to match_array([instructeur_assigned_1, instructeur_assigned_2])
end
context 'when the instructor is assigned to the procedure' do
subject { delete :remove_instructeur, params: { instructeur: { id: instructeur_assigned_1.id }, procedure_id: procedure.id, id: gi_1_1.id } }
it { expect(subject.request.flash[:notice]).to be_present }
it { expect(subject.request.flash[:alert]).to be_nil }
it { expect(response.status).to eq(302) }
it { expect(subject).to redirect_to procedure_groupe_instructeur_path(procedure, gi_1_1) }
end
context 'when the instructor is not assigned to the procedure' do
subject { delete :remove_instructeur, params: { instructeur: { id: instructeur_assigned_3.id }, procedure_id: procedure.id, id: gi_1_1.id } }
it { expect(subject.request.flash[:alert]).to be_present }
it { expect(subject.request.flash[:notice]).to be_nil }
it { expect(response.status).to eq(302) }
it { expect(subject).to redirect_to procedure_groupe_instructeur_path(procedure, gi_1_1) }
end
end
describe '#update_routing_criteria_name' do describe '#update_routing_criteria_name' do
before do before do
patch :update_routing_criteria_name, patch :update_routing_criteria_name,

View file

@ -50,7 +50,7 @@ FactoryBot.define do
type_champ { TypeDeChamp.type_champs.fetch(:datetime) } type_champ { TypeDeChamp.type_champs.fetch(:datetime) }
end end
factory :type_de_champ_drop_down_list do factory :type_de_champ_drop_down_list do
libelle { 'Menu déroulant' } libelle { 'Choix parmi une liste' }
type_champ { TypeDeChamp.type_champs.fetch(:drop_down_list) } type_champ { TypeDeChamp.type_champs.fetch(:drop_down_list) }
drop_down_list_value { "val1\r\nval2\r\n--separateur--\r\nval3" } drop_down_list_value { "val1\r\nval2\r\n--separateur--\r\nval3" }
trait :long do trait :long do

View file

@ -0,0 +1,124 @@
feature 'wcag rules for usager', js: true do
let(:procedure) { create(:procedure, :with_type_de_champ, :with_all_champs, :with_service, :for_individual, :published) }
let(:password) { 'a very complicated password' }
let(:litteraire_user) { create(:user, password: password) }
context 'pages without the need to be logged in' do
scenario 'homepage' do
visit root_path
expect(page).to be_accessible.excluding ".footer-logo"
end
scenario 'sign_up page' do
visit new_user_registration_path
expect(page).to be_accessible.excluding ".footer-logo"
end
scenario 'account confirmation page' do
visit new_user_registration_path
fill_in :user_email, with: "some@email.com"
fill_in :user_password, with: "epeciusetuir"
perform_enqueued_jobs do
click_button 'Créer un compte'
expect(page).to be_accessible.skipping(:'page-has-heading-one', :'role-img-alt', :label)
end
end
scenario 'sign_in page' do
visit new_user_session_path
expect(page).to be_accessible.excluding ".footer-logo", '#user_email'
end
scenario 'contact page' do
visit contact_path
expect(page).to be_accessible.excluding ".footer-logo"
end
scenario 'commencer page' do
visit commencer_path(path: procedure.reload.path)
expect(page).to be_accessible
end
end
context "logged in, depot d'un dossier as individual" do
before do
login_as litteraire_user, scope: :user
visit commencer_path(path: procedure.reload.path)
end
scenario 'écran identité usager' do
click_on 'Commencer la démarche'
expect(page).to be_accessible
end
# with no surprise, there's a lot of work on this one
scenario "dépot d'un dossier" do
click_on 'Commencer la démarche'
choose 'M.'
fill_in('individual_prenom', with: 'prenom')
fill_in('individual_nom', with: 'nom')
click_on 'Continuer'
expect(page).to be_accessible.skipping :'aria-input-field-name', :'heading-order', :label
end
end
context "logged in, depot d'un dossier entreprise" do
let(:procedure) { create(:procedure, :with_type_de_champ, :with_all_champs, :with_service, :published) }
before do
login_as litteraire_user, scope: :user
visit commencer_path(path: procedure.reload.path)
end
scenario "écran identification de l'entreprise" do
click_on 'Commencer la démarche'
expect(page).to be_accessible.skipping :label
end
end
context "logged in, avec des dossiers dossiers déposés" do
let(:dossier) { create(:dossier, procedure: procedure, user: litteraire_user) }
before do
login_as litteraire_user, scope: :user
end
scenario 'liste des dossiers' do
visit dossiers_path
expect(page).to be_accessible
end
scenario 'dossier' do
visit dossier_path(dossier)
expect(page).to be_accessible.skipping :'heading-order', :label, :'aria-input-field-name'
end
scenario 'merci' do
visit merci_dossier_path(dossier)
expect(page).to be_accessible
end
scenario 'demande' do
visit demande_dossier_path(dossier)
expect(page).to be_accessible
end
scenario 'messagerie' do
visit messagerie_dossier_path(dossier)
expect(page).to be_accessible
end
scenario 'modifier' do
visit modifier_dossier_path(dossier)
expect(page).to be_accessible.skipping :'aria-input-field-name', :'heading-order', :label
end
scenario 'brouillon' do
visit brouillon_dossier_path(dossier)
expect(page).to be_accessible.skipping :'aria-input-field-name', :'heading-order', :label
end
end
end

View file

@ -5,7 +5,7 @@ feature 'As an instructeur', js: true do
before do before do
login_as administrateur.user, scope: :user login_as administrateur.user, scope: :user
visit admin_procedure_assigns_path(procedure) visit admin_instructeurs_path
fill_in :instructeur_email, with: instructeur_email fill_in :instructeur_email, with: instructeur_email

View file

@ -135,7 +135,7 @@ feature 'As an administrateur I can edit types de champ', js: true do
it "Add dropdown champ" do it "Add dropdown champ" do
add_champ add_champ
select('Menu déroulant', from: 'champ-0-type_champ') select('Choix parmi une liste', from: 'champ-0-type_champ')
fill_in 'champ-0-libelle', with: 'Libellé de champ menu déroulant', fill_options: { clear: :backspace } fill_in 'champ-0-libelle', with: 'Libellé de champ menu déroulant', fill_options: { clear: :backspace }
fill_in 'champ-0-drop_down_list_value', with: 'Un menu', fill_options: { clear: :backspace } fill_in 'champ-0-drop_down_list_value', with: 'Un menu', fill_options: { clear: :backspace }

View file

@ -32,14 +32,14 @@ feature 'The routing', js: true do
# add victor to littéraire groupe # add victor to littéraire groupe
find('input.select2-search__field').send_keys('victor@inst.com', :enter) find('input.select2-search__field').send_keys('victor@inst.com', :enter)
perform_enqueued_jobs { click_on 'Affecter' } perform_enqueued_jobs { click_on 'Affecter' }
expect(page).to have_text("Linstructeur victor@inst.com a été affecté") expect(page).to have_text("Les instructeurs ont bien été affectés à la démarche")
victor = User.find_by(email: 'victor@inst.com').instructeur victor = User.find_by(email: 'victor@inst.com').instructeur
# add superwoman to littéraire groupe # add superwoman to littéraire groupe
find('input.select2-search__field').send_keys('superwoman@inst.com', :enter) find('input.select2-search__field').send_keys('superwoman@inst.com', :enter)
perform_enqueued_jobs { click_on 'Affecter' } perform_enqueued_jobs { click_on 'Affecter' }
expect(page).to have_text("Linstructeur superwoman@inst.com a été affecté") expect(page).to have_text("Les instructeurs ont bien été affectés à la démarche")
superwoman = User.find_by(email: 'superwoman@inst.com').instructeur superwoman = User.find_by(email: 'superwoman@inst.com').instructeur

View file

@ -1,13 +1,4 @@
RSpec.describe AdministrationMailer, type: :mailer do RSpec.describe AdministrationMailer, type: :mailer do
describe '#new_admin_email' do
let(:admin) { create(:administrateur) }
let(:administration) { create(:administration) }
subject { described_class.new_admin_email(admin, administration) }
it { expect(subject.subject).not_to be_empty }
end
describe '#invite_admin' do describe '#invite_admin' do
let(:admin) { create(:administrateur) } let(:admin) { create(:administrateur) }
let(:token) { "Toc toc toc" } let(:token) { "Toc toc toc" }

View file

@ -19,11 +19,6 @@ class AdministrationMailerPreview < ActionMailer::Preview
AdministrationMailer.refuse_admin('bad_admin@pipo.com') AdministrationMailer.refuse_admin('bad_admin@pipo.com')
end end
def new_admin
administration = Administration.new(email: 'superadmin@demarches-simplifiees.fr')
AdministrationMailer.new_admin_email(administrateur, administration)
end
def dossier_expiration_summary def dossier_expiration_summary
expiring_dossiers = [Dossier.new(id: 100, procedure: procedure_1)] expiring_dossiers = [Dossier.new(id: 100, procedure: procedure_1)]
expired_dossiers = [Dossier.new(id: 100, procedure: procedure_2)] expired_dossiers = [Dossier.new(id: 100, procedure: procedure_2)]

View file

@ -26,6 +26,7 @@ require 'webmock/rspec'
require 'shoulda-matchers' require 'shoulda-matchers'
require 'devise' require 'devise'
require 'factory_bot' require 'factory_bot'
require 'axe/rspec'
require 'selenium/webdriver' require 'selenium/webdriver'
Capybara.javascript_driver = :headless_chrome Capybara.javascript_driver = :headless_chrome

View file

@ -1,59 +0,0 @@
describe 'admin/assigns/show.html.haml', type: :view do
let(:admin) { create(:administrateur) }
let(:procedure) { create :procedure, administrateur: admin }
let(:assign_instructeurs) { procedure.defaut_groupe_instructeur.instructeurs }
let(:not_assign_instructeurs) { admin.instructeurs.where.not(id: assign_instructeurs.ids) }
before do
assign(:procedure, procedure)
assign(:instructeur, create(:instructeur))
assign(:instructeurs_assign, (smart_listing_create :instructeurs_assign,
assign_instructeurs,
partial: "admin/assigns/list_assign",
array: true))
assign(:instructeurs_not_assign, (smart_listing_create :instructeurs_not_assign,
not_assign_instructeurs,
partial: "admin/assigns/list_not_assign",
array: true))
end
context 'when admin have none instructeur ' do
before do
render
end
it { expect(rendered).to have_content('Aucun de disponible') }
context 'when administrateur have none instructeur assign' do
it { expect(rendered).to have_content('Aucun d\'affecté') }
end
end
context 'when administrateur have two instructeur' do
let!(:instructeur_1) { create :instructeur, email: 'plop@plop.com', administrateurs: [admin] }
let!(:instructeur_2) { create :instructeur, email: 'plip@plop.com', administrateurs: [admin] }
before do
not_assign_instructeurs.reload
assign_instructeurs.reload
assign(:instructeurs_assign, (smart_listing_create :instructeurs_assign,
assign_instructeurs,
partial: "admin/assigns/list_assign",
array: true))
assign(:instructeurs_not_assign, (smart_listing_create :instructeurs_not_assign,
not_assign_instructeurs,
partial: "admin/assigns/list_not_assign",
array: true))
render
end
it { expect(rendered).to have_content(instructeur_1.email) }
it { expect(rendered).to have_content(instructeur_2.email) }
end
end