Merge pull request #3586 from betagouv/dev

2019-03-11-01
This commit is contained in:
LeSim 2019-03-11 15:22:40 +01:00 committed by GitHub
commit f2734e2c28
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
64 changed files with 646 additions and 143 deletions

View file

@ -64,6 +64,7 @@ En local, un utilisateur de test est créé automatiquement, avec les identifian
AutoArchiveProcedureJob.set(cron: "* * * * *").perform_later
WeeklyOverviewJob.set(cron: "0 8 * * 0").perform_later
AutoReceiveDossiersForProcedureJob.set(cron: "* * * * *").perform_later(procedure_declaratoire_id, Dossier.states.fetch(:en_instruction))
SendinblueUpdateAdministrateursJob.set(cron: "0 10 * * *").perform_later
FindDubiousProceduresJob.set(cron: "0 0 * * *").perform_later
Administrateurs::ActivateBeforeExpirationJob.set(cron: "0 8 * * *").perform_later
WarnExpiringDossiersJob.set(cron: "0 0 1 * *").perform_later

View file

@ -204,7 +204,7 @@ class StatsController < ApplicationController
def max_date
if administration_signed_in?
Time.zone.now.to_date
Time.zone.now
else
Time.zone.now.beginning_of_month - 1.second
end

View file

@ -33,7 +33,7 @@ class WebhookController < ActionController::Base
private
def link_to_manager(model, url)
"<a target='_blank' href='#{url}'>#{model.model_name.human}##{model.id}</a>"
"<a target='_blank' href='#{url}' rel='noopener'>#{model.model_name.human}##{model.id}</a>"
end
def verify_signature!

View file

@ -35,7 +35,8 @@ class ProcedureDashboard < Administrate::BaseDashboard
received_mail_template: MailTemplateField,
closed_mail_template: MailTemplateField,
refused_mail_template: MailTemplateField,
without_continuation_mail_template: MailTemplateField
without_continuation_mail_template: MailTemplateField,
attestation_template: AttestationTemplateField
}.freeze
# COLLECTION_ATTRIBUTES
@ -81,7 +82,8 @@ class ProcedureDashboard < Administrate::BaseDashboard
:received_mail_template,
:closed_mail_template,
:refused_mail_template,
:without_continuation_mail_template
:without_continuation_mail_template,
:attestation_template
].freeze
# FORM_ATTRIBUTES

View file

@ -0,0 +1,4 @@
require "administrate/field/base"
class AttestationTemplateField < Administrate::Field::Base
end

View file

@ -1,7 +1,7 @@
module StringToHtmlHelper
def string_to_html(str)
html_formatted = simple_format(str)
with_links = html_formatted.gsub(URI.regexp, '<a target="_blank" href="\0">\0</a>')
sanitize(with_links, attributes: ['href', 'target'])
with_links = html_formatted.gsub(URI.regexp, '<a target="_blank" rel="noopener" href="\0">\0</a>')
sanitize(with_links, attributes: ['target', 'rel', 'href'])
end
end

View file

@ -96,7 +96,7 @@
Modèle
</label>
<template v-if="pieceJustificativeTemplateUrl">
<a :href="pieceJustificativeTemplateUrl" target="_blank">
<a :href="pieceJustificativeTemplateUrl" rel="noopener" target="_blank">
{{pieceJustificativeTemplateFilename}}
</a>
<br> Modifier :

View file

@ -0,0 +1,5 @@
class UpdateAdministrateurUsageStatisticsJob < ApplicationJob
def perform
AdministrateurUsageStatisticsService.new.update_administrateurs
end
end

73
app/lib/sendinblue/api.rb Normal file
View file

@ -0,0 +1,73 @@
class Sendinblue::Api
def self.new_properly_configured!
api = self.new
if !api.properly_configured?
raise StandardError, 'Sendinblue API is not properly configured'
end
api
end
def initialize
@failures = []
end
def properly_configured?
client_key.present?
end
def identify(email, attributes = {})
req = api_request('identify', email: email, attributes: attributes)
req.on_complete do |response|
if !response.success?
push_failure("Error while updating identity for administrateur '#{email}' in Sendinblue: #{response.response_code} '#{response.body}'")
end
end
hydra.queue(req)
end
def run
hydra.run
@hydra = nil
flush_failures
end
private
def hydra
@hydra ||= Typhoeus::Hydra.new
end
def push_failure(failure)
@failures << failure
end
def flush_failures
failures = @failures
@failures = []
if failures.present?
raise StandardError, failures.join(', ')
end
end
def api_request(path, body)
url = "#{SENDINBLUE_API_URL}/#{path}"
Typhoeus::Request.new(
url,
method: :post,
body: body.to_json,
headers: headers
)
end
def headers
{
'ma-key': client_key,
'Content-Type': 'application/json; charset=UTF-8'
}
end
def client_key
Rails.application.secrets.sendinblue[:client_key]
end
end

View file

@ -50,10 +50,12 @@ class ProcedurePresentation < ApplicationRecord
fields.concat procedure.types_de_champ
.where.not(type_champ: explanatory_types_de_champ)
.order(:id)
.map { |type_de_champ| field_hash(type_de_champ.libelle, 'type_de_champ', type_de_champ.id.to_s) }
fields.concat procedure.types_de_champ_private
.where.not(type_champ: explanatory_types_de_champ)
.order(:id)
.map { |type_de_champ| field_hash(type_de_champ.libelle, 'type_de_champ_private', type_de_champ.id.to_s) }
fields

View file

@ -40,25 +40,17 @@ class TypeDeChamp < ApplicationRecord
store_accessor :options, :cadastres, :quartiers_prioritaires, :parcelles_agricoles, :old_pj
delegate :tags_for_template, to: :dynamic_type
# TODO simplify after migrating `options` column to (non YAML encoded) JSON
class MaybeYaml
def load(options)
case options
when String
YAML.safe_load(options, [ActiveSupport::HashWithIndifferentAccess])
when Hash
options.with_indifferent_access
else
options
end
class WithIndifferentAccess
def self.load(options)
options&.with_indifferent_access
end
def dump(options)
def self.dump(options)
options
end
end
serialize :options, MaybeYaml.new
serialize :options, WithIndifferentAccess
after_initialize :set_dynamic_type
after_create :populate_stable_id

View file

@ -1,2 +1,5 @@
class TypesDeChamp::ExplicationTypeDeChamp < TypesDeChamp::TextTypeDeChamp
def tags_for_template
[]
end
end

View file

@ -1,2 +1,5 @@
class TypesDeChamp::HeaderSectionTypeDeChamp < TypesDeChamp::TypeDeChampBase
def tags_for_template
[]
end
end

View file

