Merge pull request #5534 from betagouv/dev

2020-09-03-01
This commit is contained in:
Kara Diaby 2020-09-03 15:46:02 +02:00 committed by GitHub
commit 323ef832dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
99 changed files with 815 additions and 1293 deletions

18
.github/workflows/sentry-release.yml vendored Normal file
View file

@ -0,0 +1,18 @@
on:
push:
tags:
- '*'
name: Publish release on Sentry
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Sentry Release
uses: getsentry/action-release@v1.0.0
env:
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
SENTRY_PROJECT: rails
with:
environment: production

View file

@ -22,6 +22,7 @@ gem 'delayed_job_active_record'
gem 'delayed_job_web' gem 'delayed_job_web'
gem 'devise' # Gestion des comptes utilisateurs gem 'devise' # Gestion des comptes utilisateurs
gem 'devise-async' gem 'devise-async'
gem 'devise-i18n'
gem 'discard' gem 'discard'
gem 'dotenv-rails', require: 'dotenv/rails-now' # dotenv should always be loaded before rails gem 'dotenv-rails', require: 'dotenv/rails-now' # dotenv should always be loaded before rails
gem 'ffi-geos', require: false gem 'ffi-geos', require: false

View file

@ -205,6 +205,8 @@ GEM
devise-async (1.0.0) devise-async (1.0.0)
activejob (>= 5.0) activejob (>= 5.0)
devise (>= 4.0) devise (>= 4.0)
devise-i18n (1.9.2)
devise (>= 4.7.1)
diff-lcs (1.3) diff-lcs (1.3)
discard (1.2.0) discard (1.2.0)
activerecord (>= 4.2, < 7) activerecord (>= 4.2, < 7)
@ -787,6 +789,7 @@ DEPENDENCIES
delayed_job_web delayed_job_web
devise devise
devise-async devise-async
devise-i18n
discard discard
dotenv-rails dotenv-rails
factory_bot factory_bot

View file

@ -5,32 +5,11 @@
// //
// = require trix // = require trix
// We need to override trix.csss image gallery styles to accommodate the .trix-button-group.trix-button-group--file-tools {
// <action-text-attachment> element we wrap around attachments. Otherwise, display: none;
// images in galleries will be squished by the max-width: 33%; rule. }
.trix-content {
.attachment-gallery { trix-editor {
> action-text-attachment, min-height: 10em;
> .attachment { background-color: #FFFFFF;
flex: 1 0 33%;
padding: 0 0.5em;
max-width: 33%;
}
&.attachment-gallery--2,
&.attachment-gallery--4 {
> action-text-attachment,
> .attachment {
flex-basis: 50%;
max-width: 50%;
}
}
}
action-text-attachment {
.attachment {
padding: 0 !important;
max-width: 100% !important;
}
}
} }

View file

@ -0,0 +1,11 @@
// Push the timestamps column to the right of the row
.admin-procedures-list-timestamps {
margin-left: auto;
}
// Fix a Safari flexbox bug where the inner procedure logo
// would stretch the container vertically.
// See https://stackoverflow.com/questions/57516373/image-stretching-in-flexbox-in-safari
.admin-procedures-list-row.infos {
align-items: flex-start;
}

View file

@ -1,42 +0,0 @@
class Admin::MailTemplatesController < AdminController
before_action :retrieve_procedure
def index
@mail_templates = mail_templates
end
def edit
@mail_template = find_mail_template_by_slug(params[:id])
end
def update
mail_template = find_mail_template_by_slug(params[:id])
mail_template.update(update_params)
flash.notice = "Email mis à jour"
redirect_to edit_admin_procedure_mail_template_path(mail_template.procedure_id, params[:id])
end
private
def mail_templates
[
@procedure.initiated_mail_template,
@procedure.received_mail_template,
@procedure.closed_mail_template,
@procedure.refused_mail_template,
@procedure.without_continuation_mail_template
]
end
def find_mail_template_by_slug(slug)
mail_templates.find { |template| template.class.const_get(:SLUG) == slug }
end
def update_params
{
procedure_id: params[:procedure_id],
subject: params[:mail_template][:subject],
body: params[:mail_template][:body]
}
end
end

View file

@ -2,7 +2,11 @@ class FranceConnect::ParticulierController < ApplicationController
before_action :redirect_to_login_if_fc_aborted, only: [:callback] before_action :redirect_to_login_if_fc_aborted, only: [:callback]
def login def login
redirect_to FranceConnectService.authorization_uri if FranceConnectService.enabled?
redirect_to FranceConnectService.authorization_uri
else
redirect_to new_user_session_path
end
end end
def callback def callback

View file

@ -6,6 +6,24 @@ module NewAdministrateur
@mail_templates = mail_templates @mail_templates = mail_templates
end end
def edit
@procedure = procedure
@mail_template = find_mail_template_by_slug(params[:id])
end
def update
@procedure = procedure
mail_template = find_mail_template_by_slug(params[:id])
if mail_template.update(update_params)
flash.notice = "Email mis à jour"
else
flash.alert = mail_template.errors.full_messages
end
redirect_to edit_admin_procedure_mail_template_path(mail_template.procedure_id, params[:id])
end
def preview def preview
mail_template = find_mail_template_by_slug(params[:id]) mail_template = find_mail_template_by_slug(params[:id])
dossier = Dossier.new(id: '1', procedure: procedure) dossier = Dossier.new(id: '1', procedure: procedure)
@ -13,7 +31,7 @@ module NewAdministrateur
@dossier = dossier @dossier = dossier
@logo_url = procedure.logo_url @logo_url = procedure.logo_url
@service = procedure.service @service = procedure.service
@rendered_template = sanitize(mail_template.body) @rendered_template = sanitize(mail_template.rich_body.body.to_html)
@actions = mail_template.actions_for_dossier(dossier) @actions = mail_template.actions_for_dossier(dossier)
render(template: 'notification_mailer/send_notification', layout: 'mailers/notifications_layout') render(template: 'notification_mailer/send_notification', layout: 'mailers/notifications_layout')
@ -38,5 +56,14 @@ module NewAdministrateur
def find_mail_template_by_slug(slug) def find_mail_template_by_slug(slug)
mail_templates.find { |template| template.class.const_get(:SLUG) == slug } mail_templates.find { |template| template.class.const_get(:SLUG) == slug }
end end
def update_params
mail_template_id = params[:id]
{
procedure_id: params[:procedure_id],
subject: params["mails_#{mail_template_id}"] ? params["mails_#{mail_template_id}"][:subject] : params["mails_#{mail_template_id}_mail"][:subject],
body: params["mails_#{mail_template_id}"] ? params["mails_#{mail_template_id}"][:rich_body] : params["mails_#{mail_template_id}_mail"][:rich_body]
}
end
end end
end end

View file

@ -66,6 +66,7 @@ module NewAdministrateur
def create def create
@procedure = Procedure.new(procedure_params.merge(administrateurs: [current_administrateur])) @procedure = Procedure.new(procedure_params.merge(administrateurs: [current_administrateur]))
@procedure.draft_revision = @procedure.revisions.build
if !@procedure.save if !@procedure.save
flash.now.alert = @procedure.errors.full_messages flash.now.alert = @procedure.errors.full_messages
@ -73,8 +74,6 @@ module NewAdministrateur
else else
flash.notice = 'Démarche enregistrée.' flash.notice = 'Démarche enregistrée.'
current_administrateur.instructeur.assign_to_procedure(@procedure) current_administrateur.instructeur.assign_to_procedure(@procedure)
# FIXUP: needed during transition to revisions
RevisionsMigration.add_revisions(@procedure)
redirect_to champs_admin_procedure_path(@procedure) redirect_to champs_admin_procedure_path(@procedure)
end end

View file

@ -2,7 +2,6 @@ module NewAdministrateur
class TypesDeChampController < AdministrateurController class TypesDeChampController < AdministrateurController
before_action :retrieve_procedure, only: [:create, :update, :move, :destroy] before_action :retrieve_procedure, only: [:create, :update, :move, :destroy]
before_action :procedure_locked?, only: [:create, :update, :move, :destroy] before_action :procedure_locked?, only: [:create, :update, :move, :destroy]
before_action :revisions_migration
def create def create
type_de_champ = @procedure.draft_revision.add_type_de_champ(type_de_champ_create_params) type_de_champ = @procedure.draft_revision.add_type_de_champ(type_de_champ_create_params)
@ -16,7 +15,7 @@ module NewAdministrateur
end end
def update def update
type_de_champ = @procedure.draft_revision.find_or_clone_type_de_champ(type_de_champ_stable_id) type_de_champ = @procedure.draft_revision.find_or_clone_type_de_champ(TypeDeChamp.to_stable_id(params[:id]))
if type_de_champ.update(type_de_champ_update_params) if type_de_champ.update(type_de_champ_update_params)
reset_procedure reset_procedure
@ -27,13 +26,13 @@ module NewAdministrateur
end end
def move def move
@procedure.draft_revision.move_type_de_champ(type_de_champ_stable_id, (params[:position] || params[:order_place]).to_i) @procedure.draft_revision.move_type_de_champ(TypeDeChamp.to_stable_id(params[:id]), (params[:position] || params[:order_place]).to_i)
head :no_content head :no_content
end end
def destroy def destroy
@procedure.draft_revision.remove_type_de_champ(type_de_champ_stable_id) @procedure.draft_revision.remove_type_de_champ(TypeDeChamp.to_stable_id(params[:id]))
reset_procedure reset_procedure
head :no_content head :no_content
@ -41,19 +40,11 @@ module NewAdministrateur
private private
def type_de_champ_stable_id
TypeDeChamp.find(params[:id]).stable_id
end
def revisions_migration
# FIXUP: needed during transition to revisions
RevisionsMigration.add_revisions(@procedure)
end
def serialize_type_de_champ(type_de_champ) def serialize_type_de_champ(type_de_champ)
{ {
type_de_champ: type_de_champ.as_json( type_de_champ: type_de_champ.as_json(
except: [ except: [
:id,
:created_at, :created_at,
:options, :options,
:order_place, :order_place,
@ -73,7 +64,7 @@ module NewAdministrateur
:piece_justificative_template_url, :piece_justificative_template_url,
:quartiers_prioritaires :quartiers_prioritaires
] ]
) ).merge(id: TypeDeChamp.format_stable_id(type_de_champ.stable_id))
} }
end end
@ -92,7 +83,7 @@ module NewAdministrateur
:type_champ) :type_champ)
if type_de_champ_params[:parent_id].present? if type_de_champ_params[:parent_id].present?
type_de_champ_params[:parent_id] = TypeDeChamp.find(type_de_champ_params[:parent_id]).stable_id type_de_champ_params[:parent_id] = TypeDeChamp.to_stable_id(type_de_champ_params[:parent_id])
end end
type_de_champ_params type_de_champ_params

View file

@ -313,7 +313,8 @@ class StatsController < ApplicationController
procedure_id_type_de_champs_count = TypeDeChamp procedure_id_type_de_champs_count = TypeDeChamp
.where(private: false) .where(private: false)
.group(:procedure_id) .joins(:revision)
.group('procedure_revisions.procedure_id')
.count .count
groupe_instructeur_id_type_de_champs_count = groupe_instructeurs.reduce({}) do |acc, (gi_id, procedure_id)| groupe_instructeur_id_type_de_champs_count = groupe_instructeurs.reduce({}) do |acc, (gi_id, procedure_id)|

View file

