Merge branch 'develop' into staging

This commit is contained in:
Xavier J 2016-10-24 13:36:59 +02:00
commit 1a184528fb
43 changed files with 761 additions and 185 deletions

View file

@ -63,4 +63,11 @@ function toggle_header_section_composents() {
}
});
});
$.each($("a.mask_section_button"), function (index, e) {
if (index != 0) {
$(e).click();
$(e).html('Afficher la section <i class="fa fa-chevron-down" />')
}
});
}

View file

@ -21,28 +21,30 @@ class Admin::GestionnairesController < AdminController
assign_gestionnaire!
end
return redirect_to admin_procedure_accompagnateurs_path(procedure_id: procedure_id) unless procedure_id.nil?
if procedure_id
redirect_to admin_procedure_accompagnateurs_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
def create_gestionnaire_params
params.require(:gestionnaire).permit(:email)
.merge(password: SecureRandom.hex(5))
.merge(administrateurs: [current_administrateur])
end
private
def new_gestionnaire!
@gestionnaire = Gestionnaire.create(create_gestionnaire_params)
attributes = params.require(:gestionnaire).permit(:email)
.merge(password: SecureRandom.hex(5))
@gestionnaire = Gestionnaire.create(attributes.merge(
administrateurs: [current_administrateur]
))
if @gestionnaire.errors.messages.empty?
User.create(attributes) if Features.unified_login
flash.notice = 'Accompagnateur ajouté'
GestionnaireMailer.new_gestionnaire(@gestionnaire.email, @gestionnaire.password).deliver_now!
GestionnaireMailer.new_assignement(@gestionnaire.email, current_administrateur.email).deliver_now!

View file

@ -1,4 +1,6 @@
class Gestionnaires::PasswordsController < Devise::PasswordsController
after_action :try_to_authenticate_user, only: %i(update)
# GET /resource/password/new
# def new
# super
@ -29,4 +31,11 @@ class Gestionnaires::PasswordsController < Devise::PasswordsController
# def after_sending_reset_password_instructions_path_for(resource_name)
# super(resource_name)
# end
def try_to_authenticate_user
if gestionnaire_signed_in?
user = User.find_by(email: current_gestionnaire.email)
sign_in user if user
end
end
end

View file

@ -1,4 +1,6 @@
class Users::PasswordsController < Devise::PasswordsController
after_action :try_to_authenticate_gestionnaire, only: %i(update)
# GET /resource/password/new
# def new
# super
@ -29,4 +31,11 @@ class Users::PasswordsController < Devise::PasswordsController
# def after_sending_reset_password_instructions_path_for(resource_name)
# super(resource_name)
# end
def try_to_authenticate_gestionnaire
if user_signed_in?
gestionnaire = Gestionnaire.find_by(email: current_user.email)
sign_in gestionnaire if gestionnaire
end
end
end

View file

@ -22,29 +22,47 @@ class Users::SessionsController < Sessions::SessionsController
#POST /resource/sign_in
def create
super
try_to_authenticate(User)
try_to_authenticate(Gestionnaire) if Features.unified_login
if user_signed_in?
current_user.update_attributes(loged_in_with_france_connect: '')
end
if user_signed_in?
redirect_to after_sign_in_path_for(:user)
elsif gestionnaire_signed_in?
redirect_to backoffice_path
else
new
render :new, status: 401
end
end
# DELETE /resource/sign_out
def destroy
if gestionnaire_signed_in?
sign_out :gestionnaire
end
if user_signed_in?
connected_with_france_connect = current_user.loged_in_with_france_connect
current_user.update_attributes(loged_in_with_france_connect: '')
signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
set_flash_message :notice, :signed_out if signed_out && is_flashing_format?
yield if block_given?
sign_out :user
if connected_with_france_connect == 'entreprise'
redirect_to FRANCE_CONNECT.entreprise_logout_endpoint
return
elsif connected_with_france_connect == 'particulier'
redirect_to FRANCE_CONNECT.particulier_logout_endpoint
else
respond_to_on_destroy
return
end
end
respond_to_on_destroy
end
def no_procedure
session['user_return_to'] = nil
redirect_to new_user_session_path
@ -62,4 +80,13 @@ class Users::SessionsController < Sessions::SessionsController
NumberService.to_number session["user_return_to"].split("?procedure_id=").second
end
def try_to_authenticate(klass)
if resource = klass.find_for_database_authentication(email: params[:user][:email])
if resource.valid_password?(params[:user][:password])
sign_in resource
set_flash_message :notice, :signed_in
end
end
end
end

View file

@ -35,6 +35,12 @@ class DossiersListFacades
@list_table_columns ||= @current_devise_profil.preference_list_dossiers.where(procedure: @procedure).order(:id)
end
def active_filter? preference
return true if @procedure.nil? || preference.table != 'champs' || (preference.table == 'champs' && !preference.filter.blank?)
preference_list_dossiers_filter.where(table: :champs).where.not(filter: '').size == 0
end
def brouillon_class
(@liste == 'brouillon' ? 'active' : '')
end
@ -47,6 +53,10 @@ class DossiersListFacades
(@liste == 'a_traiter' ? 'active' : '')
end
def en_construction_class
(@liste == 'a_traiter' ? 'active' : '')
end
def en_attente_class
(@liste == 'en_attente' ? 'active' : '')
end
@ -92,13 +102,15 @@ class DossiersListFacades
end
def a_traiter_total
return service.waiting_for_gestionnaire.count if gestionnaire?
service.waiting_for_user.count if user?
service.waiting_for_gestionnaire.count
end
def en_construction_total
service.en_construction.count
end
def en_attente_total
return service.waiting_for_user.count if gestionnaire?
service.waiting_for_gestionnaire.count if user?
service.waiting_for_user.count
end
def valides_total
@ -141,6 +153,10 @@ class DossiersListFacades
base_url 'a_traiter'
end
def en_construction_url
base_url 'a_traiter'
end
def en_attente_url
base_url 'en_attente'
end

View file

