commit
cfa88acf63
57 changed files with 459 additions and 477 deletions
|
@ -58,6 +58,10 @@ h5 span {
|
|||
.progress-bar-warning {
|
||||
background-color: #E4594F;
|
||||
}
|
||||
|
||||
.missing-steps {
|
||||
color: #FFA500;
|
||||
}
|
||||
}
|
||||
|
||||
.procedure-list-element:hover {
|
||||
|
|
|
@ -190,6 +190,12 @@
|
|||
}
|
||||
}
|
||||
|
||||
.lien-demarche {
|
||||
p.alert {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.button-navbar-action:hover {
|
||||
color: $light-blue;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ class Users::SessionsController < Sessions::SessionsController
|
|||
try_to_authenticate(Administrateur, remember_me)
|
||||
|
||||
if user_signed_in?
|
||||
current_user.update(loged_in_with_france_connect: '')
|
||||
current_user.update(loged_in_with_france_connect: nil)
|
||||
end
|
||||
|
||||
if gestionnaire_signed_in?
|
||||
|
@ -30,8 +30,8 @@ class Users::SessionsController < Sessions::SessionsController
|
|||
redirect_to after_sign_in_path_for(:user)
|
||||
else
|
||||
gestionnaire = current_gestionnaire
|
||||
login_token = gestionnaire.login_token!
|
||||
GestionnaireMailer.send_login_token(gestionnaire, login_token).deliver_later
|
||||
|
||||
send_login_token_or_bufferize(gestionnaire)
|
||||
|
||||
[:user, :gestionnaire, :administrateur].each { |role| sign_out(role) }
|
||||
|
||||
|
@ -103,6 +103,13 @@ class Users::SessionsController < Sessions::SessionsController
|
|||
|
||||
private
|
||||
|
||||
def send_login_token_or_bufferize(gestionnaire)
|
||||
if !gestionnaire.young_login_token?
|
||||
login_token = gestionnaire.login_token!
|
||||
GestionnaireMailer.send_login_token(gestionnaire, login_token).deliver_later
|
||||
end
|
||||
end
|
||||
|
||||
def error_procedure
|
||||
session["user_return_to"] = nil
|
||||
flash.alert = t('errors.messages.procedure_not_found')
|
||||
|
|
|
@ -9,25 +9,4 @@ module ChampHelper
|
|||
raw(champ.to_render_data.to_json)
|
||||
# rubocop:enable Rails/OutputSafety
|
||||
end
|
||||
|
||||
def formatted_value(champ)
|
||||
value = champ.value
|
||||
type = champ.type_champ
|
||||
|
||||
if type == TypeDeChamp.type_champs.fetch(:date) && value.present?
|
||||
Date.parse(value).strftime("%d/%m/%Y")
|
||||
elsif type.in? [TypeDeChamp.type_champs.fetch(:checkbox), TypeDeChamp.type_champs.fetch(:engagement)]
|
||||
value == 'on' ? 'Oui' : 'Non'
|
||||
elsif type == TypeDeChamp.type_champs.fetch(:yes_no)
|
||||
if value == 'true'
|
||||
'Oui'
|
||||
elsif value == 'false'
|
||||
'Non'
|
||||
end
|
||||
elsif type == TypeDeChamp.type_champs.fetch(:multiple_drop_down_list) && value.present?
|
||||
JSON.parse(value).join(', ')
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
module DossierLinkHelper
|
||||
def dossier_linked_path(gestionnaire, dossier)
|
||||
if dossier.procedure.gestionnaires.include?(gestionnaire)
|
||||
gestionnaire_dossier_path(dossier.procedure, dossier)
|
||||
else
|
||||
avis = dossier.avis.find_by(gestionnaire: gestionnaire)
|
||||
if avis.present?
|
||||
gestionnaire_avis_path(avis)
|
||||
def dossier_linked_path(user, dossier)
|
||||
if user.is_a?(Gestionnaire)
|
||||
if dossier.procedure.gestionnaires.include?(user)
|
||||
gestionnaire_dossier_path(dossier.procedure, dossier)
|
||||
else
|
||||
avis = dossier.avis.find_by(gestionnaire: user)
|
||||
if avis.present?
|
||||
gestionnaire_avis_path(avis)
|
||||
end
|
||||
end
|
||||
elsif user.owns_or_invite?(dossier)
|
||||
dossier_path(dossier)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -119,4 +119,8 @@ class Administrateur < ApplicationRecord
|
|||
def owns?(procedure)
|
||||
id == procedure.administrateur_id
|
||||
end
|
||||
|
||||
def gestionnaire
|
||||
Gestionnaire.find_by(email: email)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -40,32 +40,18 @@ class Champ < ApplicationRecord
|
|||
end
|
||||
|
||||
def to_s
|
||||
if value.present?
|
||||
string_value
|
||||
else
|
||||
''
|
||||
end
|
||||
value.present? ? value.to_s : ''
|
||||
end
|
||||
|
||||
def for_export
|
||||
if value.present?
|
||||
value_for_export
|
||||
else
|
||||
nil
|
||||
end
|
||||
value.presence
|
||||
end
|
||||
|
||||
def for_api
|
||||
value
|
||||
end
|
||||
|
||||
def main_value_name
|
||||
:value
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def string_value
|
||||
value.to_s
|
||||
end
|
||||
|
||||
def value_for_export
|
||||
value
|
||||
end
|
||||
end
|
||||
|
|
|
@ -88,4 +88,8 @@ class Champs::CarteChamp < Champ
|
|||
)
|
||||
end
|
||||
end
|
||||
|
||||
def for_api
|
||||
geo_json&.to_json
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,6 +6,14 @@ class Champs::CheckboxChamp < Champ
|
|||
end
|
||||
|
||||
def to_s
|
||||
value == 'on' ? 'oui' : 'non'
|
||||
value == 'on' ? 'Oui' : 'Non'
|
||||
end
|
||||
|
||||
def for_export
|
||||
value == 'on' ? 'on' : 'off'
|
||||
end
|
||||
|
||||
def for_api
|
||||
value == 'on' ? 'on' : 'off'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,10 @@ class Champs::DateChamp < Champ
|
|||
# Text search is pretty useless for dates so we’re not including these champs
|
||||
end
|
||||
|
||||
def to_s
|
||||
value.present? ? Date.parse(value).strftime('%d/%m/%Y') : ""
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def format_before_save
|
||||
|
@ -15,8 +19,4 @@ class Champs::DateChamp < Champ
|
|||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def string_value
|
||||
Date.parse(value).strftime('%d/%m/%Y')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
class Champs::DecimalNumberChamp < Champ
|
||||
validates :value, numericality: { allow_nil: true, allow_blank: true }
|
||||
|
||||
def value_for_export
|
||||
value.to_f
|
||||
def for_export
|
||||
processed_value
|
||||
end
|
||||
|
||||
def for_api
|
||||
processed_value
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def processed_value
|
||||
value&.to_f
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,2 @@
|
|||
class Champs::EngagementChamp < Champs::CheckboxChamp
|
||||
def search_terms
|
||||
if value == 'on'
|
||||
[libelle]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
class Champs::IntegerNumberChamp < Champ
|
||||
validates :value, numericality: { only_integer: true, allow_nil: true, allow_blank: true }
|
||||
|
||||
def value_for_export
|
||||
value.to_i
|
||||
def for_export
|
||||
processed_value
|
||||
end
|
||||
|
||||
def for_api
|
||||
processed_value
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def processed_value
|
||||
value&.to_i
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,8 +29,16 @@ class Champs::LinkedDropDownListChamp < Champ
|
|||
:primary_value
|
||||
end
|
||||
|
||||
def for_display
|
||||
string_value
|
||||
def to_s
|
||||
value.present? ? [primary_value, secondary_value].compact.join(' / ') : ""
|
||||
end
|
||||
|
||||
def for_export
|
||||
value.present? ? "#{primary_value || ''};#{secondary_value || ''}" : nil
|
||||
end
|
||||
|
||||
def for_api
|
||||
value.present? ? { primary: primary_value, secondary: secondary_value } : nil
|
||||
end
|
||||
|
||||
def mandatory_and_blank?
|
||||
|
@ -43,14 +51,6 @@ class Champs::LinkedDropDownListChamp < Champ
|
|||
|
||||
private
|
||||
|
||||
def string_value
|
||||
[primary_value, secondary_value].compact.join(' / ')
|
||||
end
|
||||
|
||||
def value_for_export
|
||||
"#{primary_value || ''};#{secondary_value || ''}"
|
||||
end
|
||||
|
||||
def pack_value(primary, secondary)
|
||||
self.value = JSON.generate([primary, secondary])
|
||||
end
|
||||
|
|
|
@ -2,7 +2,19 @@ class Champs::MultipleDropDownListChamp < Champ
|
|||
before_save :format_before_save
|
||||
|
||||
def search_terms
|
||||
drop_down_list.selected_options_without_decorator(self)
|
||||
selected_options
|
||||
end
|
||||
|
||||
def selected_options
|
||||
value.blank? ? [] : JSON.parse(value)
|
||||
end
|
||||
|
||||
def to_s
|
||||
selected_options.join(', ')
|
||||
end
|
||||
|
||||
def for_export
|
||||
value.present? ? selected_options.join(', ') : nil
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -18,12 +30,4 @@ class Champs::MultipleDropDownListChamp < Champ
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def string_value
|
||||
drop_down_list.selected_options_without_decorator(self).join(', ')
|
||||
end
|
||||
|
||||
def value_for_export
|
||||
drop_down_list.selected_options_without_decorator(self).join(', ')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,6 +48,10 @@ class Champs::PieceJustificativeChamp < Champ
|
|||
errors
|
||||
end
|
||||
|
||||
def for_api
|
||||
Rails.application.routes.url_helpers.url_for(piece_justificative_file)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_virus_scan
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class Champs::RepetitionChamp < Champ
|
||||
before_save :setup_dossier
|
||||
|
||||
has_many :champs, -> { ordered }, foreign_key: :parent_id, dependent: :destroy
|
||||
|
||||
accepts_nested_attributes_for :champs, allow_destroy: true
|
||||
|
@ -10,4 +12,10 @@ class Champs::RepetitionChamp < Champ
|
|||
def search_terms
|
||||
# The user cannot enter any information here so it doesn’t make much sense to search
|
||||
end
|
||||
|
||||
def setup_dossier
|
||||
champs.each do |champ|
|
||||
champ.dossier = dossier
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
class Champs::TextareaChamp < Champs::TextChamp
|
||||
private
|
||||
|
||||
def value_for_export
|
||||
ActionView::Base.full_sanitizer.sanitize(value)
|
||||
def for_export
|
||||
value.present? ? ActionView::Base.full_sanitizer.sanitize(value) : nil
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,12 +6,20 @@ class Champs::YesNoChamp < Champs::CheckboxChamp
|
|||
end
|
||||
|
||||
def to_s
|
||||
value_for_export
|
||||
processed_value
|
||||
end
|
||||
|
||||
def for_export
|
||||
processed_value
|
||||
end
|
||||
|
||||
def for_api
|
||||
processed_value
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def value_for_export
|
||||
value == 'true' ? 'oui' : 'non'
|
||||
def processed_value
|
||||
value == 'true' ? 'Oui' : 'Non'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,10 +10,6 @@ class DropDownList < ApplicationRecord
|
|||
options.select { |v| (v =~ /^--.*--$/).present? }
|
||||
end
|
||||
|
||||
def selected_options_without_decorator(champ)
|
||||
champ.value.blank? ? [] : multiple ? JSON.parse(champ.value) : [champ.value]
|
||||
end
|
||||
|
||||
def multiple
|
||||
type_de_champ.type_champ == TypeDeChamp.type_champs.fetch(:multiple_drop_down_list)
|
||||
end
|
||||
|
|
|
@ -3,7 +3,8 @@ class Gestionnaire < ApplicationRecord
|
|||
include EmailSanitizableConcern
|
||||
include ActiveRecord::SecureToken
|
||||
|
||||
LOGIN_TOKEN_VALIDITY = 30.minutes
|
||||
LOGIN_TOKEN_VALIDITY = 45.minutes
|
||||
LOGIN_TOKEN_YOUTH = 15.minutes
|
||||
|
||||
devise :database_authenticatable, :registerable, :async,
|
||||
:recoverable, :rememberable, :trackable, :validatable
|
||||
|
@ -211,6 +212,11 @@ class Gestionnaire < ApplicationRecord
|
|||
save
|
||||
end
|
||||
|
||||
def young_login_token?
|
||||
login_token_created_at.present? &&
|
||||
LOGIN_TOKEN_YOUTH.ago < login_token_created_at
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def annotations_hash(demande, annotations_privees, avis, messagerie)
|
||||
|
|
|
@ -4,8 +4,8 @@ class Procedure < ApplicationRecord
|
|||
MAX_DUREE_CONSERVATION = 36
|
||||
|
||||
has_many :types_de_piece_justificative, -> { ordered }, dependent: :destroy
|
||||
has_many :types_de_champ, -> { public_only.ordered }, dependent: :destroy
|
||||
has_many :types_de_champ_private, -> { private_only.ordered }, class_name: 'TypeDeChamp', dependent: :destroy
|
||||
has_many :types_de_champ, -> { root.public_only.ordered }, dependent: :destroy
|
||||
has_many :types_de_champ_private, -> { root.private_only.ordered }, class_name: 'TypeDeChamp', dependent: :destroy
|
||||
has_many :dossiers
|
||||
has_many :deleted_dossiers, dependent: :destroy
|
||||
|
||||
|
@ -218,6 +218,8 @@ class Procedure < ApplicationRecord
|
|||
procedure.service = self.service.clone_and_assign_to_administrateur(admin)
|
||||
end
|
||||
|
||||
admin.gestionnaire.assign_to_procedure(procedure)
|
||||
|
||||
procedure
|
||||
end
|
||||
|
||||
|
@ -360,6 +362,20 @@ class Procedure < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def missing_steps
|
||||
result = []
|
||||
|
||||
if service.nil?
|
||||
result << :service
|
||||
end
|
||||
|
||||
if gestionnaires.empty?
|
||||
result << :instructeurs
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def claim_path_ownership!(path)
|
||||
|
|
|
@ -61,12 +61,14 @@ class TypeDeChamp < ApplicationRecord
|
|||
|
||||
after_initialize :set_dynamic_type
|
||||
after_create :populate_stable_id
|
||||
before_save :setup_procedure
|
||||
|
||||
attr_reader :dynamic_type
|
||||
|
||||
scope :public_only, -> { where(private: false) }
|
||||
scope :private_only, -> { where(private: true) }
|
||||
scope :ordered, -> { order(order_place: :asc) }
|
||||
scope :root, -> { where(parent_id: nil) }
|
||||
|
||||
has_many :champ, inverse_of: :type_de_champ, dependent: :destroy do
|
||||
def build(params = {})
|
||||
|
@ -82,6 +84,7 @@ class TypeDeChamp < ApplicationRecord
|
|||
has_one_attached :piece_justificative_template
|
||||
|
||||
accepts_nested_attributes_for :drop_down_list
|
||||
accepts_nested_attributes_for :types_de_champ, allow_destroy: true
|
||||
|
||||
validates :libelle, presence: true, allow_blank: false, allow_nil: false
|
||||
validates :type_champ, presence: true, allow_blank: false, allow_nil: false
|
||||
|
@ -160,6 +163,12 @@ class TypeDeChamp < ApplicationRecord
|
|||
|
||||
private
|
||||
|
||||
def setup_procedure
|
||||
types_de_champ.each do |type_de_champ|
|
||||
type_de_champ.procedure = procedure
|
||||
end
|
||||
end
|
||||
|
||||
def populate_stable_id
|
||||
if !stable_id
|
||||
update_column(:stable_id, id)
|
||||
|
|
|
@ -13,28 +13,8 @@ class ChampSerializer < ActiveModel::Serializer
|
|||
case object
|
||||
when GeoArea
|
||||
object.geometry
|
||||
when Champs::CarteChamp
|
||||
if object.geo_json.present?
|
||||
object.geo_json.to_json
|
||||
end
|
||||
when Champs::DecimalNumberChamp
|
||||
if object.value.present?
|
||||
object.value.to_f
|
||||
end
|
||||
when Champs::IntegerNumberChamp
|
||||
if object.value.present?
|
||||
object.value.to_i
|
||||
end
|
||||
when Champs::LinkedDropDownListChamp
|
||||
if object.value.present?
|
||||
{ primary: object.primary_value, secondary: object.secondary_value }
|
||||
end
|
||||
when Champs::PieceJustificativeChamp
|
||||
if object.piece_justificative_file.attached?
|
||||
url_for(object.piece_justificative_file)
|
||||
end
|
||||
else
|
||||
object.value
|
||||
object.for_api
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -120,11 +120,9 @@ class ProcedureExportService
|
|||
|
||||
def etablissements_table_data
|
||||
@etablissements = @dossiers.flat_map do |dossier|
|
||||
dossier.champs.select do |champ|
|
||||
champ.is_a?(Champs::SiretChamp)
|
||||
end + dossier.champs_private.select do |champ|
|
||||
champ.is_a?(Champs::SiretChamp)
|
||||
end
|
||||
[dossier.champs, dossier.champs_private]
|
||||
.flatten
|
||||
.select { |champ| champ.is_a?(Champs::SiretChamp) }
|
||||
end.map(&:etablissement).compact
|
||||
|
||||
if @etablissements.any?
|
||||
|
@ -139,22 +137,13 @@ class ProcedureExportService
|
|||
end
|
||||
|
||||
def dossiers_headers
|
||||
headers = ATTRIBUTES.map do |key|
|
||||
label_for_export(key.to_s)
|
||||
end
|
||||
headers += @procedure.types_de_champ.reject(&:exclude_from_export?).map do |champ|
|
||||
label_for_export(champ.libelle)
|
||||
end
|
||||
headers += @procedure.types_de_champ_private.reject(&:exclude_from_export?).map do |champ|
|
||||
label_for_export(champ.libelle)
|
||||
end
|
||||
headers += ETABLISSEMENT_ATTRIBUTES.map do |key|
|
||||
label_for_export("etablissement.#{key}")
|
||||
end
|
||||
headers += ENTREPRISE_ATTRIBUTES.map do |key|
|
||||
label_for_export("entreprise.#{key}")
|
||||
end
|
||||
headers
|
||||
headers = ATTRIBUTES.map(&:to_s) +
|
||||
@procedure.types_de_champ.reject(&:exclude_from_export?).map(&:libelle) +
|
||||
@procedure.types_de_champ_private.reject(&:exclude_from_export?).map(&:libelle) +
|
||||
ETABLISSEMENT_ATTRIBUTES.map { |key| "etablissement.#{key}" } +
|
||||
ENTREPRISE_ATTRIBUTES.map { |key| "entreprise.#{key}" }
|
||||
|
||||
headers.map { |header| label_for_export(header) }
|
||||
end
|
||||
|
||||
def dossiers_data
|
||||
|
@ -183,37 +172,28 @@ class ProcedureExportService
|
|||
dossier.read_attribute(key)
|
||||
end
|
||||
end
|
||||
values = normalize_values(values)
|
||||
values += dossier.champs.reject(&:exclude_from_export?).map do |champ|
|
||||
value_for_export(champ)
|
||||
end
|
||||
values += dossier.champs_private.reject(&:exclude_from_export?).map do |champ|
|
||||
value_for_export(champ)
|
||||
end
|
||||
values += etablissement_data(dossier.etablissement)
|
||||
values
|
||||
|
||||
normalize_values(values) +
|
||||
dossier.champs.reject(&:exclude_from_export?).map(&:for_export) +
|
||||
dossier.champs_private.reject(&:exclude_from_export?).map(&:for_export) +
|
||||
etablissement_data(dossier.etablissement)
|
||||
end
|
||||
end
|
||||
|
||||
def etablissements_headers
|
||||
headers = [:dossier_id, :libelle]
|
||||
headers += ETABLISSEMENT_ATTRIBUTES.map do |key|
|
||||
label_for_export("etablissement.#{key}")
|
||||
end
|
||||
headers += ENTREPRISE_ATTRIBUTES.map do |key|
|
||||
label_for_export("entreprise.#{key}")
|
||||
end
|
||||
headers
|
||||
headers = ["dossier_id", "libelle"] +
|
||||
ETABLISSEMENT_ATTRIBUTES.map { |key| "etablissement.#{key}" } +
|
||||
ENTREPRISE_ATTRIBUTES.map { |key| "entreprise.#{key}" }
|
||||
|
||||
headers.map { |header| label_for_export(header) }
|
||||
end
|
||||
|
||||
def etablissements_data
|
||||
@etablissements.map do |etablissement|
|
||||
data = [
|
||||
[
|
||||
etablissement.champ.dossier_id,
|
||||
label_for_export(etablissement.champ.libelle).to_s
|
||||
]
|
||||
|
||||
data + etablissement_data(etablissement)
|
||||
] + etablissement_data(etablissement)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -245,10 +225,6 @@ class ProcedureExportService
|
|||
label.parameterize.underscore.to_sym
|
||||
end
|
||||
|
||||
def value_for_export(champ)
|
||||
champ.for_export
|
||||
end
|
||||
|
||||
def normalize_values(values)
|
||||
values.map do |value|
|
||||
case value
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
.alert.alert-info
|
||||
Cette démarche a été publiée, certains éléments ne peuvent plus être modifiés.
|
||||
|
||||
%div
|
||||
.lien-demarche
|
||||
%h3 Lien démarche
|
||||
%div{ style: 'margin-top: 30px;' }
|
||||
- if @procedure.archivee?
|
||||
|
@ -72,5 +72,15 @@
|
|||
= link_to("un service", services_path(procedure_id: @procedure))
|
||||
\.
|
||||
- else
|
||||
.alert.alert-info
|
||||
Cette démarche n’a pas encore de lien, et n’est donc pas accessible par le public.
|
||||
- if @procedure.missing_steps.include?(:service)
|
||||
%p.alert.alert-danger
|
||||
Vous devez renseigner les coordonnées de votre Service administratif avant de pouvoir publier votre démarche.
|
||||
= link_to 'Cliquez ici.', (current_administrateur.services.present? ? url_for(services_path(procedure_id: @procedure.id)) : url_for(new_service_path(procedure_id: @procedure.id)))
|
||||
|
||||
- if @procedure.missing_steps.include?(:instructeurs)
|
||||
%p.alert.alert-danger
|
||||
Vous devez affecter des instructeurs avant de pouvoir publier votre démarche.
|
||||
= link_to 'Cliquez ici.', admin_procedure_instructeurs_path(@procedure)
|
||||
|
||||
%p.alert.alert-info
|
||||
Cette démarche n’a pas encore de lien, et n’est pas accessible par le public.
|
||||
|
|
|
@ -20,11 +20,15 @@
|
|||
|
||||
%a#onglet-services{ href: current_administrateur.services.present? ? url_for(services_path(procedure_id: @procedure.id)) : url_for(new_service_path(procedure_id: @procedure.id)) }
|
||||
.procedure-list-element
|
||||
Services
|
||||
Service
|
||||
- if @procedure.missing_steps.include?(:service)
|
||||
%p.missing-steps (à compléter)
|
||||
|
||||
%a#onglet-instructeurs{ href: url_for(admin_procedure_instructeurs_path(@procedure)) }
|
||||
.procedure-list-element{ class: ('active' if active == 'Instructeurs') }
|
||||
Instructeurs
|
||||
- if @procedure.missing_steps.include?(:instructeurs)
|
||||
%p.missing-steps (à compléter)
|
||||
|
||||
- if !@procedure.locked?
|
||||
%a#onglet-champs{ href: url_for(admin_procedure_types_de_champ_path(@procedure)) }
|
||||
|
|
|
@ -33,14 +33,9 @@
|
|||
|
||||
%h2 Annotations privées
|
||||
|
||||
- if @dossier.champs_private.present?
|
||||
%table
|
||||
- @dossier.champs_private.each do |champ|
|
||||
%tr
|
||||
%th
|
||||
= champ.libelle
|
||||
%td
|
||||
= champ.value
|
||||
- champs_annotations_privees = @dossier.champs_private
|
||||
- if champs_annotations_privees.any?
|
||||
= render partial: "shared/dossiers/champs", locals: { champs: champs_annotations_privees, dossier: @dossier, demande_seen_at: nil, profile: 'instructeur' }
|
||||
- else
|
||||
Aucune annotation privée
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
.carte{ data: { geo: geo_data(champ) } }
|
||||
.geo-areas
|
||||
= render partial: 'shared/champs/carte/geo_areas', locals: { champ: champ, error: false }
|
||||
- if champ.to_s.present?
|
||||
.carte{ data: { geo: geo_data(champ) } }
|
||||
.geo-areas
|
||||
= render partial: 'shared/champs/carte/geo_areas', locals: { champ: champ, error: false }
|
||||
|
|
11
app/views/shared/champs/dossier_link/_show.html.haml
Normal file
11
app/views/shared/champs/dossier_link/_show.html.haml
Normal file
|
@ -0,0 +1,11 @@
|
|||
- dossier = Dossier.includes(:procedure).find_by(id: champ.to_s)
|
||||
- if dossier
|
||||
- path = dossier_linked_path(current_gestionnaire || current_user, dossier)
|
||||
- if path.present?
|
||||
= link_to("Dossier nº #{dossier.id}", path, target: '_blank')
|
||||
- else
|
||||
Dossier nº #{dossier.id}
|
||||
%br
|
||||
= sanitize(dossier.text_summary)
|
||||
- else
|
||||
Pas de dossier associé
|
|
@ -0,0 +1,5 @@
|
|||
- if champ.to_s.present?
|
||||
%ul
|
||||
- champ.to_s.split(", ").each do |item|
|
||||
%li
|
||||
= item
|
|
@ -0,0 +1,5 @@
|
|||
- pj = champ.piece_justificative_file
|
||||
- if pj.attached?
|
||||
= render partial: "shared/champs/piece_justificative/pj_link", locals: { champ: champ, user_can_upload: false }
|
||||
- else
|
||||
Pièce justificative non fournie
|
2
app/views/shared/champs/siret/_show.html.haml
Normal file
2
app/views/shared/champs/siret/_show.html.haml
Normal file
|
@ -0,0 +1,2 @@
|
|||
- if champ.etablissement.present?
|
||||
= render partial: "shared/dossiers/identite_entreprise", locals: { etablissement: champ.etablissement, profile: profile }
|
1
app/views/shared/champs/textarea/_show.html.haml
Normal file
1
app/views/shared/champs/textarea/_show.html.haml
Normal file
|
@ -0,0 +1 @@
|
|||
= simple_format(champ.to_s)
|
|
@ -2,74 +2,30 @@
|
|||
%tbody
|
||||
- champs.reject(&:exclude_from_view?).each do |c|
|
||||
%tr
|
||||
- value = formatted_value(c)
|
||||
- case c.type_champ
|
||||
- when TypeDeChamp.type_champs.fetch(:header_section)
|
||||
- if c.type_champ == TypeDeChamp.type_champs.fetch(:header_section)
|
||||
%th.header-section{ colspan: 3 }
|
||||
= c.libelle
|
||||
- when TypeDeChamp.type_champs.fetch(:multiple_drop_down_list)
|
||||
%th.libelle
|
||||
= "#{c.libelle} :"
|
||||
%td.rich-text
|
||||
- if value.present?
|
||||
%ul
|
||||
- value.split(", ").each do |item|
|
||||
%li
|
||||
= item
|
||||
- when TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
|
||||
%th.libelle
|
||||
= "#{c.libelle} :"
|
||||
%td= c.for_display
|
||||
- when TypeDeChamp.type_champs.fetch(:dossier_link)
|
||||
%th.libelle
|
||||
= "#{c.libelle} :"
|
||||
%td.rich-text
|
||||
- dossier = Dossier.includes(:procedure).find_by(id: value)
|
||||
- if dossier
|
||||
- path = dossier_linked_path(current_gestionnaire, dossier)
|
||||
- if path.present?
|
||||
= link_to("Dossier nº #{dossier.id}", path, target: '_blank')
|
||||
- else
|
||||
Dossier nº #{dossier.id}
|
||||
%br
|
||||
= sanitize(dossier.text_summary)
|
||||
- else
|
||||
Pas de dossier associé
|
||||
- when TypeDeChamp.type_champs.fetch(:piece_justificative)
|
||||
%th.libelle
|
||||
= "#{c.libelle} :"
|
||||
%td.rich-text
|
||||
- pj = c.piece_justificative_file
|
||||
- if pj.attached?
|
||||
= render partial: "shared/champs/piece_justificative/pj_link", locals: { champ: c, user_can_upload: false }
|
||||
- else
|
||||
Pièce justificative non fournie
|
||||
- when TypeDeChamp.type_champs.fetch(:textarea)
|
||||
%th.libelle
|
||||
= "#{c.libelle} :"
|
||||
%td.rich-text
|
||||
%span{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) }
|
||||
= simple_format(value)
|
||||
- when TypeDeChamp.type_champs.fetch(:siret)
|
||||
%th.libelle
|
||||
= "#{c.libelle} :"
|
||||
%td.rich-text
|
||||
%span{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) }
|
||||
- if c.etablissement.present?
|
||||
= render partial: "shared/dossiers/identite_entreprise", locals: { etablissement: c.etablissement, profile: profile }
|
||||
- when TypeDeChamp.type_champs.fetch(:carte)
|
||||
%th.libelle
|
||||
= "#{c.libelle} :"
|
||||
%td.rich-text
|
||||
%span{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) }
|
||||
- if value.present?
|
||||
= render partial: "shared/champs/carte/show", locals: { champ: c }
|
||||
- else
|
||||
%th.libelle
|
||||
= "#{c.libelle} :"
|
||||
%td.rich-text
|
||||
%span{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) }
|
||||
= sanitize(value)
|
||||
- case c.type_champ
|
||||
- when TypeDeChamp.type_champs.fetch(:carte)
|
||||
= render partial: "shared/champs/carte/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:dossier_link)
|
||||
= render partial: "shared/champs/dossier_link/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:multiple_drop_down_list)
|
||||
= render partial: "shared/champs/multiple_drop_down_list/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:piece_justificative)
|
||||
= render partial: "shared/champs/piece_justificative/show", locals: { champ: c }
|
||||
- when TypeDeChamp.type_champs.fetch(:siret)
|
||||
= render partial: "shared/champs/siret/show", locals: { champ: c, profile: profile }
|
||||
- when TypeDeChamp.type_champs.fetch(:textarea)
|
||||
= render partial: "shared/champs/textarea/show", locals: { champ: c }
|
||||
- else
|
||||
= sanitize(c.to_s)
|
||||
|
||||
- if c.type_champ != TypeDeChamp.type_champs.fetch(:header_section)
|
||||
%td.updated-at
|
||||
%span{ class: highlight_if_unseen_class(demande_seen_at, c.updated_at) }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- if champ.drop_down_list && champ.drop_down_list.options.any?
|
||||
= form.select :value,
|
||||
champ.drop_down_list.options,
|
||||
{ selected: champ.drop_down_list.selected_options_without_decorator(champ),
|
||||
{ selected: champ.selected_options,
|
||||
disabled: champ.drop_down_list.disabled_options },
|
||||
multiple: true,
|
||||
class: 'select2'
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
%p.mail
|
||||
Ouvrez votre boite email <b>#{@email}</b> puis cliquez sur le lien d'activation du message <b>Connexion sécurisée à demarches-simplifiees.fr</b>.
|
||||
%br
|
||||
%br
|
||||
<b>Attention</b>, ce message peut mettre jusqu'à <b>15 minutes</b> pour arriver.
|
||||
|
||||
%p.help
|
||||
En cas de difficultés, nous restons joignables sur #{link_to 'contact@demarches-simplifiees.fr', 'mailto:contact@demarches-simplifiees.fr'}.
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
require Rails.root.join("lib", "tasks", "task_helper")
|
||||
|
||||
namespace :after_party do
|
||||
desc 'Deployment task: clone_service_for_transferred_procedures'
|
||||
task clone_service_for_transferred_procedures: :environment do
|
||||
puts "Running deploy task 'clone_service_for_transferred_procedures'"
|
||||
rake_puts "Running deploy task 'clone_service_for_transferred_procedures'"
|
||||
|
||||
procedures = Procedure.includes(:service).where.not(service_id: nil)
|
||||
procedures_to_fix_in_array = procedures.select do |p|
|
||||
|
@ -16,12 +18,12 @@ namespace :after_party do
|
|||
cloned_service = Service.find(service_id).clone_and_assign_to_administrateur(Administrateur.find(administrateur_id))
|
||||
|
||||
if cloned_service.save
|
||||
puts "Fixing Service #{service_id} for Administrateur #{administrateur_id}"
|
||||
rake_puts "Fixing Service #{service_id} for Administrateur #{administrateur_id}"
|
||||
procedures_to_fix
|
||||
.where(service_id: service_id, administrateur_id: administrateur_id)
|
||||
.update_all(service_id: cloned_service.id)
|
||||
else
|
||||
puts "Cannot fix Service #{service_id} for Administrateur #{administrateur_id}, it should be fixed manually. Errors : #{cloned_service.errors.full_messages}"
|
||||
rake_puts "Cannot fix Service #{service_id} for Administrateur #{administrateur_id}, it should be fixed manually. Errors : #{cloned_service.errors.full_messages}"
|
||||
end
|
||||
progress.inc
|
||||
end
|
||||
|
|
|
@ -203,7 +203,7 @@ describe Admin::ProceduresController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when procedure is correctly saved' do
|
||||
let!(:gestionnaire) { create(:gestionnaire, email: admin.email) }
|
||||
let(:gestionnaire) { admin.gestionnaire }
|
||||
|
||||
before do
|
||||
post :create, params: { procedure: procedure_params }
|
||||
|
|
|
@ -7,9 +7,9 @@ describe Gestionnaires::PasswordsController, type: :controller do
|
|||
|
||||
describe "update" do
|
||||
context "unified login" do
|
||||
let(:gestionnaire) { create(:gestionnaire, email: 'unique@plop.com', password: 'un super mot de passe') }
|
||||
let(:user) { create(:user, email: 'unique@plop.com', password: 'un super mot de passe') }
|
||||
let(:administrateur) { create(:administrateur, email: 'unique@plop.com', password: 'un super mot de passe') }
|
||||
let(:gestionnaire) { administrateur.gestionnaire }
|
||||
|
||||
before do
|
||||
@token = gestionnaire.send(:set_reset_password_token)
|
||||
|
|
|
@ -8,12 +8,10 @@ describe Users::PasswordsController, type: :controller do
|
|||
describe "update" do
|
||||
context "unified login" do
|
||||
let(:user) { create(:user, email: 'unique@plop.com', password: 'mot de passe complexe') }
|
||||
let(:gestionnaire) { create(:gestionnaire, email: 'unique@plop.com', password: 'mot de passe complexe') }
|
||||
let(:administrateur) { create(:administrateur, email: 'unique@plop.com', password: 'mot de passe complexe') }
|
||||
|
||||
before do
|
||||
@token = user.send(:set_reset_password_token)
|
||||
gestionnaire # make sure it's created
|
||||
administrateur # make sure it's created
|
||||
end
|
||||
|
||||
|
@ -26,7 +24,7 @@ describe Users::PasswordsController, type: :controller do
|
|||
}
|
||||
}
|
||||
expect(subject.current_user).to eq(user)
|
||||
expect(subject.current_gestionnaire).to eq(gestionnaire)
|
||||
expect(subject.current_gestionnaire.email).to eq(administrateur.email)
|
||||
end
|
||||
|
||||
it "also signs administrateur in" do
|
||||
|
|
|
@ -1,129 +1,88 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Users::SessionsController, type: :controller do
|
||||
let(:email) { 'unique@plop.com' }
|
||||
let(:password) { 'un super mot de passe' }
|
||||
let(:loged_in_with_france_connect) { User.loged_in_with_france_connects.fetch(:particulier) }
|
||||
let(:user) { create(:user, loged_in_with_france_connect: loged_in_with_france_connect) }
|
||||
let!(:user) { create(:user, email: email, password: password, loged_in_with_france_connect: loged_in_with_france_connect) }
|
||||
|
||||
before do
|
||||
@request.env["devise.mapping"] = Devise.mappings[:user]
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
it { expect(described_class).to be < Sessions::SessionsController }
|
||||
context "when the user is also a gestionnaire and an administrateur" do
|
||||
let!(:administrateur) { create(:administrateur, :with_admin_trusted_device, email: email, password: password) }
|
||||
let(:gestionnaire) { administrateur.gestionnaire }
|
||||
let(:trusted_device) { true }
|
||||
let(:send_password) { password }
|
||||
|
||||
describe 'France Connect attribut' do
|
||||
before do
|
||||
post :create, params: { user: { email: user.email, password: user.password } }
|
||||
allow(controller).to receive(:trusted_device?).and_return(trusted_device)
|
||||
allow(GestionnaireMailer).to receive(:send_login_token).and_return(double(deliver_later: true))
|
||||
end
|
||||
|
||||
subject do
|
||||
post :create, params: { user: { email: email, password: send_password } }
|
||||
user.reload
|
||||
end
|
||||
|
||||
subject { user.loged_in_with_france_connect.present? }
|
||||
context 'when the device is not trusted' do
|
||||
let(:trusted_device) { false }
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
end
|
||||
it 'redirects to the confirmation link path' do
|
||||
subject
|
||||
|
||||
context "unified login" do
|
||||
let(:email) { 'unique@plop.com' }
|
||||
let(:password) { 'un super mot de passe' }
|
||||
expect(controller).to redirect_to link_sent_path(email: email)
|
||||
|
||||
let(:user) { create(:user, email: email, password: password) }
|
||||
let(:gestionnaire) { create(:gestionnaire, :with_trusted_device, email: email, password: password) }
|
||||
let(:administrateur) { create(:administrateur, email: email, password: password) }
|
||||
# do not know why, should be test related
|
||||
expect(controller.current_user).to eq(user)
|
||||
|
||||
it 'signs user in' do
|
||||
post :create, params: { 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(subject.current_administrateur).to be(nil)
|
||||
expect(user.reload.loged_in_with_france_connect).to be(nil)
|
||||
end
|
||||
expect(controller.current_gestionnaire).to be(nil)
|
||||
expect(controller.current_administrateur).to be(nil)
|
||||
expect(user.loged_in_with_france_connect).to be(nil)
|
||||
expect(GestionnaireMailer).to have_received(:send_login_token)
|
||||
end
|
||||
|
||||
it 'signs gestionnaire in' do
|
||||
post :create, params: { user: { email: gestionnaire.email, password: gestionnaire.password } }
|
||||
context 'and the user try to connect multiple times in a short period' do
|
||||
before do
|
||||
allow_any_instance_of(Gestionnaire).to receive(:young_login_token?).and_return(true)
|
||||
allow(GestionnaireMailer).to receive(:send_login_token)
|
||||
end
|
||||
|
||||
expect(subject).to redirect_to link_sent_path(email: gestionnaire.email)
|
||||
expect(subject.current_user).to be(nil)
|
||||
expect(subject.current_gestionnaire).to be(nil)
|
||||
expect(subject.current_administrateur).to be(nil)
|
||||
it 'does not renew nor send a new login token' do
|
||||
subject
|
||||
|
||||
expect(GestionnaireMailer).not_to have_received(:send_login_token)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the device is trusted' do
|
||||
before do
|
||||
allow(controller).to receive(:trusted_device?).and_return(true)
|
||||
post :create, params: { user: { email: gestionnaire.email, password: gestionnaire.password } }
|
||||
end
|
||||
it 'signs in as user, gestionnaire and adminstrateur' do
|
||||
subject
|
||||
|
||||
it 'directly log the gestionnaire' do
|
||||
expect(@response.redirect?).to be(true)
|
||||
expect(subject).not_to redirect_to link_sent_path(email: gestionnaire.email)
|
||||
expect(response.redirect?).to be(true)
|
||||
expect(controller).not_to redirect_to link_sent_path(email: email)
|
||||
# TODO when signing in as non-administrateur, and not starting a demarche, log in to gestionnaire path
|
||||
# expect(subject).to redirect_to gestionnaire_procedures_path
|
||||
expect(subject.current_user).to be(nil)
|
||||
expect(subject.current_gestionnaire).to eq(gestionnaire)
|
||||
expect(subject.current_administrateur).to be(nil)
|
||||
# expect(controller).to redirect_to gestionnaire_procedures_path
|
||||
|
||||
expect(controller.current_user).to eq(user)
|
||||
expect(controller.current_gestionnaire).to eq(gestionnaire)
|
||||
expect(controller.current_administrateur).to eq(administrateur)
|
||||
expect(user.loged_in_with_france_connect).to be(nil)
|
||||
expect(GestionnaireMailer).not_to have_received(:send_login_token)
|
||||
end
|
||||
end
|
||||
|
||||
context 'signs administrateur in' do
|
||||
# an admin has always an gestionnaire role
|
||||
before { gestionnaire }
|
||||
context 'when the credentials are wrong' do
|
||||
let(:send_password) { 'wrong_password' }
|
||||
|
||||
it 'signs administrateur in' do
|
||||
post :create, params: { user: { email: administrateur.email, password: administrateur.password } }
|
||||
it 'fails to sign in with bad credentials' do
|
||||
subject
|
||||
|
||||
expect(subject).to redirect_to link_sent_path(email: gestionnaire.email)
|
||||
expect(subject.current_user).to be(nil)
|
||||
expect(subject.current_gestionnaire).to be(nil)
|
||||
expect(subject.current_administrateur).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context {
|
||||
before do
|
||||
user
|
||||
gestionnaire
|
||||
end
|
||||
|
||||
it 'signs user + gestionnaire + administrateur in' do
|
||||
post :create, params: { user: { email: administrateur.email, password: administrateur.password } }
|
||||
|
||||
expect(subject).to redirect_to link_sent_path(email: gestionnaire.email)
|
||||
|
||||
# TODO: fix me
|
||||
# Strange behaviour: sign_out(:user) does not work in spec
|
||||
# but seems to work in live
|
||||
# expect(controller.current_user).to be(nil)
|
||||
|
||||
expect(subject.current_gestionnaire).to be(nil)
|
||||
expect(subject.current_administrateur).to be(nil)
|
||||
expect(user.reload.loged_in_with_france_connect).to be(nil)
|
||||
end
|
||||
}
|
||||
|
||||
it 'fails to sign in with bad credentials' do
|
||||
post :create, params: { 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)
|
||||
expect(subject.current_administrateur).to be(nil)
|
||||
end
|
||||
|
||||
context 'with different passwords' do
|
||||
let!(:gestionnaire) { create(:gestionnaire, email: email, password: 'mot de passe complexe') }
|
||||
let!(:administrateur) { create(:administrateur, email: email, password: 'mot de passe complexe') }
|
||||
|
||||
before do
|
||||
user
|
||||
end
|
||||
|
||||
it 'should sync passwords on login' do
|
||||
post :create, params: { user: { email: email, password: password } }
|
||||
gestionnaire.reload
|
||||
administrateur.reload
|
||||
expect(user.valid_password?(password)).to be(true)
|
||||
expect(gestionnaire.valid_password?(password)).to be(true)
|
||||
expect(administrateur.valid_password?(password)).to be(true)
|
||||
expect(response.unauthorized?).to be(true)
|
||||
expect(controller.current_user).to be(nil)
|
||||
expect(controller.current_gestionnaire).to be(nil)
|
||||
expect(controller.current_administrateur).to be(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -193,20 +152,20 @@ describe Users::SessionsController, type: :controller do
|
|||
delete :destroy
|
||||
expect(@response.headers["Location"]).to eq(FRANCE_CONNECT[:particulier][:logout_endpoint])
|
||||
end
|
||||
end
|
||||
|
||||
context "when associated administrateur" do
|
||||
let(:administrateur) { create(:administrateur, email: 'unique@plop.com') }
|
||||
context "when associated administrateur" do
|
||||
let(:administrateur) { create(:administrateur, email: 'unique@plop.com') }
|
||||
|
||||
it 'signs user + gestionnaire + administrateur out' do
|
||||
sign_in user
|
||||
sign_in gestionnaire
|
||||
sign_in administrateur
|
||||
delete :destroy
|
||||
expect(@response.redirect?).to be(true)
|
||||
expect(subject.current_user).to be(nil)
|
||||
expect(subject.current_gestionnaire).to be(nil)
|
||||
expect(subject.current_administrateur).to be(nil)
|
||||
end
|
||||
it 'signs user + gestionnaire + administrateur out' do
|
||||
sign_in user
|
||||
sign_in administrateur.gestionnaire
|
||||
sign_in administrateur
|
||||
delete :destroy
|
||||
expect(@response.redirect?).to be(true)
|
||||
expect(subject.current_user).to be(nil)
|
||||
expect(subject.current_gestionnaire).to be(nil)
|
||||
expect(subject.current_administrateur).to be(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -284,8 +243,8 @@ describe Users::SessionsController, type: :controller do
|
|||
let(:password) { 'un super mot de passe' }
|
||||
|
||||
let!(:user) { create(:user, email: email, password: password) }
|
||||
let!(:gestionnaire) { create(:gestionnaire, email: email, password: password) }
|
||||
let!(:administrateur) { create(:administrateur, email: email, password: password) }
|
||||
let(:gestionnaire) { administrateur.gestionnaire }
|
||||
|
||||
before do
|
||||
post :sign_in_by_link, params: { id: gestionnaire.id, jeton: jeton }
|
||||
|
|
|
@ -3,6 +3,16 @@ FactoryBot.define do
|
|||
factory :administrateur do
|
||||
email { generate(:administrateur_email) }
|
||||
password { 'mon chien aime les bananes' }
|
||||
|
||||
after(:create) do |admin|
|
||||
create(:gestionnaire, email: admin.email, password: admin.password)
|
||||
end
|
||||
end
|
||||
|
||||
trait :with_admin_trusted_device do
|
||||
after(:create) do |admin|
|
||||
admin.gestionnaire.update(features: { "enable_email_login_token" => true })
|
||||
end
|
||||
end
|
||||
|
||||
trait :with_api_token do
|
||||
|
|
|
@ -5,8 +5,7 @@ feature 'Administrator connection' do
|
|||
|
||||
let(:email) { 'admin1@admin.com' }
|
||||
let(:password) { 'mon chien aime les bananes' }
|
||||
let!(:admin) { create(:administrateur, :with_procedure, email: email, password: password) }
|
||||
let!(:gestionnaire) { create(:gestionnaire, :with_trusted_device, email: email, password: password) }
|
||||
let!(:admin) { create(:administrateur, :with_admin_trusted_device, :with_procedure, email: email, password: password) }
|
||||
|
||||
before do
|
||||
visit new_administrateur_session_path
|
||||
|
|
|
@ -116,7 +116,7 @@ feature 'As an administrateur I wanna create a new procedure', js: true do
|
|||
end
|
||||
end
|
||||
|
||||
scenario 'After adding champ and file, check impossibility to publish procedure, add instructeur and make publication' do
|
||||
scenario 'After adding champ and file, make publication' do
|
||||
fill_in 'procedure_types_de_champ_attributes_0_libelle', with: 'libelle de champ'
|
||||
click_on 'add_type_de_champ'
|
||||
click_on 'onglet-pieces'
|
||||
|
@ -125,17 +125,6 @@ feature 'As an administrateur I wanna create a new procedure', js: true do
|
|||
fill_in 'procedure_types_de_piece_justificative_attributes_0_libelle', with: 'libelle de piece'
|
||||
click_on 'add_piece_justificative'
|
||||
|
||||
click_on 'onglet-infos'
|
||||
expect(page).to have_current_path(admin_procedure_path(Procedure.last))
|
||||
expect(page).to have_selector('#disabled-publish-procedure')
|
||||
expect(page.find_by_id('disabled-publish-procedure')[:disabled]).to eq('true')
|
||||
|
||||
click_on 'onglet-instructeurs'
|
||||
expect(page).to have_current_path(admin_procedure_instructeurs_path(Procedure.last))
|
||||
fill_in 'gestionnaire_email', with: 'gestionnaire@apientreprise.fr'
|
||||
click_on 'add-gestionnaire-email'
|
||||
page.first('.gestionnaire-affectation').click
|
||||
|
||||
click_on 'onglet-infos'
|
||||
expect(page).to have_current_path(admin_procedure_path(Procedure.last))
|
||||
expect(page).to have_selector('#publish-procedure', visible: true)
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ChampHelper, type: :helper do
|
||||
let(:type_de_champ) { create(:type_de_champ) }
|
||||
let(:champ) { type_de_champ.champ.create }
|
||||
|
||||
describe '.formatted_value' do
|
||||
subject { formatted_value(champ) }
|
||||
|
||||
describe 'for a checkbox' do
|
||||
let(:type_de_champ) { create(:type_de_champ_checkbox) }
|
||||
|
||||
context 'when value is on' do
|
||||
before { champ.update value: 'on' }
|
||||
it { is_expected.to eq 'Oui' }
|
||||
end
|
||||
|
||||
context 'when value is other' do
|
||||
it { is_expected.to eq 'Non' }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'for a engagement' do
|
||||
let(:type_de_champ) { create(:type_de_champ_engagement) }
|
||||
|
||||
context 'when value is on' do
|
||||
before { champ.update value: 'on' }
|
||||
it { is_expected.to eq 'Oui' }
|
||||
end
|
||||
|
||||
context 'when value is other' do
|
||||
it { is_expected.to eq 'Non' }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'for a multiple_drop_down_list' do
|
||||
let(:type_de_champ) { create(:type_de_champ_multiple_drop_down_list) }
|
||||
|
||||
context 'when value is an array' do
|
||||
before { champ.update value: '["1", "2"]' }
|
||||
it { is_expected.to eq '1, 2' }
|
||||
end
|
||||
|
||||
context 'when value is empty' do
|
||||
before { champ.update value: '' }
|
||||
it { is_expected.to eq '' }
|
||||
end
|
||||
end
|
||||
|
||||
describe "for a date" do
|
||||
let(:type_de_champ) { create(:type_de_champ_date) }
|
||||
|
||||
context "when value is an ISO date" do
|
||||
before { champ.update value: "2017-12-31" }
|
||||
it { is_expected.to eq "31/12/2017" }
|
||||
end
|
||||
|
||||
context "when value is empty" do
|
||||
before { champ.update value: nil }
|
||||
it { is_expected.to eq nil }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,12 +1,19 @@
|
|||
describe DossierLinkHelper do
|
||||
describe "#dossier_linked_path" do
|
||||
context "when no access" do
|
||||
context "when no access as a gestionnaire" do
|
||||
let(:gestionnaire) { create(:gestionnaire) }
|
||||
let(:dossier) { create(:dossier) }
|
||||
|
||||
it { expect(helper.dossier_linked_path(gestionnaire, dossier)).to be_nil }
|
||||
end
|
||||
|
||||
context "when no access as a user" do
|
||||
let(:user) { create(:user) }
|
||||
let(:dossier) { create(:dossier) }
|
||||
|
||||
it { expect(helper.dossier_linked_path(user, dossier)).to be_nil }
|
||||
end
|
||||
|
||||
context "when access as gestionnaire" do
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:gestionnaire) { create(:gestionnaire) }
|
||||
|
@ -23,5 +30,14 @@ describe DossierLinkHelper do
|
|||
|
||||
it { expect(helper.dossier_linked_path(gestionnaire, dossier)).to eq(gestionnaire_avis_path(avis)) }
|
||||
end
|
||||
|
||||
context "when access as user" do
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before { dossier.user = user }
|
||||
|
||||
it { expect(helper.dossier_linked_path(user, dossier)).to eq(dossier_path(dossier)) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,7 +22,7 @@ describe Administrateur, type: :model do
|
|||
|
||||
it 'syncs credentials to associated administrateur' do
|
||||
administrateur = create(:administrateur)
|
||||
gestionnaire = create(:gestionnaire, email: administrateur.email)
|
||||
gestionnaire = administrateur.gestionnaire
|
||||
|
||||
administrateur.update(email: 'whoami@plop.com', password: 'et encore un autre mdp')
|
||||
|
||||
|
|
|
@ -104,19 +104,19 @@ describe Champ do
|
|||
context 'if yes' do
|
||||
let(:value) { 'true' }
|
||||
|
||||
it { expect(champ.for_export).to eq('oui') }
|
||||
it { expect(champ.for_export).to eq('Oui') }
|
||||
end
|
||||
|
||||
context 'if no' do
|
||||
let(:value) { 'false' }
|
||||
|
||||
it { expect(champ.for_export).to eq('non') }
|
||||
it { expect(champ.for_export).to eq('Non') }
|
||||
end
|
||||
|
||||
context 'if nil' do
|
||||
let(:value) { nil }
|
||||
|
||||
it { expect(champ.for_export).to eq(nil) }
|
||||
it { expect(champ.for_export).to eq('Non') }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -401,17 +401,31 @@ describe Champ do
|
|||
end
|
||||
|
||||
describe "repetition" do
|
||||
let(:champ) { create(:champ_repetition) }
|
||||
let(:dossier) { create(:dossier) }
|
||||
let(:champ) { create(:champ_repetition, dossier: dossier) }
|
||||
let(:champ_text) { create(:champ_text, row: 0) }
|
||||
let(:champ_integer_number) { create(:champ_integer_number, row: 0) }
|
||||
let(:champ_text2) { create(:champ_text, row: 1) }
|
||||
let(:champ_text_attrs) { attributes_for(:champ_text, row: 1) }
|
||||
|
||||
it {
|
||||
it "associates nested champs to the parent dossier" do
|
||||
expect(champ.rows.size).to eq(0)
|
||||
dossier.reload
|
||||
expect(dossier.champs.size).to eq(2)
|
||||
|
||||
champ.champs << champ_text2
|
||||
dossier.update(champs_attributes: [
|
||||
{
|
||||
id: champ.id,
|
||||
champs_attributes: [champ_text_attrs]
|
||||
}
|
||||
])
|
||||
|
||||
champ.reload
|
||||
dossier.reload
|
||||
expect(dossier.champs.size).to eq(2)
|
||||
expect(champ.rows.size).to eq(1)
|
||||
|
||||
expect(champ.champs.first.dossier).to eq(dossier)
|
||||
|
||||
champ.champs << champ_integer_number
|
||||
row = champ.reload.rows.first
|
||||
expect(row.size).to eq(1)
|
||||
|
@ -423,6 +437,6 @@ describe Champ do
|
|||
expect(row.second).to eq(champ_text)
|
||||
|
||||
expect(champ.rows.size).to eq(2)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,13 +9,13 @@ describe Champs::CheckboxChamp do
|
|||
context 'when the value is on' do
|
||||
let(:value) { 'on' }
|
||||
|
||||
it { is_expected.to eq('oui') }
|
||||
it { is_expected.to eq('Oui') }
|
||||
end
|
||||
|
||||
context 'when the value is off' do
|
||||
let(:value) { 'off' }
|
||||
|
||||
it { is_expected.to eq('non') }
|
||||
it { is_expected.to eq('Non') }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,12 +16,12 @@ describe Champs::LinkedDropDownListChamp do
|
|||
it { expect(champ.value).to eq('["tata","tutu"]') }
|
||||
end
|
||||
|
||||
describe '#for_display' do
|
||||
describe '#to_s' do
|
||||
let(:champ) { described_class.new(primary_value: primary_value, secondary_value: secondary_value) }
|
||||
let(:primary_value) { nil }
|
||||
let(:secondary_value) { nil }
|
||||
|
||||
subject { champ.for_display }
|
||||
subject { champ.to_s }
|
||||
|
||||
context 'with no value' do
|
||||
it { is_expected.to eq('') }
|
||||
|
|
|
@ -5,19 +5,19 @@ describe Champs::YesNoChamp do
|
|||
context 'when the value is false' do
|
||||
let(:value) { "false" }
|
||||
|
||||
it { is_expected.to eq("non") }
|
||||
it { is_expected.to eq("Non") }
|
||||
end
|
||||
|
||||
context 'when the value is true' do
|
||||
let(:value) { "true" }
|
||||
|
||||
it { is_expected.to eq("oui") }
|
||||
it { is_expected.to eq("Oui") }
|
||||
end
|
||||
|
||||
context 'when the value is nil' do
|
||||
let(:value) { nil }
|
||||
|
||||
it { is_expected.to eq("non") }
|
||||
it { is_expected.to eq("Non") }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -149,13 +149,12 @@ describe Gestionnaire, type: :model do
|
|||
end
|
||||
|
||||
it 'syncs credentials to associated administrateur' do
|
||||
gestionnaire = create(:gestionnaire)
|
||||
admin = create(:administrateur, email: gestionnaire.email)
|
||||
admin = create(:administrateur)
|
||||
gestionnaire = admin.gestionnaire
|
||||
|
||||
gestionnaire.update(email: 'whoami@plop.com', password: 'super secret')
|
||||
gestionnaire.update(password: 'super secret')
|
||||
|
||||
admin.reload
|
||||
expect(admin.email).to eq('whoami@plop.com')
|
||||
expect(admin.valid_password?('super secret')).to be(true)
|
||||
end
|
||||
end
|
||||
|
@ -413,6 +412,27 @@ describe Gestionnaire, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#young_login_token?' do
|
||||
let!(:gestionnaire) { create(:gestionnaire) }
|
||||
|
||||
context 'when there is a token' do
|
||||
let!(:good_token) { gestionnaire.login_token! }
|
||||
|
||||
context 'when the token has just been created' do
|
||||
it { expect(gestionnaire.young_login_token?).to be true }
|
||||
end
|
||||
|
||||
context 'when the token is a bit old' do
|
||||
before { gestionnaire.update(login_token_created_at: (Gestionnaire::LOGIN_TOKEN_YOUTH + 1.minute).ago) }
|
||||
it { expect(gestionnaire.young_login_token?).to be false }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are no token' do
|
||||
it { expect(gestionnaire.young_login_token?).to be false }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assign(procedure_to_assign)
|
||||
|
|
|
@ -361,6 +361,7 @@ describe Procedure do
|
|||
subject { @procedure }
|
||||
|
||||
it { expect(subject.parent_procedure).to eq(procedure) }
|
||||
it { expect(subject.gestionnaires.pluck(:email)).to eq([administrateur.email]) }
|
||||
|
||||
it 'should duplicate specific objects with different id' do
|
||||
expect(subject.id).not_to eq(procedure.id)
|
||||
|
@ -430,8 +431,6 @@ describe Procedure do
|
|||
|
||||
it 'should not duplicate specific related objects' do
|
||||
expect(subject.dossiers).to eq([])
|
||||
expect(subject.gestionnaires).to eq([])
|
||||
expect(subject.assign_to).to eq([])
|
||||
end
|
||||
|
||||
describe 'should not duplicate lien_notice' do
|
||||
|
|
|
@ -112,18 +112,35 @@ shared_examples 'type_de_champ_spec' do
|
|||
end
|
||||
|
||||
describe "repetition" do
|
||||
let(:type_de_champ) { create(:type_de_champ_repetition) }
|
||||
let(:procedure) { create(:procedure) }
|
||||
let(:type_de_champ) { create(:type_de_champ_repetition, procedure: procedure) }
|
||||
let(:type_de_champ_text) { create(:type_de_champ_text) }
|
||||
let(:type_de_champ_integer_number) { create(:type_de_champ_integer_number) }
|
||||
let(:type_de_champ_integer_number_attrs) { attributes_for(:type_de_champ_integer_number) }
|
||||
|
||||
it {
|
||||
it "associates nested types_de_champ to the parent procedure" do
|
||||
expect(type_de_champ.types_de_champ.size).to eq(0)
|
||||
type_de_champ.types_de_champ << type_de_champ_integer_number
|
||||
expect(procedure.types_de_champ.size).to eq(1)
|
||||
|
||||
procedure.update(types_de_champ_attributes: [
|
||||
{
|
||||
id: type_de_champ.id,
|
||||
libelle: type_de_champ.libelle,
|
||||
types_de_champ_attributes: [type_de_champ_integer_number_attrs]
|
||||
}
|
||||
])
|
||||
procedure.reload
|
||||
type_de_champ.reload
|
||||
|
||||
expect(procedure.types_de_champ.size).to eq(1)
|
||||
expect(type_de_champ.types_de_champ.size).to eq(1)
|
||||
|
||||
expect(type_de_champ.types_de_champ.first.parent).to eq(type_de_champ)
|
||||
expect(type_de_champ.types_de_champ.first.procedure).to eq(procedure)
|
||||
expect(type_de_champ.types_de_champ.first.private?).to eq(false)
|
||||
|
||||
type_de_champ.types_de_champ << type_de_champ_text
|
||||
expect(type_de_champ.types_de_champ.size).to eq(2)
|
||||
expect(type_de_champ_integer_number.parent).to eq(type_de_champ)
|
||||
expect(type_de_champ_text.parent).to eq(type_de_champ)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,7 +34,7 @@ describe 'admin/procedures/show.html.haml', type: :view do
|
|||
end
|
||||
|
||||
describe 'procedure link is not present' do
|
||||
it { expect(rendered).to have_content('Cette démarche n’a pas encore de lien, et n’est donc pas accessible par le public.') }
|
||||
it { expect(rendered).to have_content('Cette démarche n’a pas encore de lien, et n’est pas accessible par le public.') }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,21 +17,29 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
|
|||
let(:champ2) { create(:champ, :header_section, value: "Section") }
|
||||
let(:champ3) { create(:champ, :explication, value: "mazette") }
|
||||
let(:champ4) { create(:champ, :dossier_link, value: dossier.id) }
|
||||
let(:champs) { [champ1, champ2, champ3, champ4] }
|
||||
let(:champ5) { create(:champ_textarea, value: "Some long text in a textarea.") }
|
||||
let(:champs) { [champ1, champ2, champ3, champ4, champ5] }
|
||||
|
||||
before { dossier.avis << avis }
|
||||
|
||||
it { is_expected.to include(champ1.libelle) }
|
||||
it { is_expected.to include(champ1.value) }
|
||||
it "renders titles and values of champs" do
|
||||
expect(subject).to include(champ1.libelle)
|
||||
expect(subject).to include(champ1.value)
|
||||
|
||||
it { is_expected.to have_css(".header-section") }
|
||||
it { is_expected.to include(champ2.libelle) }
|
||||
expect(subject).to have_css(".header-section")
|
||||
expect(subject).to include(champ2.libelle)
|
||||
|
||||
it { is_expected.not_to include(champ3.libelle) }
|
||||
it { is_expected.not_to include(champ3.value) }
|
||||
expect(subject).to have_link("Dossier nº #{dossier.id}")
|
||||
expect(subject).to include(dossier.text_summary)
|
||||
|
||||
it { is_expected.to have_link("Dossier nº #{dossier.id}") }
|
||||
it { is_expected.to include(dossier.text_summary) }
|
||||
expect(subject).to include(champ5.libelle)
|
||||
expect(subject).to include(champ5.libelle)
|
||||
end
|
||||
|
||||
it "doesn't render explication champs" do
|
||||
expect(subject).not_to include(champ3.libelle)
|
||||
expect(subject).not_to include(champ3.value)
|
||||
end
|
||||
end
|
||||
|
||||
context "with a dossier champ, but we are not authorized to acces the dossier" do
|
||||
|
|
Loading…
Add table
Reference in a new issue