@ -259,8 +259,6 @@ module Users
return redirect_to url_for dossiers_path return redirect_to url_for dossiers_path
end end
# FIXUP: needed during transition to revisions
RevisionsMigration.add_revisions(procedure)
dossier = Dossier.new( dossier = Dossier.new(
revision: procedure.active_revision, revision: procedure.active_revision,
groupe_instructeur: procedure.defaut_groupe_instructeur, groupe_instructeur: procedure.defaut_groupe_instructeur,

View file

@ -8,8 +8,8 @@ class ProcedureDashboard < Administrate::BaseDashboard
# which determines how the attribute is displayed # which determines how the attribute is displayed
# on pages throughout the dashboard. # on pages throughout the dashboard.
ATTRIBUTE_TYPES = { ATTRIBUTE_TYPES = {
types_de_champ: TypesDeChampCollectionField, published_types_de_champ: TypesDeChampCollectionField,
types_de_champ_private: TypesDeChampCollectionField, published_types_de_champ_private: TypesDeChampCollectionField,
path: ProcedureLinkField, path: ProcedureLinkField,
dossiers: Field::HasMany, dossiers: Field::HasMany,
administrateurs: Field::HasMany, administrateurs: Field::HasMany,
@ -70,8 +70,8 @@ class ProcedureDashboard < Administrate::BaseDashboard
:whitelisted_at, :whitelisted_at,
:hidden_at, :hidden_at,
:closed_at, :closed_at,
:types_de_champ, :published_types_de_champ,
:types_de_champ_private, :published_types_de_champ_private,
:for_individual, :for_individual,
:auto_archive_on, :auto_archive_on,
:initiated_mail_template, :initiated_mail_template,

View file

@ -140,7 +140,7 @@ module ApplicationHelper
end end
def try_format_date(date) def try_format_date(date)
date.present? ? I18n.l(date) : '' date.present? ? I18n.l(date, format: :long) : ''
end end
def try_format_datetime(datetime) def try_format_datetime(datetime)

View file

@ -40,6 +40,19 @@ function MapEditor({ featureCollection, url, preview, hasCadastres, ign }) {
hasCadastres hasCadastres
]); ]);
const translations = [
['.mapbox-gl-draw_line', 'Tracer une ligne'],
['.mapbox-gl-draw_polygon', 'Dessiner un polygone'],
['.mapbox-gl-draw_point', 'Ajouter un point'],
['.mapbox-gl-draw_trash', 'Supprimer']
];
for (const [selector, translation] of translations) {
const element = document.querySelector(selector);
if (element) {
element.setAttribute('title', translation);
}
}
const onFeatureFocus = useCallback( const onFeatureFocus = useCallback(
({ detail }) => { ({ detail }) => {
const { id } = detail; const { id } = detail;

View file

@ -210,7 +210,6 @@ export const FIELDS = [
'drop_down_list_value', 'drop_down_list_value',
'libelle', 'libelle',
'mandatory', 'mandatory',
'order_place',
'parcelles_agricoles', 'parcelles_agricoles',
'parent_id', 'parent_id',
'piece_justificative_template', 'piece_justificative_template',

View file

@ -22,7 +22,7 @@ export function moveTypeDeChampOperation(typeDeChamp, index, queue) {
return queue.enqueue({ return queue.enqueue({
path: `/${typeDeChamp.id}/move`, path: `/${typeDeChamp.id}/move`,
method: 'patch', method: 'patch',
payload: { order_place: index } payload: { position: index }
}); });
} }

View file

@ -37,8 +37,7 @@ export default function typeDeChampsReducer(state, { type, params, done }) {
function addTypeDeChamp(state, typeDeChamps, insertAfter, done) { function addTypeDeChamp(state, typeDeChamps, insertAfter, done) {
const typeDeChamp = { const typeDeChamp = {
...state.defaultTypeDeChampAttributes, ...state.defaultTypeDeChampAttributes
order_place: typeDeChamps.length
}; };
createTypeDeChampOperation(typeDeChamp, state.queue) createTypeDeChampOperation(typeDeChamp, state.queue)

View file

@ -1,6 +1,7 @@
import '../shared/polyfills'; import '../shared/polyfills';
import Rails from '@rails/ujs'; import Rails from '@rails/ujs';
import * as ActiveStorage from '@rails/activestorage'; import * as ActiveStorage from '@rails/activestorage';
import 'trix';
import '@rails/actiontext'; import '@rails/actiontext';
import 'whatwg-fetch'; // window.fetch polyfill import 'whatwg-fetch'; // window.fetch polyfill
import ReactRailsUJS from 'react_ujs'; import ReactRailsUJS from 'react_ujs';

View file

@ -7,6 +7,12 @@ const COMPLETE_CLASS = 'direct-upload--complete';
rendering upload progress bar. It is used to handle rendering upload progress bar. It is used to handle
direct-upload form ujs events but also in the direct-upload form ujs events but also in the
Uploader delegate used with uploads on json api. Uploader delegate used with uploads on json api.
As the associated DOM element may disappear for some
reason (a dynamic React list, an element being removed
and recreated again later, etc.), this class doesn't
raise any error if the associated DOM element cannot
be found.
*/ */
export default class ProgressBar { export default class ProgressBar {
static init(input, id, file) { static init(input, id, file) {
@ -17,27 +23,31 @@ export default class ProgressBar {
static start(id) { static start(id) {
const element = getDirectUploadElement(id); const element = getDirectUploadElement(id);
if (element) {
element.classList.remove(PENDING_CLASS); element.classList.remove(PENDING_CLASS);
}
} }
static progress(id, progress) { static progress(id, progress) {
const element = getDirectUploadProgressElement(id); const element = getDirectUploadProgressElement(id);
if (element) {
element.style.width = `${progress}%`; element.style.width = `${progress}%`;
}
} }
static error(id, error) { static error(id, error) {
const element = getDirectUploadElement(id); const element = getDirectUploadElement(id);
if (element) {
element.classList.add(ERROR_CLASS); element.classList.add(ERROR_CLASS);
element.setAttribute('title', error); element.setAttribute('title', error);
}
} }
static end(id) { static end(id) {
const element = getDirectUploadElement(id); const element = getDirectUploadElement(id);
if (element) {
element.classList.add(COMPLETE_CLASS); element.classList.add(COMPLETE_CLASS);
}
} }
static render(id, filename) { static render(id, filename) {

View file

@ -1,6 +1,8 @@
class ApplicationJob < ActiveJob::Base class ApplicationJob < ActiveJob::Base
DEFAULT_MAX_ATTEMPTS_JOBS = 25 DEFAULT_MAX_ATTEMPTS_JOBS = 25
retry_on Excon::Error::BadRequest
before_perform do |job| before_perform do |job|
Rails.logger.info("#{job.class.name} started at #{Time.zone.now}") Rails.logger.info("#{job.class.name} started at #{Time.zone.now}")
end end

View file

@ -24,7 +24,7 @@ class FindDubiousProceduresJob < CronJob
.where(procedures: { closed_at: nil, whitelisted_at: nil }) .where(procedures: { closed_at: nil, whitelisted_at: nil })
dubious_procedures_and_tdcs = forbidden_tdcs dubious_procedures_and_tdcs = forbidden_tdcs
.group_by(&:procedure_id) .group_by { |type_de_champ| type_de_champ.procedure.id }
.map { |_procedure_id, tdcs| [tdcs[0].procedure, tdcs] } .map { |_procedure_id, tdcs| [tdcs[0].procedure, tdcs] }
AdministrationMailer.dubious_procedures(dubious_procedures_and_tdcs).deliver_later AdministrationMailer.dubious_procedures(dubious_procedures_and_tdcs).deliver_later

View file

@ -1,21 +0,0 @@
class TmpDossiersMigrateRevisionsJob < ApplicationJob
def perform(except)
dossiers = Dossier.with_discarded.where(revision_id: nil)
dossiers.where
.not(id: except)
.includes(procedure: [:draft_revision, :published_revision])
.limit(2000)
.find_each do |dossier|
if dossier.procedure.present?
dossier.update_column(:revision_id, dossier.procedure.active_revision.id)
else
except << dossier.id
end
end
if dossiers.where.not(id: except).exists?
TmpDossiersMigrateRevisionsJob.perform_later(except)
end
end
end

View file

@ -1,7 +1,10 @@
class VirusScannerJob < ApplicationJob class VirusScannerJob < ApplicationJob
queue_as :active_storage_analysis queue_as :active_storage_analysis
# If by the time the job runs the blob has been deleted, ignore the error
discard_on ActiveRecord::RecordNotFound discard_on ActiveRecord::RecordNotFound
# If the file is deleted during the scan, ignore the error
discard_on ActiveStorage::FileNotFoundError
def perform(blob) def perform(blob)
metadata = extract_metadata_via_virus_scanner(blob) metadata = extract_metadata_via_virus_scanner(blob)

View file

@ -47,6 +47,9 @@ class Champ < ApplicationRecord
scope :public_only, -> { where(private: false) } scope :public_only, -> { where(private: false) }
scope :private_only, -> { where(private: true) } scope :private_only, -> { where(private: true) }
scope :ordered, -> { includes(:type_de_champ).order(:row, 'types_de_champ.order_place') } scope :ordered, -> { includes(:type_de_champ).order(:row, 'types_de_champ.order_place') }
scope :public_ordered, -> { public_only.joins(dossier: { revision: :revision_types_de_champ }).where('procedure_revision_types_de_champ.type_de_champ_id = champs.type_de_champ_id').order(:position) }
scope :private_ordered, -> { private_only.joins(dossier: { revision: :revision_types_de_champ_private }).where('procedure_revision_types_de_champ.type_de_champ_id = champs.type_de_champ_id').order(:position) }
scope :root, -> { where(parent_id: nil) } scope :root, -> { where(parent_id: nil) }
before_validation :set_dossier_id, if: :needs_dossier_id? before_validation :set_dossier_id, if: :needs_dossier_id?

View file

@ -33,8 +33,9 @@ module MailTemplateConcern
module ClassMethods module ClassMethods
def default_for_procedure(procedure) def default_for_procedure(procedure)
template_name = default_template_name_for_procedure(procedure) template_name = default_template_name_for_procedure(procedure)
body = ActionController::Base.new.render_to_string(template: template_name) rich_body = ActionController::Base.new.render_to_string(template: template_name)
new(subject: const_get(:DEFAULT_SUBJECT), body: body, procedure: procedure) trix_rich_body = rich_body.gsub(/(?<!^|[.-])(?<!<\/strong>)\n/, '')
new(subject: const_get(:DEFAULT_SUBJECT), rich_body: trix_rich_body, procedure: procedure)
end end
def default_template_name_for_procedure(procedure) def default_template_name_for_procedure(procedure)

View file

@ -62,8 +62,8 @@ class Dossier < ApplicationRecord
has_one_attached :justificatif_motivation has_one_attached :justificatif_motivation
has_many :champs, -> { root.public_only.ordered }, inverse_of: :dossier, dependent: :destroy has_many :champs, -> { root.public_ordered }, inverse_of: :dossier, dependent: :destroy
has_many :champs_private, -> { root.private_only.ordered }, class_name: 'Champ', inverse_of: :dossier, dependent: :destroy has_many :champs_private, -> { root.private_ordered }, class_name: 'Champ', inverse_of: :dossier, dependent: :destroy
has_many :commentaires, inverse_of: :dossier, dependent: :destroy has_many :commentaires, inverse_of: :dossier, dependent: :destroy
has_many :invites, dependent: :destroy has_many :invites, dependent: :destroy
has_many :follows, -> { active }, inverse_of: :dossier has_many :follows, -> { active }, inverse_of: :dossier
@ -76,10 +76,13 @@ class Dossier < ApplicationRecord
has_many :dossier_operation_logs, -> { order(:created_at) }, dependent: :nullify, inverse_of: :dossier has_many :dossier_operation_logs, -> { order(:created_at) }, dependent: :nullify, inverse_of: :dossier
belongs_to :groupe_instructeur, optional: false belongs_to :groupe_instructeur, optional: false
has_one :procedure, through: :groupe_instructeur belongs_to :revision, class_name: 'ProcedureRevision', optional: false
belongs_to :revision, class_name: 'ProcedureRevision', optional: true
belongs_to :user, optional: false belongs_to :user, optional: false
has_one :procedure, through: :revision
has_many :types_de_champ, through: :revision
has_many :types_de_champ_private, through: :revision
accepts_nested_attributes_for :champs accepts_nested_attributes_for :champs
accepts_nested_attributes_for :champs_private accepts_nested_attributes_for :champs_private
@ -315,7 +318,6 @@ class Dossier < ApplicationRecord
accepts_nested_attributes_for :individual accepts_nested_attributes_for :individual
delegate :siret, :siren, to: :etablissement, allow_nil: true delegate :siret, :siren, to: :etablissement, allow_nil: true
delegate :types_de_champ, to: :procedure
delegate :france_connect_information, to: :user delegate :france_connect_information, to: :user
before_save :build_default_champs, if: Proc.new { groupe_instructeur_id_was.nil? } before_save :build_default_champs, if: Proc.new { groupe_instructeur_id_was.nil? }
@ -326,7 +328,7 @@ class Dossier < ApplicationRecord
after_create :send_draft_notification_email after_create :send_draft_notification_email
validates :user, presence: true validates :user, presence: true
validates :individual, presence: true, if: -> { procedure.for_individual? } validates :individual, presence: true, if: -> { revision.procedure.for_individual? }
validates :groupe_instructeur, presence: true validates :groupe_instructeur, presence: true
def motivation def motivation
@ -351,10 +353,10 @@ class Dossier < ApplicationRecord
end end
def build_default_champs def build_default_champs
procedure.build_champs.each do |champ| revision.build_champs.each do |champ|
champs << champ champs << champ
end end
procedure.build_champs_private.each do |champ| revision.build_champs_private.each do |champ|
champs_private << champ champs_private << champ
end end
end end

View file

@ -56,13 +56,16 @@ class Procedure < ApplicationRecord
MAX_DUREE_CONSERVATION = 36 MAX_DUREE_CONSERVATION = 36
MAX_DUREE_CONSERVATION_EXPORT = 3.hours MAX_DUREE_CONSERVATION_EXPORT = 3.hours
has_many :types_de_champ, -> { root.public_only.ordered }, inverse_of: :procedure, dependent: :destroy
has_many :types_de_champ_private, -> { root.private_only.ordered }, class_name: 'TypeDeChamp', inverse_of: :procedure, dependent: :destroy
has_many :revisions, -> { order(:id) }, class_name: 'ProcedureRevision', inverse_of: :procedure, dependent: :destroy has_many :revisions, -> { order(:id) }, class_name: 'ProcedureRevision', inverse_of: :procedure, dependent: :destroy
belongs_to :draft_revision, class_name: 'ProcedureRevision', optional: true belongs_to :draft_revision, class_name: 'ProcedureRevision', optional: false
belongs_to :published_revision, class_name: 'ProcedureRevision', optional: true belongs_to :published_revision, class_name: 'ProcedureRevision', optional: true
has_many :deleted_dossiers, dependent: :destroy has_many :deleted_dossiers, dependent: :destroy
has_many :published_types_de_champ, through: :published_revision, source: :types_de_champ
has_many :published_types_de_champ_private, through: :published_revision, source: :types_de_champ_private
has_many :draft_types_de_champ, through: :draft_revision, source: :types_de_champ
has_many :draft_types_de_champ_private, through: :draft_revision, source: :types_de_champ_private
has_one :module_api_carto, dependent: :destroy has_one :module_api_carto, dependent: :destroy
has_one :attestation_template, dependent: :destroy has_one :attestation_template, dependent: :destroy
@ -74,6 +77,14 @@ class Procedure < ApplicationRecord
brouillon? ? draft_revision : published_revision brouillon? ? draft_revision : published_revision
end end
def types_de_champ
brouillon? ? draft_types_de_champ : published_types_de_champ
end
def types_de_champ_private
brouillon? ? draft_types_de_champ_private : published_types_de_champ_private
end
has_many :administrateurs_procedures has_many :administrateurs_procedures
has_many :administrateurs, through: :administrateurs_procedures, after_remove: -> (procedure, _admin) { procedure.validate! } has_many :administrateurs, through: :administrateurs_procedures, after_remove: -> (procedure, _admin) { procedure.validate! }
has_many :groupe_instructeurs, dependent: :destroy has_many :groupe_instructeurs, dependent: :destroy
@ -93,9 +104,6 @@ class Procedure < ApplicationRecord
has_one_attached :notice has_one_attached :notice
has_one_attached :deliberation has_one_attached :deliberation
accepts_nested_attributes_for :types_de_champ, reject_if: proc { |attributes| attributes['libelle'].blank? }, allow_destroy: true
accepts_nested_attributes_for :types_de_champ_private, reject_if: proc { |attributes| attributes['libelle'].blank? }, allow_destroy: true
scope :brouillons, -> { where(aasm_state: :brouillon) } scope :brouillons, -> { where(aasm_state: :brouillon) }
scope :publiees, -> { where(aasm_state: :publiee) } scope :publiees, -> { where(aasm_state: :publiee) }
scope :closes, -> { where(aasm_state: [:close, :depubliee]) } scope :closes, -> { where(aasm_state: [:close, :depubliee]) }
@ -114,9 +122,15 @@ class Procedure < ApplicationRecord
scope :for_api, -> { scope :for_api, -> {
includes( includes(
:administrateurs, :administrateurs,
:types_de_champ_private, :module_api_carto,
:types_de_champ, published_revision: [
:module_api_carto :types_de_champ_private,
:types_de_champ
],
draft_revision: [
:types_de_champ_private,
:types_de_champ
]
) )
} }
@ -289,22 +303,13 @@ class Procedure < ApplicationRecord
# to save a dossier created from this method # to save a dossier created from this method
def new_dossier def new_dossier
Dossier.new( Dossier.new(
procedure: self,
revision: active_revision, revision: active_revision,
champs: build_champs, champs: active_revision.build_champs,
champs_private: build_champs_private, champs_private: active_revision.build_champs_private,
groupe_instructeur: defaut_groupe_instructeur groupe_instructeur: defaut_groupe_instructeur
) )
end end
def build_champs
types_de_champ.map(&:build_champ)
end
def build_champs_private
types_de_champ_private.map(&:build_champ)
end
def path_customized? def path_customized?
!path.match?(/[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}/) !path.match?(/[[:xdigit:]]{8}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{4}-[[:xdigit:]]{12}/)
end end
@ -318,9 +323,6 @@ class Procedure < ApplicationRecord
end end
def clone(admin, from_library) def clone(admin, from_library)
# FIXUP: needed during transition to revisions
RevisionsMigration.add_revisions(self)
is_different_admin = !admin.owns?(self) is_different_admin = !admin.owns?(self)
populate_champ_stable_ids populate_champ_stable_ids
@ -371,19 +373,11 @@ class Procedure < ApplicationRecord
end end
procedure.save procedure.save
procedure.draft_revision.types_de_champ.update_all(revision_id: procedure.draft_revision.id) procedure.draft_types_de_champ.update_all(revision_id: procedure.draft_revision.id)
procedure.draft_revision.types_de_champ_private.update_all(revision_id: procedure.draft_revision.id) procedure.draft_types_de_champ_private.update_all(revision_id: procedure.draft_revision.id)
# FIXUP: needed during transition to revisions
procedure.draft_revision.types_de_champ.each do |type_de_champ|
procedure.types_de_champ << type_de_champ
end
procedure.draft_revision.types_de_champ_private.each do |type_de_champ|
procedure.types_de_champ_private << type_de_champ
end
if is_different_admin || from_library if is_different_admin || from_library
procedure.types_de_champ.each { |tdc| tdc.options&.delete(:old_pj) } procedure.draft_types_de_champ.each { |tdc| tdc.options&.delete(:old_pj) }
end end
procedure procedure
@ -480,7 +474,7 @@ class Procedure < ApplicationRecord
def closed_mail_template_attestation_inconsistency_state def closed_mail_template_attestation_inconsistency_state
# As an optimization, dont check the predefined templates (they are presumed correct) # As an optimization, dont check the predefined templates (they are presumed correct)
if closed_mail.present? if closed_mail.present?
tag_present = closed_mail.body.include?("--lien attestation--") tag_present = closed_mail.body.to_s.include?("--lien attestation--")
if attestation_template&.activated? && !tag_present if attestation_template&.activated? && !tag_present
:missing_tag :missing_tag
elsif !attestation_template&.activated? && tag_present elsif !attestation_template&.activated? && tag_present
@ -608,23 +602,14 @@ class Procedure < ApplicationRecord
end end
def after_publish(canonical_procedure = nil) def after_publish(canonical_procedure = nil)
# FIXUP: needed during transition to revisions update!(published_at: Time.zone.now, canonical_procedure: canonical_procedure, draft_revision: create_new_revision, published_revision: draft_revision)
if RevisionsMigration.add_revisions(self)
update!(published_at: Time.zone.now, canonical_procedure: canonical_procedure)
else
update!(published_at: Time.zone.now, canonical_procedure: canonical_procedure, draft_revision: create_new_revision, published_revision: draft_revision)
end
end end
def after_close def after_close
# FIXUP: needed during transition to revisions
RevisionsMigration.add_revisions(self)
update!(closed_at: Time.zone.now) update!(closed_at: Time.zone.now)
end end
def after_unpublish def after_unpublish
# FIXUP: needed during transition to revisions
RevisionsMigration.add_revisions(self)
update!(unpublished_at: Time.zone.now) update!(unpublished_at: Time.zone.now)
end end

View file

@ -9,15 +9,22 @@
# #
class ProcedureRevision < ApplicationRecord class ProcedureRevision < ApplicationRecord
self.implicit_order_column = :created_at self.implicit_order_column = :created_at
belongs_to :procedure, -> { with_discarded }, inverse_of: :revisions belongs_to :procedure, -> { with_discarded }, inverse_of: :revisions, optional: false
has_many :revision_types_de_champ, -> { public_only.ordered }, class_name: 'ProcedureRevisionTypeDeChamp', foreign_key: :revision_id, dependent: :destroy, inverse_of: :revision has_many :revision_types_de_champ, -> { public_only.ordered }, class_name: 'ProcedureRevisionTypeDeChamp', foreign_key: :revision_id, dependent: :destroy, inverse_of: :revision
has_many :revision_types_de_champ_private, -> { private_only.ordered }, class_name: 'ProcedureRevisionTypeDeChamp', foreign_key: :revision_id, dependent: :destroy, inverse_of: :revision has_many :revision_types_de_champ_private, -> { private_only.ordered }, class_name: 'ProcedureRevisionTypeDeChamp', foreign_key: :revision_id, dependent: :destroy, inverse_of: :revision
has_many :types_de_champ, through: :revision_types_de_champ, source: :type_de_champ has_many :types_de_champ, through: :revision_types_de_champ, source: :type_de_champ
has_many :types_de_champ_private, through: :revision_types_de_champ_private, source: :type_de_champ has_many :types_de_champ_private, through: :revision_types_de_champ_private, source: :type_de_champ
def build_champs
types_de_champ.map(&:build_champ)
end
def build_champs_private
types_de_champ_private.map(&:build_champ)
end
def add_type_de_champ(params) def add_type_de_champ(params)
params[:procedure] = procedure
params[:revision] = self params[:revision] = self
if params[:parent_id] if params[:parent_id]
@ -27,15 +34,9 @@ class ProcedureRevision < ApplicationRecord
params[:order_place] = types_de_champ.present? ? types_de_champ.last.order_place + 1 : 0 params[:order_place] = types_de_champ.present? ? types_de_champ.last.order_place + 1 : 0
end.create(params) end.create(params)
elsif params[:private] elsif params[:private]
types_de_champ_private.tap do |types_de_champ| types_de_champ_private.create(params)
# FIXUP: needed during transition to revisions
params[:order_place] = types_de_champ.present? ? types_de_champ.last.order_place + 1 : 0
end.create(params)
else else
types_de_champ.tap do |types_de_champ| types_de_champ.create(params)
# FIXUP: needed during transition to revisions
params[:order_place] = types_de_champ.present? ? types_de_champ.last.order_place + 1 : 0
end.create(params)
end end
end end
@ -112,8 +113,6 @@ class ProcedureRevision < ApplicationRecord
if types_de_champ.delete_at(old_index) if types_de_champ.delete_at(old_index)
types_de_champ.insert(new_index, type_de_champ) types_de_champ.insert(new_index, type_de_champ)
.map.with_index do |type_de_champ, index| .map.with_index do |type_de_champ, index|
# FIXUP: needed during transition to revisions
type_de_champ.update!(order_place: index)
[type_de_champ.id, index] [type_de_champ.id, index]
end end
else else

View file

@ -26,15 +26,11 @@ class ProcedureRevisionTypeDeChamp < ApplicationRecord
private private
def set_position def set_position
self.position ||= if private? self.position ||= begin
if revision.types_de_champ_private.present? types_de_champ = (private? ? revision.revision_types_de_champ_private : revision.revision_types_de_champ).filter(&:persisted?)
revision.revision_types_de_champ_private.filter(&:persisted?).last.position + 1
else if types_de_champ.present?
0 types_de_champ.last.position + 1
end
else
if revision.types_de_champ.present?
revision.revision_types_de_champ.filter(&:persisted?).last.position + 1
else else
0 0
end end

View file

@ -18,6 +18,8 @@
# stable_id :bigint # stable_id :bigint
# #
class TypeDeChamp < ApplicationRecord class TypeDeChamp < ApplicationRecord
self.ignored_columns = ['procedure_id']
enum type_champs: { enum type_champs: {
text: 'text', text: 'text',
textarea: 'textarea', textarea: 'textarea',
@ -49,8 +51,8 @@ class TypeDeChamp < ApplicationRecord
repetition: 'repetition' repetition: 'repetition'
} }
belongs_to :procedure, optional: false
belongs_to :revision, class_name: 'ProcedureRevision', optional: true belongs_to :revision, class_name: 'ProcedureRevision', optional: true
has_one :procedure, through: :revision
belongs_to :parent, class_name: 'TypeDeChamp', optional: true belongs_to :parent, class_name: 'TypeDeChamp', optional: true
has_many :types_de_champ, -> { ordered }, foreign_key: :parent_id, class_name: 'TypeDeChamp', inverse_of: :parent, dependent: :destroy has_many :types_de_champ, -> { ordered }, foreign_key: :parent_id, class_name: 'TypeDeChamp', inverse_of: :parent, dependent: :destroy
@ -73,7 +75,6 @@ class TypeDeChamp < ApplicationRecord
serialize :options, WithIndifferentAccess serialize :options, WithIndifferentAccess
after_initialize :set_dynamic_type after_initialize :set_dynamic_type
before_validation :setup_procedure
after_create :populate_stable_id after_create :populate_stable_id
attr_reader :dynamic_type attr_reader :dynamic_type
@ -298,9 +299,34 @@ class TypeDeChamp < ApplicationRecord
.merge(include: { types_de_champ: TYPES_DE_CHAMP_BASE }) .merge(include: { types_de_champ: TYPES_DE_CHAMP_BASE })
def self.as_json_for_editor def self.as_json_for_editor
includes(piece_justificative_template_attachment: :blob, includes(piece_justificative_template_attachment: :blob, types_de_champ: [piece_justificative_template_attachment: :blob]).as_json(TYPES_DE_CHAMP)
types_de_champ: [piece_justificative_template_attachment: :blob]) end
.as_json(TYPES_DE_CHAMP)
def read_attribute_for_serialization(name)
if name == 'id'
self.class.format_stable_id(stable_id)
else
super
end
end
# FIXME: We are changing how id is exposed to the editor.
# We used to expose type_de_champ.id as primary key to the editor. With revisions
# we need primary key to be type_de_champ.stable_id because any update can create
# a new version but we do not want editor to know about this.
# This is only needed for a clean migration without downtime. We want to ensure
# that if editor send a simple id because it was loaded before deployment
# we would still do the right thing.
def self.format_stable_id(stable_id)
"stable:#{stable_id}"
end
def self.to_stable_id(id_or_stable_id)
if id_or_stable_id.to_s =~ /^stable:/
id_or_stable_id.to_s.gsub(/^stable:/, '')
else
find(id_or_stable_id).stable_id
end
end end
private private
@ -311,12 +337,6 @@ class TypeDeChamp < ApplicationRecord
result.blank? ? [] : [''] + result result.blank? ? [] : [''] + result
end end
def setup_procedure
types_de_champ.each do |type_de_champ|
type_de_champ.procedure = procedure
end
end
def populate_stable_id def populate_stable_id
if !stable_id if !stable_id
update_column(:stable_id, id) update_column(:stable_id, id)

View file

@ -67,7 +67,7 @@ class DossierSerializer < ActiveModel::Serializer
end end
def types_de_piece_justificative def types_de_piece_justificative
PiecesJustificativesService.serialize_types_de_champ_as_type_pj(object) PiecesJustificativesService.serialize_types_de_champ_as_type_pj(object.revision)
end end
def email def email

View file

@ -48,6 +48,6 @@ class ProcedureSerializer < ActiveModel::Serializer
end end
def types_de_piece_justificative def types_de_piece_justificative
PiecesJustificativesService.serialize_types_de_champ_as_type_pj(object) PiecesJustificativesService.serialize_types_de_champ_as_type_pj(object.active_revision)
end end
end end

View file

@ -1,4 +1,8 @@
class FranceConnectService class FranceConnectService
def self.enabled?
ENV.fetch("FRANCE_CONNECT_ENABLED", "enabled") == "enabled"
end
def self.authorization_uri def self.authorization_uri
client = FranceConnectParticulierClient.new client = FranceConnectParticulierClient.new

View file

@ -12,8 +12,8 @@ class PiecesJustificativesService
.sum(&:byte_size) .sum(&:byte_size)
end end
def self.serialize_types_de_champ_as_type_pj(procedure) def self.serialize_types_de_champ_as_type_pj(revision)
tdcs = procedure.types_de_champ.filter { |type_champ| type_champ.old_pj.present? } tdcs = revision.types_de_champ.filter { |type_champ| type_champ.old_pj.present? }
tdcs.map.with_index do |type_champ, order_place| tdcs.map.with_index do |type_champ, order_place|
description = type_champ.description description = type_champ.description
if /^(?<original_description>.*?)(?:[\r\n]+)Récupérer le formulaire vierge pour mon dossier : (?<lien_demarche>http.*)$/m =~ description if /^(?<original_description>.*?)(?:[\r\n]+)Récupérer le formulaire vierge pour mon dossier : (?<lien_demarche>http.*)$/m =~ description

View file

@ -1,36 +0,0 @@
class RevisionsMigration
def self.add_revisions(procedure)
if procedure.draft_revision.present?
return false
end
procedure.draft_revision = procedure.revisions.create
procedure.save!(validate: false)
add_types_de_champs_to_revision(procedure, :types_de_champ)
add_types_de_champs_to_revision(procedure, :types_de_champ_private)
if !procedure.brouillon?
published_revision = procedure.draft_revision
procedure.draft_revision = procedure.create_new_revision
procedure.published_revision = published_revision
procedure.save!(validate: false)
end
true
end
def self.add_types_de_champs_to_revision(procedure, types_de_champ_scope)
types_de_champ = procedure.send(types_de_champ_scope)
types_de_champ.where(revision_id: nil).update_all(revision_id: procedure.draft_revision.id)
types_de_champ.each.with_index do |type_de_champ, index|
type_de_champ.types_de_champ.where(revision_id: nil).update_all(revision_id: procedure.draft_revision.id)
procedure.draft_revision.send(:"revision_#{types_de_champ_scope}").create!(
type_de_champ: type_de_champ,
position: index
)
end
end
end

View file

@ -1,40 +0,0 @@
- if params[:id] == 'closed_mail'
= render partial: 'admin/closed_mail_template_attestation_inconsistency_alert'
.white-back
%h3
= @mail_template.class.const_get(:DISPLAYED_NAME)
= form_for @mail_template,
as: 'mail_template',
url: admin_procedure_mail_template_path(@procedure, @mail_template.class.const_get(:SLUG)),
method: :put do |f|
.row
.col-md-6
.form-group.string.optional.mail_template_subject
= f.label :subject, "Objet de l'email", class: 'control-label string optional'
= f.text_field :subject, class: 'form-control string optional'
.form-group.text.optional.mail_template_body
= f.label :body, "Corps de l'email", class: 'control-label string optional'
= f.text_area :body, class: 'wysihtml5 form-control text optional'
.text-right
= link_to "Annuler", admin_procedure_mail_templates_path(@procedure), class: "btn btn-default"
= f.submit 'Mettre à jour', class: "btn btn-default btn-success"
= link_to "Prévisualiser", preview_admin_procedure_mail_template_path(@procedure, @mail_template.class.const_get(:SLUG)), class: "btn btn-primary", target: "_blank"
.row
.col-md-12
%table.table
%tr
%th.col-md-3
Balise
%th
Description
- @mail_template.tags.each do |tag|
%tr
%td
%code{ style: "white-space: pre-wrap;" }
= "--#{tag[:libelle]}--"
%td
= tag[:description]

View file

@ -1,14 +0,0 @@
= render partial: 'admin/closed_mail_template_attestation_inconsistency_alert'
#custom-mails
.wrapper
%h1 E-mails personnalisables
%table.table
%tr
%th{ colspan: 2 }
Type d'email
- @mail_templates.each do |mail_template|
%tr
%td
= mail_template.class.const_get(:DISPLAYED_NAME)
%td.text-right
= link_to "Personnaliser l'e-mail", edit_admin_procedure_mail_template_path(@procedure, mail_template.class.const_get(:SLUG))

View file

@ -4,5 +4,5 @@
- if defined?(service) && service && service.nom.present? - if defined?(service) && service && service.nom.present?
= service.nom = service.nom
- else - else
-# The WORD JOINER unicode entity prevents email clients from auto-linking the signature -# The WORD JOINER unicode entity (&#8288;) prevents email clients from auto-linking the signature
Léquipe demarches-simplifiees&#8288;.fr Léquipe #{APPLICATION_NAME.gsub(".","&#8288;.").html_safe}

View file

@ -0,0 +1 @@
%iframe{ src: preview_admin_procedure_mail_template_path, width: '100%', height: '650px' }

View file

@ -0,0 +1,47 @@
= f.label :subject do
Objet de l'email
%span.mandatory *
= f.text_field :subject, required: true
= f.label :body do
Corps de l'email
%span.mandatory *
= f.rich_text_area :rich_body, required: true, class: "mb-4"
#tags-table
%h2.add-tag-title
Insérer une balise
%p.notice
Copiez-collez les balises ci-dessous pour afficher automatiquement linformation souhaitée.
.head
.tag Balise
.description Description
.items
- @mail_template.tags.each do |tag|
.item
%code.tag
= "--#{tag[:libelle]}--"
.description
= tag[:description]
-# Disable accepting dropped images and traduce toolbar tooltips
:javascript
addEventListener('trix-file-accept', function(e) { e.preventDefault(); });
addEventListener("trix-initialize", function(e) {
document.querySelector('button[data-trix-attribute="bold"]').setAttribute('title', 'Gras');
document.querySelector('button[data-trix-attribute="italic"]').setAttribute('title', 'Italique');
document.querySelector('button[data-trix-attribute="strike"]').setAttribute('title', 'Barrer');
document.querySelector('button[data-trix-attribute="href"]').setAttribute('title', 'Créer lien');
document.querySelector('button[data-trix-attribute="heading1"]').setAttribute('title', 'Titre');
document.querySelector('button[data-trix-attribute="quote"]').setAttribute('title', 'Citation');
document.querySelector('button[data-trix-attribute="bullet"]').setAttribute('title', 'Liste à puce');
document.querySelector('button[data-trix-attribute="number"]').setAttribute('title', 'Liste numérotée');
document.querySelector('button[data-trix-action="increaseNestingLevel"]').setAttribute('title', 'Indenter');
document.querySelector('button[data-trix-action="decreaseNestingLevel"]').setAttribute('title', 'Désindenter');
document.querySelector('button[data-trix-action="undo"]').setAttribute('title', 'Annuler la modification');
document.querySelector('button[data-trix-action="redo"]').setAttribute('title', 'Appliquer à nouveau la modification');
document.querySelector('.trix-button.trix-button--dialog[data-trix-method="setAttribute"]').value = "Créer lien";
document.querySelector('.trix-button.trix-button--dialog[data-trix-method="removeAttribute"]').value = "Effacer lien";
})

View file

@ -0,0 +1,33 @@
- if params[:id] == 'closed_mail'
= render partial: 'admin/closed_mail_template_attestation_inconsistency_alert'
= render partial: 'new_administrateur/breadcrumbs',
locals: { steps: [link_to('Démarches', admin_procedures_path),
link_to(@procedure.libelle, admin_procedure_path(@procedure)),
link_to("Emails", admin_procedure_mail_templates_path(@procedure)),
@mail_template.class.const_get(:DISPLAYED_NAME)] }
.procedure-form
.procedure-form__columns.container
= form_for @mail_template,
url: admin_procedure_mail_template_path(@procedure, @mail_template.class.const_get(:SLUG)),
method: :put,
html: { class: 'form procedure-form__column--form' } do |f|
%h1.page-title= @mail_template.class.const_get(:DISPLAYED_NAME)
= render partial: 'form', locals: { f: f }
.procedure-form__actions.sticky--bottom
.actions-right
= f.submit 'Enregistrer', class: 'button primary send'
.procedure-form__column--preview
.procedure-form__preview.sticky--top
%h3
.procedure-form__preview-title
Aperçu
.notice
Cet aperçu est mis à jour après chaque sauvegarde.
.procedure-preview
= render partial: 'apercu', locals: { procedure: @procedure }

View file

@ -8,6 +8,10 @@
.flex.justify-between .flex.justify-between
%div %div
.card-title= mail_template.class.const_get(:DISPLAYED_NAME) .card-title= mail_template.class.const_get(:DISPLAYED_NAME)
%p.notice= mail_template.class.const_get(:DISPLAYED_NAME) === 'Accusé de réception' ? 'Personnalisé' : 'Modèle standard' - if mail_template.updated_at.blank?
%p.notice= mail_template.class.const_get(:DISPLAYED_NAME) === 'Accusé de réception' ? 'Personnalisé' : 'Modèle standard'
- else
%span.badge.baseline modifié le #{mail_template.updated_at.strftime('%d-%m-%Y')}
%div %div
= link_to 'Modifier', edit_admin_procedure_mail_template_path(@procedure, mail_template.class.const_get(:SLUG)), class: 'button' = link_to 'Modifier', edit_admin_procedure_mail_template_path(@procedure, mail_template.class.const_get(:SLUG)), class: 'button'

View file

@ -1,15 +1,14 @@
- procedures.each do |procedure| - procedures.each do |procedure|
.card .card
.flex.justify-between .admin-procedures-list-row.infos.flex
.flex - if procedure.logo.present?
- if procedure.logo.present? = image_tag procedure.logo, alt: procedure.libelle, width: '100'
= image_tag procedure.logo, alt: procedure.libelle, width: '100' .flex.column.ml-1
.flex.column.ml-1 .card-title
.card-title = link_to procedure.libelle, admin_procedure_path(procedure), style: 'color: black;'
= link_to procedure.libelle, admin_procedure_path(procedure), style: 'color: black;' = link_to(procedure_lien(procedure), procedure_lien(procedure), class: 'procedure-lien mb-1')
= link_to(procedure_lien(procedure), procedure_lien(procedure), class: 'procedure-lien mb-1')
%div .admin-procedures-list-timestamps
%p.notice N° #{procedure.id} %p.notice N° #{procedure.id}
%p.notice créée le #{procedure.created_at.strftime('%d/%m/%Y')} %p.notice créée le #{procedure.created_at.strftime('%d/%m/%Y')}
- if procedure.published_at.present? - if procedure.published_at.present?
@ -17,7 +16,7 @@
- if procedure.closed_at.present? - if procedure.closed_at.present?
%p.notice archivée le #{procedure.closed_at.strftime('%d/%m/%Y')} %p.notice archivée le #{procedure.closed_at.strftime('%d/%m/%Y')}
.flex.justify-between .admin-procedures-list-row.actions.flex.justify-between
%div %div
- if feature_enabled?(:administrateur_routage) - if feature_enabled?(:administrateur_routage)
%span.icon.person %span.icon.person

View file

@ -40,7 +40,7 @@
- if !@procedure.locked? - if !@procedure.locked?
.card-admin .card-admin
- if @procedure.types_de_champ.count > 0 - if @procedure.draft_types_de_champ.count > 0
%div %div
%span.icon.accept %span.icon.accept
%p.card-admin-status-accept Validé %p.card-admin-status-accept Validé
@ -50,7 +50,7 @@
%p.card-admin-status-todo À faire %p.card-admin-status-todo À faire
%div %div
%p.card-admin-title %p.card-admin-title
%span.badge.baseline= @procedure.types_de_champ.count %span.badge.baseline= @procedure.draft_types_de_champ.count
Champs du formulaire Champs du formulaire
%p.card-admin-subtitle À remplir par les usagers %p.card-admin-subtitle À remplir par les usagers
.card-admin-action .card-admin-action
@ -148,7 +148,7 @@
- if !@procedure.locked? - if !@procedure.locked?
.card-admin .card-admin
- if @procedure.types_de_champ_private.present? - if @procedure.draft_types_de_champ_private.present?
%div %div
%span.icon.accept %span.icon.accept
%p.card-admin-status-accept Validé %p.card-admin-status-accept Validé

View file

@ -1,11 +1,14 @@
.france-connect-login - if FranceConnectService.enabled?
%h2 .france-connect-login
= t('views.shared.france_connect_login.title') %h2
%p = t('views.shared.france_connect_login.title')
= t('views.shared.france_connect_login.description') %p
.france-connect-login-buttons = t('views.shared.france_connect_login.description')
= link_to t('views.shared.france_connect_login.login_button'), url, class: "france-connect-login-button" .france-connect-login-buttons
.france-connect-help-link = link_to t('views.shared.france_connect_login.login_button'), url, class: "france-connect-login-button"
= link_to t('views.shared.france_connect_login.help_link'), "https://franceconnect.gouv.fr/", target: "_blank", rel: "noopener", class: "link" .france-connect-help-link
.france-connect-login-separator = link_to t('views.shared.france_connect_login.help_link'), "https://franceconnect.gouv.fr/", target: "_blank", rel: "noopener", class: "link"
= t('views.shared.france_connect_login.separator') .france-connect-login-separator
= t('views.shared.france_connect_login.separator')
- else
<!-- FranceConnect is not configured -->

View file

@ -2,45 +2,41 @@
#contact-form #contact-form
.container .container
%h1.new-h1 Contactez notre équipe %h1.new-h1
= t('contact_team', scope: [:supportadmin])
.description .description
En tant qu'administration, vous pouvez nous contactez via ce formulaire. Nous vous répondrons dans les plus brefs délais, par email ou par téléphone. = t('admin_intro_html', scope: [:supportadmin], contact_path: contact_path)
%br %br
%br %p.mandatory-explanation= t('asterisk_html', scope: [:utils])
%strong
Attention, ce formulaire est réservée uniquement aux organismes publics.
Il ne concerne ni les particuliers, ni les entreprises, ni les associations (sauf celles reconnues d'utilité publique). Si c'est votre cas, rendez-vous sur notre
= link_to contact_path do
formulaire de contact public
\.
= form_tag contact_path, method: :post, class: 'form' do |f| = form_tag contact_path, method: :post, class: 'form' do |f|
- if !user_signed_in? - if !user_signed_in?
.contact-champ .contact-champ
= label_tag :email do = label_tag :email do
Adresse email professionnelle = t('pro_mail', scope: [:supportadmin])
%span.mandatory * %span.mandatory *
= text_field_tag :email, params[:email], required: true = text_field_tag :email, params[:email], required: true
.contact-champ .contact-champ
= label_tag :type do = label_tag :type do
Catégorie = t('your_question', scope: [:support, :question])
%span.mandatory * %span.mandatory *
= select_tag :type, options_for_select(@options, params[:type]) = select_tag :type, options_for_select(@options, params[:type])
.contact-champ .contact-champ
= label_tag :phone, 'Numéro de téléphone professionnel (ligne directe)' = label_tag :phone do
= t('professional_phone_number', scope: [:supportadmin])
= text_field_tag :phone = text_field_tag :phone
.contact-champ .contact-champ
= label_tag :subject do = label_tag :subject do
Sujet = t('subject', scope: [:utils])
= text_field_tag :subject, params[:subject], required: false = text_field_tag :subject, params[:subject], required: false
.contact-champ .contact-champ
= label_tag :text do = label_tag :text do
Message = t('message', scope: [:utils])
%span.mandatory * %span.mandatory *
= text_area_tag :text, params[:text], rows: 6, required: true = text_area_tag :text, params[:text], rows: 6, required: true
@ -48,4 +44,4 @@
= hidden_field_tag :admin, true = hidden_field_tag :admin, true
.send-wrapper .send-wrapper
= button_tag 'Envoyer le message', type: :submit, class: 'button send primary' = button_tag t('send_mail', scope: [:utils]), type: :submit, class: 'button send primary'

View file

@ -25,7 +25,7 @@
%hr %hr
%p.center %p.center
%span Vous êtes nouveau sur demarches&#8209;simplifiees.fr ? %span Vous êtes nouveau sur #{APPLICATION_NAME.gsub("-","&#8209;").html_safe} ?
%br %br
%br %br
= link_to "Trouvez votre démarche", COMMENT_TROUVER_MA_DEMARCHE_URL, target: "_blank", class: "button expend secondary" = link_to "Trouvez votre démarche", COMMENT_TROUVER_MA_DEMARCHE_URL, target: "_blank", class: "button expend secondary"

View file

@ -1,13 +1,13 @@
require File.expand_path('boot', __dir__) require File.expand_path('boot', __dir__)
require 'rails/all' require 'rails/all'
require_relative 'application_name'
# Require the gems listed in Gemfile, including any gems # Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production. # you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups) Bundler.require(*Rails.groups)
Dotenv::Railtie.load Dotenv::Railtie.load
require_relative 'application_name'
module TPS module TPS
class Application < Rails::Application class Application < Rails::Application

View file

@ -6,6 +6,9 @@ APPLICATION_NAME="demarches-simplifiees.fr"
APPLICATION_SHORTNAME="d-s.fr" APPLICATION_SHORTNAME="d-s.fr"
APPLICATION_BASE_URL="https://www.demarches-simplifiees.fr" APPLICATION_BASE_URL="https://www.demarches-simplifiees.fr"
# Utilisation de France Connect
# FRANCE_CONNECT_ENABLED="disabled" # "enabled" par défaut
# Personnalisation d'instance - Adresses Email de l'application et téléphone # Personnalisation d'instance - Adresses Email de l'application et téléphone
# CONTACT_EMAIL="" # CONTACT_EMAIL=""
# EQUIPE_EMAIL="" # EQUIPE_EMAIL=""

View file

@ -1,5 +1,8 @@
Rails.application.config.active_storage.service_urls_expire_in = 1.hour Rails.application.config.active_storage.service_urls_expire_in = 1.hour
Rails.application.config.active_storage.analyzers.delete ActiveStorage::Analyzer::ImageAnalyzer
Rails.application.config.active_storage.analyzers.delete ActiveStorage::Analyzer::VideoAnalyzer
ActiveSupport.on_load(:active_storage_blob) do ActiveSupport.on_load(:active_storage_blob) do
include BlobSignedIdConcern include BlobSignedIdConcern
include BlobVirusScannerConcern include BlobVirusScannerConcern

View file

@ -1,60 +0,0 @@
# Additional translations at https://github.com/plataformatec/devise/wiki/I18n
en:
devise:
confirmations:
confirmed: "Your email address has been successfully confirmed."
send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes."
send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes."
failure:
already_authenticated: "You are already signed in."
inactive: "Your account is not activated yet."
invalid: "Invalid %{authentication_keys} or password."
locked: "Your account is locked."
last_attempt: "You have one more attempt before your account is locked."
not_found_in_database: "Invalid %{authentication_keys} or password."
timeout: "Your session expired. Please sign in again to continue."
unauthenticated: "You need to sign in or sign up before continuing."
unconfirmed: "You have to confirm your email address before continuing."
mailer:
confirmation_instructions:
subject: "Confirmation instructions"
reset_password_instructions:
subject: "Reset password instructions"
unlock_instructions:
subject: "Unlock instructions"
omniauth_callbacks:
failure: "Could not authenticate you from %{kind} because \"%{reason}\"."
success: "Successfully authenticated from %{kind} account."
passwords:
no_token: "You cant access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided."
send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes."
send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes."
updated: "Your password has been changed successfully. You are now signed in."
updated_not_active: "Your password has been changed successfully."
registrations:
destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon."
signed_up: "Welcome! You have signed up successfully."
signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated."
signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked."
signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account."
update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address."
updated: "Your account has been updated successfully."
sessions:
signed_in: "Signed in successfully."
signed_out: "Signed out successfully."
already_signed_out: "Signed out successfully."
unlocks:
send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes."
send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes."
unlocked: "Your account has been unlocked successfully. Please sign in to continue."
errors:
messages:
already_confirmed: "was already confirmed, please try signing in"
confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one"
expired: "has expired, please request a new one"
not_found: "not found"
not_locked: "was not locked"
not_saved:
one: "1 error prohibited this %{resource} from being saved:"
other: "%{count} errors prohibited this %{resource} from being saved:"

View file

@ -1,64 +0,0 @@
# Additional translations at https://github.com/plataformatec/devise/wiki/I18n
fr:
devise:
confirmations:
confirmed: "Votre compte a été activé."
send_instructions: "Vous allez recevoir un email avec les instructions nécessaires à lactivation de votre compte dans quelques minutes."
send_paranoid_instructions: "Si votre adresse email existe dans notre base de données, vous allez bientôt recevoir un email contenant les instructions dactivation de votre compte."
failure:
already_authenticated: "Vous êtes déjà connecté"
inactive: "Votre compte nest pas encore activé."
invalid: "adresse email ou mot de passe incorrect."
last_attempt: "Vous avez droit à une tentative avant que votre compte ne soit verrouillé."
locked: "Votre compte est verrouillé."
not_found_in_database: "adresse email ou mot de passe invalide."
timeout: "Votre session est expirée. Veuillez vous reconnecter pour continuer."
unauthenticated: "Vous devez vous connecter ou vous inscrire pour continuer."
unconfirmed: "Vous devez confirmer votre adresse email pour continuer. Cliquez sur le lien qui vous a été envoyé par email."
mailer:
confirmation_instructions:
subject: "Instructions dactivation de votre compte"
reset_password_instructions:
subject: "Instructions pour changer le mot de passe"
unlock_instructions:
subject: "Instructions pour déverrouiller le compte"
email_changed:
subject: "Changement dadresse email"
password_change:
subject: "Votre mot de passe a été modifié avec succés."
omniauth_callbacks:
failure: "Nous navons pas pu vous authentifier via %{kind} : '%{reason}'."
success: "Authentifié avec succès via %{kind}."
passwords:
no_token: "Vous ne pouvez accéder à cette page sans passer par un email de réinitialisation de mot de passe. Si vous êtes passé par un email de ce type, assurez-vous dutiliser lURL complète."
send_instructions: "Vous allez recevoir les instructions de réinitialisation du mot de passe dans quelques instants"
send_paranoid_instructions: "Si votre adresse email existe dans notre base de données, vous allez recevoir un lien de réinitialisation par email"
updated: "Votre mot de passe a été changé avec succès, vous êtes maintenant connecté"
updated_not_active: "Votre mot de passe a été changé avec succès."
registrations:
destroyed: "Votre compte a été supprimé avec succès. Nous espérons vous revoir bientôt."
signed_up: "Bienvenue, vous êtes connecté."
signed_up_but_inactive: "Vous êtes bien enregistré. Vous ne pouvez cependant pas vous connecter car votre compte nest pas encore activé."
signed_up_but_locked: "Vous êtes bien enregistré. Vous ne pouvez cependant pas vous connecter car votre compte est verrouillé."
signed_up_but_unconfirmed: "Nous vous avons envoyé un email contenant un lien dactivation. Ouvrez ce lien pour activer votre compte."
update_needs_confirmation: "Vous devez confirmer votre nouvelle adresse email. Vérifiez vos emails, et cliquez sur le lien de confirmation pour confirmer votre changement dadresse."
updated: "Votre compte a été modifié avec succès."
sessions:
signed_in: "Connecté."
signed_out: "Déconnecté."
already_signed_out: "Déconnecté."
unlocks:
send_instructions: "Vous allez recevoir les instructions nécessaires au déverrouillage de votre compte dans quelques instants"
send_paranoid_instructions: "Si votre compte existe, vous allez bientôt recevoir un email contenant les instructions pour le déverrouiller."
unlocked: "Votre compte a été déverrouillé avec succès, vous êtes maintenant connecté."
errors:
messages:
already_confirmed: "a déjà été validé(e), veuillez essayer de vous connecter"
confirmation_period_expired: "à activer dans les %{period}, merci de faire une nouvelle demande"
expired: "a expiré, merci den faire une nouvelle demande"
not_found: "na pas été trouvé(e)"
not_locked: "nétait pas verrouillé(e)"
not_saved:
one: "1 erreur a empêché ce(tte) %{resource} dêtre sauvegardé(e) :"
other: "%{count} erreurs ont empêché ce(tte) %{resource} dêtre sauvegardé(e) :"

View file

@ -22,9 +22,6 @@
en: en:
utils: utils:
deconnexion: "Log out" deconnexion: "Log out"
involved: "See concerned people"
no-commentaires: "There is no message yet, feel free to start the first one."
depositaire: "Dépositaire"
pj: "Attachments" pj: "Attachments"
asterisk_html: Fields marked by an asterisk ( <span class = mandatory>*</span> ) are mandatory. asterisk_html: Fields marked by an asterisk ( <span class = mandatory>*</span> ) are mandatory.
file_number: File number file_number: File number
@ -60,63 +57,7 @@ en:
submit: submit:
publish: Publish publish: Publish
reopen: Reopen reopen: Reopen
supportadmin:
# admin demande rdv: Demande de RDV pour une présentation à distance de demarches-simplifiees.fr
admin question: I have a question about demarches-simplifiees.fr
admin soucis: I am facing a technical issue on demarches-simplifiees.fr
admin suggestion produit: I have a suggestion for an evolution
admin demande compte: I want to open an admin account with an Orange, Wanadoo, etc. email
admin autre: Other topic
number:
currency:
format:
delimiter: ","
format: "%u%n"
precision: 2
separator: "."
significant: false
strip_insignificant_zeros: false
unit: "€"
format:
delimiter: ","
precision: 3
separator: "."
significant: false
strip_insignificant_zeros: false
human:
decimal_units:
format: "%n %u"
units:
billion: Billion
million: Million
quadrillion: Quadrillion
thousand: Thousand
trillion: Trillion
unit: ''
format:
delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
storage_units:
format: "%n %u"
units:
byte:
one: Byte
other: Bytes
gb: GB
kb: KB
mb: MB
pb: PB
tb: TB
percentage:
format:
delimiter: ''
format: "%n%"
precision:
format:
delimiter: ''
activerecord: activerecord:
attributes: attributes:
user: user:
@ -126,13 +67,7 @@ en:
password: 'password' password: 'password'
errors: errors:
messages: messages:
blank: "must be filled" not_a_phone: 'Invalid phone number'
not_a_number: 'must be a number'
not_an_integer: 'must be an integer (without digit after the comma)'
greater_than: "must be greater than %{count}"
greater_than_or_equal_to: "must be greater than or equal to %{count}"
less_than: "must be less than %{count}"
less_than_or_equal_to: "must be less than or equal to %{count}"
models: models:
attestation_template: attestation_template:
attributes: attributes:
@ -197,98 +132,9 @@ en:
# parcelles_agricoles_empty: # parcelles_agricoles_empty:
# one: "Aucune parcelle agricole sur la zone sélectionnée" # one: "Aucune parcelle agricole sur la zone sélectionnée"
# other: "Aucune parcelle agricole sur les zones sélectionnées" # other: "Aucune parcelle agricole sur les zones sélectionnées"
not_an_integer: "must be an integer (without decimal)"
blank: "can't be blank"
date:
abbr_day_names:
- Sun
- Mon
- Tue
- Wed
- Thu
- Fri
- Sat
abbr_month_names:
-
- Jan
- Feb
- Mar
- Apr
- May
- Jun
- Jul
- Aug
- Sep
- Oct
- Nov
- Dec
month_names:
-
- January
- February
- March
- April
- May
- June
- July
- August
- September
- October
- November
- December
order:
- :year
- :month
- :day
day_names:
- Sunday
- Monday
- Tuesday
- Wednesday
- Thursday
- Friday
- Saturday
formats:
default: "%Y-%m-%d"
long: "%B %d, %Y"
short: "%b %d"
datetime:
distance_in_words:
about_x_hours:
one: about an hour
other: about %{count} hours
about_x_months:
one: about a month
other: about %{count} months
about_x_years:
one: about a year
other: about %{count} years
almost_x_years:
one: almost a year
other: almost %{count} years
half_a_minute: half a minute
less_than_x_minutes:
zero: less than a minute
one: less than a minute
other: less than %{count} minutes
less_than_x_seconds:
zero: less than a second
one: less than a second
other: less than %{count} seconds
over_x_years:
one: more than a year
other: more than %{count} years
x_days:
one: 1 day
other: "%{count} days"
x_minutes:
one: 1 minute
other: "%{count} minutes"
x_months:
one: 1 month
other: "%{count} months"
x_seconds:
one: 1 second
other: "%{count} seconds"
time: time:
formats: formats:
default: "%B %d %Y %R" default: "%B %d %Y %R"

View file

@ -22,9 +22,6 @@
fr: fr:
utils: utils:
deconnexion: "Déconnexion" deconnexion: "Déconnexion"
involved: "Voir les personnes impliquées"
no-commentaires: "Il ny a aucun message dans le fil de discussion, nhésitez pas à initier le premier."
depositaire: "Dépositaire"
pj: "Pièces jointes" pj: "Pièces jointes"
asterisk_html: Les champs suivis dun astérisque ( <span class = mandatory> * </span> ) sont obligatoires. asterisk_html: Les champs suivis dun astérisque ( <span class = mandatory> * </span> ) sont obligatoires.
file_number: Numéro de dossier file_number: Numéro de dossier
@ -60,62 +57,7 @@ fr:
submit: submit:
publish: Publier publish: Publier
reopen: Réactiver reopen: Réactiver
supportadmin:
admin demande rdv: Demande de RDV pour une présentation à distance de demarches-simplifiees.fr
admin question: Jai une question sur demarches-simplifiees.fr
admin soucis: Jai un problème technique avec demarches-simplifiees.fr
admin suggestion produit: Jai une proposition dévolution
admin demande compte: Je souhaite ouvrir un compte administrateur avec un email Orange, Wanadoo, etc.
admin autre: Autre sujet
number:
currency:
format:
delimiter: " "
format: "%n %u"
precision: 2
separator: ","
significant: false
strip_insignificant_zeros: false
unit: "€"
format:
delimiter: " "
precision: 3
separator: ","
significant: false
strip_insignificant_zeros: false
human:
decimal_units:
format: "%n %u"
units:
billion: milliard
million: million
quadrillion: million de milliards
thousand: millier
trillion: billion
unit: ''
format:
delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
storage_units:
format: "%n %u"
units:
byte:
one: octet
other: octets
gb: Go
kb: ko
mb: Mo
tb: To
percentage:
format:
delimiter: ''
format: "%n%"
precision:
format:
delimiter: ''
activerecord: activerecord:
attributes: attributes:
user: user:
@ -125,14 +67,7 @@ fr:
password: 'Le mot de passe' password: 'Le mot de passe'
errors: errors:
messages: messages:
blank: "doit être rempli"
not_a_number: 'doit être un nombre'
not_an_integer: 'doit être un nombre entier (sans chiffres après la virgule)'
not_a_phone: 'Numéro de téléphone invalide' not_a_phone: 'Numéro de téléphone invalide'
greater_than: "doit être supérieur à %{count}"
greater_than_or_equal_to: "doit être supérieur ou égal à %{count}"
less_than: "doit être inférieur à %{count}"
less_than_or_equal_to: "doit être inférieur ou égal à %{count}"
models: models:
attestation_template: attestation_template:
attributes: attributes:
@ -197,98 +132,9 @@ fr:
parcelles_agricoles_empty: parcelles_agricoles_empty:
one: "Aucune parcelle agricole sur la zone sélectionnée" one: "Aucune parcelle agricole sur la zone sélectionnée"
other: "Aucune parcelle agricole sur les zones sélectionnées" other: "Aucune parcelle agricole sur les zones sélectionnées"
not_an_integer: "doit être un nombre entier (sans chiffres après la virgule)"
blank: "doit être rempli"
date:
abbr_day_names:
- dim
- lun
- mar
- mer
- jeu
- ven
- sam
abbr_month_names:
-
- jan.
- fév.
- mar.
- avr.
- mai
- juin
- juil.
- août
- sept.
- oct.
- nov.
- déc.
month_names:
-
- janvier
- février
- mars
- avril
- mai
- juin
- juillet
- août
- septembre
- octobre
- novembre
- décembre
order:
- :day
- :month
- :year
day_names:
- dimanche
- lundi
- mardi
- mercredi
- jeudi
- vendredi
- samedi
formats:
default: "%d %B %Y"
short: "%e %b"
long: "%e %B %Y"
datetime:
distance_in_words:
about_x_hours:
one: environ une heure
other: environ %{count} heures
about_x_months:
one: environ un mois
other: environ %{count} mois
about_x_years:
one: environ un an
other: environ %{count} ans
almost_x_years:
one: presquun an
other: presque %{count} ans
half_a_minute: une demi-minute
less_than_x_minutes:
zero: moins dune minute
one: moins dune minute
other: moins de %{count} minutes
less_than_x_seconds:
zero: moins dune seconde
one: moins dune seconde
other: moins de %{count} secondes
over_x_years:
one: plus dun an
other: plus de %{count} ans
x_days:
one: 1 jour
other: "%{count} jours"
x_minutes:
one: 1 minute
other: "%{count} minutes"
x_months:
one: 1 mois
other: "%{count} mois"
x_seconds:
one: 1 seconde
other: "%{count} secondes"
time: time:
formats: formats:
default: "%d %B %Y %R" default: "%d %B %Y %R"

View file

@ -30,3 +30,17 @@ en:
<p><a href=%{link_lost_user}>%{link_lost_user}</a></p>" <p><a href=%{link_lost_user}>%{link_lost_user}</a></p>"
notice_pj_product: A screenshot can help us identify the element to improve. notice_pj_product: A screenshot can help us identify the element to improve.
notice_pj_other: A screenshot can help us identify the issue. notice_pj_other: A screenshot can help us identify the issue.
supportadmin:
admin_intro_html: "<p>As an administration, you can contact us through this form. We'll answer you as quickly as possibly by e-mail or phone.</p>
<br>
<p><strong>Caution, this form is dedicated to public bodies only.</strong>
It does not concern individuals, companies nor associations (except those recognised of public utility). If you belong to one of these categories, contact us <a href=%{contact_path}>here</a>.</p>"
contact_team: Contact our team
pro_phone_number: Professional phone number (direct line)
pro_mail: Professional email address
admin demande rdv: I request an appointment for an online presentation of demarches-simplifiees.fr
admin question: I have a question about demarches-simplifiees.fr
admin soucis: I am facing a technical issue on demarches-simplifiees.fr
admin suggestion produit: I have a suggestion for an evolution
admin demande compte: I want to open an admin account with an Orange, Wanadoo, etc. email
admin autre: Other topic

View file

@ -29,3 +29,18 @@ fr:
<p><a href=%{link_lost_user}>%{link_lost_user}</a></p>" <p><a href=%{link_lost_user}>%{link_lost_user}</a></p>"
notice_pj_product: Une capture décran peut nous aider à identifier plus facilement lendroit à améliorer. notice_pj_product: Une capture décran peut nous aider à identifier plus facilement lendroit à améliorer.
notice_pj_other: Une capture décran peut nous aider à identifier plus facilement le problème. notice_pj_other: Une capture décran peut nous aider à identifier plus facilement le problème.
supportadmin:
admin_intro_html: "<p>En tant qu'administration, vous pouvez nous contactez via ce formulaire. Nous vous répondrons dans les plus brefs délais, par email ou par téléphone.</p>
<br>
<p><strong>Attention, ce formulaire est réservé uniquement aux organismes publics.</strong>
Il ne concerne ni les particuliers, ni les entreprises, ni les associations (sauf celles reconnues d'utilité publique). Si c'est votre cas, rendez-vous sur notre
<a href=%{contact_path}>formulaire de contact public</a>.</p>"
contact_team: Contactez notre équipe
pro_phone_number: Numéro de téléphone professionnel (ligne directe)
pro_mail: Adresse e-mail professionnelle
admin demande rdv: Demande de RDV pour une présentation à distance de demarches-simplifiees.fr
admin question: Jai une question sur demarches-simplifiees.fr
admin soucis: Jai un problème technique avec demarches-simplifiees.fr
admin suggestion produit: Jai une proposition dévolution
admin demande compte: Je souhaite ouvrir un compte administrateur avec un email Orange, Wanadoo, etc.
admin autre: Autre sujet

View file

@ -189,8 +189,6 @@ Rails.application.routes.draw do
delete :delete_notice delete :delete_notice
end end
resources :mail_templates, only: [:edit, :update]
put 'archive' => 'procedures#archive', as: :archive put 'archive' => 'procedures#archive', as: :archive
get 'publish_validate' => 'procedures#publish_validate', as: :publish_validate get 'publish_validate' => 'procedures#publish_validate', as: :publish_validate
put 'publish' => 'procedures#publish', as: :publish put 'publish' => 'procedures#publish', as: :publish
@ -373,6 +371,8 @@ Rails.application.routes.draw do
patch 'update_jeton' patch 'update_jeton'
end end
resources :mail_templates, only: [:edit, :update]
resources :groupe_instructeurs, only: [:index, :show, :create, :update, :destroy] do resources :groupe_instructeurs, only: [:index, :show, :create, :update, :destroy] do
member do member do
post 'add_instructeur' post 'add_instructeur'

View file

@ -1,31 +0,0 @@
describe Admin::MailTemplatesController, type: :controller do
let(:procedure) { create :procedure }
let(:initiated_mail) { Mails::InitiatedMail.default_for_procedure(procedure) }
before do
sign_in(procedure.administrateurs.first.user)
end
describe 'PATCH update' do
let(:mail_subject) { 'plop modif' }
let(:mail_body) { 'plip modif' }
before :each do
patch :update,
params: {
procedure_id: procedure.id,
id: initiated_mail.class.const_get(:SLUG),
mail_template: { subject: mail_subject, body: mail_body }
}
end
it { expect(response).to redirect_to edit_admin_procedure_mail_template_path(procedure, initiated_mail.class.const_get(:SLUG)) }
context 'the mail template' do
subject { procedure.reload; procedure.initiated_mail_template }
it { expect(subject.subject).to eq(mail_subject) }
it { expect(subject.body).to eq(mail_body) }
end
end
end

View file

@ -255,9 +255,8 @@ describe API::V1::DossiersController do
end end
describe 'repetition' do describe 'repetition' do
let(:procedure) { create(:procedure, administrateur: admin) } let(:procedure) { create(:procedure, :with_repetition, administrateur: admin) }
let(:champ) { build(:champ_repetition) } let(:dossier) { create(:dossier, :en_construction, :with_all_champs, procedure: procedure) }
let(:dossier) { create(:dossier, :en_construction, champs: [champ], procedure: procedure) }
subject { super().first[:rows] } subject { super().first[:rows] }

View file

@ -560,36 +560,34 @@ describe Instructeurs::DossiersController, type: :controller do
end end
describe "#update_annotations" do describe "#update_annotations" do
let(:procedure) do
create(:procedure, :published, types_de_champ_private: [
build(:type_de_champ_multiple_drop_down_list, position: 0),
build(:type_de_champ_linked_drop_down_list, position: 1),
build(:type_de_champ_datetime, position: 2),
build(:type_de_champ_repetition, :with_types_de_champ, position: 3)
], instructeurs: instructeurs)
end
let(:dossier) { create(:dossier, :en_construction, :with_all_annotations, procedure: procedure) }
let(:now) { Time.zone.parse('01/01/2100') }
let(:champ_multiple_drop_down_list) do let(:champ_multiple_drop_down_list) do
tdc = create(:type_de_champ_multiple_drop_down_list, :private, procedure: procedure, libelle: 'libelle') dossier.champs_private.first
create(:champ_multiple_drop_down_list, :private, type_de_champ: tdc, dossier: dossier)
end end
let(:champ_linked_drop_down_list) do let(:champ_linked_drop_down_list) do
tdc = create(:type_de_champ_linked_drop_down_list, :private, procedure: procedure, libelle: 'libelle') dossier.champs_private.second
create(:champ_linked_drop_down_list, :private, type_de_champ: tdc, dossier: dossier)
end end
let(:champ_datetime) do let(:champ_datetime) do
tdc = create(:type_de_champ_datetime, :private, procedure: procedure, libelle: 'libelle') dossier.champs_private.third
create(:champ_datetime, :private, type_de_champ: tdc, dossier: dossier)
end end
let(:champ_repetition) do let(:champ_repetition) do
tdc = create(:type_de_champ_repetition, :private, :with_types_de_champ, procedure: procedure, libelle: 'libelle') dossier.champs_private.fourth
tdc.types_de_champ << create(:type_de_champ_text, procedure: procedure, libelle: 'libelle')
champ = create(:champ_repetition, :private, type_de_champ: tdc, dossier: dossier)
champ.add_row
champ
end end
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
let(:now) { Time.zone.parse('01/01/2100') }
before do before do
dossier.champs_private << [champ_multiple_drop_down_list, champ_linked_drop_down_list, champ_datetime, champ_repetition]
Timecop.freeze(now) Timecop.freeze(now)
patch :update_annotations, params: params patch :update_annotations, params: params
@ -607,64 +605,70 @@ describe Instructeurs::DossiersController, type: :controller do
let(:params) do let(:params) do
{ {
procedure_id: procedure.id, procedure_id: procedure.id,
dossier_id: dossier.id, dossier_id: dossier.id,
dossier: { dossier: {
champs_private_attributes: { champs_private_attributes: {
'0': { '0': {
id: champ_multiple_drop_down_list.id, id: champ_multiple_drop_down_list.id,
value: ['', 'un', 'deux'] value: ['', 'un', 'deux']
}, },
'1': { '1': {
id: champ_datetime.id, id: champ_datetime.id,
'value(1i)': 2019, 'value(1i)': 2019,
'value(2i)': 12, 'value(2i)': 12,
'value(3i)': 21, 'value(3i)': 21,
'value(4i)': 13, 'value(4i)': 13,
'value(5i)': 17 'value(5i)': 17
}, },
'2': { '2': {
id: champ_linked_drop_down_list.id, id: champ_linked_drop_down_list.id,
primary_value: 'primary', primary_value: 'primary',
secondary_value: 'secondary' secondary_value: 'secondary'
}, },
'3': { '3': {
id: champ_repetition.id, id: champ_repetition.id,
champs_attributes: { champs_attributes: {
id: champ_repetition.champs.first.id, id: champ_repetition.champs.first.id,
value: 'text' value: 'text'
}
} }
} }
} }
} }
}
end end
it { expect(champ_multiple_drop_down_list.value).to eq('["un", "deux"]') }
it { expect(champ_linked_drop_down_list.primary_value).to eq('primary') } it {
it { expect(champ_linked_drop_down_list.secondary_value).to eq('secondary') } expect(champ_multiple_drop_down_list.value).to eq('["un", "deux"]')
it { expect(champ_datetime.value).to eq('21/12/2019 13:17') } expect(champ_linked_drop_down_list.primary_value).to eq('primary')
it { expect(champ_repetition.champs.first.value).to eq('text') } expect(champ_linked_drop_down_list.secondary_value).to eq('secondary')
it { expect(dossier.reload.last_champ_private_updated_at).to eq(now) } expect(champ_datetime.value).to eq('21/12/2019 13:17')
it { expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier)) } expect(champ_repetition.champs.first.value).to eq('text')
expect(dossier.reload.last_champ_private_updated_at).to eq(now)
expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier))
}
end end
context "without new values for champs_private" do context "without new values for champs_private" do
let(:params) do let(:params) do
{ {
procedure_id: procedure.id, procedure_id: procedure.id,
dossier_id: dossier.id, dossier_id: dossier.id,
dossier: { dossier: {
champs_private_attributes: {}, champs_private_attributes: {},
champs_attributes: { champs_attributes: {
'0': { '0': {
id: champ_multiple_drop_down_list.id, id: champ_multiple_drop_down_list.id,
value: ['', 'un', 'deux'] value: ['', 'un', 'deux']
}
} }
} }
} }
}
end end
it { expect(dossier.reload.last_champ_private_updated_at).to eq(nil) }
it { expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier)) } it {
expect(dossier.reload.last_champ_private_updated_at).to eq(nil)
expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier))
}
end end
end end

View file

@ -17,7 +17,7 @@ describe Manager::ProceduresController, type: :controller do
describe '#show' do describe '#show' do
render_views render_views
let(:procedure) { create(:procedure, :with_repetition) } let(:procedure) { create(:procedure, :published, :with_repetition) }
before do before do
get :show, params: { id: procedure.id } get :show, params: { id: procedure.id }

View file

@ -42,4 +42,27 @@ describe NewAdministrateur::MailTemplatesController, type: :controller do
expect(response.body).to include(procedure.service.telephone) expect(response.body).to include(procedure.service.telephone)
end end
end end
describe 'PATCH update' do
let(:mail_subject) { 'Mise à jour de votre démarche' }
let(:mail_body) { '<div>Une mise à jour a été effectuée sur votre démarche n° --demarche-id--.</div>' }
before :each do
patch :update,
params: {
procedure_id: procedure.id,
id: initiated_mail.class.const_get(:SLUG),
mails_initiated_mail: { subject: mail_subject, rich_body: mail_body }
}
end
it { expect(response).to redirect_to edit_admin_procedure_mail_template_path(procedure, initiated_mail.class.const_get(:SLUG)) }
context 'the mail template' do
subject { procedure.reload; procedure.initiated_mail_template }
it { expect(subject.subject).to eq(mail_subject) }
it { expect(subject.body).to eq(mail_body) }
end
end
end end

View file

@ -2,17 +2,17 @@ describe StatsController, type: :controller do
describe "#last_four_months_hash" do describe "#last_four_months_hash" do
context "while a regular user is logged in" do context "while a regular user is logged in" do
before do before do
FactoryBot.create(:procedure, :created_at => 6.months.ago, :updated_at => 6.months.ago) create(:procedure, created_at: 6.months.ago, updated_at: 6.months.ago)
FactoryBot.create(:procedure, :created_at => 2.months.ago, :updated_at => 62.days.ago) create(:procedure, created_at: 2.months.ago, updated_at: 62.days.ago)
FactoryBot.create(:procedure, :created_at => 2.months.ago, :updated_at => 62.days.ago) create(:procedure, created_at: 2.months.ago, updated_at: 62.days.ago)
FactoryBot.create(:procedure, :created_at => 2.months.ago, :updated_at => 31.days.ago) create(:procedure, created_at: 2.months.ago, updated_at: 31.days.ago)
FactoryBot.create(:procedure, :created_at => 2.months.ago, :updated_at => Time.zone.now) create(:procedure, created_at: 2.months.ago, updated_at: Time.zone.now)
@controller = StatsController.new @controller = StatsController.new
allow(@controller).to receive(:administration_signed_in?).and_return(false) allow(@controller).to receive(:administration_signed_in?).and_return(false)
end end
let (:association) { Procedure.all } let(:association) { Procedure.all }
subject { @controller.send(:last_four_months_hash, association, :updated_at) } subject { @controller.send(:last_four_months_hash, association, :updated_at) }
@ -26,10 +26,10 @@ describe StatsController, type: :controller do
context "while a super admin is logged in" do context "while a super admin is logged in" do
before do before do
FactoryBot.create(:procedure, :updated_at => 6.months.ago) create(:procedure, updated_at: 6.months.ago)
FactoryBot.create(:procedure, :updated_at => 45.days.ago) create(:procedure, updated_at: 45.days.ago)
FactoryBot.create(:procedure, :updated_at => 1.day.ago) create(:procedure, updated_at: 1.day.ago)
FactoryBot.create(:procedure, :updated_at => 1.day.ago) create(:procedure, updated_at: 1.day.ago)
@controller = StatsController.new @controller = StatsController.new
@ -52,11 +52,11 @@ describe StatsController, type: :controller do
describe '#cumulative_hash' do describe '#cumulative_hash' do
before do before do
Timecop.freeze(Time.zone.local(2016, 10, 2)) Timecop.freeze(Time.zone.local(2016, 10, 2))
FactoryBot.create(:procedure, :created_at => 55.days.ago, :updated_at => 43.days.ago) create(:procedure, created_at: 55.days.ago, updated_at: 43.days.ago)
FactoryBot.create(:procedure, :created_at => 45.days.ago, :updated_at => 40.days.ago) create(:procedure, created_at: 45.days.ago, updated_at: 40.days.ago)
FactoryBot.create(:procedure, :created_at => 45.days.ago, :updated_at => 20.days.ago) create(:procedure, created_at: 45.days.ago, updated_at: 20.days.ago)
FactoryBot.create(:procedure, :created_at => 15.days.ago, :updated_at => 20.days.ago) create(:procedure, created_at: 15.days.ago, updated_at: 20.days.ago)
FactoryBot.create(:procedure, :created_at => 15.days.ago, :updated_at => 1.hour.ago) create(:procedure, created_at: 15.days.ago, updated_at: 1.hour.ago)
end end
after { Timecop.return } after { Timecop.return }
@ -104,24 +104,24 @@ describe StatsController, type: :controller do
# dossier_p1_c: 5 days # dossier_p1_c: 5 days
before do before do
procedure_1 = FactoryBot.create(:procedure) procedure_1 = create(:procedure)
procedure_2 = FactoryBot.create(:procedure) procedure_2 = create(:procedure)
dossier_p1_a = FactoryBot.create(:dossier, :accepte, dossier_p1_a = create(:dossier, :accepte,
:procedure => procedure_1, procedure: procedure_1,
:en_construction_at => 2.months.ago.beginning_of_month, en_construction_at: 2.months.ago.beginning_of_month,
:processed_at => 2.months.ago.beginning_of_month + 3.days) processed_at: 2.months.ago.beginning_of_month + 3.days)
dossier_p1_b = FactoryBot.create(:dossier, :accepte, dossier_p1_b = create(:dossier, :accepte,
:procedure => procedure_1, procedure: procedure_1,
:en_construction_at => 2.months.ago.beginning_of_month, en_construction_at: 2.months.ago.beginning_of_month,
:processed_at => 2.months.ago.beginning_of_month + 1.day) processed_at: 2.months.ago.beginning_of_month + 1.day)
dossier_p1_c = FactoryBot.create(:dossier, :accepte, dossier_p1_c = create(:dossier, :accepte,
:procedure => procedure_1, procedure: procedure_1,
:en_construction_at => 1.month.ago.beginning_of_month, en_construction_at: 1.month.ago.beginning_of_month,
:processed_at => 1.month.ago.beginning_of_month + 5.days) processed_at: 1.month.ago.beginning_of_month + 5.days)
dossier_p2_a = FactoryBot.create(:dossier, :accepte, dossier_p2_a = create(:dossier, :accepte,
:procedure => procedure_2, procedure: procedure_2,
:en_construction_at => 2.months.ago.beginning_of_month, en_construction_at: 2.months.ago.beginning_of_month,
:processed_at => 2.months.ago.beginning_of_month + 4.days) processed_at: 2.months.ago.beginning_of_month + 4.days)
@expected_hash = { @expected_hash = {
(2.months.ago.beginning_of_month).to_s => 3.0, (2.months.ago.beginning_of_month).to_s => 3.0,
@ -149,28 +149,28 @@ describe StatsController, type: :controller do
# dossier_p1_c: 50 minutes # dossier_p1_c: 50 minutes
before do before do
procedure_1 = FactoryBot.create(:procedure, :with_type_de_champ, :types_de_champ_count => 24) procedure_1 = create(:procedure, :with_type_de_champ, types_de_champ_count: 24)
procedure_2 = FactoryBot.create(:procedure, :with_type_de_champ, :types_de_champ_count => 48) procedure_2 = create(:procedure, :with_type_de_champ, types_de_champ_count: 48)
dossier_p1_a = FactoryBot.create(:dossier, :accepte, dossier_p1_a = create(:dossier, :accepte,
:procedure => procedure_1, procedure: procedure_1,
:created_at => 2.months.ago.beginning_of_month, created_at: 2.months.ago.beginning_of_month,
:en_construction_at => 2.months.ago.beginning_of_month + 30.minutes, en_construction_at: 2.months.ago.beginning_of_month + 30.minutes,
:processed_at => 2.months.ago.beginning_of_month + 1.day) processed_at: 2.months.ago.beginning_of_month + 1.day)
dossier_p1_b = FactoryBot.create(:dossier, :accepte, dossier_p1_b = create(:dossier, :accepte,
:procedure => procedure_1, procedure: procedure_1,
:created_at => 2.months.ago.beginning_of_month, created_at: 2.months.ago.beginning_of_month,
:en_construction_at => 2.months.ago.beginning_of_month + 10.minutes, en_construction_at: 2.months.ago.beginning_of_month + 10.minutes,
:processed_at => 2.months.ago.beginning_of_month + 1.day) processed_at: 2.months.ago.beginning_of_month + 1.day)
dossier_p1_c = FactoryBot.create(:dossier, :accepte, dossier_p1_c = create(:dossier, :accepte,
:procedure => procedure_1, procedure: procedure_1,
:created_at => 1.month.ago.beginning_of_month, created_at: 1.month.ago.beginning_of_month,
:en_construction_at => 1.month.ago.beginning_of_month + 50.minutes, en_construction_at: 1.month.ago.beginning_of_month + 50.minutes,
:processed_at => 1.month.ago.beginning_of_month + 1.day) processed_at: 1.month.ago.beginning_of_month + 1.day)
dossier_p2_a = FactoryBot.create(:dossier, :accepte, dossier_p2_a = create(:dossier, :accepte,
:procedure => procedure_2, procedure: procedure_2,
:created_at => 2.months.ago.beginning_of_month, created_at: 2.months.ago.beginning_of_month,
:en_construction_at => 2.months.ago.beginning_of_month + 80.minutes, en_construction_at: 2.months.ago.beginning_of_month + 80.minutes,
:processed_at => 2.months.ago.beginning_of_month + 1.day) processed_at: 2.months.ago.beginning_of_month + 1.day)
@expected_hash = { @expected_hash = {
(2.months.ago.beginning_of_month).to_s => 30.0, (2.months.ago.beginning_of_month).to_s => 30.0,

View file

@ -56,7 +56,7 @@ describe Users::ProfilController, type: :controller do
end end
it { expect(response).to redirect_to(profil_path) } it { expect(response).to redirect_to(profil_path) }
it { expect(flash.alert).to eq(['Email invalide']) } it { expect(flash.alert).to eq(['Courriel invalide']) }
end end
context 'when the user has an instructeur role' do context 'when the user has an instructeur role' do

View file

@ -62,7 +62,7 @@ describe Users::SessionsController, type: :controller do
subject subject
expect(response).to render_template(:new) expect(response).to render_template(:new)
expect(flash.alert).to eq(I18n.t('devise.failure.invalid')) expect(flash.alert).to eq('Courriel ou mot de passe incorrect.')
end end
end end
end end

View file

@ -161,23 +161,20 @@ FactoryBot.define do
existing_type_de_champ_text = types_de_champ.find { |tdc| tdc.libelle == 'Nom' } existing_type_de_champ_text = types_de_champ.find { |tdc| tdc.libelle == 'Nom' }
type_de_champ_text = existing_type_de_champ_text || build( type_de_champ_text = existing_type_de_champ_text || build(
:type_de_champ_text, :type_de_champ_text,
order_place: 0, position: 0,
procedure: champ_repetition.dossier.procedure,
parent: champ_repetition.type_de_champ, parent: champ_repetition.type_de_champ,
libelle: 'Nom' libelle: 'Nom'
) )
types_de_champ << type_de_champ_text
existing_type_de_champ_number = types_de_champ.find { |tdc| tdc.libelle == 'Age' } existing_type_de_champ_number = types_de_champ.find { |tdc| tdc.libelle == 'Age' }
type_de_champ_number = existing_type_de_champ_number || build( type_de_champ_number = existing_type_de_champ_number || build(
:type_de_champ_number, :type_de_champ_number,
order_place: 1, position: 1,
procedure: champ_repetition.dossier.procedure,
parent: champ_repetition.type_de_champ, parent: champ_repetition.type_de_champ,
libelle: 'Age' libelle: 'Age'
) )
types_de_champ << type_de_champ_number
champ_repetition.type_de_champ.types_de_champ << [type_de_champ_text, type_de_champ_number]
champ_repetition.champs << [ champ_repetition.champs << [
build(:champ_text, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_text, parent: champ_repetition), build(:champ_text, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_text, parent: champ_repetition),
build(:champ_number, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_number, parent: champ_repetition), build(:champ_number, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_number, parent: champ_repetition),
@ -198,13 +195,11 @@ FactoryBot.define do
after(:build) do |champ_repetition, _evaluator| after(:build) do |champ_repetition, _evaluator|
type_de_champ_pj0 = build(:type_de_champ_piece_justificative, type_de_champ_pj0 = build(:type_de_champ_piece_justificative,
procedure: champ_repetition.dossier.procedure, position: 0,
order_place: 0,
parent: champ_repetition.type_de_champ, parent: champ_repetition.type_de_champ,
libelle: 'Justificatif de domicile') libelle: 'Justificatif de domicile')
type_de_champ_pj1 = build(:type_de_champ_piece_justificative, type_de_champ_pj1 = build(:type_de_champ_piece_justificative,
procedure: champ_repetition.dossier.procedure, position: 1,
order_place: 1,
parent: champ_repetition.type_de_champ, parent: champ_repetition.type_de_champ,
libelle: 'Carte d\'identité') libelle: 'Carte d\'identité')

View file

@ -15,6 +15,8 @@ FactoryBot.define do
procedure = create(:procedure, :published, :with_type_de_champ, :with_type_de_champ_private) procedure = create(:procedure, :published, :with_type_de_champ, :with_type_de_champ_private)
end end
dossier.revision = procedure.active_revision
# Assign the procedure to the dossier through the groupe_instructeur # Assign the procedure to the dossier through the groupe_instructeur
if dossier.groupe_instructeur.nil? if dossier.groupe_instructeur.nil?
dossier.groupe_instructeur = procedure.defaut_groupe_instructeur dossier.groupe_instructeur = procedure.defaut_groupe_instructeur
@ -71,7 +73,7 @@ FactoryBot.define do
linked_dossier = create(:dossier, :en_construction) linked_dossier = create(:dossier, :en_construction)
# find first type de champ dossier_link # find first type de champ dossier_link
type_de_champ = dossier.procedure.types_de_champ.find do |t| type_de_champ = dossier.types_de_champ.find do |t|
t.type_champ == TypeDeChamp.type_champs.fetch(:dossier_link) t.type_champ == TypeDeChamp.type_champs.fetch(:dossier_link)
end end
@ -202,7 +204,7 @@ FactoryBot.define do
trait :with_all_champs do trait :with_all_champs do
after(:create) do |dossier, _evaluator| after(:create) do |dossier, _evaluator|
dossier.champs = dossier.procedure.types_de_champ.map do |type_de_champ| dossier.champs = dossier.types_de_champ.map do |type_de_champ|
build(:"champ_#{type_de_champ.type_champ}", dossier: dossier, type_de_champ: type_de_champ) build(:"champ_#{type_de_champ.type_champ}", dossier: dossier, type_de_champ: type_de_champ)
end end
dossier.save! dossier.save!
@ -211,7 +213,7 @@ FactoryBot.define do
trait :with_all_annotations do trait :with_all_annotations do
after(:create) do |dossier, _evaluator| after(:create) do |dossier, _evaluator|
dossier.champs = dossier.procedure.types_de_champ.map do |type_de_champ| dossier.champs = dossier.types_de_champ.map do |type_de_champ|
build(:"champ_#{type_de_champ.type_champ}", dossier: dossier, type_de_champ: type_de_champ) build(:"champ_#{type_de_champ.type_champ}", dossier: dossier, type_de_champ: type_de_champ)
end end
dossier.save! dossier.save!

View file

@ -16,6 +16,9 @@ FactoryBot.define do
transient do transient do
administrateur { } administrateur { }
instructeurs { [] } instructeurs { [] }
types_de_champ { [] }
types_de_champ_private { [] }
updated_at { nil }
end end
after(:build) do |procedure, evaluator| after(:build) do |procedure, evaluator|
@ -24,10 +27,35 @@ FactoryBot.define do
elsif procedure.administrateurs.empty? elsif procedure.administrateurs.empty?
procedure.administrateurs = [create(:administrateur)] procedure.administrateurs = [create(:administrateur)]
end end
procedure.draft_revision = build(:procedure_revision, procedure: procedure)
evaluator.types_de_champ.each do |type_de_champ|
type_de_champ.revision = procedure.draft_revision
type_de_champ.private = false
type_de_champ.revision.revision_types_de_champ << build(:procedure_revision_type_de_champ,
revision: procedure.draft_revision,
position: type_de_champ.order_place,
type_de_champ: type_de_champ)
end
evaluator.types_de_champ_private.each do |type_de_champ|
type_de_champ.revision = procedure.draft_revision
type_de_champ.private = true
type_de_champ.revision.revision_types_de_champ_private << build(:procedure_revision_type_de_champ,
revision: procedure.draft_revision,
position: type_de_champ.order_place,
type_de_champ: type_de_champ)
end
end end
after(:create) do |procedure, evaluator| after(:create) do |procedure, evaluator|
evaluator.instructeurs.each { |i| i.assign_to_procedure(procedure) } evaluator.instructeurs.each { |i| i.assign_to_procedure(procedure) }
if evaluator.updated_at
procedure.update_column(:updated_at, evaluator.updated_at)
end
procedure.reload
end end
factory :procedure_with_dossiers do factory :procedure_with_dossiers do
@ -38,9 +66,7 @@ FactoryBot.define do
after(:create) do |procedure, evaluator| after(:create) do |procedure, evaluator|
user = create(:user) user = create(:user)
evaluator.dossiers_count.times do evaluator.dossiers_count.times do
dossier = procedure.new_dossier create(:dossier, procedure: procedure, user: user)
dossier.user = user
dossier.save!
end end
end end
end end
@ -48,7 +74,7 @@ FactoryBot.define do
factory :simple_procedure do factory :simple_procedure do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
procedure.for_individual = true procedure.for_individual = true
procedure.types_de_champ << build(:type_de_champ, libelle: 'Texte obligatoire', mandatory: true) build(:type_de_champ, libelle: 'Texte obligatoire', mandatory: true, procedure: procedure)
procedure.path = generate(:published_path) procedure.path = generate(:published_path)
procedure.publish! procedure.publish!
end end
@ -96,10 +122,8 @@ FactoryBot.define do
end end
after(:build) do |procedure, evaluator| after(:build) do |procedure, evaluator|
evaluator.types_de_champ_count.times do evaluator.types_de_champ_count.times do |position|
type_de_champ = build(:type_de_champ) build(:type_de_champ, procedure: procedure, position: position)
procedure.types_de_champ << type_de_champ
end end
end end
end end
@ -110,68 +134,51 @@ FactoryBot.define do
end end
after(:build) do |procedure, evaluator| after(:build) do |procedure, evaluator|
evaluator.types_de_champ_private_count.times do evaluator.types_de_champ_private_count.times do |position|
type_de_champ = build(:type_de_champ, :private) build(:type_de_champ, :private, procedure: procedure, position: position)
procedure.types_de_champ_private << type_de_champ
end end
end end
end end
trait :with_type_de_champ_mandatory do trait :with_type_de_champ_mandatory do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
type_de_champ = build(:type_de_champ, mandatory: true) build(:type_de_champ, mandatory: true, procedure: procedure)
procedure.types_de_champ << type_de_champ
end end
end end
trait :with_datetime do trait :with_datetime do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
type_de_champ = build(:type_de_champ_datetime, mandatory: true) build(:type_de_champ_datetime, mandatory: true, procedure: procedure)
procedure.types_de_champ << type_de_champ
end end
end end
trait :with_dossier_link do trait :with_dossier_link do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
type_de_champ = build(:type_de_champ_dossier_link) build(:type_de_champ_dossier_link, procedure: procedure)
procedure.types_de_champ << type_de_champ
end end
end end
trait :with_yes_no do trait :with_yes_no do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
type_de_champ = build(:type_de_champ_yes_no) build(:type_de_champ_yes_no, procedure: procedure)
procedure.types_de_champ << type_de_champ
end end
end end
trait :with_piece_justificative do trait :with_piece_justificative do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
type_de_champ = build(:type_de_champ_piece_justificative) build(:type_de_champ_piece_justificative, procedure: procedure)
procedure.types_de_champ << type_de_champ
end end
end end
trait :with_repetition do trait :with_repetition do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
type_de_champ = build(:type_de_champ_repetition) build(:type_de_champ_repetition, :with_types_de_champ, procedure: procedure)
procedure.types_de_champ << type_de_champ
type_de_champ.types_de_champ << build(:type_de_champ, libelle: 'sub type de champ')
end end
end end
trait :with_number do trait :with_number do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
type_de_champ = build(:type_de_champ_number) build(:type_de_champ_number, procedure: procedure)
procedure.types_de_champ << type_de_champ
end end
end end
@ -228,35 +235,35 @@ FactoryBot.define do
trait :with_all_champs_mandatory do trait :with_all_champs_mandatory do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
procedure.types_de_champ = TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index| TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index|
if libelle == 'drop_down_list' if libelle == 'drop_down_list'
libelle = 'simple_drop_down_list' libelle = 'simple_drop_down_list'
end end
build(:"type_de_champ_#{type_champ}", procedure: procedure, mandatory: true, libelle: libelle, order_place: index) build(:"type_de_champ_#{type_champ}", procedure: procedure, mandatory: true, libelle: libelle, position: index)
end end
procedure.types_de_champ << build(:type_de_champ_drop_down_list, :long, procedure: procedure, mandatory: true, libelle: 'simple_choice_drop_down_list_long') build(:type_de_champ_drop_down_list, :long, procedure: procedure, mandatory: true, libelle: 'simple_choice_drop_down_list_long', position: TypeDeChamp.type_champs.size)
procedure.types_de_champ << build(:type_de_champ_multiple_drop_down_list, :long, procedure: procedure, mandatory: true, libelle: 'multiple_choice_drop_down_list_long') build(:type_de_champ_multiple_drop_down_list, :long, procedure: procedure, mandatory: true, libelle: 'multiple_choice_drop_down_list_long', position: TypeDeChamp.type_champs.size + 1)
end end
end end
trait :with_all_champs do trait :with_all_champs do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
procedure.types_de_champ = TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index| TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index|
if libelle == 'drop_down_list' if libelle == 'drop_down_list'
libelle = 'simple_drop_down_list' libelle = 'simple_drop_down_list'
end end
build(:"type_de_champ_#{type_champ}", procedure: procedure, libelle: libelle, order_place: index) build(:"type_de_champ_#{type_champ}", procedure: procedure, libelle: libelle, position: index)
end end
end end
end end
trait :with_all_annotations do trait :with_all_annotations do
after(:build) do |procedure, _evaluator| after(:build) do |procedure, _evaluator|
procedure.types_de_champ_private = TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index| TypeDeChamp.type_champs.map.with_index do |(libelle, type_champ), index|
if libelle == 'drop_down_list' if libelle == 'drop_down_list'
libelle = 'simple_drop_down_list' libelle = 'simple_drop_down_list'
end end
build(:"type_de_champ_#{type_champ}", procedure: procedure, private: true, libelle: libelle, order_place: index) build(:"type_de_champ_#{type_champ}", procedure: procedure, private: true, libelle: libelle, position: index)
end end
end end
end end

View file

@ -0,0 +1,4 @@
FactoryBot.define do
factory :procedure_revision do
end
end

View file

@ -0,0 +1,4 @@
FactoryBot.define do
factory :procedure_revision_type_de_champ do
end
end

View file

@ -7,7 +7,40 @@ FactoryBot.define do
mandatory { false } mandatory { false }
add_attribute(:private) { false } add_attribute(:private) { false }
association :procedure transient do
procedure { nil }
position { nil }
parent { nil }
end
after(:build) do |type_de_champ, evaluator|
if evaluator.procedure
type_de_champ.revision = evaluator.procedure.active_revision
build(:procedure_revision_type_de_champ,
position: evaluator.position,
revision: evaluator.procedure.active_revision,
type_de_champ: type_de_champ)
if type_de_champ.private?
type_de_champ.revision.types_de_champ_private << type_de_champ
else
type_de_champ.revision.types_de_champ << type_de_champ
end
elsif evaluator.parent
type_de_champ.revision = evaluator.parent.revision
type_de_champ.order_place = evaluator.position || evaluator.parent.types_de_champ.size
evaluator.parent.types_de_champ << type_de_champ
else
type_de_champ.order_place = evaluator.position
end
end
trait :private do
add_attribute(:private) { true }
sequence(:libelle) { |n| "Libelle champ privé #{n}" }
sequence(:description) { |n| "description du champ privé #{n}" }
end
factory :type_de_champ_text do factory :type_de_champ_text do
type_champ { TypeDeChamp.type_champs.fetch(:text) } type_champ { TypeDeChamp.type_champs.fetch(:text) }
@ -96,8 +129,8 @@ FactoryBot.define do
factory :type_de_champ_piece_justificative do factory :type_de_champ_piece_justificative do
type_champ { TypeDeChamp.type_champs.fetch(:piece_justificative) } type_champ { TypeDeChamp.type_champs.fetch(:piece_justificative) }
after(:build) do |tc, _evaluator| after(:build) do |type_de_champ, _evaluator|
tc.piece_justificative_template.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain") type_de_champ.piece_justificative_template.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain")
end end
end end
factory :type_de_champ_siret do factory :type_de_champ_siret do
@ -109,17 +142,23 @@ FactoryBot.define do
factory :type_de_champ_repetition do factory :type_de_champ_repetition do
type_champ { TypeDeChamp.type_champs.fetch(:repetition) } type_champ { TypeDeChamp.type_champs.fetch(:repetition) }
transient do
types_de_champ { [] }
end
after(:build) do |type_de_champ_repetition, evaluator|
evaluator.types_de_champ.each do |type_de_champ|
type_de_champ.revision = type_de_champ_repetition.revision
type_de_champ.order_place = type_de_champ_repetition.types_de_champ.size
type_de_champ_repetition.types_de_champ << type_de_champ
end
end
trait :with_types_de_champ do trait :with_types_de_champ do
after(:build) do |type_de_champ, _evaluator| after(:build) do |type_de_champ, _evaluator|
type_de_champ.types_de_champ << build(:type_de_champ, procedure: type_de_champ.procedure, libelle: 'sub type de champ') build(:type_de_champ, libelle: 'sub type de champ', parent: type_de_champ)
end end
end end
end end
trait :private do
add_attribute(:private) { true }
sequence(:libelle) { |n| "Libelle champ privé #{n}" }
sequence(:description) { |n| "description du champ privé #{n}" }
end
end end
end end

View file

@ -6,11 +6,11 @@ feature 'As an administrateur I wanna clone a procedure', js: true do
let(:administrateur) { create(:administrateur) } let(:administrateur) { create(:administrateur) }
before do before do
create :procedure, :with_service, :with_instructeur, create(:procedure, :with_service, :with_instructeur,
aasm_state: :publiee, published_at: Time.zone.now, aasm_state: :publiee,
administrateurs: [administrateur], administrateurs: [administrateur],
libelle: 'libellé de la procédure', libelle: 'libellé de la procédure',
path: 'libelle-de-la-procedure' path: 'libelle-de-la-procedure')
login_as administrateur.user, scope: :user login_as administrateur.user, scope: :user
end end

View file

@ -91,7 +91,7 @@ feature 'Instructing a dossier:' do
end end
scenario 'A instructeur can see the personnes impliquées' do scenario 'A instructeur can see the personnes impliquées' do
instructeur2 = FactoryBot.create(:instructeur, password: password) instructeur2 = create(:instructeur, password: password)
log_in(instructeur.email, password) log_in(instructeur.email, password)
@ -113,8 +113,8 @@ feature 'Instructing a dossier:' do
end end
scenario 'A instructeur can send a dossier to several instructeurs', js: true do scenario 'A instructeur can send a dossier to several instructeurs', js: true do
instructeur_2 = FactoryBot.create(:instructeur) instructeur_2 = create(:instructeur)
instructeur_3 = FactoryBot.create(:instructeur) instructeur_3 = create(:instructeur)
procedure.defaut_groupe_instructeur.instructeurs << [instructeur_2, instructeur_3] procedure.defaut_groupe_instructeur.instructeurs << [instructeur_2, instructeur_3]
send_dossier = double() send_dossier = double()

View file

@ -122,7 +122,7 @@ feature 'As an administrateur I can edit types de champ', js: true do
fill_in 'champ-0-libelle', with: 'Libellé de champ carte', fill_options: { clear: :backspace } fill_in 'champ-0-libelle', with: 'Libellé de champ carte', fill_options: { clear: :backspace }
check 'Cadastres' check 'Cadastres'
wait_until { procedure.types_de_champ.first.cadastres == true } wait_until { procedure.draft_types_de_champ.first.cadastres == true }
expect(page).to have_content('Formulaire enregistré') expect(page).to have_content('Formulaire enregistré')
preview_window = window_opened_by { click_on 'Prévisualiser le formulaire' } preview_window = window_opened_by { click_on 'Prévisualiser le formulaire' }
@ -139,7 +139,7 @@ feature 'As an administrateur I can edit types de champ', js: true do
fill_in 'champ-0-libelle', with: 'Libellé de champ menu déroulant', fill_options: { clear: :backspace } fill_in 'champ-0-libelle', with: 'Libellé de champ menu déroulant', fill_options: { clear: :backspace }
fill_in 'champ-0-drop_down_list_value', with: 'Un menu', fill_options: { clear: :backspace } fill_in 'champ-0-drop_down_list_value', with: 'Un menu', fill_options: { clear: :backspace }
wait_until { procedure.types_de_champ.first.drop_down_list_options == ['', 'Un menu'] } wait_until { procedure.draft_types_de_champ.first.drop_down_list_options == ['', 'Un menu'] }
expect(page).to have_content('Formulaire enregistré') expect(page).to have_content('Formulaire enregistré')
page.refresh page.refresh

View file

@ -60,7 +60,7 @@ feature 'Signin in:' do
click_on 'Connexion' click_on 'Connexion'
sign_in_with user.email, password sign_in_with user.email, password
expect(page).to have_content 'Vous devez confirmer votre adresse email pour continuer' expect(page).to have_content('Vous devez confirmer votre compte par courriel.')
end end
end end
end end

View file

@ -97,9 +97,7 @@ feature 'The user' do
end end
let(:procedure_with_repetition) do let(:procedure_with_repetition) do
tdc = create(:type_de_champ_repetition, libelle: 'repetition') create(:procedure, :published, :for_individual, :with_repetition)
tdc.types_de_champ << create(:type_de_champ_text, libelle: 'text')
create(:procedure, :published, :for_individual, types_de_champ: [tdc])
end end
scenario 'fill a dossier with repetition', js: true do scenario 'fill a dossier with repetition', js: true do
@ -107,13 +105,13 @@ feature 'The user' do
fill_individual fill_individual
fill_in('text', with: 'super texte') fill_in('sub type de champ', with: 'super texte')
expect(page).to have_field('text', with: 'super texte') expect(page).to have_field('sub type de champ', with: 'super texte')
click_on 'Ajouter un élément pour' click_on 'Ajouter un élément pour'
within '.row-1' do within '.row-1' do
fill_in('text', with: 'un autre texte') fill_in('sub type de champ', with: 'un autre texte')
end end
expect(page).to have_content('Supprimer', count: 2) expect(page).to have_content('Supprimer', count: 2)
@ -132,7 +130,7 @@ feature 'The user' do
end end
let(:simple_procedure) do let(:simple_procedure) do
tdcs = [create(:type_de_champ, mandatory: true, libelle: 'texte obligatoire')] tdcs = [build(:type_de_champ, mandatory: true, libelle: 'texte obligatoire')]
create(:procedure, :published, :for_individual, types_de_champ: tdcs) create(:procedure, :published, :for_individual, types_de_champ: tdcs)
end end
@ -161,14 +159,14 @@ feature 'The user' do
end end
let(:procedure_with_pj) do let(:procedure_with_pj) do
tdcs = [create(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative')] tdcs = [build(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative')]
create(:procedure, :published, :for_individual, types_de_champ: tdcs) create(:procedure, :published, :for_individual, types_de_champ: tdcs)
end end
let(:procedure_with_pjs) do let(:procedure_with_pjs) do
tdcs = [ tdcs = [
create(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative 1', order_place: 1), build(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative 1', position: 1),
create(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative 2', order_place: 2) build(:type_de_champ_piece_justificative, mandatory: true, libelle: 'Pièce justificative 2', position: 2)
] ]
create(:procedure, :published, :for_individual, types_de_champ: tdcs) create(:procedure, :published, :for_individual, types_de_champ: tdcs)
end end

View file

@ -41,7 +41,7 @@ feature 'Invitations' do
# Confirm the account # Confirm the account
# (The user should be redirected to the dossier they was invited on) # (The user should be redirected to the dossier they was invited on)
click_confirmation_link_for invite.email click_confirmation_link_for invite.email
expect(page).to have_content('Votre compte a été activé') expect(page).to have_content('Votre compte a bien été confirmé.')
expect(page).to have_current_path(brouillon_dossier_path(dossier)) expect(page).to have_current_path(brouillon_dossier_path(dossier))
end end
end end

View file

@ -13,12 +13,10 @@ feature 'linked dropdown lists' do
Secondary 2.3 Secondary 2.3
END_OF_LIST END_OF_LIST
end end
let(:type_de_champ) { create(:type_de_champ_linked_drop_down_list, libelle: 'linked dropdown', drop_down_list_value: list_items) } let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, libelle: 'linked dropdown', drop_down_list_value: list_items) }
let!(:procedure) do let!(:procedure) do
p = create(:procedure, :published, :for_individual) create(:procedure, :published, :for_individual, types_de_champ: [type_de_champ])
p.types_de_champ << type_de_champ
p
end end
let(:user_dossier) { user.dossiers.first } let(:user_dossier) { user.dossiers.first }

View file

@ -13,7 +13,7 @@ feature 'Managing password:' do
perform_enqueued_jobs do perform_enqueued_jobs do
click_on 'Réinitialiser' click_on 'Réinitialiser'
end end
expect(page).to have_content 'vous allez recevoir un lien de réinitialisation par email' expect(page).to have_content('Si votre courriel existe dans notre base de données, vous recevrez un lien vous permettant de récupérer votre mot de passe.')
click_reset_password_link_for user.email click_reset_password_link_for user.email
expect(page).to have_content 'Changement de mot de passe' expect(page).to have_content 'Changement de mot de passe'
@ -21,7 +21,7 @@ feature 'Managing password:' do
fill_in 'user_password', with: new_password fill_in 'user_password', with: new_password
fill_in 'user_password_confirmation', with: new_password fill_in 'user_password_confirmation', with: new_password
click_on 'Changer le mot de passe' click_on 'Changer le mot de passe'
expect(page).to have_content('Votre mot de passe a été changé avec succès') expect(page).to have_content('Votre mot de passe a bien été modifié.')
end end
end end
@ -40,7 +40,7 @@ feature 'Managing password:' do
perform_enqueued_jobs do perform_enqueued_jobs do
click_on 'Réinitialiser' click_on 'Réinitialiser'
end end
expect(page).to have_content 'vous allez recevoir un lien de réinitialisation par email' expect(page).to have_content('Si votre courriel existe dans notre base de données, vous recevrez un lien vous permettant de récupérer votre mot de passe.')
click_reset_password_link_for user.email click_reset_password_link_for user.email
@ -49,7 +49,7 @@ feature 'Managing password:' do
fill_in 'user_password', with: new_password fill_in 'user_password', with: new_password
fill_in 'user_password_confirmation', with: new_password fill_in 'user_password_confirmation', with: new_password
click_on 'Changer le mot de passe' click_on 'Changer le mot de passe'
expect(page).to have_content('Votre mot de passe a été changé avec succès') expect(page).to have_content('Votre mot de passe a bien été modifié.')
end end
end end
end end

View file

@ -10,7 +10,7 @@ feature 'Signing up:' do
expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}" expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}"
click_confirmation_link_for user_email click_confirmation_link_for user_email
expect(page).to have_content 'Votre compte a été activé' expect(page).to have_content('Votre compte a bien été confirmé.')
expect(page).to have_current_path dossiers_path expect(page).to have_current_path dossiers_path
end end
@ -80,7 +80,7 @@ feature 'Signing up:' do
# After confirmation, the user is redirected to the procedure they were initially starting # After confirmation, the user is redirected to the procedure they were initially starting
# (even when confirming the account in another browser). # (even when confirming the account in another browser).
expect(page).to have_current_path(commencer_path(path: procedure.path)) expect(page).to have_current_path(commencer_path(path: procedure.path))
expect(page).to have_content 'Votre compte a été activé' expect(page).to have_content I18n.t('devise.confirmations.confirmed')
click_on 'Commencer la démarche' click_on 'Commencer la démarche'
expect(page).to have_current_path identite_dossier_path(procedure.reload.dossiers.last) expect(page).to have_current_path identite_dossier_path(procedure.reload.dossiers.last)
@ -112,7 +112,7 @@ feature 'Signing up:' do
# After confirmation, the user is redirected to the procedure they were initially starting # After confirmation, the user is redirected to the procedure they were initially starting
# (even when confirming the account in another browser). # (even when confirming the account in another browser).
expect(page).to have_current_path(commencer_path(path: procedure.path)) expect(page).to have_current_path(commencer_path(path: procedure.path))
expect(page).to have_content 'Votre compte a été activé' expect(page).to have_content I18n.t('devise.confirmations.confirmed')
expect(page).to have_content 'Commencer la démarche' expect(page).to have_content 'Commencer la démarche'
end end
end end

View file

@ -1,23 +1,24 @@
RSpec.describe FindDubiousProceduresJob, type: :job do RSpec.describe FindDubiousProceduresJob, type: :job do
describe 'perform' do describe 'perform' do
let(:mailer_double) { double('mailer', deliver_later: true) } let(:mailer_double) { double('mailer', deliver_later: true) }
let(:procedure) { create(:procedure) } let(:procedure) { create(:procedure, types_de_champ: tdcs) }
let(:allowed_tdc) { create(:type_de_champ, libelle: 'fournir') } let(:allowed_tdc) { build(:type_de_champ, libelle: 'fournir') }
before do before do
procedure
allow(AdministrationMailer).to receive(:dubious_procedures) do |arg| allow(AdministrationMailer).to receive(:dubious_procedures) do |arg|
@dubious_procedures_args = arg @dubious_procedures_args = arg
end.and_return(mailer_double) end.and_return(mailer_double)
procedure.types_de_champ << tdcs
FindDubiousProceduresJob.new.perform FindDubiousProceduresJob.new.perform
end end
context 'with suspicious champs' do context 'with suspicious champs' do
let(:forbidden_tdcs) do let(:forbidden_tdcs) do
[ [
create(:type_de_champ, libelle: 'num de securite sociale, stp'), build(:type_de_champ, libelle: 'num de securite sociale, stp'),
create(:type_de_champ, libelle: "t'aurais une carte bancaire ?") build(:type_de_champ, libelle: "t'aurais une carte bancaire ?")
] ]
end end

View file

@ -1,24 +0,0 @@
RSpec.describe TmpDossiersMigrateRevisionsJob, type: :job do
let(:procedure) { create(:procedure, :published) }
let!(:dossier1) { create(:dossier, procedure: procedure, updated_at: 1.day.ago) }
let!(:dossier2) { create(:dossier, procedure: procedure, updated_at: 2.days.ago) }
context "add revision to dossiers" do
before do
RevisionsMigration.add_revisions(procedure)
end
it {
expect(dossier1.revision).to be_nil
expect(dossier2.revision).to be_nil
TmpDossiersMigrateRevisionsJob.new.perform([])
[dossier1, dossier2].each(&:reload)
expect(dossier1.revision).to eq procedure.active_revision
expect(dossier2.revision).to eq procedure.active_revision
expect(dossier1.updated_at < 1.day.ago).to be_truthy
expect(dossier2.updated_at < 1.day.ago).to be_truthy
}
end
end

View file

@ -427,10 +427,9 @@ describe Champ do
end end
describe 'repetition' do describe 'repetition' do
let(:procedure) { build(:procedure, :published, :with_type_de_champ, :with_type_de_champ_private) } let(:procedure) { create(:procedure, :published, :with_type_de_champ, :with_type_de_champ_private, types_de_champ: [build(:type_de_champ_repetition, types_de_champ: [tdc_text, tdc_integer])]) }
let(:tdc_text) { build(:type_de_champ_text, procedure: procedure) } let(:tdc_text) { build(:type_de_champ_text) }
let(:tdc_integer) { build(:type_de_champ_integer_number, procedure: procedure) } let(:tdc_integer) { build(:type_de_champ_integer_number) }
let(:tdc_repetition) { build(:type_de_champ_repetition, procedure: procedure, types_de_champ: [tdc_text, tdc_integer]) }
let(:dossier) { create(:dossier, procedure: procedure) } let(:dossier) { create(:dossier, procedure: procedure) }
let(:champ) { dossier.champs.find(&:repetition?) } let(:champ) { dossier.champs.find(&:repetition?) }
@ -438,12 +437,6 @@ describe Champ do
let(:champ_integer) { champ.champs.find { |c| c.type_champ == 'integer_number' } } let(:champ_integer) { champ.champs.find { |c| c.type_champ == 'integer_number' } }
let(:champ_text_attrs) { attributes_for(:champ_text, type_de_champ: tdc_text, row: 1) } let(:champ_text_attrs) { attributes_for(:champ_text, type_de_champ: tdc_text, row: 1) }
before do
procedure.types_de_champ << tdc_repetition
procedure.save!
procedure.reload
end
context 'when creating the model directly' do context 'when creating the model directly' do
let(:champ_text_row_1) { create(:champ_text, type_de_champ: tdc_text, row: 2, parent: champ, dossier: nil) } let(:champ_text_row_1) { create(:champ_text, type_de_champ: tdc_text, row: 2, parent: champ, dossier: nil) }

View file

@ -18,7 +18,7 @@ describe Champs::DecimalNumberChamp do
let(:value) { 'toto' } let(:value) { 'toto' }
it { is_expected.to_not be_valid } it { is_expected.to_not be_valid }
it { expect(subject.errors[:value]).to eq(["« #{subject.libelle} » doit être un nombre"]) } it { expect(subject.errors[:value]).to eq(["« #{subject.libelle} » n'est pas un nombre"]) }
end end
context 'when the value is blank' do context 'when the value is blank' do

View file

@ -2,11 +2,11 @@ describe Champs::HeaderSectionChamp do
describe '#section_index' do describe '#section_index' do
let(:types_de_champ) do let(:types_de_champ) do
[ [
create(:type_de_champ_header_section, order_place: 1), build(:type_de_champ_header_section, position: 1),
create(:type_de_champ_civilite, order_place: 2), build(:type_de_champ_civilite, position: 2),
create(:type_de_champ_text, order_place: 3), build(:type_de_champ_text, position: 3),
create(:type_de_champ_header_section, order_place: 4), build(:type_de_champ_header_section, position: 4),
create(:type_de_champ_email, order_place: 5) build(:type_de_champ_email, position: 5)
] ]
end end
@ -23,17 +23,12 @@ describe Champs::HeaderSectionChamp do
end end
context 'for repetition champs' do context 'for repetition champs' do
let(:procedure) { create(:procedure, :with_repetition) } let(:procedure) { create(:procedure, types_de_champ: [build(:type_de_champ_repetition, types_de_champ: types_de_champ)]) }
let(:dossier) { create(:dossier, procedure: procedure) } let(:dossier) { create(:dossier, procedure: procedure) }
let(:repetition_tdc) { procedure.types_de_champ.find(&:repetition?) }
let(:first_header) { dossier.champs.first.champs[0] } let(:first_header) { dossier.champs.first.champs[0] }
let(:second_header) { dossier.champs.first.champs[3] } let(:second_header) { dossier.champs.first.champs[3] }
before do
repetition_tdc.types_de_champ = types_de_champ
end
it 'returns the index of the section in the repetition (starting from 1)' do it 'returns the index of the section in the repetition (starting from 1)' do
expect(first_header.section_index).to eq 1 expect(first_header.section_index).to eq 1
expect(second_header.section_index).to eq 2 expect(second_header.section_index).to eq 2

View file

@ -97,8 +97,8 @@ describe TagsSubstitutionConcern, type: :model do
context 'when the procedure has a type de champ named libelleA et libelleB' do context 'when the procedure has a type de champ named libelleA et libelleB' do
let(:types_de_champ) do let(:types_de_champ) do
[ [
create(:type_de_champ, libelle: 'libelleA'), build(:type_de_champ, libelle: 'libelleA'),
create(:type_de_champ, libelle: 'libelleB') build(:type_de_champ, libelle: 'libelleB')
] ]
end end
@ -141,7 +141,7 @@ describe TagsSubstitutionConcern, type: :model do
context 'when the procedure has a type de champ with apostrophes' do context 'when the procedure has a type de champ with apostrophes' do
let(:types_de_champ) do let(:types_de_champ) do
[ [
create(:type_de_champ, libelle: "Intitulé de l'‘«\"évènement\"»’") build(:type_de_champ, libelle: "Intitulé de l'‘«\"évènement\"»’")
] ]
end end
@ -165,9 +165,9 @@ describe TagsSubstitutionConcern, type: :model do
let(:template) { '--Répétition--' } let(:template) { '--Répétition--' }
let(:types_de_champ) do let(:types_de_champ) do
[ [
create(:type_de_champ_repetition, libelle: 'Répétition', types_de_champ: [ build(:type_de_champ_repetition, libelle: 'Répétition', types_de_champ: [
create(:type_de_champ_text, libelle: 'Nom', order_place: 1), build(:type_de_champ_text, libelle: 'Nom', order_place: 1),
create(:type_de_champ_text, libelle: 'Prénom', order_place: 2) build(:type_de_champ_text, libelle: 'Prénom', order_place: 2)
]) ])
] ]
end end
@ -190,7 +190,7 @@ describe TagsSubstitutionConcern, type: :model do
context 'when the procedure has a linked drop down menus type de champ' do context 'when the procedure has a linked drop down menus type de champ' do
let(:type_de_champ) do let(:type_de_champ) do
create(:type_de_champ_linked_drop_down_list, libelle: 'libelle') build(:type_de_champ_linked_drop_down_list, libelle: 'libelle')
end end
let(:types_de_champ) { [type_de_champ] } let(:types_de_champ) { [type_de_champ] }
let(:template) { 'tout : --libelle--, primaire : --libelle/primaire--, secondaire : --libelle/secondaire--' } let(:template) { 'tout : --libelle--, primaire : --libelle/primaire--, secondaire : --libelle/secondaire--' }
@ -219,7 +219,7 @@ describe TagsSubstitutionConcern, type: :model do
let(:types_de_champ) do let(:types_de_champ) do
[ [
type_de_champ, type_de_champ,
create(:type_de_champ_header_section, libelle: 'libelle') build(:type_de_champ_header_section, libelle: 'libelle')
] ]
end end
@ -253,7 +253,7 @@ describe TagsSubstitutionConcern, type: :model do
end end
context 'when the procedure has a type de champ prive named libelleA' do context 'when the procedure has a type de champ prive named libelleA' do
let(:types_de_champ_private) { [create(:type_de_champ, :private, libelle: 'libelleA')] } let(:types_de_champ_private) { [build(:type_de_champ, :private, libelle: 'libelleA')] }
context 'and it is used in the template' do context 'and it is used in the template' do
let(:template) { '--libelleA--' } let(:template) { '--libelleA--' }
@ -274,13 +274,13 @@ describe TagsSubstitutionConcern, type: :model do
# The dossier just transitionned from brouillon to en construction, # The dossier just transitionned from brouillon to en construction,
# so champs private are not valid tags yet # so champs private are not valid tags yet
let(:types_de_champ_private) { [create(:type_de_champ, :private, libelle: 'libelleA')] } let(:types_de_champ_private) { [build(:type_de_champ, :private, libelle: 'libelleA')] }
it { is_expected.to eq('--libelleA--') } it { is_expected.to eq('--libelleA--') }
end end
context 'champs publics are valid tags' do context 'champs publics are valid tags' do
let(:types_de_champ) { [create(:type_de_champ, libelle: 'libelleA')] } let(:types_de_champ) { [build(:type_de_champ, libelle: 'libelleA')] }
before { dossier.champs.first.update(value: 'libelle1') } before { dossier.champs.first.update(value: 'libelle1') }
@ -291,8 +291,8 @@ describe TagsSubstitutionConcern, type: :model do
context 'when the procedure has 2 types de champ date and datetime' do context 'when the procedure has 2 types de champ date and datetime' do
let(:types_de_champ) do let(:types_de_champ) do
[ [
create(:type_de_champ_date, libelle: TypeDeChamp.type_champs.fetch(:date)), build(:type_de_champ_date, libelle: TypeDeChamp.type_champs.fetch(:date)),
create(:type_de_champ_datetime, libelle: TypeDeChamp.type_champs.fetch(:datetime)) build(:type_de_champ_datetime, libelle: TypeDeChamp.type_champs.fetch(:datetime))
] ]
end end
@ -358,13 +358,13 @@ describe TagsSubstitutionConcern, type: :model do
shared_examples "treat all kinds of space as equivalent" do shared_examples "treat all kinds of space as equivalent" do
context 'and the champ has a non breaking space' do context 'and the champ has a non breaking space' do
let(:types_de_champ) { [create(:type_de_champ, libelle: 'mon tag')] } let(:types_de_champ) { [build(:type_de_champ, libelle: 'mon tag')] }
it { is_expected.to eq('valeur') } it { is_expected.to eq('valeur') }
end end
context 'and the champ has an ordinary space' do context 'and the champ has an ordinary space' do
let(:types_de_champ) { [create(:type_de_champ, libelle: 'mon tag')] } let(:types_de_champ) { [build(:type_de_champ, libelle: 'mon tag')] }
it { is_expected.to eq('valeur') } it { is_expected.to eq('valeur') }
end end
@ -401,12 +401,12 @@ describe TagsSubstitutionConcern, type: :model do
let(:types_de_champ) do let(:types_de_champ) do
[ [
create(:type_de_champ, libelle: 'public'), build(:type_de_champ, libelle: 'public'),
create(:type_de_champ_header_section, libelle: 'entête de section'), build(:type_de_champ_header_section, libelle: 'entête de section'),
create(:type_de_champ_explication, libelle: 'explication') build(:type_de_champ_explication, libelle: 'explication')
] ]
end end
let(:types_de_champ_private) { [create(:type_de_champ, :private, libelle: 'privé')] } let(:types_de_champ_private) { [build(:type_de_champ, :private, libelle: 'privé')] }
context 'do not generate tags for champs that cannot have usager content' do context 'do not generate tags for champs that cannot have usager content' do
it { is_expected.not_to include(include({ libelle: 'entête de section' })) } it { is_expected.not_to include(include({ libelle: 'entête de section' })) }

View file

@ -29,14 +29,8 @@ describe Dossier do
end end
describe 'with_champs' do describe 'with_champs' do
let(:procedure) { create(:procedure) } let(:procedure) { create(:procedure, types_de_champ: [build(:type_de_champ, libelle: 'l1', position: 1), build(:type_de_champ, libelle: 'l3', position: 3), build(:type_de_champ, libelle: 'l2', position: 2)]) }
let(:dossier) { Dossier.create(user: create(:user), groupe_instructeur: procedure.defaut_groupe_instructeur) } let(:dossier) { create(:dossier, procedure: procedure) }
before do
create(:type_de_champ, libelle: 'l1', order_place: 1, procedure: procedure)
create(:type_de_champ, libelle: 'l3', order_place: 3, procedure: procedure)
create(:type_de_champ, libelle: 'l2', order_place: 2, procedure: procedure)
end
it do it do
expect(Dossier.with_champs.find(dossier.id).champs.map(&:libelle)).to match(['l1', 'l2', 'l3']) expect(Dossier.with_champs.find(dossier.id).champs.map(&:libelle)).to match(['l1', 'l2', 'l3'])
@ -255,27 +249,15 @@ describe Dossier do
end end
describe '#champs' do describe '#champs' do
let(:procedure) { create(:procedure) } let(:procedure) { create(:procedure, types_de_champ: [build(:type_de_champ, :private, libelle: 'l1', position: 1), build(:type_de_champ, :private, libelle: 'l3', position: 3), build(:type_de_champ, :private, libelle: 'l2', position: 2)]) }
let(:dossier) { Dossier.create(user: create(:user), groupe_instructeur: procedure.defaut_groupe_instructeur) } let(:dossier) { create(:dossier, procedure: procedure) }
before do
create(:type_de_champ, libelle: 'l1', order_place: 1, procedure: procedure)
create(:type_de_champ, libelle: 'l3', order_place: 3, procedure: procedure)
create(:type_de_champ, libelle: 'l2', order_place: 2, procedure: procedure)
end
it { expect(dossier.champs.pluck(:libelle)).to match(['l1', 'l2', 'l3']) } it { expect(dossier.champs.pluck(:libelle)).to match(['l1', 'l2', 'l3']) }
end end
describe '#champs_private' do describe '#champs_private' do
let(:procedure) { create :procedure } let(:procedure) { create(:procedure, types_de_champ_private: [build(:type_de_champ, :private, libelle: 'l1', position: 1), build(:type_de_champ, :private, libelle: 'l3', position: 3), build(:type_de_champ, :private, libelle: 'l2', position: 2)]) }
let(:dossier) { Dossier.create(user: create(:user), groupe_instructeur: procedure.defaut_groupe_instructeur) } let(:dossier) { create(:dossier, procedure: procedure) }
before do
create :type_de_champ, :private, libelle: 'l1', order_place: 1, procedure: procedure
create :type_de_champ, :private, libelle: 'l3', order_place: 3, procedure: procedure
create :type_de_champ, :private, libelle: 'l2', order_place: 2, procedure: procedure
end
it { expect(dossier.champs_private.pluck(:libelle)).to match(['l1', 'l2', 'l3']) } it { expect(dossier.champs_private.pluck(:libelle)).to match(['l1', 'l2', 'l3']) }
end end
@ -525,7 +507,7 @@ describe Dossier do
dossier = nil dossier = nil
expect do expect do
perform_enqueued_jobs do perform_enqueued_jobs do
dossier = Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:brouillon), user: user) dossier = create(:dossier, procedure: procedure, state: Dossier.states.fetch(:brouillon), user: user)
end end
end.to change(ActionMailer::Base.deliveries, :size).from(0).to(1) end.to change(ActionMailer::Base.deliveries, :size).from(0).to(1)
@ -535,17 +517,19 @@ describe Dossier do
end end
it "does not send an email when the dossier is created with a non brouillon state" do it "does not send an email when the dossier is created with a non brouillon state" do
expect { Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:en_construction), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) expect { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_construction), user: user) }.not_to change(ActionMailer::Base.deliveries, :size)
expect { Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:en_instruction), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) expect { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction), user: user) }.not_to change(ActionMailer::Base.deliveries, :size)
expect { Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:accepte), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) expect { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:accepte), user: user) }.not_to change(ActionMailer::Base.deliveries, :size)
expect { Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:refuse), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) expect { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:refuse), user: user) }.not_to change(ActionMailer::Base.deliveries, :size)
expect { Dossier.create(groupe_instructeur: procedure.defaut_groupe_instructeur, state: Dossier.states.fetch(:sans_suite), user: user) }.not_to change(ActionMailer::Base.deliveries, :size) expect { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:sans_suite), user: user) }.not_to change(ActionMailer::Base.deliveries, :size)
end end
end end
describe "#unspecified_attestation_champs" do describe "#unspecified_attestation_champs" do
let(:procedure) { create(:procedure, attestation_template: attestation_template) } let(:procedure) { create(:procedure, attestation_template: attestation_template, types_de_champ: types_de_champ, types_de_champ_private: types_de_champ_private) }
let(:dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) } let(:dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) }
let(:types_de_champ) { [] }
let(:types_de_champ_private) { [] }
subject { dossier.unspecified_attestation_champs.map(&:libelle) } subject { dossier.unspecified_attestation_champs.map(&:libelle) }
@ -574,14 +558,17 @@ describe Dossier do
context "wich is enabled" do context "wich is enabled" do
let(:activated) { true } let(:activated) { true }
let!(:tdc_1) { create(:type_de_champ, libelle: "specified champ-in-title", procedure: procedure) } let(:types_de_champ) { [tdc_1, tdc_2, tdc_3, tdc_4] }
let!(:tdc_2) { create(:type_de_champ, libelle: "unspecified champ-in-title", procedure: procedure) } let(:types_de_champ_private) { [tdc_5, tdc_6, tdc_7, tdc_8] }
let!(:tdc_3) { create(:type_de_champ, libelle: "specified champ-in-body", procedure: procedure) }
let!(:tdc_4) { create(:type_de_champ, libelle: "unspecified champ-in-body", procedure: procedure) } let(:tdc_1) { build(:type_de_champ, libelle: "specified champ-in-title") }
let!(:tdc_5) { create(:type_de_champ, private: true, libelle: "specified annotation privée-in-title", procedure: procedure) } let(:tdc_2) { build(:type_de_champ, libelle: "unspecified champ-in-title") }
let!(:tdc_6) { create(:type_de_champ, private: true, libelle: "unspecified annotation privée-in-title", procedure: procedure) } let(:tdc_3) { build(:type_de_champ, libelle: "specified champ-in-body") }
let!(:tdc_7) { create(:type_de_champ, private: true, libelle: "specified annotation privée-in-body", procedure: procedure) } let(:tdc_4) { build(:type_de_champ, libelle: "unspecified champ-in-body") }
let!(:tdc_8) { create(:type_de_champ, private: true, libelle: "unspecified annotation privée-in-body", procedure: procedure) } let(:tdc_5) { build(:type_de_champ, private: true, libelle: "specified annotation privée-in-title") }
let(:tdc_6) { build(:type_de_champ, private: true, libelle: "unspecified annotation privée-in-title") }
let(:tdc_7) { build(:type_de_champ, private: true, libelle: "specified annotation privée-in-body") }
let(:tdc_8) { build(:type_de_champ, private: true, libelle: "unspecified annotation privée-in-body") }
before do before do
(dossier.champs + dossier.champs_private) (dossier.champs + dossier.champs_private)
@ -1014,7 +1001,7 @@ describe Dossier do
end end
context "with mandatory SIRET champ" do context "with mandatory SIRET champ" do
let(:type_de_champ) { create(:type_de_champ_siret, mandatory: true) } let(:type_de_champ) { create(:type_de_champ_siret, mandatory: true, procedure: procedure) }
let(:champ_siret) { create(:champ_siret, type_de_champ: type_de_champ) } let(:champ_siret) { create(:champ_siret, type_de_champ: type_de_champ) }
before do before do
@ -1041,12 +1028,11 @@ describe Dossier do
end end
context "with champ repetition" do context "with champ repetition" do
let(:procedure) { create(:procedure) } let(:procedure) { create(:procedure, types_de_champ: [type_de_champ_repetition]) }
let(:type_de_champ_repetition) { create(:type_de_champ_repetition, mandatory: true) } let(:type_de_champ_repetition) { build(:type_de_champ_repetition, mandatory: true) }
before do before do
procedure.types_de_champ << type_de_champ_repetition create(:type_de_champ_text, mandatory: true, parent: type_de_champ_repetition)
type_de_champ_repetition.types_de_champ << create(:type_de_champ_text, mandatory: true)
end end
context "when no champs" do context "when no champs" do
@ -1261,9 +1247,14 @@ describe Dossier do
end end
describe "to_feature_collection" do describe "to_feature_collection" do
let(:dossier) { create(:dossier) }
let(:type_de_champ_carte) { create(:type_de_champ_carte, procedure: dossier.procedure) }
let(:geo_area) { create(:geo_area, :selection_utilisateur, :polygon) } let(:geo_area) { create(:geo_area, :selection_utilisateur, :polygon) }
let(:champ) { create(:champ_carte, geo_areas: [geo_area]) } let(:champ_carte) { create(:champ_carte, type_de_champ: type_de_champ_carte, geo_areas: [geo_area]) }
let(:dossier) { create(:dossier, champs: [champ]) }
before do
dossier.champs << champ_carte
end
it 'should have all champs carto' do it 'should have all champs carto' do
expect(dossier.to_feature_collection).to eq({ expect(dossier.to_feature_collection).to eq({
@ -1279,7 +1270,7 @@ describe Dossier do
}, },
properties: { properties: {
area: 219.0, area: 219.0,
champ_id: champ.stable_id, champ_id: champ_carte.stable_id,
dossier_id: dossier.id, dossier_id: dossier.id,
id: geo_area.id, id: geo_area.id,
source: 'selection_utilisateur' source: 'selection_utilisateur'

View file

@ -50,7 +50,7 @@ describe ProcedurePresentation do
describe "#fields" do describe "#fields" do
context 'when the procedure can have a SIRET number' do context 'when the procedure can have a SIRET number' do
let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private, :types_de_champ_count => 4, :types_de_champ_private_count => 4) } let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private, types_de_champ_count: 4, types_de_champ_private_count: 4) }
let(:tdc_1) { procedure.types_de_champ[0] } let(:tdc_1) { procedure.types_de_champ[0] }
let(:tdc_2) { procedure.types_de_champ[1] } let(:tdc_2) { procedure.types_de_champ[1] }
let(:tdc_private_1) { procedure.types_de_champ_private[0] } let(:tdc_private_1) { procedure.types_de_champ_private[0] }