@ -39,7 +39,7 @@ class Champ < ActiveRecord::Base
end
def self.departements
JSON.parse(Carto::GeoAPI::Driver.departements).inject([]){|acc, liste| acc.push(liste['code'] + ' - ' + liste['nom']) }
JSON.parse(Carto::GeoAPI::Driver.departements).inject([]){|acc, liste| acc.push(liste['code'] + ' - ' + liste['nom']) }.push('99 - Étranger')
end
def self.pays

View file

@ -47,7 +47,7 @@ class Dossier < ActiveRecord::Base
NOUVEAUX = %w(initiated)
WAITING_FOR_GESTIONNAIRE = %w(updated)
WAITING_FOR_USER = %w(replied validated)
WAITING_FOR_USER_WITHOUT_VALIDATED = %w(replied)
EN_CONSTRUCTION = %w(initiated updated replied)
VALIDES = %w(validated)
DEPOSES = %w(submitted)
EN_INSTRUCTION = %w(submitted received)
@ -185,8 +185,8 @@ class Dossier < ActiveRecord::Base
WAITING_FOR_USER.include?(state)
end
def waiting_for_user_without_validated?
WAITING_FOR_USER_WITHOUT_VALIDATED.include?(state)
def en_construction?
EN_CONSTRUCTION.include?(state)
end
def deposes?
@ -225,8 +225,8 @@ class Dossier < ActiveRecord::Base
where(state: WAITING_FOR_USER, archived: false).order("updated_at #{order}")
end
def self.waiting_for_user_without_validated order = 'ASC'
where(state: WAITING_FOR_USER_WITHOUT_VALIDATED, archived: false).order("updated_at #{order}")
def self.en_construction order = 'ASC'
where(state: EN_CONSTRUCTION, archived: false).order("updated_at #{order}")
end
def self.valides order = 'ASC'

View file

@ -14,6 +14,7 @@ class Gestionnaire < ActiveRecord::Base
after_create :build_default_preferences_list_dossier
after_create :build_default_preferences_smart_listing_page
after_update :sync_credentials, if: -> { Features.unified_login }
def dossiers_follow
dossiers.joins(:follows).where("follows.gestionnaire_id = #{id}")
@ -84,4 +85,16 @@ class Gestionnaire < ActiveRecord::Base
couples.include?({table: table, column: column})
end
def sync_credentials
if email_changed? || encrypted_password_changed?
user = User.find_by(email: email_was)
if user
return user.update_columns(
email: email,
encrypted_password: encrypted_password)
end
end
true
end
end

View file

