2019-07-10-01 (#4077)

2019-07-10-01
This commit is contained in:
Pierre de La Morinerie 2019-07-10 17:30:39 +02:00 committed by GitHub
commit 96766f0ad0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 322 additions and 150 deletions

View file

@ -21,6 +21,14 @@
}
}
&.warning {
border-top: 8px solid $orange;
.card-title {
color: $orange;
}
}
&.feedback {
max-width: 600px;
margin: 30px auto;

View file

@ -12,4 +12,8 @@
p {
margin: 16px auto;
}
.email-address {
font-weight: bold;
}
}

View file

@ -265,7 +265,7 @@ class Admin::ProceduresController < AdminController
end
def procedure_params
editable_params = [:libelle, :description, :organisation, :direction, :lien_site_web, :cadre_juridique, :deliberation, :notice, :expects_multiple_submissions, :web_hook_url, :euro_flag, :logo, :auto_archive_on]
editable_params = [:libelle, :description, :organisation, :direction, :lien_site_web, :cadre_juridique, :deliberation, :notice, :web_hook_url, :euro_flag, :logo, :auto_archive_on]
if @procedure&.locked?
params.require(:procedure).permit(*editable_params)
else

View file

@ -13,7 +13,7 @@ class FranceConnect::ParticulierController < ApplicationController
fetched_fci.tap(&:save)
if fci.user.nil?
user = User.find_or_create_by(email: fci.email_france_connect) do |new_user|
user = User.find_or_create_by!(email: fci.email_france_connect.downcase) do |new_user|
new_user.password = Devise.friendly_token[0, 20]
new_user.confirmed_at = Time.zone.now
end

View file

@ -138,7 +138,7 @@ module Gestionnaires
end
def commentaire_params
params.require(:commentaire).permit(:body, :file)
params.require(:commentaire).permit(:body, :piece_jointe)
end
end
end

View file

@ -166,7 +166,7 @@ module Gestionnaires
end
def commentaire_params
params.require(:commentaire).permit(:body, :file)
params.require(:commentaire).permit(:body, :piece_jointe)
end
def champs_private_params

View file

@ -52,7 +52,7 @@ class SupportController < ApplicationController
email: email,
phone: params[:phone],
text: params[:text],
file: params[:file],
file: params[:piece_jointe],
dossier_id: dossier&.id,
browser: browser_name,
tags: tags
@ -61,7 +61,7 @@ class SupportController < ApplicationController
def create_commentaire
attributes = {
file: params[:file],
piece_jointe: params[:piece_jointe],
body: "[#{params[:subject]}]<br><br>#{params[:text]}"
}
commentaire = CommentaireService.build(current_user, dossier, attributes)

View file

@ -354,7 +354,7 @@ module Users
end
def commentaire_params
params.require(:commentaire).permit(:body, :file)
params.require(:commentaire).permit(:body, :piece_jointe)
end
def passage_en_construction?

View file

@ -12,8 +12,9 @@ module Users
def update_email
if @current_user.update(update_email_params)
flash.notice = t('devise.registrations.update_needs_confirmation')
# to avoid leaking who has signed in
elsif @current_user.errors&.details&.dig(:email)&.any? { |e| e[:error] == :taken }
UserMailer.account_already_taken(@current_user, requested_email).deliver_later
# avoid leaking information about whether an account with this email exists or not
flash.notice = t('devise.registrations.update_needs_confirmation')
else
flash.alert = @current_user.errors.full_messages
@ -27,5 +28,9 @@ module Users
def update_email_params
params.require(:user).permit(:email)
end
def requested_email
update_email_params[:email]
end
end
end

View file