View file

@ -9,10 +9,6 @@ describe ProcedureRevision do
type_de_champ type_de_champ
end end
before do
RevisionsMigration.add_revisions(procedure)
end
describe '#add_type_de_champ' do describe '#add_type_de_champ' do
it 'type_de_champ' do it 'type_de_champ' do
expect(revision.types_de_champ.size).to eq(2) expect(revision.types_de_champ.size).to eq(2)
@ -20,11 +16,8 @@ describe ProcedureRevision do
type_champ: TypeDeChamp.type_champs.fetch(:text), type_champ: TypeDeChamp.type_champs.fetch(:text),
libelle: "Un champ text" libelle: "Un champ text"
}) })
procedure.reload revision.reload
expect(revision.types_de_champ.size).to eq(3) expect(revision.types_de_champ.size).to eq(3)
expect(procedure.types_de_champ.size).to eq(3)
expect(procedure.types_de_champ.last).to eq(new_type_de_champ)
expect(revision.types_de_champ.last).to eq(new_type_de_champ) expect(revision.types_de_champ.last).to eq(new_type_de_champ)
expect(revision.revision_types_de_champ.last.position).to eq(2) expect(revision.revision_types_de_champ.last.position).to eq(2)
expect(revision.revision_types_de_champ.last.type_de_champ).to eq(new_type_de_champ) expect(revision.revision_types_de_champ.last.type_de_champ).to eq(new_type_de_champ)
@ -37,9 +30,8 @@ describe ProcedureRevision do
libelle: "Un champ text", libelle: "Un champ text",
private: true private: true
}) })
procedure.reload revision.reload
expect(revision.types_de_champ_private.size).to eq(2) expect(revision.types_de_champ_private.size).to eq(2)
expect(procedure.types_de_champ_private.size).to eq(2)
end end
it 'type_de_champ_repetition' do it 'type_de_champ_repetition' do
@ -49,7 +41,6 @@ describe ProcedureRevision do
libelle: "Un champ text", libelle: "Un champ text",
parent_id: type_de_champ_repetition.stable_id parent_id: type_de_champ_repetition.stable_id
}) })
type_de_champ_repetition.reload
expect(type_de_champ_repetition.types_de_champ.size).to eq(2) expect(type_de_champ_repetition.types_de_champ.size).to eq(2)
end end
end end
@ -113,26 +104,21 @@ describe ProcedureRevision do
revision.remove_type_de_champ(type_de_champ.stable_id) revision.remove_type_de_champ(type_de_champ.stable_id)
procedure.reload procedure.reload
expect(revision.types_de_champ.size).to eq(1) expect(revision.types_de_champ.size).to eq(1)
expect(procedure.types_de_champ.size).to eq(1)
end end
it 'type_de_champ_private' do it 'type_de_champ_private' do
expect(revision.types_de_champ_private.size).to eq(1) expect(revision.types_de_champ_private.size).to eq(1)
revision.remove_type_de_champ(type_de_champ_private.stable_id) revision.remove_type_de_champ(type_de_champ_private.stable_id)
procedure.reload
expect(revision.types_de_champ_private.size).to eq(0) expect(revision.types_de_champ_private.size).to eq(0)
expect(procedure.types_de_champ_private.size).to eq(0)
end end
it 'type_de_champ_repetition' do it 'type_de_champ_repetition' do
expect(type_de_champ_repetition.types_de_champ.size).to eq(1) expect(type_de_champ_repetition.types_de_champ.size).to eq(1)
expect(revision.types_de_champ.size).to eq(2) expect(revision.types_de_champ.size).to eq(2)
revision.remove_type_de_champ(type_de_champ_repetition.types_de_champ.first.stable_id) revision.remove_type_de_champ(type_de_champ_repetition.types_de_champ.first.stable_id)
procedure.reload
type_de_champ_repetition.reload type_de_champ_repetition.reload
expect(type_de_champ_repetition.types_de_champ.size).to eq(0) expect(type_de_champ_repetition.types_de_champ.size).to eq(0)
expect(revision.types_de_champ.size).to eq(2) expect(revision.types_de_champ.size).to eq(2)
expect(procedure.types_de_champ.size).to eq(2)
end end
end end