@ -23,25 +23,25 @@ class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBas
def tags_for_template
tags = super
l = libelle
tdc = @type_de_champ
tags.push(
{
libelle: "#{l}/primaire",
libelle: "#{libelle}/primaire",
description: "#{description} (menu primaire)",
lambda: -> (champs) {
champs
.detect { |champ| champ.libelle == l }
.detect { |champ| champ.type_de_champ == tdc }
&.primary_value
}
}
)
tags.push(
{
libelle: "#{l}/secondaire",
libelle: "#{libelle}/secondaire",
description: "#{description} (menu secondaire)",
lambda: -> (champs) {
champs
.detect { |champ| champ.libelle == l }
.detect { |champ| champ.type_de_champ == tdc }
&.secondary_value
}
}

View file

@ -8,13 +8,13 @@ class TypesDeChamp::TypeDeChampBase
end
def tags_for_template
l = libelle
tdc = @type_de_champ
[
{
libelle: l,
libelle: libelle,
description: description,
lambda: -> (champs) {
champs.detect { |champ| champ.libelle == l }
champs.detect { |champ| champ.type_de_champ == tdc }
}
}
]

View file

@ -0,0 +1,166 @@
# Note: this class uses a `synthetic_state` for Dossier, that diverges from the standard state:
# - 'termine' is the synthetic_state for all dossiers
# whose state is 'accepte', 'refuse' or 'sans_suite',
# even when `archive` is true
# - 'archive' is the synthetic_state for all dossiers
# where archive is true,
# except those whose synthetic_state is already 'termine'
# - For all other dossiers, the synthetic_state and the state are the same
class AdministrateurUsageStatisticsService
def update_administrateurs
Administrateur.find_each do |administrateur|
stats = administrateur_stats(administrateur)
api.identify(administrateur.email, stats)
end
api.run
end
private
def api
@api ||= Sendinblue::Api.new_properly_configured!
end
def administrateur_stats(administrateur)
nb_dossiers_by_procedure_id = nb_dossiers_by_procedure_id(administrateur.id)
nb_dossiers_by_synthetic_state = nb_dossiers_by_synthetic_state(administrateur.id)
result = {
ds_sign_in_count: administrateur.sign_in_count,
ds_created_at: administrateur.created_at,
ds_active: administrateur.active,
ds_id: administrateur.id,
ds_features: administrateur.features.to_json,
nb_services: nb_services_by_administrateur_id[administrateur.id],
nb_instructeurs: nb_instructeurs_by_administrateur_id[administrateur.id],
ds_nb_demarches_actives: nb_demarches_by_administrateur_id_and_state[[administrateur.id, "publiee"]],
ds_nb_demarches_archives: nb_demarches_by_administrateur_id_and_state[[administrateur.id, "archivee"]],
ds_nb_demarches_brouillons: nb_demarches_by_administrateur_id_and_state[[administrateur.id, "brouillon"]],
nb_demarches_test: nb_dossiers_by_procedure_id
.select { |procedure_id, count| count > 0 && is_brouillon(procedure_id) }
.count,
nb_demarches_prod: nb_dossiers_by_procedure_id
.reject { |procedure_id, count| count == 0 || is_brouillon(procedure_id) }
.count,
nb_demarches_prod_20: nb_dossiers_by_procedure_id
.reject { |procedure_id, count| count < 20 || is_brouillon(procedure_id) }
.count,
nb_dossiers: nb_dossiers_by_procedure_id
.reject { |procedure_id, _count| is_brouillon(procedure_id) }
.map { |_procedure_id, count| count }
.sum,
nb_dossiers_max: nb_dossiers_by_procedure_id
.reject { |procedure_id, _count| is_brouillon(procedure_id) }
.map { |_procedure_id, count| count }
.max || 0,
nb_dossiers_traite: nb_dossiers_by_synthetic_state['termine'],
nb_dossiers_dossier_en_instruction: nb_dossiers_by_synthetic_state['en_instruction']
}
if administrateur.current_sign_in_at.present?
result[:ds_current_sign_in_at] = administrateur.current_sign_in_at
end
if administrateur.last_sign_in_at.present?
result[:ds_last_sign_in_at] = administrateur.last_sign_in_at
end
result
end
# Returns a hash { procedure_id => dossier_count }:
# - The keys are the ids of procedures owned by administrateur_id
# - The values are the number of dossiers for that procedure.
# Brouillons, and dossiers that are 'archive' but not 'termine', are not counted.
def nb_dossiers_by_procedure_id(administrateur_id)
with_default(
0,
nb_dossiers_by_administrateur_id_and_procedure_id_and_synthetic_state[administrateur_id]
.map do |procedure_id, nb_dossiers_by_synthetic_state|
[
procedure_id,
nb_dossiers_by_synthetic_state
.reject { |synthetic_state, _count| ['brouillon', 'archive'].include?(synthetic_state) }
.map { |_synthetic_state, count| count }
.sum
]
end
.to_h
)
end
# Returns a hash { synthetic_state => dossier_count }
# - The keys are dossier synthetic_states (see class comment)
# - The values are the number of dossiers in that synthetic state, for procedures owned by `administrateur_id`
# Dossier on procedures en test are not counted
def nb_dossiers_by_synthetic_state(administrateur_id)
with_default(
0,
nb_dossiers_by_administrateur_id_and_procedure_id_and_synthetic_state[administrateur_id]
.reject { |procedure_id, _nb_dossiers_by_synthetic_state| is_brouillon(procedure_id) }
.flat_map { |_procedure_id, nb_dossiers_by_synthetic_state| nb_dossiers_by_synthetic_state.to_a }
.group_by { |synthetic_state, _count| synthetic_state }
.map { |synthetic_state, synthetic_states_and_counts| [synthetic_state, synthetic_states_and_counts.map { |_synthetic_state, count| count }.sum] }
.to_h
)
end
def nb_demarches_by_administrateur_id_and_state
@nb_demarches_by_administrateur_id_and_state ||= with_default(0, Procedure.group(:administrateur_id, :aasm_state).count)
end
def nb_services_by_administrateur_id
@nb_services_by_administrateur_id ||= with_default(0, Service.group(:administrateur_id).count)
end
def nb_instructeurs_by_administrateur_id
@nb_instructeurs_by_administrateur_id ||= with_default(0, Administrateur.joins(:gestionnaires).group(:administrateur_id).count)
end
def nb_dossiers_by_administrateur_id_and_procedure_id_and_synthetic_state
if @nb_dossiers_by_administrateur_id_and_procedure_id_and_synthetic_state.present?
return @nb_dossiers_by_administrateur_id_and_procedure_id_and_synthetic_state
end
result = {}
Dossier
.joins(:procedure)
.group(
:administrateur_id,
:procedure_id,
<<~EOSQL
CASE
WHEN state IN('accepte', 'refuse', 'sans_suite') THEN 'termine'
WHEN archived THEN 'archive'
ELSE state
END
EOSQL
)
.count
.each do |(administrateur_id, procedure_id, synthetic_state), count|
result.deep_merge!(
{ administrateur_id => { procedure_id => { synthetic_state => count } } }
)
end
@nb_dossiers_by_administrateur_id_and_procedure_id_and_synthetic_state =
with_default({}, result)
end
def is_brouillon(procedure_id)
procedure_states[procedure_id] == 'brouillon'
end
def procedure_states
@procedure_states ||= Procedure.pluck(:id, :aasm_state).to_h
end
def with_default(default, hash)
hash.default = default
hash
end
end

View file

@ -30,7 +30,7 @@
%p.help-block
%i.fa.fa-info-circle
Vous pouvez définir un lien de rappel HTTP (aussi appelé webhook) pour notifier un service tiers du changement de l'état dun dossier de cette démarche sur demarches-simplifiees.fr.
= link_to("Consulter la documentation du webhook", WEBHOOK_DOC_URL, target: "_blank")
= link_to("Consulter la documentation du webhook", WEBHOOK_DOC_URL, target: "_blank", rel: "noopener")
\.
.form-group
@ -40,7 +40,7 @@
%li Texte de loi (loi, décret, circulaire, arrêté,…)
%li Texte juridique (statuts, délibération, décision du conseil d'administration…)
%li
= link_to("En savoir plus", CADRE_JURIDIQUE_URL, target: "_blank")
= link_to("En savoir plus", CADRE_JURIDIQUE_URL, target: "_blank", rel: "noopener")
%p.help-block
%i.fa.fa-info-circle
@ -57,7 +57,7 @@
= f.file_field :deliberation,
direct_upload: true
- else
%a{ href: url_for(deliberation), target: '_blank' }
%a{ href: url_for(deliberation), target: '_blank', rel: 'noopener' }
= deliberation.filename.to_s
- if @procedure.persisted?
= link_to 'supprimer', delete_deliberation_admin_procedure_path(@procedure), method: :delete
@ -73,7 +73,7 @@
= f.file_field :notice,
direct_upload: true
- else
%a{ href: url_for(notice), target: '_blank' }
%a{ href: url_for(notice), target: '_blank', rel: 'noopener' }
= notice.filename.to_s
- if @procedure.persisted?
\-

View file

@ -23,7 +23,7 @@
%td{ style: 'width: 750px;' }
= procedure.libelle
%td{ style: 'padding-right: 10px; padding-left: 10px; width: 60px;' }
= link_to('Consulter', apercu_procedure_path(id: procedure.id), target: "_blank")
= link_to('Consulter', apercu_procedure_path(id: procedure.id), target: "_blank", rel: "noopener")
%td
= link_to('Cloner', admin_procedure_clone_path(procedure.id, from_new_from_existing: true), 'data-method' => :put, class: 'btn-sm btn-primary clone-btn')
%td{ style: 'padding-left: 10px;' }

View file

@ -54,7 +54,7 @@
- elsif @procedure.publiee?
Cette démarche est <strong>publiée</strong>, certains éléments ne peuvent plus être modifiés.
Pour y accéder vous pouvez utiliser le lien :
= link_to procedure_lien(@procedure), sanitize_url(procedure_lien(@procedure)), target: :blank
= link_to procedure_lien(@procedure), sanitize_url(procedure_lien(@procedure)), target: :blank, rel: :noopener
%br
%br
Attention, diffusez toujours le <strong>lien complet</strong> affiché ci-dessus, et non pas un lien générique vers demarches-simplifiees.fr. Ne dites pas non plus aux usagers de se rendre sur le site générique demarches-simplifiees.fr, donnez-leur toujours le lien complet.
@ -63,7 +63,7 @@
%p
Cette démarche est actuellement <strong>en test</strong>,
pour y accéder vous pouvez utiliser le lien :
= link_to procedure_lien(@procedure), sanitize_url(procedure_lien(@procedure)), target: :blank
= link_to procedure_lien(@procedure), sanitize_url(procedure_lien(@procedure)), target: :blank, rel: :noopener
%p
Tout personne ayant la connaissance de ce lien pourra ainsi remplir des dossiers de test sur votre démarche.
%br

View file

@ -29,7 +29,7 @@
= ff.file_field :piece_justificative_template,
direct_upload: true
- else
= link_to template.filename.to_s, url_for(template), target: '_blank'
= link_to template.filename.to_s, url_for(template), target: '_blank', rel: 'noopener'
%br
Modifier :
= ff.file_field :piece_justificative_template,

View file

@ -50,7 +50,7 @@
%span.mandatory *
%p.intro{ :style => "font-weight: normal" }
Vous utilisez un email orange, wanadoo, free, gmail etc. ? Merci de nous
%a{ href: contact_admin_path, target:'_blank' }
%a{ href: contact_admin_path, target:'_blank', rel: 'noopener' }
contacter préalablement.
= email_field_tag :email, nil, placeholder: 'jean.martin@developpement-durable.gouv.fr', required: true

View file

@ -6,6 +6,6 @@
%p
Pour le consulter, merci de vous rendre sur
= link_to messagerie_dossier_url(@dossier), messagerie_dossier_url(@dossier), target: '_blank'
= link_to messagerie_dossier_url(@dossier), messagerie_dossier_url(@dossier), target: '_blank', rel:'noopener'
= render partial: "layouts/mailers/signature"

View file

@ -5,6 +5,6 @@
Vous pouvez retrouver et compléter le brouillon que vous avez créé pour la démarche
%strong= @dossier.procedure.libelle
à l'adresse suivante :
= link_to dossier_url(@dossier), dossier_url(@dossier), target: '_blank'
= link_to dossier_url(@dossier), dossier_url(@dossier), target: '_blank', rel: 'noopener'
= render partial: "layouts/mailers/signature"

View file

@ -0,0 +1,33 @@
- if field.data
%strong Activée
%p
= field.data.activated
%strong Logo
%p
- if field.data.logo.present?
= image_tag field.data.logo.url
- else
Aucun
%strong Titre
%pre{ style: "white-space: pre-wrap;" }
= field.data.title
%strong Corps
%pre{ style: "white-space: pre-wrap;" }
= field.data.body
%strong Signature
%p
- if field.data.signature.present?
= image_tag field.data.signature.url
- else
Aucun
%strong Pied de page
%pre{ style: "white-space: pre-wrap;" }
= field.data.footer
- else
Aucun modèle d'attestation

View file

@ -1,4 +1,4 @@
- if field.data.present?
= link_to Addressable::URI.parse(procedure_lien(field.resource)).path, procedure_lien(field.resource), target: '_blank'
= link_to Addressable::URI.parse(procedure_lien(field.resource)).path, procedure_lien(field.resource), target: '_blank', rel: 'noopener'
- else
Plus en ligne

View file

@ -5,6 +5,10 @@
Veuillez cliquer sur le lien suivant pour vous connecter sur le site demarches-simplifiees.fr : 
= link_to(sign_in_by_link_url(@gestionnaire_id, jeton: @login_token), sign_in_by_link_url(@gestionnaire_id, jeton: @login_token))
%p Ce lien est valide une semaine.
%p
Ce lien est
%b valide une semaine
et peut-être réutilisé
%b plusieurs fois.
= render partial: "layouts/mailers/signature"

View file

@ -11,6 +11,6 @@
\-
= contact_link 'Contact'
\-
= link_to 'FAQ', "https://faq.demarches-simplifiees.fr"
= link_to 'FAQ', FAQ_URL
\-
= link_to 'Documentation', "http://doc.demarches-simplifiees.fr"
= link_to 'Documentation', DOC_URL

View file

@ -23,7 +23,7 @@
addEventListener('turbolinks:load', function(event) {
if (previousPageUrl) {
_paq.push(['setReferrerUrl', previousPageUrl]);
_paq.push(['setCustomUrl', '/' + window.location.href]);
_paq.push(['setCustomUrl', window.location.href]);
_paq.push(['setDocumentTitle', document.title]);
if (event.data && event.data.timing) {
_paq.push(['setGenerationTimeMs', event.data.timing.visitEnd - event.data.timing.visitStart]);

View file

@ -10,7 +10,7 @@
#navbar-body
.row
%div{ style: "vertical-align: middle;float:left;position:absolute;line-height: 60px;z-index:2;" }
Besoin d'aide ? <a href="tel:#{CONTACT_PHONE}">#{CONTACT_PHONE}</a> ou <a href="#{contact_admin_path}" target="_blank">par email</a>
Besoin d'aide ? <a href="tel:#{CONTACT_PHONE}">#{CONTACT_PHONE}</a> ou <a href="#{contact_admin_path}" target="_blank" rel="noopener">par email</a>
-# BEST WTF EVER
-# this begin rescue hides potentials bugs by displaying another navbar
- begin

View file

@ -3,6 +3,6 @@
#outdated-browser-banner
.container
Attention, votre navigateur (#{browser.name} #{browser.version}) est trop ancien pour utiliser demarches-simplifiees.fr : certaines parties du site ne fonctionneront pas correctement. Nous vous recommendons fortement de
%a{ href: "https://browser-update.org/fr/update.html", target: "_blank" }mettre à jour votre navigateur
%a{ href: "https://browser-update.org/fr/update.html", target: "_blank", rel: "noopener" }mettre à jour votre navigateur
%span<>
\.

View file

@ -1,27 +0,0 @@
:javascript
(function() {
window.sib = { equeue: [], client_key: "pcxtf4lpkka986pf4l1kt" };
/* OPTIONAL: email for identify request*/
window.sib.email_id = '#{current_administrateur.email}';
window.sendinblue = {}; for (var j = ['track', 'identify', 'trackLink', 'page'], i = 0; i < j.length; i++) { (function(k) { window.sendinblue[k] = function() { var arg = Array.prototype.slice.call(arguments); (window.sib[k] || function() { var t = {}; t[k] = arg; window.sib.equeue.push(t);})(arg[0], arg[1], arg[2]);};})(j[i]);}var n = document.createElement("script"),i = document.getElementsByTagName("script")[0]; n.type = "text/javascript", n.id = "sendinblue-js", n.async = !0, n.src = "https://sibautomation.com/sa.js?key=" + window.sib.client_key, i.parentNode.insertBefore(n, i), window.sendinblue.page();
})();
sendinblue.identify('#{current_administrateur.email}', {
'DS_NB_DEMARCHES_BROUILLONS': '#{current_administrateur.procedures.brouillons.count}',
'DS_NB_DEMARCHES_ACTIVES': '#{current_administrateur.procedures.publiees.count}',
'DS_NB_DEMARCHES_ARCHIVES': '#{current_administrateur.procedures.archivees.count}',
'DS_SIGN_IN_COUNT' : '#{current_administrateur.sign_in_count}',
'DS_CREATED_AT' : '#{current_administrateur.created_at}',
'DS_ACTIVE' : '#{current_administrateur.active}',
'DS_ID' : '#{current_administrateur.id}'
// Dans l'ideal :
// 'nom' : //pour personnaliser les emails
// 'prenom' : //pour personnaliser les emails
// 'nb_demarches_prod' : // Avec plus de 20 dossiers
// 'nb_demarches_test' : // Avec entre 1 et 20 dossiers
// 'nb_services' : //combien de service ?
// 'nb_instructeurs' : //combien d'instructeur en tout ?
// 'nb_dossiers' : //combien de dossier en tout ?
});

View file

@ -17,7 +17,6 @@
= csrf_meta_tags
= render partial: "layouts/matomo"
= render partial: "layouts/sendinblue"
:javascript
DATA = [{

View file

@ -50,7 +50,7 @@
.procedure-list-element{ class: ('active' if active == 'Annotations privées') }
Annotations privées
%a#onglet-preview{ href: url_for(apercu_procedure_path(@procedure)), target: "_blank" }
%a#onglet-preview{ href: url_for(apercu_procedure_path(@procedure)), target: "_blank", rel: "noopener" }
.procedure-list-element{ class: ('active' if active == 'Prévisualisation') }
Prévisualisation

View file

@ -49,7 +49,7 @@
<tbody>
<tr>
<td style="word-wrap:break-word;font-size:0px;padding:0;padding-top:0px;padding-bottom:0px;" align="left">
<div class="" style="cursor:auto;color:#55575d;font-family:Helvetica, Arial, sans-serif;font-size:11px;line-height:22px;text-align:left;">
<div class="" style="cursor:auto;color:#55575d;font-family:Helvetica, Arial, sans-serif;font-size:11px;text-align:left;">
<img align="middle" alt="Logo demarches-simplifiees.fr" src="<%= image_url('mailer/gestionnaire_mailer/logo.png') %>" style="max-width=600px; padding=30px 0; display=inline !important; vertical-align=bottom; border=0; height=auto; outline=none; text-decoration=none; -ms-interpolation-mode=bicubic;" />
</div>
</td>

View file

@ -2,6 +2,6 @@
%strong
Merci de ne pas répondre à cet email. Pour vous adresser à votre administration, passez directement par votre
= succeed '.' do
= link_to 'messagerie', messagerie_dossier_url(@dossier), target: '_blank'
= link_to 'messagerie', messagerie_dossier_url(@dossier), target: '_blank', rel: 'noopener'
= render template: 'layouts/mailers/layout'

View file

@ -4,4 +4,4 @@
- steps.each do |step|
%li= step
- if defined?(preview) && preview
= link_to "Prévisualiser le formulaire", apercu_procedure_path(@procedure), target: "_blank", class: 'button'
= link_to "Prévisualiser le formulaire", apercu_procedure_path(@procedure), target: "_blank", rel: "noopener", class: 'button'

View file

@ -15,7 +15,7 @@
%span.mandatory *
%p
Pour trouver votre numéro SIRET, utilisez
%a{ href: 'https://entreprise.data.gouv.fr/', target: '_blank' }
%a{ href: 'https://entreprise.data.gouv.fr/', target: '_blank', rel: 'noopener' }
entreprise.data.gouv.fr
ou renseignez-vous auprès de votre service comptable
= f.number_field :siret, required: true

View file

@ -15,7 +15,7 @@
%span.icon.printer
%ul.print-menu.dropdown-content
%li
= link_to "Tout le dossier", print_gestionnaire_dossier_path(dossier.procedure, dossier), target: "_blank", class: "menu-item menu-link"
= link_to "Tout le dossier", print_gestionnaire_dossier_path(dossier.procedure, dossier), target: "_blank", rel: "noopener", class: "menu-item menu-link"
%li
= link_to "Uniquement cet onglet", "#", onclick: "window.print()", class: "menu-item menu-link"

View file

@ -64,7 +64,7 @@
- if dossier.attestation.present?
%h4 Attestation
%p.attestation L'acceptation du dossier a envoyé automatiquement une attestation au demandeur
= link_to "Voir l'attestation", attestation_gestionnaire_dossier_path(dossier.procedure, dossier), target: '_blank', class: 'button'
= link_to "Voir l'attestation", attestation_gestionnaire_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener', class: 'button'
- else
%span.label{ class: button_or_label_class(dossier) }
= dossier_display_state(dossier, lower: true)

View file

@ -30,6 +30,6 @@
= text_area :dossier, :motivation, class: 'motivation-text-area', placeholder: placeholder, required: true
.text-right
- if title == 'Accepter' && dossier.procedure.attestation_template&.activated?
= link_to "Voir l'attestation", apercu_attestation_gestionnaire_dossier_path(dossier.procedure, dossier), target: '_blank', class: 'button', title: "Voir l'attestation qui sera envoyée au demandeur"
= link_to "Voir l'attestation", apercu_attestation_gestionnaire_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener', class: 'button', title: "Voir l'attestation qui sera envoyée au demandeur"
%span.button{ onclick: 'DS.motivationCancel();' } Annuler
= button_tag 'Valider la décision', name: :process_action, value: process_action, class: 'button primary', title: title, data: { confirm: confirm }

View file

@ -5,8 +5,8 @@
.dropdown-content.fade-in-down
%ul.dropdown-items
%li
= link_to "Au format .csv", download_dossiers_gestionnaire_procedure_path(format: :csv, procedure_id: procedure.id), target: "_blank"
= link_to "Au format .csv", download_dossiers_gestionnaire_procedure_path(format: :csv, procedure_id: procedure.id), target: "_blank", rel: "noopener"
%li
= link_to "Au format .xlsx", download_dossiers_gestionnaire_procedure_path(format: :xlsx, procedure_id: procedure.id, tables: [:etablissements]), target: "_blank"
= link_to "Au format .xlsx", download_dossiers_gestionnaire_procedure_path(format: :xlsx, procedure_id: procedure.id, tables: [:etablissements]), target: "_blank", rel: "noopener"
%li
= link_to "Au format .ods", download_dossiers_gestionnaire_procedure_path(format: :ods, procedure_id: procedure.id, tables: [:etablissements]), target: "_blank"
= link_to "Au format .ods", download_dossiers_gestionnaire_procedure_path(format: :ods, procedure_id: procedure.id, tables: [:etablissements]), target: "_blank", rel: "noopener"

View file

@ -4,4 +4,8 @@
= link_to "Mentions légales", MENTIONS_LEGALES_URL, :class => "footer-link", :target => "_blank", rel: "noopener noreferrer"
= link_to 'FAQ', FAQ_URL
= link_to 'Documentation', DOC_URL
= contact_link "Contact technique", class: "footer-link", dossier_id: dossier&.id

View file

@ -65,7 +65,7 @@
- if dossier.attestation.present?
.action
= link_to attestation_dossier_path(dossier), target: '_blank', class: 'button primary' do
= link_to attestation_dossier_path(dossier), target: '_blank', rel: 'noopener', class: 'button primary' do
%span.icon.download
Télécharger lattestation

View file

@ -19,7 +19,7 @@
%li.footer-column
%ul.footer-links
%li.footer-link
= link_to "Newsletter", "https://my.sendinblue.com/users/subscribe/js_id/3s2q1/id/1", :class => "footer-link", :target => "_blank"
= link_to "Newsletter", "https://my.sendinblue.com/users/subscribe/js_id/3s2q1/id/1", :class => "footer-link", :target => "_blank", rel: "noopener"
%li.footer-link
= link_to "Nouveautés", "https://github.com/betagouv/tps/releases", :class => "footer-link"
%li.footer-link

View file

@ -5,16 +5,16 @@
%h1.new-h1 Accessibilité
%p.new-p
Nous travaillons à améliorer le niveau d'accessibilité du site et sa conformité avec les normes en la matière. Une première version optimisée pour la partie « Usager » du site ainsi qu'une déclaration de conformité <a href="https://references.modernisation.gouv.fr/rgaa-accessibilite/" target="_blank">RGAA</a> seront disponibles en août 2018.
Nous travaillons à améliorer le niveau d'accessibilité du site et sa conformité avec les normes en la matière. Une première version optimisée pour la partie « Usager » du site ainsi qu'une déclaration de conformité <a href="https://references.modernisation.gouv.fr/rgaa-accessibilite/" target="_blank" rel="noopener">RGAA</a> seront disponibles en août 2018.
%h2.new-h2 Signaler un dysfonctionnement
%p.new-p
Si, malgré notre vigilance, vous rencontriez le moindre problème daccessibilité sur notre site, nhésitez pas à #{contact_link('nous écrire', tags: 'a11y')}.
Si, malgré notre vigilance, vous rencontriez le moindre problème daccessibilité sur notre site, nhésitez pas à #{contact_link('nous écrire', tags: 'accessibilite')}.
%h2.new-h2 Défenseur des droits
%p.new-p
Si vous constatez un défaut d'accessibilité vous empêchant d'accéder à un contenu ou une fonctionnalité du site, que vous nous le signalez et que vous ne parvenez pas à obtenir une réponse rapide de notre part, vous êtes en droit de faire parvenir vos doléances ou une demande de saisine au Défenseur des droits. Plusieurs moyens sont à votre disposition :
%ul
%li un <a href="http://www.defenseurdesdroits.fr/contact" target="_blank">formulaire de contact</a> ;
%li la <a href="http://www.defenseurdesdroits.fr/office/" target="_blank">liste du ou des délégués de votre région</a> avec leurs informations de contact direct ;
%li un <a href="http://www.defenseurdesdroits.fr/contact" target="_blank" rel="noopener">formulaire de contact</a> ;
%li la <a href="http://www.defenseurdesdroits.fr/office/" target="_blank" rel="noopener">liste du ou des délégués de votre région</a> avec leurs informations de contact direct ;
%li une adresse postale : Le Défenseur des droits - 7 rue Saint-Florentin - 75409 Paris Cedex 08.

View file

@ -86,7 +86,7 @@
%p.quote-author
%span.quote-author-name Elodie Le Rhun
%br
Chef de bureau, DRIEA Ile-de-France
Cheffe de bureau, DRIEA Ile-de-France
%li.quote
%img.quote-quotation-mark{ :src => image_url("landing/testimonials/quotation-mark.svg"), alt: "" }

View file

@ -16,8 +16,8 @@
Rien d'exceptionnel, pas de passe-droit. Nous respectons simplement la loi, qui dit que certains outils de suivi daudience, correctement configurés pour respecter la vie privée, sont exemptés dautorisation préalable.
%br
%br
Nous utilisons pour cela <a href="https://matomo.org/" target="_blank" >Matomo</a>, un outil <a href="https://matomo.org/free-software/" target="_blank">libre</a>, paramétré pour être en conformité avec la <a href="https://www.cnil.fr/fr/solutions-pour-la-mesure-daudience">recommandation « Cookies » </a>de la CNIL. Cela signifie que votre adresse IP, par exemple, est anonymisée avant dêtre enregistrée. Il est donc impossible dassocier vos visites sur ce site à votre personne.
Nous utilisons pour cela <a href="https://matomo.org/" target="_blank" rel="noopener">Matomo</a>, un outil <a href="https://matomo.org/free-software/" target="_blank" rel="noopener">libre</a>, paramétré pour être en conformité avec la <a href="https://www.cnil.fr/fr/solutions-pour-la-mesure-daudience">recommandation « Cookies » </a>de la CNIL. Cela signifie que votre adresse IP, par exemple, est anonymisée avant dêtre enregistrée. Il est donc impossible dassocier vos visites sur ce site à votre personne.
%h2.new-h2 Je contribue à enrichir vos données, puis-je y accéder ?
%p.new-p
Bien sûr ! Les statistiques dusage sont en accès libre sur <a href="https://stats.data.gouv.fr/index.php?module=MultiSites&action=index&idSite=1&period=range&date=previous30&updated=1#?idSite=1&period=range&date=previous30&category=Dashboard_Dashboard&subcategory=1&module=MultiSites&action=index" target="_blank">stats.data.gouv.fr</a>.
Bien sûr ! Les statistiques dusage sont en accès libre sur <a href="https://stats.data.gouv.fr/index.php?module=MultiSites&action=index&idSite=1&period=range&date=previous30&updated=1#?idSite=1&period=range&date=previous30&category=Dashboard_Dashboard&subcategory=1&module=MultiSites&action=index" target="_blank" rel="noopener">stats.data.gouv.fr</a>.

View file

@ -54,30 +54,30 @@
%ul
%li
= link_to("Étape Normandie, le 26 septembre à Rouen", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-etape-normandie", target: "_blank")
= link_to("Étape Normandie, le 26 septembre à Rouen", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-etape-normandie", target: "_blank", rel: "noopener")
%li
= link_to("Étape Occitanie, le 15 octobre à Toulouse", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-occitanie", target: "_blank")
= link_to("Étape Occitanie, le 15 octobre à Toulouse", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-occitanie", target: "_blank", rel: "noopener")
%li
= link_to("Étape Nouvelle-Aquitaine, le 18 octobre à Bordeaux", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-aquitaine", target: "_blank")
= link_to("Étape Nouvelle-Aquitaine, le 18 octobre à Bordeaux", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-aquitaine", target: "_blank", rel: "noopener")
%li
= link_to("Étape Martinique, le 24 octobre à Fort-de-France", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-martinique", target: "_blank")
= link_to("Étape Martinique, le 24 octobre à Fort-de-France", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-martinique", target: "_blank", rel: "noopener")
%li
= link_to("Étape PACA, le 6 novembre à Marseille", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-paca", target: "_blank")
= link_to("Étape PACA, le 6 novembre à Marseille", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-paca", target: "_blank", rel: "noopener")
%li
= link_to("Étape Corse, le 8 novembre à Ajaccio", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-corse", target: "_blank")
= link_to("Étape Corse, le 8 novembre à Ajaccio", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-corse", target: "_blank", rel: "noopener")
%li
= link_to("Étape Ile-de-France, le 13 novembre à Paris", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-iledefrance", target: "_blank")
= link_to("Étape Ile-de-France, le 13 novembre à Paris", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-iledefrance", target: "_blank", rel: "noopener")
%li
= link_to("Étape Bourgogne Franche-Comté, le 14 novembre à Dijon", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-bourgogne-fc", target: "_blank")
= link_to("Étape Bourgogne Franche-Comté, le 14 novembre à Dijon", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-bourgogne-fc", target: "_blank", rel: "noopener")
%li
= link_to("Étape Pays de la Loire, le 20 novembre à Nantes", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-paysloire", target: "_blank")
= link_to("Étape Pays de la Loire, le 20 novembre à Nantes", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-paysloire", target: "_blank", rel: "noopener")
%li
= link_to("Étape Bretagne, le 22 novembre à Rennes", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-bretagne", target: "_blank")
= link_to("Étape Bretagne, le 22 novembre à Rennes", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-bretagne", target: "_blank", rel: "noopener")
%li
= link_to("Étape Hauts-de-France, le 27 novembre à Lille", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-hautsdefrance", target: "_blank")
= link_to("Étape Hauts-de-France, le 27 novembre à Lille", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-hautsdefrance", target: "_blank", rel: "noopener")
%li
= link_to("Étape Grand-Est, le 29 novembre à Metz", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-grand-est", target: "_blank")
= link_to("Étape Grand-Est, le 29 novembre à Metz", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-fr-grand-est", target: "_blank", rel: "noopener")
%li
= link_to("Étape Centre Val-de-Loire, le 5 décembre à Orleans", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-centre-vdl", target: "_blank")
= link_to("Étape Centre Val-de-Loire, le 5 décembre à Orleans", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-centre-vdl", target: "_blank", rel: "noopener")
%li
= link_to("Étape Auvergne-Rhone-Alpes, le 7 décembre à Lyon", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-auvergne-rhon", target: "_blank")
= link_to("Étape Auvergne-Rhone-Alpes, le 7 décembre à Lyon", "https://www.demarches-simplifiees.fr/commencer/tour-de-france-demarches-simplifiees-auvergne-rhon", target: "_blank", rel: "noopener")

View file

@ -2,7 +2,7 @@
- if dossier
- path = dossier_linked_path(current_gestionnaire || current_user, dossier)
- if path.present?
= link_to("Dossier nº #{dossier.id}", path, target: '_blank')
= link_to("Dossier nº #{dossier.id}", path, target: '_blank', rel: 'noopener')
- else
Dossier nº #{dossier.id}
%br

View file

@ -2,7 +2,7 @@
.pj-link
- if champ.virus_scan.blank? || champ.virus_scan.safe?
= link_to url_for(pj), target: '_blank', title: "Télécharger la pièce jointe" do
= link_to url_for(pj), target: '_blank', rel: 'noopener', title: "Télécharger la pièce jointe" do
%span.icon.attachment
= pj.filename.to_s
- if champ.virus_scan.blank?

View file

@ -4,7 +4,7 @@
- when :not_found
Nous navons pas trouvé détablissement correspondant à ce numéro de SIRET.
= link_to('Plus dinformations', "https://faq.demarches-simplifiees.fr/article/4-erreur-siret", target: '_blank')
= link_to('Plus dinformations', "https://faq.demarches-simplifiees.fr/article/4-erreur-siret", target: '_blank', rel: 'noopener')
- else
- if siret.present? && siret == etablissement&.siret

View file

@ -17,7 +17,7 @@
) sont obligatoires.
- if notice_url(dossier.procedure).present?
= link_to notice_url(dossier.procedure), target: '_blank', class: 'button notice', title: "Pour vous aider à remplir votre dossier, vous pouvez consulter le guide de cette démarche." do
= link_to notice_url(dossier.procedure), target: '_blank', rel: 'noopener', class: 'button notice', title: "Pour vous aider à remplir votre dossier, vous pouvez consulter le guide de cette démarche." do
%span.icon.info>
Guide de la démarche
@ -54,13 +54,13 @@
- if tpj.lien_demarche.present?
%p.piece-description
Récupérer le formulaire vierge pour mon dossier :
= link_to "Télécharger", tpj.lien_demarche, target: :blank
= link_to "Télécharger", tpj.lien_demarche, target: :blank, rel: :noopener
- if dossier.was_piece_justificative_uploaded_for_type_id?(tpj.id)
- pj = dossier.retrieve_last_piece_justificative_by_type(tpj.id)
%p
Pièce jointe déjà importée :
= link_to pj.original_filename, pj.content_url, target: :blank
= link_to pj.original_filename, pj.content_url, target: :blank, rel: :noopener
= file_field_tag "piece_justificative_#{tpj.id}",
accept: PieceJustificative.accept_format,

View file

@ -10,7 +10,7 @@
%span{ class: highlight_if_unseen_class(demande_seen_at, pj.updated_at) }
= display_pj_filename(pj)
·
= link_to "Télécharger", pj.content_url, class: "link", target: :blank
= link_to "Télécharger", pj.content_url, class: "link", target: :blank, rel: :noopener
- if pjs.present?
%br
%span.dropdown
@ -20,7 +20,7 @@
%ul.dropdown-items
- pjs.each do |pj|
%li
= link_to pj.content_url, { target: :blank } do
= link_to pj.content_url, { target: :blank, rel: :noopener } do
%span.filename= display_pj_filename(pj)
%span
ajoutée le #{pj.created_at.strftime('%d/%m/%Y à %H:%M')}

View file

@ -4,7 +4,7 @@
- if champ.type_de_champ.piece_justificative_template.attached?
%p.edit-pj-template.mb-1
Veuillez télécharger, remplir et joindre
= link_to('le modèle suivant', url_for(champ.type_de_champ.piece_justificative_template), target: '_blank')
= link_to('le modèle suivant', url_for(champ.type_de_champ.piece_justificative_template), target: '_blank', rel: 'noopener')
- if pj.attached?
.piece-justificative-actions{ id: "piece_justificative_#{champ.id}" }

View file

@ -12,11 +12,11 @@
- if commentaire.piece_justificative
.attachment-link
= link_to commentaire.piece_justificative.content_url, class: "button", target: "_blank", title: "Télécharger" do
= link_to commentaire.piece_justificative.content_url, class: "button", target: "_blank", rel: "noopener", title: "Télécharger" do
%span.icon.attachment
= commentaire.piece_justificative.original_filename
- elsif commentaire.file.present?
.attachment-link
= link_to commentaire.file_url, class: "button", target: "_blank", title: "Télécharger" do
= link_to commentaire.file_url, class: "button", target: "_blank", rel: "noopener", title: "Télécharger" do
%span.icon.attachment
= commentaire.file_identifier

View file

@ -19,4 +19,4 @@
= link_to "", france_connect_particulier_path, class: "login-with-fc"
.center
= link_to "Quest-ce que FranceConnect ?", "https://franceconnect.gouv.fr/", target: "_blank", class: "link"
= link_to "Quest-ce que FranceConnect ?", "https://franceconnect.gouv.fr/", target: "_blank", rel: "noopener", class: "link"

View file

@ -14,7 +14,7 @@
<b>Attention</b>, ce message peut mettre jusqu'à <b>15 minutes</b> pour arriver.
%p.help
Si vous voyez cette page trop souvent, consultez notre aide : #{link_to 'https://faq.demarches-simplifiees.fr/article/34-je-dois-confirmer-mon-compte-a-chaque-connexion', 'https://faq.demarches-simplifiees.fr/article/34-je-dois-confirmer-mon-compte-a-chaque-connexion', target: '_blank' }
Si vous voyez cette page trop souvent, consultez notre aide : #{link_to 'https://faq.demarches-simplifiees.fr/article/34-je-dois-confirmer-mon-compte-a-chaque-connexion', 'https://faq.demarches-simplifiees.fr/article/34-je-dois-confirmer-mon-compte-a-chaque-connexion', target: '_blank', rel: 'noopener' }
%br
%br
En cas de difficultés, nous restons joignables sur #{link_to 'contact@demarches-simplifiees.fr', 'mailto:contact@demarches-simplifiees.fr'}.
En cas de difficultés, nous restons joignables sur #{link_to CONTACT_EMAIL, "mailto:#{CONTACT_EMAIL}"}.

View file

@ -36,4 +36,4 @@
= link_to "", france_connect_particulier_path, class: "login-with-fc"
.center
= link_to "Quest-ce que FranceConnect ?", "https://franceconnect.gouv.fr/", target: "_blank", class: "link"
= link_to "Quest-ce que FranceConnect ?", "https://franceconnect.gouv.fr/", target: "_blank", rel: "noopener", class: "link"

View file

@ -6,6 +6,7 @@ API_GEO_URL = ENV.fetch("API_GEO_URL", "https://geo.api.gouv.fr")
API_GEO_SANDBOX_URL = ENV.fetch("API_GEO_SANDBOX_URL", "https://sandbox.geo.api.gouv.fr")
HELPSCOUT_API_URL = ENV.fetch("HELPSCOUT_API_URL", "https://api.helpscout.net/v2")
PIPEDRIVE_API_URL = ENV.fetch("PIPEDRIVE_API_URL", "https://api.pipedrive.com/v1")
SENDINBLUE_API_URL = ENV.fetch("SENDINBLUE_API_URL", "https://in-automate.sendinblue.com/api/v2")
# Internal URLs
FOG_BASE_URL = "https://static.demarches-simplifiees.fr"

View file

@ -51,6 +51,8 @@ defaults: &defaults
client_id: <%= ENV['HELPSCOUT_CLIENT_ID'] %>
client_secret: <%= ENV['HELPSCOUT_CLIENT_SECRET'] %>
webhook_secret: <%= ENV['HELPSCOUT_WEBHOOK_SECRET'] %>
sendinblue:
client_key: <%= ENV['SENDINBLUE_CLIENT_KEY'] %>
development:
<<: *defaults

View file

@ -45,7 +45,7 @@
<div class='container'>
<h1 class='new-h1'>Une erreur est survenue</h1>
<div class='description'>
Nos équipes ont été averties. Si le problème persiste ou si vous voulez nous donner des détails concernant l'erreur qui vient de se produire, vous pouvez nous contacter à l'adresse <a href="mailto:contact@demarches-simplifiees.fr" target="_blank">contact@demarches-simplifiees.fr</a>.
Nos équipes ont été averties. Si le problème persiste ou si vous voulez nous donner des détails concernant l'erreur qui vient de se produire, vous pouvez nous contacter à l'adresse <a href="mailto:contact@demarches-simplifiees.fr" target="_blank" rel="noopener">contact@demarches-simplifiees.fr</a>.
</div>
</div>
</div>

View file

@ -11,7 +11,7 @@ RSpec.describe StringToHtmlHelper, type: :helper do
context "with a link" do
let(:description) { "https://d-s.fr" }
it { is_expected.to eq("<p><a target=\"_blank\" href=\"https://d-s.fr\">https://d-s.fr</a></p>") }
it { is_expected.to eq("<p><a target=\"_blank\" rel=\"noopener\" href=\"https://d-s.fr\">https://d-s.fr</a></p>") }
end
context "with empty decription" do

View file

@ -115,12 +115,10 @@ describe TagsSubstitutionConcern, type: :model do
end
context 'when the procedure has a linked drop down menus type de champ' do
let(:types_de_champ) do
[
create(:type_de_champ_linked_drop_down_list, libelle: 'libelle')
]
let(:type_de_champ) do
create(:type_de_champ_linked_drop_down_list, libelle: 'libelle')
end
let(:types_de_champ) { [type_de_champ] }
let(:template) { 'tout : --libelle--, primaire : --libelle/primaire--, secondaire : --libelle/secondaire--' }
context 'and the champ has no value' do
@ -129,22 +127,31 @@ describe TagsSubstitutionConcern, type: :model do
context 'and the champ has a primary value' do
before do
c = dossier.champs.detect { |champ| champ.libelle == 'libelle' }
c.primary_value = 'primo'
c.save
dossier.champs.find_by(type_de_champ: type_de_champ).update(primary_value: 'primo')
dossier.reload
end
it { is_expected.to eq('tout : primo, primaire : primo, secondaire : ') }
end
context 'and the champ has a primary and secondary value' do
before do
c = dossier.champs.detect { |champ| champ.libelle == 'libelle' }
c.primary_value = 'primo'
c.secondary_value = 'secundo'
c.save
context 'and the champ has a secondary value' do
before do
dossier.champs.find_by(type_de_champ: type_de_champ).update(secondary_value: 'secundo')
dossier.reload
end
it { is_expected.to eq('tout : primo / secundo, primaire : primo, secondaire : secundo') }
context 'and the same libelle is used by a header' do
let(:types_de_champ) do
[
type_de_champ,
create(:type_de_champ_header_section, libelle: 'libelle')
]
end
it { is_expected.to eq('tout : primo / secundo, primaire : primo, secondaire : secundo') }
end
end
it { is_expected.to eq('tout : primo / secundo, primaire : primo, secondaire : secundo') }
end
end
@ -314,9 +321,20 @@ describe TagsSubstitutionConcern, type: :model do
describe 'tags' do
subject { template_concern.tags }
let(:types_de_champ) { [create(:type_de_champ, libelle: 'public')] }
let(:types_de_champ) do
[
create(:type_de_champ, libelle: 'public'),
create(:type_de_champ_header_section, libelle: 'entête de section'),
create(:type_de_champ_explication, libelle: 'explication')
]
end
let(:types_de_champ_private) { [create(:type_de_champ, :private, libelle: 'privé')] }
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: 'explication' })) }
end
context 'when generating a document for a dossier terminé' do
it { is_expected.to include(include({ libelle: 'motivation' })) }
it { is_expected.to include(include({ libelle: 'date de décision' })) }

View file

@ -0,0 +1,218 @@
require 'spec_helper'
describe AdministrateurUsageStatisticsService do
describe '#administrateur_stats' do
let(:service) { AdministrateurUsageStatisticsService.new }
subject { service.send(:administrateur_stats, administrateur) }
before { Timecop.freeze(Time.zone.now) }
after { Timecop.return }
context 'for an administrateur that has nothing' do
let(:administrateur) { create(:administrateur) }
it do
is_expected.to eq(
ds_sign_in_count: 0,
ds_created_at: Time.zone.now,
ds_active: false,
ds_id: administrateur.id,
ds_features: "{}",
nb_services: 0,
nb_instructeurs: 0,
ds_nb_demarches_actives: 0,
ds_nb_demarches_archives: 0,
ds_nb_demarches_brouillons: 0,
nb_demarches_test: 0,
nb_demarches_prod: 0,
nb_demarches_prod_20: 0,
nb_dossiers: 0,
nb_dossiers_max: 0,
nb_dossiers_traite: 0,
nb_dossiers_dossier_en_instruction: 0
)
end
end
context 'for an administrateur that has plenty of things' do
let(:administrateur) do
create(:administrateur,
sign_in_count: 17,
current_sign_in_at: Time.zone.local(2019, 3, 7),
last_sign_in_at: Time.zone.local(2019, 2, 27),
active: true,
features: { holy_hand_grenade_of_antioch: true },
services: [create(:service)],
gestionnaires: [create(:gestionnaire)])
end
it do
is_expected.to include(
ds_sign_in_count: 17,
ds_current_sign_in_at: Time.zone.local(2019, 3, 7),
ds_last_sign_in_at: Time.zone.local(2019, 2, 27),
ds_created_at: Time.zone.now,
ds_active: true,
ds_id: administrateur.id,
ds_features: { holy_hand_grenade_of_antioch: true }.to_json,
nb_services: 1,
nb_instructeurs: 1
)
end
end
context 'counting procedures and dossiers' do
let(:administrateur) do
create(:administrateur, procedures: [procedure])
end
context 'with a freshly active procedure' do
let(:procedure) { create(:procedure, aasm_state: 'publiee') }
it do
is_expected.to include(
ds_nb_demarches_actives: 1,
ds_nb_demarches_archives: 0,
ds_nb_demarches_brouillons: 0,
nb_demarches_test: 0,
nb_demarches_prod: 0,
nb_demarches_prod_20: 0,
nb_dossiers: 0,
nb_dossiers_max: 0,
nb_dossiers_traite: 0,
nb_dossiers_dossier_en_instruction: 0
)
end
end
context 'with a procedure archivee' do
let(:procedure) { create(:procedure, aasm_state: 'archivee', dossiers: dossiers) }
let(:dossiers) do
(1..7).flat_map do
[
create(:dossier, :en_construction),
create(:dossier, :en_instruction),
create(:dossier, :accepte)
]
end
end
it do
is_expected.to include(
ds_nb_demarches_actives: 0,
ds_nb_demarches_archives: 1,
ds_nb_demarches_brouillons: 0,
nb_demarches_test: 0,
nb_demarches_prod: 1,
nb_demarches_prod_20: 1,
nb_dossiers: 21,
nb_dossiers_max: 21,
nb_dossiers_traite: 7,
nb_dossiers_dossier_en_instruction: 7
)
end
end
context 'with a procedure brouillon' do
let(:procedure) { create(:procedure) }
it do
is_expected.to include(
ds_nb_demarches_actives: 0,
ds_nb_demarches_archives: 0,
ds_nb_demarches_brouillons: 1,
nb_demarches_test: 0,
nb_demarches_prod: 0,
nb_demarches_prod_20: 0,
nb_dossiers: 0,
nb_dossiers_max: 0,
nb_dossiers_traite: 0,
nb_dossiers_dossier_en_instruction: 0
)
end
end
context 'with a procedure en test' do
let(:procedure) { create(:procedure, dossiers: dossiers) }
let(:dossiers) do
(1..7).flat_map do
[
create(:dossier, :en_construction),
create(:dossier, :en_instruction),
create(:dossier, :accepte)
]
end
end
it do
is_expected.to include(
ds_nb_demarches_actives: 0,
ds_nb_demarches_archives: 0,
ds_nb_demarches_brouillons: 1,
nb_demarches_test: 1,
nb_demarches_prod: 0,
nb_demarches_prod_20: 0,
nb_dossiers: 0,
nb_dossiers_max: 0,
nb_dossiers_traite: 0,
nb_dossiers_dossier_en_instruction: 0
)
end
end
context 'with a procedure en prod' do
let(:procedure) { create(:procedure, aasm_state: 'publiee', dossiers: dossiers) }
let(:dossiers) do
[
create(:dossier, :en_construction),
create(:dossier, :en_instruction),
create(:dossier, :accepte)
]
end
it do
is_expected.to include(
ds_nb_demarches_actives: 1,
ds_nb_demarches_archives: 0,
ds_nb_demarches_brouillons: 0,
nb_demarches_test: 0,
nb_demarches_prod: 1,
nb_demarches_prod_20: 0,
nb_dossiers: 3,
nb_dossiers_max: 3,
nb_dossiers_traite: 1,
nb_dossiers_dossier_en_instruction: 1
)
end
end
context 'with a procedure en prod and more than 20 dossiers' do
let(:procedure) { create(:procedure, aasm_state: 'publiee', dossiers: dossiers) }
let(:dossiers) do
(1..7).flat_map do
[
create(:dossier, :en_construction),
create(:dossier, :en_instruction),
create(:dossier, :accepte)
]
end
end
it do
is_expected.to include(
ds_nb_demarches_actives: 1,
ds_nb_demarches_archives: 0,
ds_nb_demarches_brouillons: 0,
nb_demarches_test: 0,
nb_demarches_prod: 1,
nb_demarches_prod_20: 1,
nb_dossiers: 21,
nb_dossiers_max: 21,
nb_dossiers_traite: 7,
nb_dossiers_dossier_en_instruction: 7
)
end
end
end
end
end