@ -23,7 +23,8 @@ class PreferenceListDossier < ActiveRecord::Base
}
columns = columns.merge({
champs: columns_champs_procedure(procedure_id)
champs: columns_champs_procedure(procedure_id),
champs_private: columns_champs_private_procedure(procedure_id)
}) unless procedure_id.nil?
columns
@ -103,6 +104,17 @@ class PreferenceListDossier < ActiveRecord::Base
end
end
def self.columns_champs_private_procedure procedure_id
table = 'champs_private'
Procedure.find(procedure_id).types_de_champ_private.inject({}) do |acc, type_de_champ|
acc = acc.merge({
"type_de_champ_private_#{type_de_champ.id}" => create_column(type_de_champ.libelle, table, type_de_champ.id, 'value', 2)
}) if type_de_champ.field_for_list?
acc
end
end
def self.create_column libelle, table, attr, attr_decorate, bootstrap_lg
{
libelle: libelle,

View file

@ -15,6 +15,7 @@ class User < ActiveRecord::Base
delegate :given_name, :family_name, :email_france_connect, :gender, :birthdate, :birthplace, :france_connect_particulier_id, to: :france_connect_information
accepts_nested_attributes_for :france_connect_information
after_update :sync_credentials, if: -> { Features.unified_login }
def self.find_for_france_connect email, siret
user = User.find_by_email(email)
@ -33,4 +34,18 @@ class User < ActiveRecord::Base
def invite? dossier_id
invites.pluck(:dossier_id).include?(dossier_id.to_i)
end
private
def sync_credentials
if email_changed? || encrypted_password_changed?
gestionnaire = Gestionnaire.find_by(email: email_was)
if gestionnaire
return gestionnaire.update_columns(
email: email,
encrypted_password: encrypted_password)
end
end
true
end
end

View file

@ -44,6 +44,7 @@ class DossiersListGestionnaireService
def filter_dossiers
@filter_dossiers ||= @procedure.nil? ? @current_devise_profil.dossiers.joins(joins_filter).where(where_filter) : @procedure.dossiers.joins(joins_filter).where(where_filter)
@filter_dossiers.uniq
end
def filter_procedure_reset!
@ -105,9 +106,10 @@ class DossiersListGestionnaireService
reset_sort!
@current_devise_profil.preference_list_dossiers
preference = @current_devise_profil.preference_list_dossiers
.find_by(table: table, attr: attr, procedure: @procedure)
.update order: order
preference.update order: order unless (preference.nil?)
end
def reset_sort!
@ -119,7 +121,7 @@ class DossiersListGestionnaireService
def joins_filter
filter_preference_list.inject([]) do |acc, preference|
acc.push(preference.table.to_sym) unless preference.table.blank?
acc.push(preference.table.to_sym) unless preference.table.blank? || preference.filter.blank?
acc
end
end
@ -127,12 +129,21 @@ class DossiersListGestionnaireService
def where_filter
filter_preference_list.inject('') do |acc, preference|
unless preference.filter.blank?
filter = preference.filter.gsub('*', '%')
filter = preference.filter.gsub('*', '%').gsub("'", "''")
filter = "%"+filter+"%" unless filter.include? '%'
value = preference.table_with_s_attr
if preference.table_attr.include?('champs')
value = 'champs.value'
acc += (acc.to_s.empty? ? ''.to_s : " AND ") +
'champs.type_de_champ_id = ' + preference.attr
end
acc += (acc.to_s.empty? ? ''.to_s : " AND ") +
"CAST(" +
preference.table_with_s_attr +
value +
" as TEXT)" +
" LIKE " +
"'" +
@ -152,7 +163,7 @@ class DossiersListGestionnaireService
@current_devise_profil.preference_list_dossiers
.find_by(table: table, attr: attr, procedure: @procedure)
.update filter: filter
.update filter: filter.strip
end
private

View file

@ -6,9 +6,7 @@ class DossiersListUserService
def dossiers_to_display
{'brouillon' => brouillon,
'nouveaux' => nouveaux,
'a_traiter' => waiting_for_user,
'en_attente' => waiting_for_gestionnaire,
'a_traiter' => en_construction,
'valides' => valides,
'en_instruction' => en_instruction,
'termine' => termine,
@ -16,23 +14,15 @@ class DossiersListUserService
end
def self.dossiers_liste_libelle
['brouillon', 'nouveaux', 'a_traiter', 'en_attente', 'valides', 'en_instruction', 'termine', 'invite']
['brouillon', 'a_traiter', 'valides', 'en_instruction', 'termine', 'invite']
end
def brouillon
@brouillon ||= @current_devise_profil.dossiers.brouillon
end
def nouveaux
@nouveaux ||= @current_devise_profil.dossiers.nouveaux
end
def waiting_for_gestionnaire
@waiting_for_gestionnaire ||= @current_devise_profil.dossiers.waiting_for_gestionnaire
end
def waiting_for_user
@waiting_for_user ||= @current_devise_profil.dossiers.waiting_for_user_without_validated
def en_construction
@en_construction ||= @current_devise_profil.dossiers.en_construction
end
def invite

View file

@ -2,10 +2,11 @@
%thead
- @dossiers_list_facade.preference_list_dossiers_filter.each do |preference|
%th{class: "col-md-#{preference.bootstrap_lg} col-lg-#{preference.bootstrap_lg}"}
- if preference.table == 'champs'
- if preference.table.to_s.include? 'champs'
= preference.libelle
-else
= smart_listing.sortable preference.libelle, preference.table_attr
- if @dossiers_list_facade.active_filter? preference
%i.filter.fa.fa-filter{style: "cursor: pointer; margin-left:3px; font-size: 1.1em; color:#{(preference.filter.blank? ? 'grey' : 'orange')}", id: "filter_"+preference.table_attr.sub('.', '_')}
= render partial: 'backoffice/dossiers/filter_framed', locals:{preference: preference, filter_framed_id: "framed_filter_"+preference.table_attr.sub('.', '_')}
@ -21,6 +22,8 @@
- value = dossier.decorate.public_send(preference.attr_decorate)
- elsif preference.table == 'champs'
- value = dossier.champs.find_by_type_de_champ_id(preference.attr).value
- elsif preference.table == 'champs_private'
- value = dossier.champs_private.find_by_type_de_champ_id(preference.attr).value
- else
- begin
- value = dossier.public_send(preference.table).decorate.public_send(preference.attr_decorate)

View file

@ -1,6 +1,3 @@
=link_to 'Tous mes dossiers en CSV', backoffice_download_dossiers_tps_path, {class: 'btn btn-success btn-sm', style: 'float: right; margin-right: 4%; margin-top: 7px'}
%h1 Gestion des dossiers
#filter_by_procedure{style:'margin-left: 5%'}
%select{onchange: 'location = this.value', style:'margin-top: 10px; margin-bottom: 10px', id: 'filter_by_procedure_select'}
%option{value: backoffice_dossiers_path}

View file

@ -23,7 +23,7 @@
%table
- PreferenceListDossier.available_columns_for(@dossiers_list_facade.procedure_id).each_with_index do |tables, index|
- if index%2 == 0 || tables.first == :champs
- if index%2 == 0 || tables.first.to_s.include?('champs')
%tr
%td.col-sm-5.col-md-5.col-lg-5{style: 'vertical-align: top', colspan: (tables.first == :champs ? 2 : 1)}

View file

@ -1,6 +1,11 @@
#backoffice_index
#pref_list_menu
= render partial: 'backoffice/dossiers/pref_list'
=link_to 'Tous mes dossiers en CSV', backoffice_download_dossiers_tps_path, {class: 'btn btn-success btn-sm', style: 'float: right; margin-right: 4%; margin-top: 7px'}
%h1 Gestion des dossiers
-unless Features.opensimplif
= render partial: 'backoffice/dossiers/onglets'
= smart_listing_render :dossiers

View file

@ -93,22 +93,22 @@
-if gestionnaire_signed_in?
-if !@facade.dossier.read_only?
= form_tag(url_for({controller: 'backoffice/dossiers', action: :valid, dossier_id: @facade.dossier.id}), class: 'form-inline', method: 'POST') do
%button#action_button.btn.btn-success
= 'Valider le dossier'
%button.action_button.btn.btn-success{'data-toggle' => :tooltip, title: 'En cliquant ici, vous figez le dossier et autorisez le dépôt du dossier pour instruction.'}
= 'Déclarer complet'
-elsif @facade.dossier.submitted?
= form_tag(url_for({controller: 'backoffice/dossiers', action: :receive, dossier_id: @facade.dossier.id}), class: 'form-inline', method: 'POST') do
%button#action_button.btn.btn-success
%button.action_button.btn.btn-success
= 'Notifier de la bonne réception'
-elsif @facade.dossier.received?
= form_tag(url_for({controller: 'backoffice/dossiers', action: :close, dossier_id: @facade.dossier.id}), class: 'form-inline action_button', method: 'POST', style: 'display:inline', 'data-toggle' => :tooltip, title: 'Accepter') do
%button#action_button.btn.btn-success
%button.action_button.btn.btn-success
%i.fa.fa-check
= form_tag(url_for({controller: 'backoffice/dossiers', action: :refuse, dossier_id: @facade.dossier.id}), class: 'form-inline action_button', method: 'POST', style: 'display:inline', 'data-toggle' => :tooltip, title: 'Refuser') do
%button#action_button.btn.btn-danger
%button.action_button.btn.btn-danger
%i.fa.fa-times
= form_tag(url_for({controller: 'backoffice/dossiers', action: :without_continuation, dossier_id: @facade.dossier.id}), class: 'form-inline action_button', method: 'POST', style: 'display:inline', 'data-toggle' => :tooltip, title: 'Classer sans suite') do
%button#action_button.btn.btn-warning
%button.action_button.btn.btn-warning
%i.fa.fa-circle-o

View file

@ -7,25 +7,31 @@
%a{href: '/'}
= image_tag('logo-tps.png', class: 'logo')
- if gestionnaire_signed_in?
%a{href: (current_gestionnaire.procedure_filter.blank? ? '/' : backoffice_dossiers_procedure_path(current_gestionnaire.procedure_filter)), class: 'btn btn-md'}
- if gestionnaire_signed_in? && user_signed_in?
%a{href: (current_gestionnaire.procedure_filter.blank? ? backoffice_dossiers_path : backoffice_dossiers_procedure_path(current_gestionnaire.procedure_filter)), class: 'btn btn-md'}
Dossiers
%a{href: users_dossiers_path, class: 'btn btn-md'}
Mes Dossiers
- elsif gestionnaire_signed_in?
%a{href: (current_gestionnaire.procedure_filter.blank? ? backoffice_dossiers_path : backoffice_dossiers_procedure_path(current_gestionnaire.procedure_filter)), class: 'btn btn-md'}
Mes Dossiers
- elsif user_signed_in?
%a{href: '/', class: 'btn btn-md'}
%a{href: users_dossiers_path, class: 'btn btn-md'}
Mes Dossiers
- elsif administrateur_signed_in?
%a{href: '/', class: 'btn btn-md'}
%a{href: admin_procedures_path, class: 'btn btn-md'}
Mes Procédures
#sign_out
-if gestionnaire_signed_in?
-if user_signed_in?
= render partial: 'users/login_banner'
-elsif gestionnaire_signed_in?
= render partial: 'gestionnaires/login_banner'
-elsif administrateur_signed_in?
= render partial: 'administrateurs/login_banner'
- elsif user_signed_in?
= render partial: 'users/login_banner'
-else
= link_to "Utilisateur", '/users/sign_in', method: :get, :class => 'btn btn-md'
-unless Features.unified_login
= link_to "Accompagnateur", '/gestionnaires/sign_in', method: :get, :class => 'btn btn-md'
= link_to "Administrateur", '/administrateurs/sign_in', method: :get, :class => 'btn btn-md'

View file

@ -1,6 +1,6 @@
Bonjour <%= @user.email %>
Votre dossier N°<%=@dossier.id%> a été validé par votre accompagnateur.
Votre dossier N°<%=@dossier.id%> est prêt à être déposé pour instruction.
Afin de finaliser son dépôt, merci de vous rendre sur <%=users_dossier_recapitulatif_url(dossier_id: @dossier.id)%>

View file

@ -1,6 +1,6 @@
%h3.text-primary.page-header
=champ.libelle
%span.mask_section{style:'float: right'}
%a.mask_section_button.btn.btn-xs.btn-default{id: "mask_button_"+champ.id.to_s}
%a.mask_section_button.btn.btn-xs.btn-info{id: "mask_button_"+champ.id.to_s}
Masquer la section
%i.fa.fa-chevron-up

View file

@ -1,5 +1,3 @@
%h1 Mes dossiers
%br
#onglets
%ul.nav.nav-tabs
@ -10,26 +8,12 @@
.badge.progress-bar-default
= @dossiers_list_facade.brouillon_total
%li{ class: @dossiers_list_facade.nouveaux_class }
%a{:href => "#{url_for users_dossiers_path(liste: 'nouveaux')}", 'data-toggle' => :tooltip, title: 'Les nouveaux dossiers qui n\'ont pas encore été vus par votre accompagnateur.'}
%h5.text-info
= "Nouveaux"
.badge.progress-bar-info
= @dossiers_list_facade.nouveaux_total
%li{ class: @dossiers_list_facade.a_traiter_class }
%li{ class: @dossiers_list_facade.en_construction_class }
%a{:href => "#{url_for users_dossiers_path(liste: 'a_traiter')}", 'data-toggle' => :tooltip, title: 'Les dossiers qui requièrent une action de votre part.'}
%h5.text-danger
= "Action requise"
= "En construction"
.badge.progress-bar-danger
= @dossiers_list_facade.a_traiter_total
%li{ class: @dossiers_list_facade.en_attente_class }
%a{:href => "#{url_for users_dossiers_path(liste: 'en_attente')}", 'data-toggle' => :tooltip, title: 'Les dossiers en cours de relecture par votre accompagnateur.'}
%h5.text-default
="Etude en cours"
.badge.progress-bar-default
= @dossiers_list_facade.en_attente_total
= @dossiers_list_facade.en_construction_total
%li{ class: @dossiers_list_facade.valides_class }
%a{:href => "#{url_for users_dossiers_path(liste: 'valides')}", 'data-toggle' => :tooltip, title: 'Les dossiers relus par votre accompagnateur pouvant être déposés pour examen.'}

View file

@ -1,4 +1,7 @@
#users_index
%h1 Mes dossiers
-unless Features.opensimplif
= render partial: 'onglets'
= smart_listing_render :dossiers

View file

@ -1 +1,3 @@
remote_storage: true
unified_login: false
opensimplif: false

View file

@ -147,6 +147,27 @@ describe Admin::GestionnairesController, type: :controller do
}
end
end
context 'unified login' do
before do
allow(Features).to receive(:unified_login).and_return(true)
subject
end
it "creates associated user with same credentials" do
gestionnaire = controller.instance_variable_get(:@gestionnaire)
user = User.find_by(email: gestionnaire.email)
expect(user.valid_password?(gestionnaire.password)).to be(true)
end
context 'invalid email' do
let(:email) { 'fail' }
it "won't create associated user" do
expect(User.where(email: email).exists?).to be(false)
end
end
end
end
describe 'DELETE #destroy' do

View file

@ -0,0 +1,30 @@
require "spec_helper"
describe Gestionnaires::PasswordsController, type: :controller do
before do
@request.env["devise.mapping"] = Devise.mappings[:gestionnaire]
end
describe "update" do
context "unified login" do
let(:gestionnaire) { create(:gestionnaire, email: 'unique@plop.com', password: 'password') }
let(:user) { create(:user, email: 'unique@plop.com', password: 'password') }
before do
allow(Features).to receive(:unified_login).and_return(true)
@token = gestionnaire.send(:set_reset_password_token)
user # make sure it's created
end
it "also signs user in" do
put :update, gestionnaire: {
reset_password_token: @token,
password: "supersecret",
password_confirmation: "supersecret",
}
expect(subject.current_gestionnaire).to eq(gestionnaire)
expect(subject.current_user).to eq(user)
end
end
end
end

View file

@ -40,4 +40,18 @@ describe RootController, type: :controller do
it { expect(response.body).to have_css('#landing') }
end
context "unified login" do
render_views
before do
allow(Features).to receive(:unified_login).and_return(true)
subject
end
it "won't have gestionnaire login link" do
expect(response.body).to have_css("a[href='#{new_user_session_path}']")
expect(response.body).to_not have_css("a[href='#{new_gestionnaire_session_path}']")
end
end
end

View file

@ -418,14 +418,40 @@ describe Users::DossiersController, type: :controller do
end
end
describe 'GET #en_attente' do
describe 'GET #valides' do
context 'when user is connected' do
before do
sign_in user
end
it 'returns http success' do
get :index, liste: :en_attente
get :index, liste: :valides
expect(response).to have_http_status(200)
end
end
end
describe 'GET #en_instruction' do
context 'when user is connected' do
before do
sign_in user
end
it 'returns http success' do
get :index, liste: :en_instruction
expect(response).to have_http_status(200)
end
end
end
describe 'GET #brouillon' do
context 'when user is connected' do
before do
sign_in user
end
it 'returns http success' do
get :index, liste: :brouillon
expect(response).to have_http_status(200)
end
end

View file

@ -0,0 +1,30 @@
require "spec_helper"
describe Users::PasswordsController, type: :controller do
before do
@request.env["devise.mapping"] = Devise.mappings[:user]
end
describe "update" do
context "unified login" do
let(:user) { create(:user, email: 'unique@plop.com', password: 'password') }
let(:gestionnaire) { create(:gestionnaire, email: 'unique@plop.com', password: 'password') }
before do
allow(Features).to receive(:unified_login).and_return(true)
@token = user.send(:set_reset_password_token)
gestionnaire # make sure it's created
end
it "also signs gestionnaire in" do
put :update, user: {
reset_password_token: @token,
password: "supersecret",
password_confirmation: "supersecret",
}
expect(subject.current_user).to eq(user)
expect(subject.current_gestionnaire).to eq(gestionnaire)
end
end
end
end

View file

@ -33,6 +33,42 @@ describe Users::SessionsController, type: :controller do
it { is_expected.to be_falsey }
end
context "unified login" do
let(:user) { create(:user, email: 'unique@plop.com', password: 'password') }
let(:gestionnaire) { create(:gestionnaire, email: 'unique@plop.com', password: 'password') }
before { allow(Features).to receive(:unified_login).and_return(true) }
it 'signs user in' do
post :create, user: { email: user.email, password: user.password }
expect(@response.redirect?).to be(true)
expect(subject.current_user).to eq(user)
expect(subject.current_gestionnaire).to be(nil)
expect(user.reload.loged_in_with_france_connect).to be(nil)
end
it 'signs gestionnaire in' do
post :create, user: { email: gestionnaire.email, password: gestionnaire.password }
expect(@response.redirect?).to be(true)
expect(subject.current_user).to be(nil)
expect(subject.current_gestionnaire).to eq(gestionnaire)
end
it 'signs user + gestionnaire in' do
post :create, user: { email: user.email, password: gestionnaire.password }
expect(@response.redirect?).to be(true)
expect(subject.current_user).to eq(user)
expect(subject.current_gestionnaire).to eq(gestionnaire)
expect(user.reload.loged_in_with_france_connect).to be(nil)
end
it 'fails to sign in with bad credentials' do
post :create, user: { email: user.email, password: 'wrong_password' }
expect(@response.unauthorized?).to be(true)
expect(subject.current_user).to be(nil)
expect(subject.current_gestionnaire).to be(nil)
end
end
end
describe '.destroy' do
@ -66,6 +102,41 @@ describe Users::SessionsController, type: :controller do
expect(response).to redirect_to(root_path)
end
end
context "when associated gestionnaire" do
let(:user) { create(:user, email: 'unique@plop.com', password: 'password') }
let(:gestionnaire) { create(:gestionnaire, email: 'unique@plop.com', password: 'password') }
it 'signs user out' do
sign_in user
delete :destroy
expect(@response.redirect?).to be(true)
expect(subject.current_user).to be(nil)
end
it 'signs gestionnaire out' do
sign_in gestionnaire
delete :destroy
expect(@response.redirect?).to be(true)
expect(subject.current_gestionnaire).to be(nil)
end
it 'signs user + gestionnaire out' do
sign_in user
sign_in gestionnaire
delete :destroy
expect(@response.redirect?).to be(true)
expect(subject.current_user).to be(nil)
expect(subject.current_gestionnaire).to be(nil)
end
it 'signs user out from france connect' do
user.update_attributes(loged_in_with_france_connect: 'particulier')
sign_in user
delete :destroy
expect(@response.headers["Location"]).to eq(FRANCE_CONNECT.particulier_logout_endpoint)
end
end
end
describe '.new' do

View file

@ -6,22 +6,22 @@ describe DossiersListFacades do
let(:procedure) { create :procedure }
let(:procedure_2) { create :procedure, libelle: 'plop' }
let!(:preference) { create :preference_list_dossier,
gestionnaire: gestionnaire,
table: nil,
attr: 'state',
attr_decorate: 'display_state' }
let!(:preference_2) { create :preference_list_dossier,
gestionnaire: gestionnaire,
table: 'champs',
attr: 'state',
attr_decorate: 'display_state',
procedure_id: procedure.id }
before do
create :assign_to, procedure: procedure, gestionnaire: gestionnaire
create :assign_to, procedure: procedure_2, gestionnaire: gestionnaire
create :preference_list_dossier,
gestionnaire: gestionnaire,
table: nil,
attr: 'state',
attr_decorate: 'display_state'
create :preference_list_dossier,
gestionnaire: gestionnaire,
table: nil,
attr: 'state',
attr_decorate: 'display_state',
procedure_id: procedure.id
end
describe '#preference_list_dossiers_filter' do
@ -55,4 +55,80 @@ describe DossiersListFacades do
it { expect(subject.last[:libelle]).to eq procedure_2.libelle }
end
describe '#active_filter?' do
let(:table) { nil }
let(:filter) { nil }
let(:facade) { described_class.new gestionnaire, 'nouveaux', procedure_2 }
let!(:preference) { create :preference_list_dossier,
gestionnaire: gestionnaire,
table: table,
attr: 'state',
attr_decorate: 'display_state',
filter: filter,
procedure_id: procedure_id }
subject { facade.active_filter? preference }
context 'when gestionnaire does not have select a procedure' do
let(:procedure_2) { nil }
let(:procedure_id) { nil }
it { expect(preference.procedure).to be_nil }
it { is_expected.to be_truthy }
end
context 'when gestionnaire have select a procedure' do
let(:procedure_id) { procedure_2.id }
it { expect(preference.procedure).not_to be_nil }
context 'when preference is not a champs filter' do
let(:table) { 'entreprises' }
it { is_expected.to be_truthy }
end
context 'when gestionnaire have an existant filter with a champ' do
let(:table) { 'champs' }
let(:filter) { 'plop' }
context 'when the preference is the existant champ filter' do
it { is_expected.to be_truthy }
end
context 'when the preference is not the existant champ filter' do
let(:preference) { preference_2 }
before do
create :preference_list_dossier,
gestionnaire: gestionnaire,
table: 'champs',
attr: 'state',
attr_decorate: 'display_state',
filter: 'plop',
procedure_id: procedure_id
end
it { is_expected.to be_falsey }
end
end
context 'when gestionnaire does not have an existant filter with a champ' do
let(:table) { nil }
let(:filter) { 'plop' }
context 'when the preference is the existant preference filter' do
it { is_expected.to be_truthy }
end
context 'when the preference is not the existant preference filter' do
let(:preference) { preference_2 }
it { is_expected.to be_truthy }
end
end
end
end
end

View file

@ -89,4 +89,16 @@ feature 'on click on tabs button' do
end
end
end
context "OpenSimplif" do
before do
allow(Features).to receive(:opensimplif).and_return(true)
visit backoffice_dossiers_url
end
scenario "it hides the tabs" do
expect(page).to_not have_css('#filter_by_procedure')
expect(page).to_not have_css('#onglets')
end
end
end

View file

@ -22,21 +22,10 @@ feature 'on click on tabs button' do
end
context 'when user is logged in' do
context 'when he click on tabs nouveaux' do
before do
visit users_dossiers_url(liste: :nouveaux)
page.click_on 'Nouveaux 1'
end
scenario 'it redirect to users dossier termine' do
expect(page).to have_css('#users_index')
end
end
context 'when he click on tabs a traite' do
context 'when he click on tabs en construction' do
before do
visit users_dossiers_url(liste: :a_traiter)
page.click_on 'Action requise 1'
page.click_on 'En construction 3'
end
scenario 'it redirect to users dossier termine' do
@ -44,17 +33,6 @@ feature 'on click on tabs button' do
end
end
context 'when he click on tabs en attente' do
before do
visit users_dossiers_url(liste: :en_attente)
page.click_on 'Etude en cours 1'
end
scenario 'it redirect to users dossier en attente' do
expect(page).to have_css('#users_index')
end
end
context 'when he click on tabs a deposes' do
before do
visit users_dossiers_url(liste: :valides)
@ -99,4 +77,15 @@ feature 'on click on tabs button' do
end
end
end
context "OpenSimplif" do
before do
allow(Features).to receive(:opensimplif).and_return(true)
visit users_dossiers_url
end
scenario "it hides the tabs" do
expect(page).to_not have_css('#onglets')
end
end
end

View file

@ -0,0 +1,70 @@
---
http_interactions:
- request:
method: get
uri: https://geo.api.gouv.fr/departements?fields=nom
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Ruby
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Wed, 19 Oct 2016 09:31:34 GMT
Content-Type:
- application/json; charset=utf-8
Transfer-Encoding:
- chunked
Connection:
- keep-alive
Vary:
- Accept-Encoding
- Accept-Encoding
X-Powered-By:
- Express
Access-Control-Allow-Origin:
- "*"
Etag:
- W/"cc1-lXUcIlpPmDfvrGONl0WWsQ"
Strict-Transport-Security:
- max-age=15552000
Content-Encoding:
- gzip
body:
encoding: ASCII-8BIT
string: !binary |-
H4sIAAAAAAAAA22Wy27bMBBFfyXwJpsKqF96dOfYrZsibow4MFAUXTARGxOQ
xZYSjbpF/yfZ5w/0YyVlpDq0sxTmajg8vJzh1z+9Um9773oTVfbe9O51Lt3H
237v75suUpUSsQFjRaGkQXAYBH/IKspl9FHYWkZLo3eyvGeqEdStqIomhfsJ
CccnCRfCqFptA1VMlcmbx/sN10nCsCzL4O80CKvm8YE/Z4zaO4T6b4OQQ/ef
YD8guJN7o8G3T4YX2rpqHSgb3WyaZ7LuE+dUFDuRa8Dpk99UlLUoUAHJTTfC
yLJmgUT2Eo5e2CIN2U03POw+uU21Mc3jb65AcC5cSb/Flc275IPJsQGiVgjF
BRTT5tn5KD+/huMGBN0KHMnzidlqish7aqQNliDkmTa5fuAZDAh5pu0dDmBA
xjPTPG9ZOgm/t4YhQvWhSNbRlVYsmXA/qFJVdfMY5CDeuTDAOqQvD5fPCbRz
fQd2SG5zabCrIWnNlfuRzh4S18fmyQhb1MhLXJdF0W5trQqhgtUJ7rLMubEh
ubWxFzosnwQvqxDNkOw+WSNQHqldCbczbHxEbv44/MKh50fE5iWoaURuB+zH
CrJrY9GkLtzFVT8tE5FhKwPgEdFdaUYIzkV89SfnPiK4K/07JDciuYU/s1fY
j8hwIcqg147J0LUTnvqY8A6AjhVEuBB736m7wxsT30JaU2/a+ha6ks5pEBKg
E/K6j8lvoc2d2gi05jEhniYmvc9uUuxogDHpfXadBBWR2bViQTGJXQfAYgJb
inaYujEgFEwbE9nS7r1mFnaimNyWe9M8lc2Tn7X/vcd8rwzl7p9uRzE5Ium1
UW7SiIIXKybUC7ePmw2fGzGpel8cx8n1eEbGJHsw1UqEYzQh4UPwFVsnhL0S
3lzdbhNSXomdVgwGLbF97JxISHXpXjAgnpDkSvpLdzqHEyI8iLzzwwuWEOSX
nSxcLi5EjjNpf0Wr1sGUkOZKbznQUmK8dSt3eFKy86FXe09KiGuBaZeS4FrY
+yK4synprWWZO/ticfJbO/exZ6TkdrDHiYTU1rp6IJCUzL6EMzQlrFtp3LvU
N+uzXJ5dyOK7NmjOGeG9r6owU3bcGdur3h5zt88s8GDrk5Vr0XU0k+55AF0I
s/CpjoySBUCFk5yHTSkj07kVuSy0/cFiguvi0tfujRJMsSy4M3O7F8FmkmAW
irOb5smWiq/kLAnauNjrmi/YzF+Jb/8A5ygzwMEMAAA=
http_version:
recorded_at: Wed, 19 Oct 2016 09:31:33 GMT
recorded_with: VCR 3.0.1

View file

@ -18,7 +18,7 @@ RSpec.describe NotificationMailer, type: :mailer do
subject(:subject) { described_class.dossier_validated(dossier) }
it { expect(subject.body).to match("Votre dossier N°#{dossier.id} a été validé par votre accompagnateur.") }
it { expect(subject.body).to match("Votre dossier N°#{dossier.id} est prêt à être déposé pour instruction.") }
it { expect(subject.body).to include("Afin de finaliser son dépôt, merci de vous rendre sur #{users_dossier_recapitulatif_url(dossier_id: dossier.id)}") }
it { expect(subject.subject).to eq("Votre dossier TPS N°#{dossier.id} a été validé") }
end

View file

@ -35,4 +35,10 @@ shared_examples 'champ_spec' do
it { is_expected.to eq 'typeahead' }
end
end
describe '.departement', vcr: {cassette_name: 'call_geo_api_departements'} do
subject { Champ.departements }
it { expect(subject).to include '99 - Étranger' }
end
end

View file

@ -184,4 +184,19 @@ describe Gestionnaire, type: :model do
end
end
end
context 'unified login' do
before { allow(Features).to receive(:unified_login).and_return(true) }
it 'syncs credentials to associated user' do
gestionnaire = create(:gestionnaire)
user = create(:user, email: gestionnaire.email)
gestionnaire.update_attributes(email: 'whoami@plop.com', password: 'super secret')
user.reload
expect(user.email).to eq('whoami@plop.com')
expect(user.valid_password?('super secret')).to be(true)
end
end
end

View file

@ -296,7 +296,7 @@ describe PreferenceListDossier do
end
context 'when a procedure ID is pasted' do
let(:procedure) { (create :procedure, :with_type_de_champ) }
let(:procedure) { (create :procedure, :with_type_de_champ, :with_type_de_champ_private) }
let(:procedure_id) { procedure.id }
describe 'champs' do
@ -316,6 +316,24 @@ describe PreferenceListDossier do
it { expect(subject[:filter]).to be_nil }
end
end
describe 'champs private' do
subject { super()[:champs_private] }
it { expect(subject.size).to eq 1 }
describe 'first champs' do
subject { super()["type_de_champ_private_#{procedure.types_de_champ_private.first.id}"] }
it { expect(subject[:libelle]).to eq 'Description' }
it { expect(subject[:table]).to eq 'champs_private' }
it { expect(subject[:attr]).to eq procedure.types_de_champ_private.first.id }
it { expect(subject[:attr_decorate]).to eq 'value' }
it { expect(subject[:bootstrap_lg]).to eq 2 }
it { expect(subject[:order]).to be_nil }
it { expect(subject[:filter]).to be_nil }
end
end
end
end
end

View file

@ -72,4 +72,19 @@ describe User, type: :model do
it { is_expected.to be_falsey }
end
end
context 'unified login' do
before { allow(Features).to receive(:unified_login).and_return(true) }
it 'syncs credentials to associated gestionnaire' do
user = create(:user)
gestionnaire = create(:gestionnaire, email: user.email)
user.update_attributes(email: 'whoami@plop.com', password: 'super secret')
gestionnaire.reload
expect(gestionnaire.email).to eq('whoami@plop.com')
expect(gestionnaire.valid_password?('super secret')).to be(true)
end
end
end

View file

@ -125,6 +125,43 @@ describe DossiersListGestionnaireService do
end
end
describe '#join_filter' do
subject { DossiersListGestionnaireService.new(gestionnaire, liste, nil).joins_filter }
it { is_expected.to eq []}
context 'when a filter is fielded' do
before do
gestionnaire.preference_list_dossiers
.find_by(table: 'entreprise', attr: 'raison_sociale', procedure: nil)
.update_column :filter, 'plop'
end
it { is_expected.to eq [:entreprise] }
end
context 'when a filter is empty' do
before do
gestionnaire.preference_list_dossiers
.find_by(table: 'entreprise', attr: 'raison_sociale', procedure: nil)
.update_column :filter, ''
end
it { is_expected.to eq [] }
end
context 'when a filter is nil' do
before do
gestionnaire.preference_list_dossiers
.find_by(table: 'entreprise', attr: 'raison_sociale', procedure: nil)
.update_column :filter, nil
end
it { is_expected.to eq [] }
end
end
describe '#where_filter' do
before do
gestionnaire.preference_list_dossiers
@ -170,6 +207,41 @@ describe DossiersListGestionnaireService do
it { is_expected.to eq "CAST(dossiers.id as TEXT) LIKE '%23%' AND CAST(entreprises.raison_sociale as TEXT) LIKE 'plop%plip'" }
end
context "when filter containe the character <'> " do
before do
gestionnaire.preference_list_dossiers
.find_by(table: 'entreprise', attr: 'raison_sociale', procedure: nil)
.update_column :filter, "MCDONALD'S FRANCE"
end
it { is_expected.to eq "CAST(dossiers.id as TEXT) LIKE '%23%' AND CAST(entreprises.raison_sociale as TEXT) LIKE '%MCDONALD''S FRANCE%'" }
end
context "when filter is empty " do
before do
gestionnaire.preference_list_dossiers
.find_by(table: 'entreprise', attr: 'raison_sociale', procedure: nil)
.update_column :filter, ""
end
it { is_expected.to eq "CAST(dossiers.id as TEXT) LIKE '%23%'" }
end
context 'when preference list contain a champ' do
before do
create :preference_list_dossier,
gestionnaire: gestionnaire,
table: 'champs',
attr: '34',
attr_decorate: '',
filter: 'plop',
procedure_id: create(:procedure)
end
it { is_expected.to eq "CAST(dossiers.id as TEXT) LIKE '%23%' AND CAST(entreprises.raison_sociale as TEXT) LIKE '%plop%' AND champs.type_de_champ_id = 34 AND CAST(champs.value as TEXT) LIKE '%plop%'" }
end
end
describe '#default_page' do

View file

@ -75,6 +75,20 @@ module SmartListing
end
end
class Features
#def self.remote_storage
# true
#end
def self.unified_login
false
end
def self.opensimplif
false
end
end
WebMock.disable_net_connect!(allow_localhost: true)
RSpec.configure do |config|

View file

@ -59,9 +59,9 @@ describe 'backoffice/dossiers/show.html.haml', type: :view do
it { expect(rendered).to have_content('Nouveau') }
it 'button Valider le dossier is present' do
expect(rendered).to have_css('#action_button')
expect(rendered).to have_content('Valider le dossier')
it 'button Déclarer complet is present' do
expect(rendered).to have_css('.action_button')
expect(rendered).to have_content('Déclarer complet')
end
end
@ -74,9 +74,9 @@ describe 'backoffice/dossiers/show.html.haml', type: :view do
it { expect(rendered).to have_content('Répondu') }
it 'button Valider le dossier is present' do
expect(rendered).to have_css('#action_button')
expect(rendered).to have_content('Valider le dossier')
it 'button Déclarer complet is present' do
expect(rendered).to have_css('.action_button')
expect(rendered).to have_content('Déclarer complet')
end
end
@ -89,9 +89,9 @@ describe 'backoffice/dossiers/show.html.haml', type: :view do
it { expect(rendered).to have_content('Mis à jour') }
it 'button Valider le dossier is present' do
expect(rendered).to have_css('#action_button')
expect(rendered).to have_content('Valider le dossier')
it 'button Déclarer complet is present' do
expect(rendered).to have_css('.action_button')
expect(rendered).to have_content('Déclarer complet')
end
end
@ -104,9 +104,9 @@ describe 'backoffice/dossiers/show.html.haml', type: :view do
it { expect(rendered).to have_content('Figé') }
it 'button Valider le dossier is not present' do
expect(rendered).not_to have_css('#action_button')
expect(rendered).not_to have_content('Valider le dossier')
it 'button Déclarer complet is not present' do
expect(rendered).not_to have_css('.action_button')
expect(rendered).not_to have_content('Déclarer complet')
end
end
@ -120,11 +120,11 @@ describe 'backoffice/dossiers/show.html.haml', type: :view do
it { expect(rendered).to have_content('Déposé') }
it 'button notifier de la bonne réception is present' do
expect(rendered).to have_css('#action_button')
expect(rendered).to have_css('.action_button')
expect(rendered).to have_content('Notifier de la bonne réception')
end
it 'button Valider le dossier is not present' do
it 'button Déclarer complet is not present' do
expect(rendered).not_to have_content('Accepter le dossier')
end
end
@ -170,7 +170,7 @@ describe 'backoffice/dossiers/show.html.haml', type: :view do
it { expect(rendered).to have_content('Sans suite') }
it 'button Valider le dossier is not present' do
it 'button Déclarer complet is not present' do
expect(rendered).not_to have_css('.action_button[data-toggle="tooltip"][title="Accepter"]')
expect(rendered).not_to have_css('.action_button[data-toggle="tooltip"][title="Classer sans suite"]')
expect(rendered).not_to have_css('.action_button[data-toggle="tooltip"][title="Refuser"]')
@ -186,7 +186,7 @@ describe 'backoffice/dossiers/show.html.haml', type: :view do
it { expect(rendered).to have_content('Refusé') }
it 'button Valider le dossier is not present' do
it 'button Déclarer complet is not present' do
expect(rendered).not_to have_css('.action_button[data-toggle="tooltip"][title="Accepter"]')
expect(rendered).not_to have_css('.action_button[data-toggle="tooltip"][title="Classer sans suite"]')
expect(rendered).not_to have_css('.action_button[data-toggle="tooltip"][title="Refuser"]')

View file

@ -46,33 +46,19 @@ describe 'users/dossiers/index.html.haml', type: :view do
end
end
describe 'on tab nouveaux' do
let(:total_dossiers) { 1 }
let(:active_class) { '.active .text-info' }
let(:dossiers_to_display) { user.dossiers.nouveaux }
let(:liste) { 'nouveaux' }
describe 'on tab en construction' do
let(:total_dossiers) { 3 }
let(:active_class) { '.active .text-danger' }
let(:dossiers_to_display) { user.dossiers.en_construction }
let(:liste) { 'a_traiter' }
it_behaves_like 'check_tab_content' do
let(:decorate_dossier_at_check) { decorate_dossier_initiated }
end
end
describe 'on tab action requise' do
let(:total_dossiers) { 1 }
let(:active_class) { '.active .text-danger' }
let(:dossiers_to_display) { user.dossiers.waiting_for_user_without_validated }
let(:liste) { 'a_traiter' }
it_behaves_like 'check_tab_content' do
let(:decorate_dossier_at_check) { decorate_dossier_replied }
end
end
describe 'on tab etude en cours' do
let(:total_dossiers) { 1 }
let(:active_class) { '.active .text-default' }
let(:dossiers_to_display) { user.dossiers.waiting_for_gestionnaire }
let(:liste) { 'en_attente' }
it_behaves_like 'check_tab_content' do
let(:decorate_dossier_at_check) { decorate_dossier_updated }