View file

@ -42,7 +42,7 @@ describe Procedure do
describe 'closed mail template body' do describe 'closed mail template body' do
let(:procedure) { create(:procedure) } let(:procedure) { create(:procedure) }
subject { procedure.closed_mail_template.body } subject { procedure.closed_mail_template.rich_body.body.to_html }
context 'for procedures without an attestation' do context 'for procedures without an attestation' do
it { is_expected.not_to include('lien attestation') } it { is_expected.not_to include('lien attestation') }
@ -279,15 +279,6 @@ describe Procedure do
end end
end end
describe '#types_de_champ (ordered)' do
let(:procedure) { create(:procedure) }
let!(:type_de_champ_0) { create(:type_de_champ, procedure: procedure, order_place: 1) }
let!(:type_de_champ_1) { create(:type_de_champ, procedure: procedure, order_place: 0) }
subject { procedure.types_de_champ }
it { expect(subject.first).to eq(type_de_champ_1) }
it { expect(subject.last).to eq(type_de_champ_0) }
end
describe 'active' do describe 'active' do
let(:procedure) { create(:procedure) } let(:procedure) { create(:procedure) }
subject { Procedure.active(procedure.id) } subject { Procedure.active(procedure.id) }
@ -333,22 +324,22 @@ describe Procedure do
end end
describe 'clone' do describe 'clone' do
let!(:service) { create(:service) } let(:service) { create(:service) }
let(:procedure) { create(:procedure, received_mail: received_mail, service: service) } let(:procedure) { create(:procedure, received_mail: received_mail, service: service, types_de_champ: [type_de_champ_0, type_de_champ_1, type_de_champ_2, type_de_champ_pj], types_de_champ_private: [type_de_champ_private_0, type_de_champ_private_1, type_de_champ_private_2]) }
let!(:type_de_champ_0) { create(:type_de_champ, procedure: procedure, order_place: 0) } let(:type_de_champ_0) { build(:type_de_champ, position: 0) }
let!(:type_de_champ_1) { create(:type_de_champ, procedure: procedure, order_place: 1) } let(:type_de_champ_1) { build(:type_de_champ, position: 1) }
let!(:type_de_champ_2) { create(:type_de_champ_drop_down_list, procedure: procedure, order_place: 2) } let(:type_de_champ_2) { build(:type_de_champ_drop_down_list, position: 2) }
let!(:type_de_champ_pj) { create(:type_de_champ_piece_justificative, procedure: procedure, order_place: 3, old_pj: { stable_id: 2713 }) } let(:type_de_champ_pj) { build(:type_de_champ_piece_justificative, position: 3, old_pj: { stable_id: 2713 }) }
let!(:type_de_champ_private_0) { create(:type_de_champ, :private, procedure: procedure, order_place: 0) } let(:type_de_champ_private_0) { build(:type_de_champ, :private, position: 0) }
let!(:type_de_champ_private_1) { create(:type_de_champ, :private, procedure: procedure, order_place: 1) } let(:type_de_champ_private_1) { build(:type_de_champ, :private, position: 1) }
let!(:type_de_champ_private_2) { create(:type_de_champ_drop_down_list, :private, procedure: procedure, order_place: 2) } let(:type_de_champ_private_2) { build(:type_de_champ_drop_down_list, :private, position: 2) }
let(:received_mail) { build(:received_mail) } let(:received_mail) { build(:received_mail) }
let(:from_library) { false } let(:from_library) { false }
let(:administrateur) { procedure.administrateurs.first } let(:administrateur) { procedure.administrateurs.first }
let!(:groupe_instructeur_1) { create(:groupe_instructeur, procedure: procedure, label: "groupe_1") } let(:groupe_instructeur_1) { create(:groupe_instructeur, procedure: procedure, label: "groupe_1") }
let!(:instructeur_1) { create(:instructeur) } let(:instructeur_1) { create(:instructeur) }
let!(:instructeur_2) { create(:instructeur) } let(:instructeur_2) { create(:instructeur) }
let!(:assign_to_1) { create(:assign_to, procedure: procedure, groupe_instructeur: groupe_instructeur_1, instructeur: instructeur_1) } let!(:assign_to_1) { create(:assign_to, procedure: procedure, groupe_instructeur: groupe_instructeur_1, instructeur: instructeur_1) }
let!(:assign_to_2) { create(:assign_to, procedure: procedure, groupe_instructeur: groupe_instructeur_1, instructeur: instructeur_2) } let!(:assign_to_2) { create(:assign_to, procedure: procedure, groupe_instructeur: groupe_instructeur_1, instructeur: instructeur_2) }
@ -379,28 +370,18 @@ describe Procedure do
it 'should duplicate specific objects with different id' do it 'should duplicate specific objects with different id' do
expect(subject.id).not_to eq(procedure.id) expect(subject.id).not_to eq(procedure.id)
expect(subject.types_de_champ.size).to eq(procedure.types_de_champ.size) expect(subject.draft_types_de_champ.size).to eq(procedure.draft_types_de_champ.size)
expect(subject.types_de_champ_private.size).to eq procedure.types_de_champ_private.size expect(subject.draft_types_de_champ_private.size).to eq(procedure.draft_types_de_champ_private.size)
expect(subject.types_de_champ.map(&:drop_down_options).compact.size).to eq procedure.types_de_champ.map(&:drop_down_options).compact.size
expect(subject.types_de_champ_private.map(&:drop_down_options).compact.size).to eq procedure.types_de_champ_private.map(&:drop_down_options).compact.size
expect(subject.draft_revision.types_de_champ.size).to eq(procedure.draft_revision.types_de_champ.size)
expect(subject.draft_revision.types_de_champ_private.size).to eq(procedure.draft_revision.types_de_champ_private.size)
procedure.types_de_champ.zip(subject.types_de_champ).each do |ptc, stc| procedure.draft_types_de_champ.zip(subject.draft_types_de_champ).each do |ptc, stc|
expect(stc).to have_same_attributes_as(ptc, except: ["revision_id"]) expect(stc).to have_same_attributes_as(ptc, except: ["revision_id"])
expect(stc.revision).to eq(subject.draft_revision) expect(stc.revision).to eq(subject.draft_revision)
end end
procedure.types_de_champ.zip(procedure.draft_revision.types_de_champ).each do |ptc, rtc|
expect(ptc).to eq(rtc)
end
subject.types_de_champ_private.zip(procedure.types_de_champ_private).each do |stc, ptc| procedure.draft_types_de_champ_private.zip(subject.draft_types_de_champ_private).each do |ptc, stc|
expect(stc).to have_same_attributes_as(ptc, except: ["revision_id"]) expect(stc).to have_same_attributes_as(ptc, except: ["revision_id"])
expect(stc.revision).to eq(subject.draft_revision) expect(stc.revision).to eq(subject.draft_revision)
end end
procedure.types_de_champ_private.zip(procedure.draft_revision.types_de_champ_private).each do |ptc, rtc|
expect(ptc).to eq(rtc)
end
expect(subject.attestation_template.title).to eq(procedure.attestation_template.title) expect(subject.attestation_template.title).to eq(procedure.attestation_template.title)
@ -423,7 +404,7 @@ describe Procedure do
end end
it 'should discard old pj information' do it 'should discard old pj information' do
subject.types_de_champ.each do |stc| subject.draft_types_de_champ.each do |stc|
expect(stc.old_pj).to be_nil expect(stc.old_pj).to be_nil
end end
end end
@ -459,7 +440,7 @@ describe Procedure do
end end
it 'should discard old pj information' do it 'should discard old pj information' do
subject.types_de_champ.each do |stc| subject.draft_types_de_champ.each do |stc|
expect(stc.old_pj).to be_nil expect(stc.old_pj).to be_nil
end end
end end
@ -519,12 +500,12 @@ describe Procedure do
end end
it 'should keep types_de_champ ids stable' do it 'should keep types_de_champ ids stable' do
expect(subject.types_de_champ.first.id).not_to eq(procedure.types_de_champ.first.id) expect(subject.draft_types_de_champ.first.id).not_to eq(procedure.draft_types_de_champ.first.id)
expect(subject.types_de_champ.first.stable_id).to eq(procedure.types_de_champ.first.id) expect(subject.draft_types_de_champ.first.stable_id).to eq(procedure.draft_types_de_champ.first.id)
end end
it 'should duplicate piece_justificative_template on a type_de_champ' do it 'should duplicate piece_justificative_template on a type_de_champ' do
expect(subject.types_de_champ.where(type_champ: "piece_justificative").first.piece_justificative_template.attached?).to be true expect(subject.draft_types_de_champ.where(type_champ: "piece_justificative").first.piece_justificative_template.attached?).to be true
end end
context 'with a notice attached' do context 'with a notice attached' do
@ -805,7 +786,7 @@ describe Procedure do
end end
describe 'suggested_path' do describe 'suggested_path' do
let(:procedure) { create :procedure, aasm_state: :publiee, libelle: 'Inscription au Collège' } let(:procedure) { create(:procedure, aasm_state: :publiee, libelle: 'Inscription au Collège') }
subject { procedure.suggested_path(procedure.administrateurs.first) } subject { procedure.suggested_path(procedure.administrateurs.first) }
@ -821,7 +802,7 @@ describe Procedure do
context 'when the suggestion conflicts with one procedure' do context 'when the suggestion conflicts with one procedure' do
before do before do
create :procedure, aasm_state: :publiee, path: 'inscription-au-college' create(:procedure, aasm_state: :publiee, path: 'inscription-au-college')
end end
it { is_expected.to eq 'inscription-au-college-2' } it { is_expected.to eq 'inscription-au-college-2' }
@ -829,8 +810,8 @@ describe Procedure do
context 'when the suggestion conflicts with several procedures' do context 'when the suggestion conflicts with several procedures' do
before do before do
create :procedure, aasm_state: :publiee, path: 'inscription-au-college' create(:procedure, aasm_state: :publiee, path: 'inscription-au-college')
create :procedure, aasm_state: :publiee, path: 'inscription-au-college-2' create(:procedure, aasm_state: :publiee, path: 'inscription-au-college-2')
end end
it { is_expected.to eq 'inscription-au-college-3' } it { is_expected.to eq 'inscription-au-college-3' }
@ -838,7 +819,7 @@ describe Procedure do
context 'when the suggestion conflicts with another procedure of the same admin' do context 'when the suggestion conflicts with another procedure of the same admin' do
before do before do
create :procedure, aasm_state: :publiee, path: 'inscription-au-college', administrateurs: procedure.administrateurs create(:procedure, aasm_state: :publiee, path: 'inscription-au-college', administrateurs: procedure.administrateurs)
end end
it { is_expected.to eq 'inscription-au-college' } it { is_expected.to eq 'inscription-au-college' }
@ -903,13 +884,14 @@ describe Procedure do
describe '#new_dossier' do describe '#new_dossier' do
let(:procedure) do let(:procedure) do
procedure = create(:procedure) create(:procedure,
types_de_champ: [
create(:type_de_champ_text, procedure: procedure, order_place: 1) build(:type_de_champ_text, position: 0),
create(:type_de_champ_number, procedure: procedure, order_place: 2) build(:type_de_champ_number, position: 1)
create(:type_de_champ_textarea, :private, procedure: procedure) ],
types_de_champ_private: [
procedure build(:type_de_champ_textarea, :private)
])
end end
let(:dossier) { procedure.new_dossier } let(:dossier) { procedure.new_dossier }