@ -22,7 +22,6 @@ class TypesDeChampEditor extends Component {
type_champ: 'text',
types_de_champ: [],
private: props.isAnnotation,
drop_down_list_value: '--Premier élément du menu--\n',
libelle: `${
props.isAnnotation ? 'Nouvelle annotation' : 'Nouveau champ'
} ${props.typeDeChampsTypes[0][0]}`

View file

@ -115,6 +115,18 @@ function updateTypeDeChamp(
{ typeDeChamp, field, value },
done
) {
if (field == 'type_champ' && !typeDeChamp.drop_down_list_value) {
switch (value) {
case 'linked_drop_down_list':
typeDeChamp.drop_down_list_value =
'--Fromage--\nbleu de sassenage\npicodon\n--Dessert--\néclair\ntarte aux pommes\n';
break;
case 'drop_down_list':
case 'multiple_drop_down_list':
typeDeChamp.drop_down_list_value = '--Premier élément du menu--\n';
}
}
typeDeChamp[field] = value;
getUpdateHandler(typeDeChamp, state)(done);

View file

@ -1,10 +1,5 @@
module BizDev
BIZ_DEV_MAPPING = {
8 =>
{
full_name: "Camille Garrigue",
pipedrive_id: 3189424
},
9 =>
{
full_name: "Philippe Vrignaud",
@ -14,11 +9,6 @@ module BizDev
{
full_name: "Benjamin Doberset",
pipedrive_id: 4223834
},
11 =>
{
full_name: "Rédouane Bouchane",
pipedrive_id: 4438645
}
}

View file

@ -8,4 +8,12 @@ class UserMailer < ApplicationMailer
mail(to: user.email, subject: @subject)
end
def account_already_taken(user, requested_email)
@user = user
@requested_email = requested_email
@subject = "Changement dadresse email"
mail(to: requested_email, subject: @subject)
end
end

View file

@ -5,9 +5,10 @@ class Commentaire < ApplicationRecord
belongs_to :gestionnaire
mount_uploader :file, CommentaireFileUploader
validates :file, file_size: { maximum: 20.megabytes, message: "La taille du fichier doit être inférieure à 20 Mo" }
validate :is_virus_free?
validate :messagerie_available?, on: :create
has_one_attached :piece_jointe
validates :body, presence: { message: "Votre message ne peut être vide" }
default_scope { order(created_at: :asc) }
@ -47,10 +48,15 @@ class Commentaire < ApplicationRecord
end
def file_url
if Flipflop.remote_storage?
if piece_jointe.attached?
if piece_jointe.virus_scanner.safe?
Rails.application.routes.url_helpers.url_for(piece_jointe)
end
elsif Flipflop.remote_storage?
RemoteDownloader.new(file.path).url
else
file.url
elsif file&.url
# FIXME: this is horrible but used only in dev and will be removed after migration
File.join(LOCAL_DOWNLOAD_URL, file.url)
end
end
@ -74,12 +80,6 @@ class Commentaire < ApplicationRecord
DossierMailer.notify_new_answer(dossier).deliver_later
end
def is_virus_free?
if file.present? && file_changed? && !ClamavService.safe_file?(file.path)
errors.add(:file, "Virus détecté dans le fichier joint, merci de changer de fichier")
end
end
def messagerie_available?
return if sent_by_system?
if dossier.present? && !dossier.messagerie_available?

View file

@ -1,6 +1,8 @@
class Dossier < ApplicationRecord
include DossierFilteringConcern
self.ignored_columns = [:expects_multiple_submissions]
enum state: {
brouillon: 'brouillon',
en_construction: 'en_construction',
@ -115,7 +117,7 @@ class Dossier < ApplicationRecord
scope :nearing_end_of_retention, -> (duration = '1 month') { joins(:procedure).where("en_instruction_at + (duree_conservation_dossiers_dans_ds * interval '1 month') - now() < interval ?", duration) }
scope :since, -> (since) { where('dossiers.en_construction_at >= ?', since) }
scope :for_api, -> {
includes(commentaires: [],
includes(commentaires: { piece_jointe_attachment: :blob },
champs: [
:geo_areas,
:etablissement,

View file

@ -13,6 +13,11 @@ class CommentaireService
def build_with_email(email, dossier, params)
attributes = params.merge(email: email, dossier: dossier)
# For some reason ActiveStorage trows an error in tests if we passe an empty string here.
# I suspect it could be resolved in rails 6 by using explicit `attach()`
if attributes[:piece_jointe].blank?
attributes.delete(:piece_jointe)
end
Commentaire.new(attributes)
end
end

View file

@ -14,7 +14,7 @@ class LocalDownloader
end
def url
@url ||= File.join(TPS::Application::URL, 'downloads', random_folder_name, "#{@filename_suffix}.#{@extension}")
@url ||= File.join(LOCAL_DOWNLOAD_URL, 'downloads', random_folder_name, "#{@filename_suffix}.#{@extension}")
end
protected

View file

@ -127,15 +127,6 @@
.col-md-6
%h4 Options avancées
= f.label :expects_multiple_submissions do
= f.check_box :expects_multiple_submissions
Ajuster pour le dépôt récurrent de dossiers
%p.help-block
%i.fa.fa-info-circle
Si cette démarche est conçue pour quune même personne y dépose régulièrement plusieurs
dossiers, linterface est ajustée pour rendre plus facile la création de plusieurs dossiers
à la suite.
- if Flipflop.web_hook?
%label{ for: :web_hook_url } Lien de rappel HTTP (webhook)
= f.text_field :web_hook_url, class: 'form-control', placeholder: 'https://callback.exemple.fr/'

View file

@ -15,4 +15,4 @@
Nous restons à votre disposition si vous avez besoin daccompagnement.
%p
= render partial: "layouts/mailers/bizdev_signature", locals: { author_name: "Camille Garrigue" }
= render partial: "layouts/mailers/bizdev_signature", locals: { author_name: "Benjamin Doberset" }

View file

@ -11,7 +11,7 @@
%h4 En construction
Vous permettez à l'usager de modifier ses réponses au formulaire
%li
= link_to passer_en_instruction_gestionnaire_dossier_path(dossier.procedure, dossier), method: :post, data: { remote: true, confirm: "Confirmer vous le passage en instruction de ce dossier ?" } do
= link_to passer_en_instruction_gestionnaire_dossier_path(dossier.procedure, dossier), method: :post, data: { remote: true, confirm: "Confirmez-vous le passage en instruction de ce dossier ?" } do
%span.icon.in-progress
.dropdown-description
%h4 Passer en instruction
@ -19,7 +19,7 @@
- if dossier.en_instruction?
%li
= link_to repasser_en_construction_gestionnaire_dossier_path(dossier.procedure, dossier), method: :post, data: { remote:true, confirm: "Confirmer vous le passage en construction de ce dossier ?" } do
= link_to repasser_en_construction_gestionnaire_dossier_path(dossier.procedure, dossier), method: :post, data: { remote:true, confirm: "Confirmez-vous le passage en construction de ce dossier ?" } do
%span.icon.edit
.dropdown-description
%h4 Repasser en construction

View file

@ -61,7 +61,7 @@
.messagerie
%ul.messages-list
- @dossier.commentaires.each do |commentaire|
- @dossier.commentaires.with_attached_piece_jointe.each do |commentaire|
%li
= render partial: "shared/dossiers/messages/message", locals: { commentaire: commentaire, connected_user: current_gestionnaire, messagerie_seen_at: nil }

View file

@ -26,11 +26,11 @@
= link_to admin_procedures_path, class: "menu-item menu-link" do
= image_tag "icons/switch-profile.svg"
Passer en administrateur
%li
= link_to profil_path, class: "menu-item menu-link" do
= image_tag "icons/switch-profile.svg"
Voir mon profil
%li
= link_to profil_path, class: "menu-item menu-link" do
= image_tag "icons/switch-profile.svg"
Voir mon profil
%li
= link_to destroy_user_session_path, method: :delete, class: "menu-item menu-link" do
= image_tag "icons/sign-out.svg"

View file

@ -157,6 +157,11 @@
Titre de la carte mise en avant
%p Et voici le contenu de la carte
.card.warning
.card-title
Titre de la carte davertissement
%p Et voici le contenu de la carte
.card.feedback
.card-title
Titre de la carte pour demander un avis

View file

@ -1,6 +1,6 @@
.messagerie.container
%ul.messages-list
- dossier.commentaires.each do |commentaire|
- dossier.commentaires.with_attached_piece_jointe.each do |commentaire|
%li.message{ class: commentaire_is_from_me_class(commentaire, connected_user) }
= render partial: "shared/dossiers/messages/message", locals: { commentaire: commentaire, connected_user: connected_user, messagerie_seen_at: messagerie_seen_at }

View file

@ -2,8 +2,8 @@
= f.text_area :body, rows: 5, placeholder: 'Répondre ici', required: true, class: 'message-textarea'
.flex.justify-between.wrap
%div
= f.file_field :file, id: :file, accept: commentaire.file.accept_extension_list
%label{ for: :file }
= f.file_field :piece_jointe, id: 'piece_jointe', direct_upload: true
%label{ for: :piece_jointe }
.notice
(taille max : 20 Mo)

View file

@ -10,7 +10,10 @@
= commentaire_date(commentaire)
.rich-text= sanitize(simple_format(commentaire.body))
- if commentaire.file.present?
- if commentaire.piece_jointe.attached?
.attachment-link
= render partial: "shared/attachment/show", locals: { attachment: commentaire.piece_jointe.attachment }
- elsif commentaire.file.present?
.attachment-link
= link_to commentaire.file_url, class: "button", target: "_blank", rel: "noopener", title: "Télécharger" do
%span.icon.attachment

View file

@ -76,7 +76,7 @@
Une capture décran peut nous aider à identifier plus facilement lendroit à améliorer.
.notice.hidden{ data: { 'contact-type-only': Helpscout::FormAdapter::TYPE_AUTRE } }
Une capture décran peut nous aider à identifier plus facilement le problème.
= file_field_tag :file
= file_field_tag :piece_jointe
= hidden_field_tag :tags, @tags&.join(',')

View file

@ -0,0 +1,20 @@
- content_for(:title, @subject)
%p
Bonjour,
%p
Lutilisateur « #{@user.email} » a demandé le changement de son adresse vers « #{@requested_email} ».
%p
Malheureusement, votre compte « #{@requested_email} » existe déjà. Nous ne pouvons pas fusionner automatiquement vos comptes.
%p
%strong Nous ne pouvons donc pas effectuer le changement dadresse email.
%p
Si vous n'êtes pas à lorigine de cette demande, vous pouvez ignorer ce message. Et si vous avez besoin dassistance, nhésitez pas à nous contacter à
= succeed '.' do
= mail_to CONTACT_EMAIL
= render partial: "layouts/mailers/signature"

View file

@ -1,5 +1,5 @@
- has_delete_action = dossier.can_be_deleted_by_user?
- has_new_dossier_action = dossier.procedure.expects_multiple_submissions? && dossier.procedure.accepts_new_dossiers?
- has_new_dossier_action = dossier.procedure.accepts_new_dossiers?
- has_actions = has_delete_action || has_new_dossier_action

View file

@ -20,4 +20,6 @@
et
%b échanger avec un instructeur.
= link_to 'Accéder à votre dossier', dossier_path(@dossier), class: 'button large primary'
.flex.column.align-center
= link_to 'Accéder à votre dossier', dossier_path(@dossier), class: 'button large primary'
= link_to 'Déposer un autre dossier', procedure_lien(@dossier.procedure)

View file

@ -7,12 +7,16 @@
.card
.card-title Coordonnées
%p Votre email est actuellement #{current_user.email}
%p
Votre email est actuellement
%span.email-address= current_user.email
- if current_user.unconfirmed_email.present?
%p
Un email a été envoyé à #{current_user.unconfirmed_email}.
%br
Merci de vérifier vos emails et de cliquer sur le lien dactivation pour finaliser la validation de votre nouvelle adresse.
.card.warning
.card-title
Changement en attente :
%span.email-address= current_user.unconfirmed_email
%p
Pour finaliser votre changement dadresse, vérifiez vos emails et cliquez sur le lien de confirmation.
= form_for @current_user, url: update_email_path, method: :patch, html: { class: 'form' } do |f|
= f.email_field :email, value: nil, placeholder: 'Nouvelle adresse email', required: true

View file

@ -31,8 +31,6 @@ module TPS
config.assets.paths << Rails.root.join('app', 'assets', 'fonts')
config.assets.precompile += ['.woff']
URL = ENV['APP_HOST'] || "http://localhost:3000/"
config.active_job.queue_adapter = :delayed_job
config.action_view.sanitized_allowed_tags = ActionView::Base.sanitized_allowed_tags + ['u']

View file

@ -28,3 +28,6 @@ FAQ_ADMIN_URL = "https://faq.demarches-simplifiees.fr/collection/1-administrateu
COMMENT_TROUVER_MA_DEMARCHE_URL = [FAQ_URL, "article", "59-comment-trouver-ma-demarche"].join("/")
STATUS_PAGE_URL = "https://status.demarches-simplifiees.fr"
MATOMO_IFRAME_URL = "https://stats.data.gouv.fr/index.php?module=CoreAdminHome&action=optOut&language=fr&&fontColor=333333&fontSize=16px&fontFamily=Muli"
# FIXME: This is only used in dev in couple of places and should be removed after PJ migration
LOCAL_DOWNLOAD_URL = "http://#{ENV.fetch('APP_HOST', 'localhost:3000')}"

View file

@ -42,7 +42,7 @@ fr:
signed_up_but_inactive: "Vous êtes bien enregistré. Vous ne pouvez cependant pas vous connecter car votre compte n'est 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 d'activation. Ouvrez ce lien pour activer votre compte."
update_needs_confirmation: "Votre compte a bien été mis à jour mais nous devons vérifier votre nouvelle adresse email. Merci de vérifier vos emails et de cliquer sur le lien dactivation pour finaliser la validation de votre nouvelle adresse."
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é."

View file

@ -0,0 +1,37 @@
namespace :'2019_05_29_migrate_commentaire_pj' do
task run: :environment do
commentaires = Commentaire.where
.not(file: nil)
.left_joins(:piece_jointe_attachment)
.where('active_storage_attachments.id IS NULL')
.order(:created_at)
limit = ENV['LIMIT']
if limit
commentaires.limit!(limit.to_i)
end
progress = ProgressReport.new(commentaires.count)
commentaires.find_each do |commentaire|
if commentaire.file.present?
uri = URI.parse(URI.escape(commentaire.file_url))
response = Typhoeus.get(uri)
if response.success?
filename = commentaire.file.filename || commentaire.file_identifier
updated_at = commentaire.updated_at
dossier_updated_at = commentaire.dossier.updated_at
commentaire.piece_jointe.attach(
io: StringIO.new(response.body),
filename: filename,
content_type: commentaire.file.content_type,
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
)
commentaire.update_column(:updated_at, updated_at)
commentaire.dossier.update_column(:updated_at, dossier_updated_at)
end
end
progress.inc
end
progress.finish
end
end

View file

@ -71,11 +71,30 @@ describe FranceConnect::ParticulierController, type: :controller do
end
context 'when france_connect_particulier_id does not have an associate user' do
it { is_expected.to redirect_to(root_path) }
context 'when the email address is not used yet' do
it { expect { subject }.to change(User, :count).by(1) }
it { is_expected.to redirect_to(root_path) }
end
it do
subject
expect(User.find_by(email: email)).not_to be_nil
context 'when the email address is already used' do
let!(:user) { create(:user, email: email, france_connect_information: nil) }
it 'associates the france_connect infos with the existing user' do
expect { subject }.not_to change(User, :count)
expect(user.reload.loged_in_with_france_connect).to eq(User.loged_in_with_france_connects.fetch(:particulier))
expect(subject).to redirect_to(root_path)
end
end
context 'when a differently cased email address is already used' do
let(:email) { 'TEST@test.com' }
let!(:user) { create(:user, email: email.downcase, france_connect_information: nil) }
it 'associates the france_connect infos with the existing user' do
expect { subject }.not_to change(User, :count)
expect(user.reload.loged_in_with_france_connect).to eq(User.loged_in_with_france_connects.fetch(:particulier))
expect(subject).to redirect_to(root_path)
end
end
end
end

View file

@ -92,7 +92,7 @@ describe Gestionnaires::AvisController, type: :controller do
let(:file) { nil }
let(:scan_result) { true }
subject { post :create_commentaire, params: { id: avis_without_answer.id, commentaire: { body: 'commentaire body', file: file } } }
subject { post :create_commentaire, params: { id: avis_without_answer.id, commentaire: { body: 'commentaire body', piece_jointe: file } } }
before do
allow(ClamavService).to receive(:safe_file?).and_return(scan_result)
@ -110,16 +110,10 @@ describe Gestionnaires::AvisController, type: :controller do
it do
subject
expect(Commentaire.last.file.path).to include("piece_justificative_0.pdf")
expect(Commentaire.last.piece_jointe.filename).to eq("piece_justificative_0.pdf")
end
it { expect { subject }.to change(Commentaire, :count).by(1) }
context "and a virus" do
let(:scan_result) { false }
it { expect { subject }.not_to change(Commentaire, :count) }
end
end
end

View file

@ -350,15 +350,15 @@ describe Gestionnaires::DossiersController, type: :controller do
expect(flash.notice).to be_present
end
context "when the commentaire creation fails" do
context "when the commentaire created with virus file" do
let(:scan_result) { false }
it "renders the messagerie page with the invalid commentaire" do
expect { subject }.not_to change(Commentaire, :count)
it "creates a commentaire (shows message that file have a virus)" do
expect { subject }.to change(Commentaire, :count).by(1)
expect(gestionnaire.followed_dossiers).to include(dossier)
expect(response).to render_template :messagerie
expect(flash.alert).to be_present
expect(assigns(:commentaire).body).to eq("avant\napres")
expect(response).to redirect_to(messagerie_gestionnaire_dossier_path(dossier.procedure, dossier))
expect(flash.notice).to be_present
end
end
end

View file

@ -806,7 +806,7 @@ describe Users::DossiersController, type: :controller do
id: dossier.id,
commentaire: {
body: body,
file: file
piece_jointe: file
}
}
}
@ -822,18 +822,6 @@ describe Users::DossiersController, type: :controller do
expect(response).to redirect_to(messagerie_dossier_path(dossier))
expect(flash.notice).to be_present
end
context "when the commentaire creation fails" do
let(:scan_result) { false }
it "renders the messagerie page with the invalid commentaire" do
expect { subject }.not_to change(Commentaire, :count)
expect(response).to render_template :messagerie
expect(flash.alert).to be_present
expect(assigns(:commentaire).body).to eq("avant\napres")
end
end
end
describe '#ask_deletion' do

View file

@ -1,6 +1,8 @@
require 'spec_helper'
describe Users::ProfilController, type: :controller do
include ActiveJob::TestHelper
let(:user) { create(:user) }
before { sign_in(user) }
@ -34,13 +36,17 @@ describe Users::ProfilController, type: :controller do
end
context 'when the mail is already taken' do
let!(:user2) { create(:user) }
let(:existing_user) { create(:user) }
before do
patch :update_email, params: { user: { email: user2.email } }
perform_enqueued_jobs do
patch :update_email, params: { user: { email: existing_user.email } }
end
user.reload
end
it { expect(user.unconfirmed_email).to be_nil }
it { expect(ActionMailer::Base.deliveries.last.to).to eq([existing_user.email]) }
it { expect(response).to redirect_to(profil_path) }
it { expect(flash.notice).to eq(I18n.t('devise.registrations.update_needs_confirmation')) }
end

View file

@ -41,12 +41,12 @@ FactoryBot.define do
factory :champ_date, class: 'Champs::DateChamp' do
type_de_champ { create(:type_de_champ_date) }
value { 1.day.ago.iso8601 }
value { '2019-07-10' }
end
factory :champ_datetime, class: 'Champs::DatetimeChamp' do
type_de_champ { create(:type_de_champ_datetime) }
value { 1.day.ago.iso8601 }
value { '15/09/1962 15:35' }
end
factory :champ_number, class: 'Champs::NumberChamp' do
@ -96,17 +96,17 @@ FactoryBot.define do
factory :champ_drop_down_list, class: 'Champs::DropDownListChamp' do
type_de_champ { create(:type_de_champ_drop_down_list) }
value { '' }
value { 'choix 1' }
end
factory :champ_multiple_drop_down_list, class: 'Champs::MultipleDropDownListChamp' do
type_de_champ { create(:type_de_champ_multiple_drop_down_list) }
value { '' }
value { '["choix 1", "choix 2"]' }
end
factory :champ_linked_drop_down_list, class: 'Champs::LinkedDropDownListChamp' do
type_de_champ { create(:type_de_champ_linked_drop_down_list) }
value { '{}' }
value { '["categorie 1", "choix 1"]' }
end
factory :champ_pays, class: 'Champs::PaysChamp' do
@ -116,12 +116,12 @@ FactoryBot.define do
factory :champ_regions, class: 'Champs::RegionChamp' do
type_de_champ { create(:type_de_champ_regions) }
value { '' }
value { 'Guadeloupe' }
end
factory :champ_departements, class: 'Champs::DepartementChamp' do
type_de_champ { create(:type_de_champ_departements) }
value { '' }
value { '971 - Guadeloupe' }
end
factory :champ_engagement, class: 'Champs::EngagementChamp' do
@ -136,7 +136,7 @@ FactoryBot.define do
factory :champ_explication, class: 'Champs::ExplicationChamp' do
type_de_champ { create(:type_de_champ_explication) }
value { 'une explication' }
value { '' }
end
factory :champ_dossier_link, class: 'Champs::DossierLinkChamp' do
@ -164,5 +164,15 @@ FactoryBot.define do
factory :champ_repetition, class: 'Champs::RepetitionChamp' do
type_de_champ { create(:type_de_champ_repetition) }
after(:build) do |champ_repetition, _evaluator|
type_de_champ_text = create(:type_de_champ_text, order_place: 0, parent: champ_repetition.type_de_champ, libelle: 'Nom')
type_de_champ_number = create(:type_de_champ_number, order_place: 1, parent: champ_repetition.type_de_champ, libelle: 'Age')
create(:champ_text, row: 0, type_de_champ: type_de_champ_text, parent: champ_repetition)
create(:champ_number, row: 0, type_de_champ: type_de_champ_number, parent: champ_repetition)
create(:champ_text, row: 1, type_de_champ: type_de_champ_text, parent: champ_repetition)
create(:champ_number, row: 1, type_de_champ: type_de_champ_number, parent: champ_repetition)
end
end
end

View file

@ -7,5 +7,9 @@ FactoryBot.define do
commentaire.dossier = create :dossier, :en_construction
end
end
trait :with_file do
file { Rack::Test::UploadedFile.new("./spec/fixtures/files/logo_test_procedure.png", 'application/pdf') }
end
end
end

View file

@ -19,14 +19,15 @@ feature 'Changing an email' do
click_button 'Changer mon adresse'
end
user.reload
expect(user.email).to eq(old_email)
expect(user.unconfirmed_email).to eq(new_email)
expect(page).to have_content(I18n.t('devise.registrations.update_needs_confirmation'))
expect(page).to have_content(old_email)
expect(page).to have_content(new_email)
click_confirmation_link_for(new_email)
user.reload
expect(user.email).to eq(new_email)
expect(user.unconfirmed_email).to be_nil
expect(page).to have_content(I18n.t('devise.confirmations.confirmed'))
expect(page).not_to have_content(old_email)
expect(page).to have_content(new_email)
expect(user.reload.email).to eq(new_email)
end
end

View file

@ -0,0 +1,42 @@
describe '2019_05_29_migrate_commentaire_pj.rake' do
let(:rake_task) { Rake::Task['2019_05_29_migrate_commentaire_pj:run'] }
let!(:commentaires) do
create(:commentaire)
create(:commentaire, :with_file)
create(:commentaire, :with_file)
end
before do
Commentaire.all.each do |commentaire|
if commentaire.file.present?
stub_request(:get, commentaire.file_url)
.to_return(status: 200, body: File.read(commentaire.file.path))
end
end
end
after do
ENV['LIMIT'] = nil
rake_task.reenable
end
it 'should migrate pj' do
comment_updated_at = Commentaire.last.updated_at
dossier_updated_at = Commentaire.last.dossier.updated_at
expect(Commentaire.all.map(&:piece_jointe).map(&:attached?)).to eq([false, false, false])
rake_task.invoke
expect(Commentaire.where(file: nil).count).to eq(1)
expect(Commentaire.all.map(&:piece_jointe).map(&:attached?)).to eq([false, true, true])
expect(Commentaire.last.updated_at).to eq(comment_updated_at)
expect(Commentaire.last.dossier.updated_at).to eq(dossier_updated_at)
end
it 'should migrate pj within limit' do
expect(Commentaire.all.map(&:piece_jointe).map(&:attached?)).to eq([false, false, false])
ENV['LIMIT'] = '1'
rake_task.invoke
expect(Commentaire.where(file: nil).count).to eq(1)
expect(Commentaire.all.map(&:piece_jointe).map(&:attached?)).to eq([false, true, false])
end
end

View file

@ -3,6 +3,10 @@ class UserMailerPreview < ActionMailer::Preview
UserMailer.new_account_warning(user)
end
def account_already_taken
UserMailer.account_already_taken(user, 'dircab@territoires.gouv.fr')
end
private
def user

View file

@ -0,0 +1,21 @@
require "rails_helper"
RSpec.describe UserMailer, type: :mailer do
let(:user) { build(:user) }
describe '.new_account_warning' do
subject { described_class.new_account_warning(user) }
it { expect(subject.to).to eq([user.email]) }
it { expect(subject.body).to include(user.email) }
end
describe '.account_already_taken' do
let(:requested_email) { 'new@exemple.fr' }
subject { described_class.account_already_taken(user, requested_email) }
it { expect(subject.to).to eq([requested_email]) }
it { expect(subject.body).to include(requested_email) }
end
end

View file

@ -395,7 +395,7 @@ describe Champ do
describe "repetition" do
let(:dossier) { create(:dossier) }
let(:champ) { create(:champ_repetition, dossier: dossier) }
let(:champ) { Champs::RepetitionChamp.create(dossier: dossier) }
let(:champ_text) { create(:champ_text, row: 0) }
let(:champ_integer_number) { create(:champ_integer_number, row: 0) }
let(:champ_text_attrs) { attributes_for(:champ_text, row: 1) }

View file

@ -1,4 +1,4 @@
require 'spec_helper'
require 'rails_helper'
describe Dossier do
include ActiveJob::TestHelper
@ -31,7 +31,7 @@ describe Dossier do
let(:procedure) { create(:procedure, duree_conservation_dossiers_dans_ds: 6) }
let!(:young_dossier) { create(:dossier, procedure: procedure) }
let!(:expiring_dossier) { create(:dossier, :en_instruction, en_instruction_at: 170.days.ago, procedure: procedure) }
let!(:just_expired_dossier) { create(:dossier, :en_instruction, en_instruction_at: (6.months + 1.hour + 1.second).ago, procedure: procedure) }
let!(:just_expired_dossier) { create(:dossier, :en_instruction, en_instruction_at: (6.months + 1.hour + 10.seconds).ago, procedure: procedure) }
let!(:long_expired_dossier) { create(:dossier, :en_instruction, en_instruction_at: 1.year.ago, procedure: procedure) }
context 'with default delay to end of retention' do
@ -420,7 +420,6 @@ describe Dossier do
it "send an email when the dossier is created for the very first time" do
dossier = nil
ActiveJob::Base.queue_adapter = :test
expect do
perform_enqueued_jobs do
dossier = Dossier.create(procedure: procedure, state: Dossier.states.fetch(:brouillon), user: user)
@ -887,7 +886,7 @@ describe Dossier do
describe "#check_mandatory_champs" do
let(:procedure) { create(:procedure, :with_type_de_champ) }
let(:dossier) { create(:dossier, :with_all_champs, procedure: procedure) }
let(:dossier) { create(:dossier, procedure: procedure) }
it 'no mandatory champs' do
expect(dossier.check_mandatory_champs).to be_empty
@ -946,7 +945,11 @@ describe Dossier do
end
context "when no champs" do
let(:champ_with_error) { dossier.champs.first }
let(:champ_with_error) do
repetition_champ = dossier.champs.first
text_champ = repetition_champ.rows.first.first
text_champ
end
it 'should have errors' do
errors = dossier.check_mandatory_champs

View file

@ -41,7 +41,7 @@ describe DossierSerializer do
expect(subject[3][:value]).to eq(42)
expect(subject[4][:value]).to eq(42.1)
expect(subject[5][:value]).to eq({ primary: nil, secondary: nil })
expect(subject[5][:value]).to eq({ primary: 'categorie 1', secondary: 'choix 1' })
}
end
end

View file

@ -1,24 +1,21 @@
require 'spec_helper'
describe CommentaireService do
include ActiveJob::TestHelper
describe '.create' do
let(:dossier) { create :dossier, :en_construction }
let(:sender) { dossier.user }
let(:body) { 'Contenu du message.' }
let(:file) { nil }
let(:scan_result) { true }
subject(:commentaire) { CommentaireService.build(sender, dossier, { body: body, file: file }) }
before do
allow(ClamavService).to receive(:safe_file?).and_return(scan_result)
end
subject(:commentaire) { CommentaireService.build(sender, dossier, { body: body, piece_jointe: file }) }
it 'creates a new valid commentaire' do
expect(commentaire.email).to eq sender.email
expect(commentaire.dossier).to eq dossier
expect(commentaire.body).to eq 'Contenu du message.'
expect(commentaire.file).to be_blank
expect(commentaire.piece_jointe.attached?).to be_falsey
expect(commentaire).to be_valid
end
@ -34,14 +31,15 @@ describe CommentaireService do
context 'when it has a file' do
let(:file) { Rack::Test::UploadedFile.new("./spec/fixtures/files/piece_justificative_0.pdf", 'application/pdf') }
it 'saves the attached file' do
expect(commentaire.file).to be_present
expect(commentaire).to be_valid
before do
expect(ClamavService).to receive(:safe_file?).and_return(true)
end
context 'and a virus' do
let(:scan_result) { false }
it { expect(commentaire).not_to be_valid }
it 'saves the attached file' do
perform_enqueued_jobs do
commentaire.save
expect(commentaire.piece_jointe.attached?).to be_truthy
end
end
end
end

View file

@ -157,15 +157,6 @@ describe ProcedureExportV2Service do
context 'with repetitions' do
let!(:dossier) { create(:dossier, :en_instruction, :with_all_champs, :for_individual, procedure: procedure) }
let(:champ_repetition) { dossier.champs.find { |champ| champ.type_champ == 'repetition' } }
let(:type_de_champ_text) { create(:type_de_champ_text, order_place: 0, parent: champ_repetition.type_de_champ) }
let(:type_de_champ_number) { create(:type_de_champ_number, order_place: 1, parent: champ_repetition.type_de_champ) }
before do
create(:champ_text, row: 0, type_de_champ: type_de_champ_text, parent: champ_repetition)
create(:champ_number, row: 0, type_de_champ: type_de_champ_number, parent: champ_repetition)
create(:champ_text, row: 1, type_de_champ: type_de_champ_text, parent: champ_repetition)
create(:champ_number, row: 1, type_de_champ: type_de_champ_number, parent: champ_repetition)
end
it 'should have sheets' do
expect(subject.sheets.map(&:name)).to eq(['Dossiers', 'Etablissements', 'Avis', champ_repetition.libelle])
@ -175,8 +166,8 @@ describe ProcedureExportV2Service do
expect(repetition_sheet.headers).to eq([
"Dossier ID",
"Ligne",
type_de_champ_text.libelle,
type_de_champ_number.libelle
"Nom",
"Age"
])
end

View file

@ -1,5 +1,5 @@
describe 'users/dossiers/dossier_actions.html.haml', type: :view do
let(:procedure) { create(:procedure, :published, expects_multiple_submissions: true) }
let(:procedure) { create(:procedure, :published) }
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
subject { render 'users/dossiers/dossier_actions.html.haml', dossier: dossier }
@ -12,18 +12,13 @@ describe 'users/dossiers/dossier_actions.html.haml', type: :view do
it { is_expected.not_to have_link('Supprimer le dossier') }
end
context 'when the procedure doesnt expect multiple submissions' do
let(:procedure) { create(:procedure, :published, expects_multiple_submissions: false) }
it { is_expected.not_to have_link('Commencer un autre dossier') }
end
context 'when the procedure is closed' do
let(:procedure) { create(:procedure, :archived, expects_multiple_submissions: true) }
let(:procedure) { create(:procedure, :archived) }
it { is_expected.not_to have_link('Commencer un autre dossier') }
end
context 'when there are no actions to display' do
let(:procedure) { create(:procedure, :published, expects_multiple_submissions: false) }
let(:procedure) { create(:procedure, :archived) }
let(:dossier) { create(:dossier, :accepte, procedure: procedure) }
it 'doesnt render the menu at all' do