View file

@ -153,44 +153,6 @@ shared_examples 'type_de_champ_spec' do
end end
end end
describe "repetition" do
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, procedure: procedure) }
let(:type_de_champ_integer_number_attrs) { attributes_for(:type_de_champ_integer_number) }
it "associates nested types_de_champ to the parent procedure" do
expect(type_de_champ.types_de_champ.size).to eq(0)
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_text.parent).to eq(type_de_champ)
admin = create(:administrateur)
cloned_procedure = procedure.clone(admin, false)
expect(cloned_procedure.types_de_champ.first.types_de_champ).not_to be_empty
end
end
describe "linked_drop_down_list" do describe "linked_drop_down_list" do
let(:type_de_champ) { create(:type_de_champ_linked_drop_down_list) } let(:type_de_champ) { create(:type_de_champ_linked_drop_down_list) }

View file

@ -49,12 +49,11 @@ describe DossierSerializer do
context 'when a type de champ PJ was cloned from a legacy PJ' do context 'when a type de champ PJ was cloned from a legacy PJ' do
let(:original_pj_id) { 3 } let(:original_pj_id) { 3 }
let(:cloned_type_de_champ) do let(:cloned_type_de_champ) do
tdc = create(:type_de_champ_piece_justificative, build(:type_de_champ_piece_justificative,
libelle: "Vidéo de votre demande de subvention", libelle: "Vidéo de votre demande de subvention",
description: "Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique.\r\nRécupérer le formulaire vierge pour mon dossier : https://www.dance-academy.gouv.fr", description: "Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique.\r\nRécupérer le formulaire vierge pour mon dossier : https://www.dance-academy.gouv.fr",
order_place: 0) old_pj: { stable_id: original_pj_id },
tdc.old_pj = { stable_id: original_pj_id } position: 0)
tdc
end end
let(:procedure) { create(:procedure, :published, types_de_champ: [cloned_type_de_champ]) } let(:procedure) { create(:procedure, :published, types_de_champ: [cloned_type_de_champ]) }
let(:dossier) { create(:dossier, procedure: procedure) } let(:dossier) { create(:dossier, procedure: procedure) }

View file

@ -12,12 +12,11 @@ describe ProcedureSerializer do
context 'when a type PJ was cloned to a type champ PJ' do context 'when a type PJ was cloned to a type champ PJ' do
let(:original_pj_id) { 3 } let(:original_pj_id) { 3 }
let(:cloned_type_de_champ) do let(:cloned_type_de_champ) do
tdc = create(:type_de_champ_piece_justificative, build(:type_de_champ_piece_justificative,
libelle: "Vidéo de votre demande de subvention", libelle: "Vidéo de votre demande de subvention",
description: "Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique.\r\nRécupérer le formulaire vierge pour mon dossier : https://www.dance-academy.gouv.fr", description: "Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique.\r\nRécupérer le formulaire vierge pour mon dossier : https://www.dance-academy.gouv.fr",
order_place: 0) old_pj: { stable_id: original_pj_id },
tdc.old_pj = { stable_id: original_pj_id } position: 0)
tdc
end end
let(:procedure) { create(:procedure, :published, types_de_champ: [cloned_type_de_champ]) } let(:procedure) { create(:procedure, :published, types_de_champ: [cloned_type_de_champ]) }

View file

@ -61,7 +61,7 @@ describe AdministrateurUsageStatisticsService do
end end
context 'with a freshly active procedure' do context 'with a freshly active procedure' do
let(:procedure) { create(:procedure, aasm_state: 'publiee') } let(:procedure) { create(:procedure, :published) }
it do it do
is_expected.to include( is_expected.to include(
@ -82,7 +82,7 @@ describe AdministrateurUsageStatisticsService do
end end
context 'with a procedure close' do context 'with a procedure close' do
let(:procedure) { create(:procedure, aasm_state: 'close') } let(:procedure) { create(:procedure, :closed) }
let!(:dossiers) do let!(:dossiers) do
(1..7).flat_map do (1..7).flat_map do
[ [
@ -163,7 +163,7 @@ describe AdministrateurUsageStatisticsService do
end end
context 'with a procedure en prod' do context 'with a procedure en prod' do
let(:procedure) { create(:procedure, aasm_state: 'publiee') } let(:procedure) { create(:procedure, :published) }
let!(:dossiers) do let!(:dossiers) do
[ [
create(:dossier, :en_construction, procedure: procedure), create(:dossier, :en_construction, procedure: procedure),
@ -191,7 +191,7 @@ describe AdministrateurUsageStatisticsService do
end end
context 'with a procedure en prod and more than 20 dossiers' do context 'with a procedure en prod and more than 20 dossiers' do
let(:procedure) { create(:procedure, aasm_state: 'publiee') } let(:procedure) { create(:procedure, :published) }
let!(:dossiers) do let!(:dossiers) do
(1..7).flat_map do (1..7).flat_map do
[ [

View file

@ -18,10 +18,10 @@ describe ProcedureExportService do
before do before do
# change one tdc place to check if the header is ordered # change one tdc place to check if the header is ordered
tdc_first = procedure.types_de_champ.first tdc_first = procedure.active_revision.revision_types_de_champ.first
tdc_last = procedure.types_de_champ.last tdc_last = procedure.active_revision.revision_types_de_champ.last
tdc_first.update(order_place: tdc_last.order_place + 1) tdc_first.update(position: tdc_last.position + 1)
procedure.reload procedure.reload
end end

View file

@ -12,11 +12,6 @@ module FeatureHelpers
login_as instructeur, scope: :instructeur login_as instructeur, scope: :instructeur
end end
def create_dossier
dossier = FactoryBot.create(:dossier)
dossier
end
def sign_in_with(email, password, sign_in_by_link = false) def sign_in_with(email, password, sign_in_by_link = false)
fill_in :user_email, with: email fill_in :user_email, with: email
fill_in :user_password, with: password fill_in :user_password, with: password

View file

@ -1,10 +1,10 @@
describe 'admin/mail_templates/edit.html.haml', type: :view do describe 'new_administrateur/mail_templates/edit.html.haml', type: :view do
let(:procedure) { create(:procedure) } let(:procedure) { create(:procedure) }
let(:mail_template) { create(:received_mail, procedure: procedure) } let(:mail_template) { create(:received_mail, procedure: procedure) }
let(:all_tags) { mail_template.tags } let(:all_tags) { mail_template.tags }
before do before do
allow(view).to receive(:admin_procedure_mail_template_path).and_return("/toto") allow(view).to receive(:admin_procedure_mail_templates_path).and_return("/toto")
allow(view).to receive(:admin_procedure_mail_templates_path).and_return("/toto") allow(view).to receive(:admin_procedure_mail_templates_path).and_return("/toto")
assign(:mail_template, mail_template) assign(:mail_template, mail_template)
@ -13,6 +13,5 @@ describe 'admin/mail_templates/edit.html.haml', type: :view do
context "Champs are listed in the page" do context "Champs are listed in the page" do
it { expect(all_tags).to include(include({ libelle: 'numéro du dossier' })) } it { expect(all_tags).to include(include({ libelle: 'numéro du dossier' })) }
it { expect(render).to include("numéro du dossier") }
end end
end end

View file

@ -38,7 +38,7 @@ describe 'shared/dossiers/demande.html.haml', type: :view do
expect(subject).to include(individual.gender) expect(subject).to include(individual.gender)
expect(subject).to include(individual.nom) expect(subject).to include(individual.nom)
expect(subject).to include(individual.prenom) expect(subject).to include(individual.prenom)
expect(subject).to include(I18n.l(individual.birthdate)) expect(subject).to include(I18n.l(individual.birthdate, format: :long))
end end
end end