From 09efd06dffab53884fb4f399d49deeb32a5bd930 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Mon, 15 Jul 2019 17:55:22 +0200 Subject: [PATCH 01/26] forms: add a focus indicator to focused fields --- app/assets/stylesheets/new_design/forms.scss | 30 +++++++++++--------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/app/assets/stylesheets/new_design/forms.scss b/app/assets/stylesheets/new_design/forms.scss index 00fc6984c..5cd2d9590 100644 --- a/app/assets/stylesheets/new_design/forms.scss +++ b/app/assets/stylesheets/new_design/forms.scss @@ -145,12 +145,27 @@ border: solid 1px $border-grey; padding: $default-padding; + &.small { + padding: $default-padding / 2; + } + &:disabled { background-color: $border-grey; } - &.small { - padding: $default-padding / 2; + &:focus { + border: 1px solid $blue; + box-shadow: 0px 0px 2px 1px $blue; + } + + // Hide the browser default invalidity indicator until the field is touched + &:invalid:not(:focus) { + box-shadow: none; + } + + &.touched:invalid { + border: 1px solid $dark-red; + box-shadow: 0px 0px 2px 1px $dark-red; } } @@ -188,17 +203,6 @@ max-width: 180px; } - input:invalid, - textarea:invalid { - box-shadow: none; - } - - input.touched:invalid, - textarea.touched:invalid { - border: 1px solid $dark-red; - box-shadow: 0px 0px 5px $dark-red; - } - select, .select2-selection { // hack found here: https://stackoverflow.com/questions/1895476/how-to-style-a-select-dropdown-with-css-only-without-javascript From 92dd91a31b89412cd53be421d34f9067fe3ad80e Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Tue, 16 Jul 2019 10:11:24 +0000 Subject: [PATCH 02/26] messagerie: add a reply button next to the latest message --- app/assets/images/icons/reply.svg | 1 + app/assets/stylesheets/new_design/icons.scss | 4 ++++ .../stylesheets/new_design/message.scss | 4 ++++ app/helpers/messagerie_helper.rb | 9 ++++++++ .../gestionnaires/dossiers/print.html.haml | 2 +- app/views/root/patron.html.haml | 1 + .../shared/dossiers/_messagerie.html.haml | 2 +- .../dossiers/messages/_message.html.haml | 22 ++++++++++++------- .../dossiers/show/_latest_message.html.haml | 2 +- .../messages/message.html.haml_spec.rb | 4 +++- 10 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 app/assets/images/icons/reply.svg create mode 100644 app/helpers/messagerie_helper.rb diff --git a/app/assets/images/icons/reply.svg b/app/assets/images/icons/reply.svg new file mode 100644 index 000000000..d2de6d058 --- /dev/null +++ b/app/assets/images/icons/reply.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/stylesheets/new_design/icons.scss b/app/assets/stylesheets/new_design/icons.scss index 19c858ac7..20a290c7d 100644 --- a/app/assets/stylesheets/new_design/icons.scss +++ b/app/assets/stylesheets/new_design/icons.scss @@ -91,6 +91,10 @@ background-image: image-url("icons/mail.svg"); } + &.reply { + background-image: image-url("icons/reply.svg"); + } + &.search { background-image: image-url("icons/search-blue.svg"); } diff --git a/app/assets/stylesheets/new_design/message.scss b/app/assets/stylesheets/new_design/message.scss index 7c87e763e..4edc672ac 100644 --- a/app/assets/stylesheets/new_design/message.scss +++ b/app/assets/stylesheets/new_design/message.scss @@ -38,4 +38,8 @@ .attachment-link { margin-top: $default-spacer; } + + .message-answer-button { + margin-left: auto; + } } diff --git a/app/helpers/messagerie_helper.rb b/app/helpers/messagerie_helper.rb new file mode 100644 index 000000000..cfea65b62 --- /dev/null +++ b/app/helpers/messagerie_helper.rb @@ -0,0 +1,9 @@ +module MessagerieHelper + def show_reply_button(commentaire, connected_user) + commentaire.dossier.present? && + commentaire.dossier.messagerie_available? && + commentaire.dossier.user == connected_user && + !commentaire.sent_by?(connected_user) && + commentaire.dossier.commentaires.last == commentaire + end +end diff --git a/app/views/gestionnaires/dossiers/print.html.haml b/app/views/gestionnaires/dossiers/print.html.haml index e41192349..acacdad2d 100644 --- a/app/views/gestionnaires/dossiers/print.html.haml +++ b/app/views/gestionnaires/dossiers/print.html.haml @@ -63,7 +63,7 @@ %ul.messages-list - @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 } + = render partial: "shared/dossiers/messages/message", locals: { commentaire: commentaire, connected_user: current_gestionnaire, messagerie_seen_at: nil, show_reply_button: false } %script{ type: "text/javascript" } window.print(); diff --git a/app/views/root/patron.html.haml b/app/views/root/patron.html.haml index fa905ce27..dcb3462bd 100644 --- a/app/views/root/patron.html.haml +++ b/app/views/root/patron.html.haml @@ -21,6 +21,7 @@ %span.icon.person %span.icon.super-admin %span.icon.mail + %span.icon.reply %span.icon.search %span.icon.sign-out %span.icon.info diff --git a/app/views/shared/dossiers/_messagerie.html.haml b/app/views/shared/dossiers/_messagerie.html.haml index 123b5f510..abc4c3707 100644 --- a/app/views/shared/dossiers/_messagerie.html.haml +++ b/app/views/shared/dossiers/_messagerie.html.haml @@ -2,7 +2,7 @@ %ul.messages-list - 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 } + = render partial: "shared/dossiers/messages/message", locals: { commentaire: commentaire, connected_user: connected_user, messagerie_seen_at: messagerie_seen_at, show_reply_button: show_reply_button(commentaire, connected_user) } - if dossier.messagerie_available? = render partial: "shared/dossiers/messages/form", locals: { commentaire: new_commentaire, form_url: form_url } diff --git a/app/views/shared/dossiers/messages/_message.html.haml b/app/views/shared/dossiers/messages/_message.html.haml index 4ccfa7707..0c1dc7bb8 100644 --- a/app/views/shared/dossiers/messages/_message.html.haml +++ b/app/views/shared/dossiers/messages/_message.html.haml @@ -10,11 +10,17 @@ = commentaire_date(commentaire) .rich-text= sanitize(simple_format(commentaire.body)) - - 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 - = commentaire.file_identifier + .message-extras.flex.justify-start + - 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 + = commentaire.file_identifier + + - if show_reply_button + = button_tag type: 'button', class: 'button small message-answer-button', onclick: 'document.querySelector("#commentaire_body").focus()' do + %span.icon.reply + Répondre diff --git a/app/views/users/dossiers/show/_latest_message.html.haml b/app/views/users/dossiers/show/_latest_message.html.haml index 255e79696..fa86d6a8b 100644 --- a/app/views/users/dossiers/show/_latest_message.html.haml +++ b/app/views/users/dossiers/show/_latest_message.html.haml @@ -4,6 +4,6 @@ %h3.tab-title Dernier message .message.inverted-background - = render partial: "shared/dossiers/messages/message", locals: { commentaire: latest_message, connected_user: current_user, messagerie_seen_at: nil } + = render partial: "shared/dossiers/messages/message", locals: { commentaire: latest_message, connected_user: current_user, messagerie_seen_at: nil, show_reply_button: false } = link_to commentaire_answer_action(latest_message, current_user), messagerie_dossier_url(dossier, anchor: 'new_commentaire'), class: 'button send' diff --git a/spec/views/shared/dossiers/messages/message.html.haml_spec.rb b/spec/views/shared/dossiers/messages/message.html.haml_spec.rb index 725fdf50c..e5674ae6b 100644 --- a/spec/views/shared/dossiers/messages/message.html.haml_spec.rb +++ b/spec/views/shared/dossiers/messages/message.html.haml_spec.rb @@ -1,12 +1,14 @@ describe 'shared/dossiers/messages/message.html.haml', type: :view do before { view.extend DossierHelper } - subject { render 'shared/dossiers/messages/message.html.haml', commentaire: commentaire, messagerie_seen_at: seen_at, connected_user: dossier.user } + subject { render 'shared/dossiers/messages/message.html.haml', commentaire: commentaire, messagerie_seen_at: seen_at, connected_user: dossier.user, show_reply_button: true } let(:dossier) { create(:dossier, :en_construction) } let(:commentaire) { create(:commentaire, dossier: dossier) } let(:seen_at) { commentaire.created_at + 1.hour } + it { is_expected.to have_button("Répondre") } + context "with a seen_at after commentaire created_at" do let(:seen_at) { commentaire.created_at + 1.hour } From b4fe6e236e9147041a295f09ad9b0ddc65a33f1b Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Tue, 16 Jul 2019 12:15:50 +0200 Subject: [PATCH 03/26] messagerie: improve the textarea placeholder --- app/views/shared/dossiers/messages/_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/dossiers/messages/_form.html.haml b/app/views/shared/dossiers/messages/_form.html.haml index 594bec357..30a598ff9 100644 --- a/app/views/shared/dossiers/messages/_form.html.haml +++ b/app/views/shared/dossiers/messages/_form.html.haml @@ -1,5 +1,5 @@ = form_for(commentaire, url: form_url, html: { class: 'form' }) do |f| - = f.text_area :body, rows: 5, placeholder: 'Répondre ici', required: true, class: 'message-textarea' + = f.text_area :body, rows: 5, placeholder: 'Écrivez votre message à l’administration ici', required: true, class: 'message-textarea' .flex.justify-between.wrap %div = f.file_field :piece_jointe, id: 'piece_jointe', direct_upload: true From d86030fb767d0153d42990dd25dab1bce7861951 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Tue, 16 Jul 2019 12:24:16 +0200 Subject: [PATCH 04/26] dossier: add a reply icon near to "Reply to message" button --- app/views/users/dossiers/show/_latest_message.html.haml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/users/dossiers/show/_latest_message.html.haml b/app/views/users/dossiers/show/_latest_message.html.haml index fa86d6a8b..a35d6547a 100644 --- a/app/views/users/dossiers/show/_latest_message.html.haml +++ b/app/views/users/dossiers/show/_latest_message.html.haml @@ -6,4 +6,6 @@ .message.inverted-background = render partial: "shared/dossiers/messages/message", locals: { commentaire: latest_message, connected_user: current_user, messagerie_seen_at: nil, show_reply_button: false } - = link_to commentaire_answer_action(latest_message, current_user), messagerie_dossier_url(dossier, anchor: 'new_commentaire'), class: 'button send' + = link_to messagerie_dossier_url(dossier, anchor: 'new_commentaire'), class: 'button send' do + %span.icon.reply + = commentaire_answer_action(latest_message, current_user) From b8fa567c81b3096a95b98dd7d79b1d4c4e9076df Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Mon, 15 Jul 2019 20:51:03 +0200 Subject: [PATCH 05/26] ajout du tag 'lien document justificatif' --- .../concerns/tags_substitution_concern.rb | 20 ++++--- .../concern/mail_template_concern_spec.rb | 57 ++++++++++++++++++- 2 files changed, 69 insertions(+), 8 deletions(-) diff --git a/app/models/concerns/tags_substitution_concern.rb b/app/models/concerns/tags_substitution_concern.rb index 6be66c76a..0d3c0cc6e 100644 --- a/app/models/concerns/tags_substitution_concern.rb +++ b/app/models/concerns/tags_substitution_concern.rb @@ -59,14 +59,20 @@ module TagsSubstitutionConcern { libelle: 'lien attestation', description: '', - lambda: -> (d) { - links = [external_link(attestation_dossier_url(d))] - if d.justificatif_motivation.attached? - links.push external_link("Télécharger le justificatif", url_for_justificatif_motivation(d)) - end - links.join "
\n" - }, + lambda: -> (d) { external_link(attestation_dossier_url(d)) }, available_for_states: [Dossier.states.fetch(:accepte)] + }, + { + libelle: 'lien document justificatif', + description: '', + lambda: -> (d) { + if d.justificatif_motivation.attached? + external_link(url_for_justificatif_motivation(d), "Télécharger le document justificatif") + else + return "[l'instructeur n'a pas joint de document supplémentaire]" + end + }, + available_for_states: Dossier::SOUMIS } ] diff --git a/spec/models/concern/mail_template_concern_spec.rb b/spec/models/concern/mail_template_concern_spec.rb index 2598aa46a..6ebdc4c7a 100644 --- a/spec/models/concern/mail_template_concern_spec.rb +++ b/spec/models/concern/mail_template_concern_spec.rb @@ -89,7 +89,7 @@ describe MailTemplateConcern do it { expect(dossier.justificatif_motivation).to be_attached } it { is_expected.to include("http://localhost:3000/dossiers/#{dossier.id}/attestation") } - it { is_expected.to include("Télécharger le justificatif") } + it { is_expected.to_not include("Télécharger le justificatif") } end describe "in refuse mail" do @@ -104,6 +104,61 @@ describe MailTemplateConcern do it { is_expected.to eq("--lien attestation--") } end end + + describe '--lien document justificatif--' do + let(:procedure) { create(:procedure) } + + subject { mail.body_for_dossier(dossier) } + + before do + mail.body = "--lien document justificatif--" + end + + describe "in closed mail" do + let(:mail) { create(:closed_mail, procedure: procedure) } + describe 'without justificatif' do + it { is_expected.to include("[l'instructeur n'a pas joint de document supplémentaire]") } + end + + describe 'with justificatif' do + before do + dossier.justificatif_motivation.attach(justificatif) + end + it { expect(dossier.justificatif_motivation).to be_attached } + it { is_expected.to include("Télécharger le document justificatif") } + end + end + + describe "in refused mail" do + let(:mail) { create(:refused_mail, procedure: procedure) } + describe 'without justificatif' do + it { is_expected.to include("[l'instructeur n'a pas joint de document supplémentaire]") } + end + + describe 'with justificatif' do + before do + dossier.justificatif_motivation.attach(justificatif) + end + it { expect(dossier.justificatif_motivation).to be_attached } + it { is_expected.to include("Télécharger le document justificatif") } + end + end + + describe "in without continuation mail" do + let(:mail) { create(:without_continuation_mail, procedure: procedure) } + describe 'without justificatif' do + it { is_expected.to include("[l'instructeur n'a pas joint de document supplémentaire]") } + end + + describe 'with justificatif' do + before do + dossier.justificatif_motivation.attach(justificatif) + end + it { expect(dossier.justificatif_motivation).to be_attached } + it { is_expected.to include("Télécharger le document justificatif") } + end + end + end end describe '#replace_tags' do From 7eeddc0b79fe54eccb5965c99c544f8fdfc068c9 Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Tue, 16 Jul 2019 12:14:07 +0200 Subject: [PATCH 06/26] using a shared example + scoped to state TERMINE --- .../concerns/tags_substitution_concern.rb | 2 +- .../concern/mail_template_concern_spec.rb | 60 +++++++------------ 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/app/models/concerns/tags_substitution_concern.rb b/app/models/concerns/tags_substitution_concern.rb index 0d3c0cc6e..537cd46ba 100644 --- a/app/models/concerns/tags_substitution_concern.rb +++ b/app/models/concerns/tags_substitution_concern.rb @@ -72,7 +72,7 @@ module TagsSubstitutionConcern return "[l'instructeur n'a pas joint de document supplémentaire]" end }, - available_for_states: Dossier::SOUMIS + available_for_states: Dossier::TERMINE } ] diff --git a/spec/models/concern/mail_template_concern_spec.rb b/spec/models/concern/mail_template_concern_spec.rb index 6ebdc4c7a..18deda804 100644 --- a/spec/models/concern/mail_template_concern_spec.rb +++ b/spec/models/concern/mail_template_concern_spec.rb @@ -105,7 +105,7 @@ describe MailTemplateConcern do end end - describe '--lien document justificatif--' do + shared_examples 'inserting the --lien document justificatif-- tag' do let(:procedure) { create(:procedure) } subject { mail.body_for_dossier(dossier) } @@ -114,50 +114,32 @@ describe MailTemplateConcern do mail.body = "--lien document justificatif--" end - describe "in closed mail" do - let(:mail) { create(:closed_mail, procedure: procedure) } - describe 'without justificatif' do - it { is_expected.to include("[l'instructeur n'a pas joint de document supplémentaire]") } - end - - describe 'with justificatif' do - before do - dossier.justificatif_motivation.attach(justificatif) - end - it { expect(dossier.justificatif_motivation).to be_attached } - it { is_expected.to include("Télécharger le document justificatif") } - end + describe 'without justificatif' do + it { is_expected.to include("[l'instructeur n'a pas joint de document supplémentaire]") } end - describe "in refused mail" do - let(:mail) { create(:refused_mail, procedure: procedure) } - describe 'without justificatif' do - it { is_expected.to include("[l'instructeur n'a pas joint de document supplémentaire]") } - end - - describe 'with justificatif' do - before do - dossier.justificatif_motivation.attach(justificatif) - end - it { expect(dossier.justificatif_motivation).to be_attached } - it { is_expected.to include("Télécharger le document justificatif") } + describe 'with justificatif' do + before do + dossier.justificatif_motivation.attach(justificatif) end + it { expect(dossier.justificatif_motivation).to be_attached } + it { is_expected.to include("Télécharger le document justificatif") } end + end - describe "in without continuation mail" do - let(:mail) { create(:without_continuation_mail, procedure: procedure) } - describe 'without justificatif' do - it { is_expected.to include("[l'instructeur n'a pas joint de document supplémentaire]") } - end + context 'in closed mail' do + let(:mail) { create(:closed_mail, procedure: procedure) } + it_behaves_like 'inserting the --lien document justificatif-- tag' + end - describe 'with justificatif' do - before do - dossier.justificatif_motivation.attach(justificatif) - end - it { expect(dossier.justificatif_motivation).to be_attached } - it { is_expected.to include("Télécharger le document justificatif") } - end - end + context 'in refused mail' do + let(:mail) { create(:refused_mail, procedure: procedure) } + it_behaves_like 'inserting the --lien document justificatif-- tag' + end + + context 'in without continuation mail' do + let(:mail) { create(:without_continuation_mail, procedure: procedure) } + it_behaves_like 'inserting the --lien document justificatif-- tag' end end From 5bafda661951fa027970e3002c94000badf0f468 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 14:24:48 +0200 Subject: [PATCH 07/26] factories: fix unmatching MIME type in fixtures --- spec/factories/commentaire.rb | 2 +- spec/factories/procedure.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/factories/commentaire.rb b/spec/factories/commentaire.rb index dc092a50d..360a4b05e 100644 --- a/spec/factories/commentaire.rb +++ b/spec/factories/commentaire.rb @@ -9,7 +9,7 @@ FactoryBot.define do end trait :with_file do - file { Rack::Test::UploadedFile.new("./spec/fixtures/files/logo_test_procedure.png", 'application/pdf') } + file { Rack::Test::UploadedFile.new("./spec/fixtures/files/logo_test_procedure.png", 'image/png') } end end end diff --git a/spec/factories/procedure.rb b/spec/factories/procedure.rb index 8c62169b3..2e5bd901d 100644 --- a/spec/factories/procedure.rb +++ b/spec/factories/procedure.rb @@ -42,7 +42,7 @@ FactoryBot.define do end trait :with_logo do - logo { Rack::Test::UploadedFile.new("./spec/fixtures/files/logo_test_procedure.png", 'application/pdf') } + logo { Rack::Test::UploadedFile.new("./spec/fixtures/files/logo_test_procedure.png", 'image/png') } end trait :with_path do From 44574b2b93f726e8e03ab9f93a9efcbbaeb9c4a2 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 14:40:17 +0200 Subject: [PATCH 08/26] mailer_preview: improve data used for generating previews --- .../previews/dossier_mailer_preview.rb | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/spec/mailers/previews/dossier_mailer_preview.rb b/spec/mailers/previews/dossier_mailer_preview.rb index d34d4f0e6..8ac4eab87 100644 --- a/spec/mailers/previews/dossier_mailer_preview.rb +++ b/spec/mailers/previews/dossier_mailer_preview.rb @@ -1,7 +1,7 @@ # Preview all emails at http://localhost:3000/rails/mailers/dossier_mailer class DossierMailerPreview < ActionMailer::Preview def notify_new_draft - DossierMailer.notify_new_draft(dossier) + DossierMailer.notify_new_draft(draft) end def notify_new_answer @@ -26,11 +26,24 @@ class DossierMailerPreview < ActionMailer::Preview DeletedDossier.new(dossier_id: 1, procedure: procedure) end + def draft + Dossier.new(id: 47882, procedure: procedure, user: User.new(email: "usager@example.com")) + end + def dossier - Dossier.new(id: 1, procedure: procedure, user: User.new(email: "usager@example.com")) + Dossier.new(id: 47882, state: :en_instruction, procedure: procedure, user: User.new(email: "usager@example.com")) end def procedure - Procedure.new(libelle: 'Démarche pour des marches') + Procedure.new(libelle: 'Dotation d’Équipement des Territoires Ruraux - Exercice 2019', service: service, logo: Rack::Test::UploadedFile.new("./spec/fixtures/files/logo_test_procedure.png", 'image/png')) + end + + def service + Service.new( + nom: 'Direction du Territoire des Vosges', + email: 'prms@ddt.vosges.gouv.fr', + telephone: '01 34 22 33 85', + horaires: 'Du lundi au vendredi, de 9 h à 18 h' + ) end end From bd39eb345358d72896db4f40e21f40286aa6c5ea Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 13:39:17 +0200 Subject: [PATCH 09/26] emails: remove dead code --- app/mailers/dossier_mailer.rb | 9 -------- .../notify_unmigrated_to_user.html.haml | 22 ------------------- 2 files changed, 31 deletions(-) delete mode 100644 app/views/dossier_mailer/notify_unmigrated_to_user.html.haml diff --git a/app/mailers/dossier_mailer.rb b/app/mailers/dossier_mailer.rb index a26caff85..7182c95e2 100644 --- a/app/mailers/dossier_mailer.rb +++ b/app/mailers/dossier_mailer.rb @@ -47,15 +47,6 @@ class DossierMailer < ApplicationMailer mail(to: dossier.user.email, subject: @subject) end - def notify_unmigrated_to_user(dossier, new_procedure) - @dossier = dossier - @dossier_kind = dossier.brouillon? ? 'brouillon' : 'dossier' - @subject = "Changement de procédure pour votre #{@dossier_kind} n° #{@dossier.id}" - @new_procedure = new_procedure - - mail(to: dossier.user.email, subject: @subject) - end - def notify_revert_to_instruction(dossier) @dossier = dossier @subject = "Votre dossier n° #{@dossier.id} est en train d'être réexaminé" diff --git a/app/views/dossier_mailer/notify_unmigrated_to_user.html.haml b/app/views/dossier_mailer/notify_unmigrated_to_user.html.haml deleted file mode 100644 index 438f68252..000000000 --- a/app/views/dossier_mailer/notify_unmigrated_to_user.html.haml +++ /dev/null @@ -1,22 +0,0 @@ -- content_for(:title, @subject) - -%h1 Bonjour, - -%p - Vous avez commencé un #{@dossier_kind}, - = link_to("n° #{@dossier.id}", dossier_url(@dossier)) - sur la procédure « #{@dossier.procedure.libelle} ». - En raison d’un changement dans la procédure, votre #{@dossier_kind} a été inaccessible pendant quelques jours. - L’accès est à présent à nouveau possible. - -%p - Malheureusement, en raison des changements dans le procédure, vous ne pourrez pas mener à terme le #{@dossier_kind} commencé. - Si votre démarche est toujours d’actualité, nous vous invitons à la recommencer sur - = link_to("la nouvelle procédure", commencer_url(@new_procedure.path)) - \. - -%p - Nous avons pris des mesures pour nous assurer qu’un tel désagrément ne se reproduise pas, - et vous présentons nos excuses pour la gène occasionnée. - -= render partial: "layouts/mailers/signature" From bc42c90fe53eeb2c150efa6a190f4474b514db5d Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 13:15:07 +0200 Subject: [PATCH 10/26] emails: make signature more compact --- app/views/layouts/mailers/_signature.html.haml | 5 ++--- app/views/notification_mailer/_signature.html.haml | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/views/layouts/mailers/_signature.html.haml b/app/views/layouts/mailers/_signature.html.haml index ea217a250..ca5ad2778 100644 --- a/app/views/layouts/mailers/_signature.html.haml +++ b/app/views/layouts/mailers/_signature.html.haml @@ -1,5 +1,4 @@ %p Bonne journée, - -%p - L'équipe demarches-simplifiees.fr + %br + L’équipe demarches-simplifiees.fr diff --git a/app/views/notification_mailer/_signature.html.haml b/app/views/notification_mailer/_signature.html.haml index 132bfafa4..9aef6f966 100644 --- a/app/views/notification_mailer/_signature.html.haml +++ b/app/views/notification_mailer/_signature.html.haml @@ -1,4 +1,4 @@ %p Bonne journée, - -%p --nom du service-- + %br + \ --nom du service-- From 71dfb3878765de806dfeedcb6eee6fdeb0599ec6 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 13:42:14 +0200 Subject: [PATCH 11/26] emails: improve typography of titles --- app/mailers/dossier_mailer.rb | 12 ++++++------ spec/mailers/dossier_mailer_spec.rb | 6 +++--- spec/models/dossier_spec.rb | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/mailers/dossier_mailer.rb b/app/mailers/dossier_mailer.rb index 7182c95e2..37f92f447 100644 --- a/app/mailers/dossier_mailer.rb +++ b/app/mailers/dossier_mailer.rb @@ -4,7 +4,7 @@ class DossierMailer < ApplicationMailer def notify_new_draft(dossier) @dossier = dossier - subject = "Retrouvez votre brouillon pour la démarche \"#{dossier.procedure.libelle}\"" + subject = "Retrouvez votre brouillon pour la démarche « #{dossier.procedure.libelle} »" mail(to: dossier.user.email, subject: subject) end @@ -20,21 +20,21 @@ class DossierMailer < ApplicationMailer def notify_deletion_to_user(deleted_dossier, to_email) @deleted_dossier = deleted_dossier - subject = "Votre dossier n° #{@deleted_dossier.dossier_id} a bien été supprimé" + subject = "Votre dossier nº #{@deleted_dossier.dossier_id} a bien été supprimé" mail(to: to_email, subject: subject) end def notify_deletion_to_administration(deleted_dossier, to_email) @deleted_dossier = deleted_dossier - subject = "Le dossier n° #{@deleted_dossier.dossier_id} a été supprimé à la demande de l'usager" + subject = "Le dossier nº #{@deleted_dossier.dossier_id} a été supprimé à la demande de l'usager" mail(to: to_email, subject: subject) end def notify_unhide_to_user(dossier) @dossier = dossier - subject = "Votre dossier n° #{@dossier.id} n'a pas pu être supprimé" + subject = "Votre dossier nº #{@dossier.id} n'a pas pu être supprimé" mail(to: dossier.user.email, subject: subject) end @@ -42,14 +42,14 @@ class DossierMailer < ApplicationMailer def notify_undelete_to_user(dossier) @dossier = dossier @dossier_kind = dossier.brouillon? ? 'brouillon' : 'dossier' - @subject = "Votre #{@dossier_kind} n° #{@dossier.id} est à nouveau accessible" + @subject = "Votre #{@dossier_kind} nº #{@dossier.id} est à nouveau accessible" mail(to: dossier.user.email, subject: @subject) end def notify_revert_to_instruction(dossier) @dossier = dossier - @subject = "Votre dossier n° #{@dossier.id} est en train d'être réexaminé" + @subject = "Votre dossier nº #{@dossier.id} est en train d'être réexaminé" mail(to: dossier.user.email, subject: @subject) end diff --git a/spec/mailers/dossier_mailer_spec.rb b/spec/mailers/dossier_mailer_spec.rb index eaec0fc93..626d1513b 100644 --- a/spec/mailers/dossier_mailer_spec.rb +++ b/spec/mailers/dossier_mailer_spec.rb @@ -29,7 +29,7 @@ RSpec.describe DossierMailer, type: :mailer do subject { described_class.notify_deletion_to_user(deleted_dossier, to_email) } - it { expect(subject.subject).to eq("Votre dossier n° #{deleted_dossier.dossier_id} a bien été supprimé") } + it { expect(subject.subject).to eq("Votre dossier nº #{deleted_dossier.dossier_id} a bien été supprimé") } it { expect(subject.body).to include("Votre dossier") } it { expect(subject.body).to include(deleted_dossier.dossier_id) } it { expect(subject.body).to include("a bien été supprimé") } @@ -41,7 +41,7 @@ RSpec.describe DossierMailer, type: :mailer do subject { described_class.notify_deletion_to_administration(deleted_dossier, to_email) } - it { expect(subject.subject).to eq("Le dossier n° #{deleted_dossier.dossier_id} a été supprimé à la demande de l'usager") } + it { expect(subject.subject).to eq("Le dossier nº #{deleted_dossier.dossier_id} a été supprimé à la demande de l'usager") } it { expect(subject.body).to include("À la demande de l'usager") } it { expect(subject.body).to include(deleted_dossier.dossier_id) } it { expect(subject.body).to include(deleted_dossier.procedure.libelle) } @@ -52,7 +52,7 @@ RSpec.describe DossierMailer, type: :mailer do subject { described_class.notify_unhide_to_user(dossier) } - it { expect(subject.subject).to eq("Votre dossier n° #{dossier.id} n'a pas pu être supprimé") } + it { expect(subject.subject).to eq("Votre dossier nº #{dossier.id} n'a pas pu être supprimé") } it { expect(subject.body).to include(dossier.id) } it { expect(subject.body).to include("n'a pas pu être supprimé") } it { expect(subject.body).to include(dossier.procedure.libelle) } diff --git a/spec/models/dossier_spec.rb b/spec/models/dossier_spec.rb index 312e5d9ab..8a5edc1d3 100644 --- a/spec/models/dossier_spec.rb +++ b/spec/models/dossier_spec.rb @@ -449,7 +449,7 @@ describe Dossier do end.to change(ActionMailer::Base.deliveries, :size).from(0).to(1) mail = ActionMailer::Base.deliveries.last - expect(mail.subject).to eq("Retrouvez votre brouillon pour la démarche \"#{procedure.libelle}\"") + expect(mail.subject).to eq("Retrouvez votre brouillon pour la démarche « #{procedure.libelle} »") expect(mail.html_part.body).to include(dossier_url(dossier)) end From 727702ad4be350856ea301c357f350a5a3693fa3 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 13:42:51 +0200 Subject: [PATCH 12/26] emails: mention the procedure name in the email title --- app/mailers/dossier_mailer.rb | 2 +- app/models/mails/closed_mail.rb | 2 +- app/models/mails/initiated_mail.rb | 2 +- app/models/mails/received_mail.rb | 2 +- app/models/mails/refused_mail.rb | 2 +- app/models/mails/without_continuation_mail.rb | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/mailers/dossier_mailer.rb b/app/mailers/dossier_mailer.rb index 37f92f447..c07fed240 100644 --- a/app/mailers/dossier_mailer.rb +++ b/app/mailers/dossier_mailer.rb @@ -11,7 +11,7 @@ class DossierMailer < ApplicationMailer def notify_new_answer(dossier) @dossier = dossier - subject = "Nouveau message pour votre dossier nº #{dossier.id}" + subject = "Nouveau message pour votre dossier nº #{dossier.id} (#{dossier.procedure.libelle})" mail(to: dossier.user.email, subject: subject) do |format| format.html { render layout: 'mailers/notification' } diff --git a/app/models/mails/closed_mail.rb b/app/models/mails/closed_mail.rb index 1c954c9f0..a0245bac6 100644 --- a/app/models/mails/closed_mail.rb +++ b/app/models/mails/closed_mail.rb @@ -6,7 +6,7 @@ module Mails SLUG = "closed_mail" DISPLAYED_NAME = "Accusé d'acceptation" - DEFAULT_SUBJECT = 'Votre dossier demarches-simplifiees.fr nº --numéro du dossier-- a été accepté' + DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- a été accepté (--libellé démarche--)' DOSSIER_STATE = Dossier.states.fetch(:accepte) def self.default_template_name_for_procedure(procedure) diff --git a/app/models/mails/initiated_mail.rb b/app/models/mails/initiated_mail.rb index ab438e023..fc32ae5da 100644 --- a/app/models/mails/initiated_mail.rb +++ b/app/models/mails/initiated_mail.rb @@ -7,7 +7,7 @@ module Mails SLUG = "initiated_mail" DEFAULT_TEMPLATE_NAME = "notification_mailer/initiated_mail" DISPLAYED_NAME = 'Accusé de réception' - DEFAULT_SUBJECT = 'Votre dossier demarches-simplifiees.fr nº --numéro du dossier-- a bien été reçu' + DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- a bien été reçu (--libellé démarche--)' DOSSIER_STATE = Dossier.states.fetch(:en_construction) end end diff --git a/app/models/mails/received_mail.rb b/app/models/mails/received_mail.rb index 59832b9dd..5cb3258e1 100644 --- a/app/models/mails/received_mail.rb +++ b/app/models/mails/received_mail.rb @@ -7,7 +7,7 @@ module Mails SLUG = "received_mail" DEFAULT_TEMPLATE_NAME = "notification_mailer/received_mail" DISPLAYED_NAME = 'Accusé de passage en instruction' - DEFAULT_SUBJECT = 'Votre dossier demarches-simplifiees.fr nº --numéro du dossier-- va être instruit' + DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- va être instruit (--libellé démarche--)' DOSSIER_STATE = Dossier.states.fetch(:en_instruction) end end diff --git a/app/models/mails/refused_mail.rb b/app/models/mails/refused_mail.rb index 19d66db10..d4b4d25db 100644 --- a/app/models/mails/refused_mail.rb +++ b/app/models/mails/refused_mail.rb @@ -7,7 +7,7 @@ module Mails SLUG = "refused_mail" DEFAULT_TEMPLATE_NAME = "notification_mailer/refused_mail" DISPLAYED_NAME = 'Accusé de rejet du dossier' - DEFAULT_SUBJECT = 'Votre dossier demarches-simplifiees.fr nº --numéro du dossier-- a été refusé' + DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- a été refusé (--libellé démarche--)' DOSSIER_STATE = Dossier.states.fetch(:refuse) end end diff --git a/app/models/mails/without_continuation_mail.rb b/app/models/mails/without_continuation_mail.rb index b70102b32..11cd9a182 100644 --- a/app/models/mails/without_continuation_mail.rb +++ b/app/models/mails/without_continuation_mail.rb @@ -7,7 +7,7 @@ module Mails SLUG = "without_continuation" DEFAULT_TEMPLATE_NAME = "notification_mailer/without_continuation_mail" DISPLAYED_NAME = 'Accusé de classement sans suite' - DEFAULT_SUBJECT = 'Votre dossier demarches-simplifiees.fr nº --numéro du dossier-- a été classé sans suite' + DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- a été classé sans suite (--libellé démarche--)' DOSSIER_STATE = Dossier.states.fetch(:sans_suite) end end From d8b63cd4c9857a029b00bce26ecea2a061bc5710 Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Tue, 16 Jul 2019 17:24:31 +0200 Subject: [PATCH 13/26] added 'monavis' inside the procedure and for users --- .../admin/procedures_controller.rb | 16 +++++- app/views/admin/procedures/_monavis.html.haml | 14 +++++ app/views/admin/procedures/monavis.html.haml | 6 ++ ...dmin_procedurescontroller_navbar.html.haml | 4 ++ app/views/users/dossiers/merci.html.haml | 1 + config/routes.rb | 2 + ...0190716141633_add_monavis_to_procedures.rb | 5 ++ db/schema.rb | 3 +- .../admin/procedures_controller_spec.rb | 57 ++++++++++++++++++- 9 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 app/views/admin/procedures/_monavis.html.haml create mode 100644 app/views/admin/procedures/monavis.html.haml create mode 100644 db/migrate/20190716141633_add_monavis_to_procedures.rb diff --git a/app/controllers/admin/procedures_controller.rb b/app/controllers/admin/procedures_controller.rb index 98cb9b81d..a3e7a74c4 100644 --- a/app/controllers/admin/procedures_controller.rb +++ b/app/controllers/admin/procedures_controller.rb @@ -2,7 +2,7 @@ class Admin::ProceduresController < AdminController include SmartListing::Helper::ControllerExtensions helper SmartListing::Helper - before_action :retrieve_procedure, only: [:show, :edit, :delete_logo, :delete_deliberation, :delete_notice] + before_action :retrieve_procedure, only: [:show, :edit, :delete_logo, :delete_deliberation, :delete_notice, :monavis, :update_monavis] def index if current_administrateur.procedures.count != 0 @@ -198,6 +198,18 @@ class Admin::ProceduresController < AdminController render layout: 'application' end + def monavis + end + + def update_monavis + if !@procedure.update(procedure_params) + flash.now.alert = @procedure.errors.full_messages + else + flash.notice = 'le champ MonAvis a bien été mis à jour' + end + render 'monavis' + end + def active_class @active_class = 'active' end @@ -265,7 +277,7 @@ class Admin::ProceduresController < AdminController end def procedure_params - editable_params = [:libelle, :description, :organisation, :direction, :lien_site_web, :cadre_juridique, :deliberation, :notice, :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, :monavis] if @procedure&.locked? params.require(:procedure).permit(*editable_params) else diff --git a/app/views/admin/procedures/_monavis.html.haml b/app/views/admin/procedures/_monavis.html.haml new file mode 100644 index 000000000..aea72f433 --- /dev/null +++ b/app/views/admin/procedures/_monavis.html.haml @@ -0,0 +1,14 @@ +.form-group + %h3 Insérer un lien vers « Mon avis » + %p + Proposez aux usagers de donner un avis sur votre démarche. Pour ce faire, vous devez précédemment aller sur « + %a{ :href => "https://monavis.numerique.gouv.fr" } https://monavis.numerique.gouv.fr + », créer un compte, et référencer là démarche que vous venez de publier. + + %p + Dès que vous avez effectué le référencement de celle-ci, vous pouvez suivre le guide d’intégration du bouton que vous trouverez à + %a{ :href => "https://monavis.numerique.gouv.fr/Aide/Int%C3%A9gration%20du%20bouton%20MonAvis" } l’adresse suivante. + + %p Une fois en possession du code généré sur le site MonAvis, vous pouvez le coller dans le champ ci-dessous : + + = f.text_area :monavis, rows: '6', placeholder: 'Insérer le code généré par MonAvis', class: 'form-control' diff --git a/app/views/admin/procedures/monavis.html.haml b/app/views/admin/procedures/monavis.html.haml new file mode 100644 index 000000000..226c2f24b --- /dev/null +++ b/app/views/admin/procedures/monavis.html.haml @@ -0,0 +1,6 @@ +.row.white-back + #procedure_new.section.section-label + = form_for @procedure, url: url_for({ controller: 'admin/procedures', action: :update_monavis, id: @procedure.id }), multipart: true do |f| + = render partial: 'monavis', locals: { f: f } + .text-right + = f.button 'Enregistrer', class: 'btn btn-success' diff --git a/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml index 0bd32e889..1343d1268 100644 --- a/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml +++ b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml @@ -64,6 +64,10 @@ .procedure-list-element{ class: ('active' if active == 'Attestation') } Attestation + %a#onglet-description{ href: url_for(admin_procedure_monavis_path(@procedure)) } + .procedure-list-element{ class: ('active' if active == 'Mon avis') } + Mon avis + .split-hr-left diff --git a/app/views/users/dossiers/merci.html.haml b/app/views/users/dossiers/merci.html.haml index 23ec4da75..0e39a8040 100644 --- a/app/views/users/dossiers/merci.html.haml +++ b/app/views/users/dossiers/merci.html.haml @@ -23,3 +23,4 @@ .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) + != @dossier.procedure.monavis diff --git a/config/routes.rb b/config/routes.rb index 6abccf8e2..e77e6eb5f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -206,6 +206,8 @@ Rails.application.routes.draw do put 'publish' => 'procedures#publish', as: :publish post 'transfer' => 'procedures#transfer', as: :transfer put 'clone' => 'procedures#clone', as: :clone + get 'monavis' => 'procedures#monavis', as: :monavis + patch 'monavis' => 'procedures#update_monavis', as: :update_monavis resource :instructeurs, only: [:show, :update] diff --git a/db/migrate/20190716141633_add_monavis_to_procedures.rb b/db/migrate/20190716141633_add_monavis_to_procedures.rb new file mode 100644 index 000000000..0fdc98478 --- /dev/null +++ b/db/migrate/20190716141633_add_monavis_to_procedures.rb @@ -0,0 +1,5 @@ +class AddMonavisToProcedures < ActiveRecord::Migration[5.2] + def change + add_column :procedures, :monavis, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index 70076f057..5b102ddac 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_07_11_135457) do +ActiveRecord::Schema.define(version: 2019_07_16_141633) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -500,6 +500,7 @@ ActiveRecord::Schema.define(version: 2019_07_11_135457) do t.boolean "durees_conservation_required", default: true t.string "path" t.string "declarative_with_state" + t.text "monavis" t.index ["declarative_with_state"], name: "index_procedures_on_declarative_with_state" t.index ["hidden_at"], name: "index_procedures_on_hidden_at" t.index ["parent_procedure_id"], name: "index_procedures_on_parent_procedure_id" diff --git a/spec/controllers/admin/procedures_controller_spec.rb b/spec/controllers/admin/procedures_controller_spec.rb index 1ed713d56..d87a8bb5f 100644 --- a/spec/controllers/admin/procedures_controller_spec.rb +++ b/spec/controllers/admin/procedures_controller_spec.rb @@ -14,6 +14,7 @@ describe Admin::ProceduresController, type: :controller do let(:cadre_juridique) { 'cadre juridique' } let(:duree_conservation_dossiers_dans_ds) { 3 } let(:duree_conservation_dossiers_hors_ds) { 6 } + let(:monavis) { nil } let(:procedure_params) { { @@ -24,7 +25,8 @@ describe Admin::ProceduresController, type: :controller do direction: direction, cadre_juridique: cadre_juridique, duree_conservation_dossiers_dans_ds: duree_conservation_dossiers_dans_ds, - duree_conservation_dossiers_hors_ds: duree_conservation_dossiers_hors_ds + duree_conservation_dossiers_hors_ds: duree_conservation_dossiers_hors_ds, + monavis: monavis } } @@ -745,4 +747,57 @@ describe Admin::ProceduresController, type: :controller do } end end + + describe 'PATCH #monavis' do + let!(:procedure) { create(:procedure, :with_type_de_champ, :with_two_type_de_piece_justificative, administrateur: admin) } + let(:procedure_params) { + { + monavis: monavis + } + } + + context 'when administrateur is not connected' do + before do + sign_out admin + end + + subject { patch :update_monavis, params: { procedure_id: procedure.id } } + + it { is_expected.to redirect_to new_user_session_path } + end + + context 'when administrateur is connected' do + def update_monavis + patch :update_monavis, params: { procedure_id: procedure.id, procedure: procedure_params } + procedure.reload + end + + context 'when all attributes are present' do + render_views + let(:monavis) { 'code html for monavis' } + + before { update_monavis } + + describe 'the monavis field is updated' do + subject { procedure } + + it { expect(subject.monavis).to eq(monavis) } + end + + it { expect(flash[:notice]).to be_present } + it { expect(response.body).to include "MonAvis" } + end + + context 'when procedure is published' do + let(:procedure) { create(:procedure, :with_type_de_champ, :with_two_type_de_piece_justificative, :published, administrateur: admin) } + let(:monavis) { 'code html for monavis' } + + subject { update_monavis } + + describe 'the monavis field is updated' do + it { expect(subject.monavis).to eq procedure_params[:monavis] } + end + end + end + end end From 8d2c5cfa14dc800491daa1e7b25d81f333f70cb0 Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Wed, 17 Jul 2019 14:59:23 +0200 Subject: [PATCH 14/26] validation par regex --- app/models/procedure.rb | 9 +++++++++ app/views/admin/procedures/_monavis.html.haml | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/models/procedure.rb b/app/models/procedure.rb index dcddab930..14595964e 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -72,6 +72,15 @@ class Procedure < ApplicationRecord validates :duree_conservation_dossiers_dans_ds, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 1, less_than_or_equal_to: MAX_DUREE_CONSERVATION }, unless: :durees_conservation_required validates :duree_conservation_dossiers_hors_ds, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, unless: :durees_conservation_required + class MonavisValidator < ActiveModel::Validator + def validate(record) + r = Regexp.new('\s*Je donne mon avis\s*', Regexp::MULTILINE) + if record.monavis.present? && !r.match?(record.monavis) + record.errors[:base] << "Le code fourni ne correspond pas au format des codes Monavis reconnus par la plateforme." + end + end + end + validates_with MonavisValidator before_save :update_juridique_required before_save :update_durees_conservation_required before_create :ensure_path_exists diff --git a/app/views/admin/procedures/_monavis.html.haml b/app/views/admin/procedures/_monavis.html.haml index aea72f433..36d631868 100644 --- a/app/views/admin/procedures/_monavis.html.haml +++ b/app/views/admin/procedures/_monavis.html.haml @@ -11,4 +11,6 @@ %p Une fois en possession du code généré sur le site MonAvis, vous pouvez le coller dans le champ ci-dessous : - = f.text_area :monavis, rows: '6', placeholder: 'Insérer le code généré par MonAvis', class: 'form-control' + .form-group + = f.label :monavis, "Mon avis" + = f.text_area :monavis, rows: '6', placeholder: 'Je donne mon avis', class: 'form-control' From c8f9e3b5f8353378361028ee6b08502eb2858ae6 Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Wed, 17 Jul 2019 15:12:07 +0200 Subject: [PATCH 15/26] automated test --- spec/models/procedure_spec.rb | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index c907f88a9..8526a0975 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -198,6 +198,43 @@ describe Procedure do it { expect(procedure.valid?).to eq(true) } end + context 'monavis' do + context 'nil is allowed' do + it { is_expected.to allow_value(nil).for(:monavis) } + it { is_expected.to allow_value('').for(:monavis) } + end + + context 'random string is not allowed' do + let(:procedure) { build(:procedure, monavis: "plop") } + it { expect(procedure.valid?).to eq(false) } + end + + context 'random html is not allowed' do + let(:procedure) { build(:procedure, monavis: '') } + it { expect(procedure.valid?).to eq(false) } + end + + context 'Monavis embed code with white button is allowed' do + monavis_blanc = <<-MSG + + Je donne mon avis + +MSG + let(:procedure) { build(:procedure, monavis: monavis_blanc) } + it { expect(procedure.valid?).to eq(true) } + end + + context 'Monavis embed code with blue button is allowed' do + monavis_blanc = <<-MSG + + Je donne mon avis + +MSG + let(:procedure) { build(:procedure, monavis: monavis_blanc) } + it { expect(procedure.valid?).to eq(true) } + end + end + shared_examples 'duree de conservation' do context 'duree_conservation_required it true, the field gets validated' do before { subject.durees_conservation_required = true } From 6d43465ee509bf30c8432145a208a2839115229b Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Wed, 17 Jul 2019 15:34:10 +0200 Subject: [PATCH 16/26] renammed into monavis_embed --- .../admin/procedures_controller.rb | 2 +- app/models/procedure.rb | 4 +- app/views/admin/procedures/_monavis.html.haml | 4 +- app/views/users/dossiers/merci.html.haml | 2 +- ...190717132452_add_monavis_to_procedures.rb} | 2 +- db/schema.rb | 4 +- .../admin/procedures_controller_spec.rb | 44 ++++++++++++++----- spec/models/procedure_spec.rb | 30 ++++++------- 8 files changed, 56 insertions(+), 36 deletions(-) rename db/migrate/{20190716141633_add_monavis_to_procedures.rb => 20190717132452_add_monavis_to_procedures.rb} (62%) diff --git a/app/controllers/admin/procedures_controller.rb b/app/controllers/admin/procedures_controller.rb index a3e7a74c4..448df9f3c 100644 --- a/app/controllers/admin/procedures_controller.rb +++ b/app/controllers/admin/procedures_controller.rb @@ -277,7 +277,7 @@ class Admin::ProceduresController < AdminController end def procedure_params - editable_params = [:libelle, :description, :organisation, :direction, :lien_site_web, :cadre_juridique, :deliberation, :notice, :web_hook_url, :euro_flag, :logo, :auto_archive_on, :monavis] + editable_params = [:libelle, :description, :organisation, :direction, :lien_site_web, :cadre_juridique, :deliberation, :notice, :web_hook_url, :euro_flag, :logo, :auto_archive_on, :monavis_embed] if @procedure&.locked? params.require(:procedure).permit(*editable_params) else diff --git a/app/models/procedure.rb b/app/models/procedure.rb index 14595964e..e94691871 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -74,8 +74,8 @@ class Procedure < ApplicationRecord class MonavisValidator < ActiveModel::Validator def validate(record) - r = Regexp.new('\s*Je donne mon avis\s*', Regexp::MULTILINE) - if record.monavis.present? && !r.match?(record.monavis) + r = Regexp.new('\s*Je donne mon avis\s*', Regexp::MULTILINE) + if record.monavis_embed.present? && !r.match?(record.monavis_embed) record.errors[:base] << "Le code fourni ne correspond pas au format des codes Monavis reconnus par la plateforme." end end diff --git a/app/views/admin/procedures/_monavis.html.haml b/app/views/admin/procedures/_monavis.html.haml index 36d631868..a1f861cf1 100644 --- a/app/views/admin/procedures/_monavis.html.haml +++ b/app/views/admin/procedures/_monavis.html.haml @@ -12,5 +12,5 @@ %p Une fois en possession du code généré sur le site MonAvis, vous pouvez le coller dans le champ ci-dessous : .form-group - = f.label :monavis, "Mon avis" - = f.text_area :monavis, rows: '6', placeholder: 'Je donne mon avis', class: 'form-control' + = f.label :monavis_embed, "Mon avis" + = f.text_area :monavis_embed, rows: '6', placeholder: 'Je donne mon avis', class: 'form-control' diff --git a/app/views/users/dossiers/merci.html.haml b/app/views/users/dossiers/merci.html.haml index 0e39a8040..941ffe36f 100644 --- a/app/views/users/dossiers/merci.html.haml +++ b/app/views/users/dossiers/merci.html.haml @@ -23,4 +23,4 @@ .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) - != @dossier.procedure.monavis + != @dossier.procedure.monavis_embed diff --git a/db/migrate/20190716141633_add_monavis_to_procedures.rb b/db/migrate/20190717132452_add_monavis_to_procedures.rb similarity index 62% rename from db/migrate/20190716141633_add_monavis_to_procedures.rb rename to db/migrate/20190717132452_add_monavis_to_procedures.rb index 0fdc98478..d97b5056f 100644 --- a/db/migrate/20190716141633_add_monavis_to_procedures.rb +++ b/db/migrate/20190717132452_add_monavis_to_procedures.rb @@ -1,5 +1,5 @@ class AddMonavisToProcedures < ActiveRecord::Migration[5.2] def change - add_column :procedures, :monavis, :text + add_column :procedures, :monavis_embed, :text end end diff --git a/db/schema.rb b/db/schema.rb index 5b102ddac..b38ea35e9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2019_07_16_141633) do +ActiveRecord::Schema.define(version: 2019_07_17_132452) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -500,7 +500,7 @@ ActiveRecord::Schema.define(version: 2019_07_16_141633) do t.boolean "durees_conservation_required", default: true t.string "path" t.string "declarative_with_state" - t.text "monavis" + t.text "monavis_embed" t.index ["declarative_with_state"], name: "index_procedures_on_declarative_with_state" t.index ["hidden_at"], name: "index_procedures_on_hidden_at" t.index ["parent_procedure_id"], name: "index_procedures_on_parent_procedure_id" diff --git a/spec/controllers/admin/procedures_controller_spec.rb b/spec/controllers/admin/procedures_controller_spec.rb index d87a8bb5f..4acaf3531 100644 --- a/spec/controllers/admin/procedures_controller_spec.rb +++ b/spec/controllers/admin/procedures_controller_spec.rb @@ -14,7 +14,7 @@ describe Admin::ProceduresController, type: :controller do let(:cadre_juridique) { 'cadre juridique' } let(:duree_conservation_dossiers_dans_ds) { 3 } let(:duree_conservation_dossiers_hors_ds) { 6 } - let(:monavis) { nil } + let(:monavis_embed) { nil } let(:procedure_params) { { @@ -26,7 +26,7 @@ describe Admin::ProceduresController, type: :controller do cadre_juridique: cadre_juridique, duree_conservation_dossiers_dans_ds: duree_conservation_dossiers_dans_ds, duree_conservation_dossiers_hors_ds: duree_conservation_dossiers_hors_ds, - monavis: monavis + monavis_embed: monavis_embed } } @@ -752,7 +752,7 @@ describe Admin::ProceduresController, type: :controller do let!(:procedure) { create(:procedure, :with_type_de_champ, :with_two_type_de_piece_justificative, administrateur: admin) } let(:procedure_params) { { - monavis: monavis + monavis_embed: monavis_embed } } @@ -771,31 +771,51 @@ describe Admin::ProceduresController, type: :controller do patch :update_monavis, params: { procedure_id: procedure.id, procedure: procedure_params } procedure.reload end + let(:monavis_embed) { + <<-MSG + + Je donne mon avis + + MSG + } context 'when all attributes are present' do render_views - let(:monavis) { 'code html for monavis' } before { update_monavis } - describe 'the monavis field is updated' do - subject { procedure } + context 'when the embed code is valid' do + describe 'the monavis field is updated' do + subject { procedure } - it { expect(subject.monavis).to eq(monavis) } + it { expect(subject.monavis_embed).to eq(monavis_embed) } + end + + it { expect(flash[:notice]).to be_present } + it { expect(response.body).to include "MonAvis" } end - it { expect(flash[:notice]).to be_present } - it { expect(response.body).to include "MonAvis" } + context 'when the embed code is not valid' do + let(:monavis_embed) { 'invalid embed code' } + + describe 'the monavis field is not updated' do + subject { procedure } + + it { expect(subject.monavis_embed).to eq(nil) } + end + + it { expect(flash[:alert]).to be_present } + it { expect(response.body).to include "MonAvis" } + end end context 'when procedure is published' do let(:procedure) { create(:procedure, :with_type_de_champ, :with_two_type_de_piece_justificative, :published, administrateur: admin) } - let(:monavis) { 'code html for monavis' } subject { update_monavis } - describe 'the monavis field is updated' do - it { expect(subject.monavis).to eq procedure_params[:monavis] } + describe 'the monavis field is not updated' do + it { expect(subject.monavis_embed).to eq monavis_embed } end end end diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index 8526a0975..81f94e500 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -200,37 +200,37 @@ describe Procedure do context 'monavis' do context 'nil is allowed' do - it { is_expected.to allow_value(nil).for(:monavis) } - it { is_expected.to allow_value('').for(:monavis) } + it { is_expected.to allow_value(nil).for(:monavis_embed) } + it { is_expected.to allow_value('').for(:monavis_embed) } end context 'random string is not allowed' do - let(:procedure) { build(:procedure, monavis: "plop") } + let(:procedure) { build(:procedure, monavis_embed: "plop") } it { expect(procedure.valid?).to eq(false) } end context 'random html is not allowed' do - let(:procedure) { build(:procedure, monavis: '') } + let(:procedure) { build(:procedure, monavis_embed: '') } it { expect(procedure.valid?).to eq(false) } end context 'Monavis embed code with white button is allowed' do monavis_blanc = <<-MSG - - Je donne mon avis - -MSG - let(:procedure) { build(:procedure, monavis: monavis_blanc) } + + Je donne mon avis + + MSG + let(:procedure) { build(:procedure, monavis_embed: monavis_blanc) } it { expect(procedure.valid?).to eq(true) } end context 'Monavis embed code with blue button is allowed' do - monavis_blanc = <<-MSG - - Je donne mon avis - -MSG - let(:procedure) { build(:procedure, monavis: monavis_blanc) } + monavis_bleu = <<-MSG + + Je donne mon avis + + MSG + let(:procedure) { build(:procedure, monavis_embed: monavis_bleu) } it { expect(procedure.valid?).to eq(true) } end end From 92ec62742514a015dc9dfba8443fcf6490605985 Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Wed, 17 Jul 2019 16:04:05 +0200 Subject: [PATCH 17/26] update brakeman configuration --- config/brakeman.ignore | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/config/brakeman.ignore b/config/brakeman.ignore index bc55c5c1e..6deac25d4 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -1,5 +1,24 @@ { "ignored_warnings": [ + { + "warning_type": "Cross-Site Scripting", + "warning_code": 2, + "fingerprint": "483ae8c038244eb3ed709e89846335e2c8ff6579260348ec31d3d03d1c94ad64", + "check_name": "CrossSiteScripting", + "message": "Unescaped model attribute", + "file": "app/views/users/dossiers/merci.html.haml", + "line": 26, + "link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting", + "code": "current_user.dossiers.includes(:procedure).find(params[:id]).procedure.monavis_embed", + "render_path": [{"type":"controller","class":"Users::DossiersController","method":"merci","line":178,"file":"app/controllers/users/dossiers_controller.rb"}], + "location": { + "type": "template", + "template": "users/dossiers/merci" + }, + "user_input": "current_user.dossiers.includes(:procedure)", + "confidence": "Weak", + "note": "" + }, { "warning_type": "SQL Injection", "warning_code": 0, @@ -27,7 +46,7 @@ "check_name": "SQL", "message": "Possible SQL injection", "file": "app/models/procedure_presentation.rb", - "line": 97, + "line": 98, "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", "code": "((\"self\" == \"self\") ? (dossiers) : (dossiers.includes(\"self\"))).order(\"#{self.class.sanitized_column(\"self\", column)} #{order}\")", "render_path": null, @@ -47,7 +66,7 @@ "check_name": "SQL", "message": "Possible SQL injection", "file": "app/models/procedure_presentation.rb", - "line": 93, + "line": 94, "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", "code": "dossiers.includes(((\"type_de_champ\" == \"type_de_champ\") ? (:champs) : (:champs_private))).where(\"champs.type_de_champ_id = #{column.to_i}\").order(\"champs.value #{order}\")", "render_path": null, @@ -61,6 +80,6 @@ "note": "`column` and `order` come from the model, which is validated to prevent injection attacks. Furthermore, the sql injection attack on `column` would need to survive the `to_i`" } ], - "updated": "2019-03-04 11:59:49 +0100", + "updated": "2019-07-17 16:03:11 +0200", "brakeman_version": "4.3.1" } From 91d10c0cf79bc2c9b4e5df06ced03ea8637149fb Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Wed, 17 Jul 2019 16:21:59 +0200 Subject: [PATCH 18/26] added navbar for mon avis --- app/views/admin/procedures/_monavis.html.haml | 2 +- .../_left_panel_admin_procedurescontroller_monavis.html.haml | 1 + .../_left_panel_admin_procedurescontroller_navbar.html.haml | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_monavis.html.haml diff --git a/app/views/admin/procedures/_monavis.html.haml b/app/views/admin/procedures/_monavis.html.haml index a1f861cf1..fed4302bd 100644 --- a/app/views/admin/procedures/_monavis.html.haml +++ b/app/views/admin/procedures/_monavis.html.haml @@ -1,5 +1,5 @@ .form-group - %h3 Insérer un lien vers « Mon avis » + %h3 Insérer un lien vers « MonAvis » %p Proposez aux usagers de donner un avis sur votre démarche. Pour ce faire, vous devez précédemment aller sur « %a{ :href => "https://monavis.numerique.gouv.fr" } https://monavis.numerique.gouv.fr diff --git a/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_monavis.html.haml b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_monavis.html.haml new file mode 100644 index 000000000..fad3db3bb --- /dev/null +++ b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_monavis.html.haml @@ -0,0 +1 @@ += render partial: 'layouts/left_panels/left_panel_admin_procedurescontroller_navbar', locals: { active: 'MonAvis' } diff --git a/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml index 1343d1268..877dfc045 100644 --- a/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml +++ b/app/views/layouts/left_panels/_left_panel_admin_procedurescontroller_navbar.html.haml @@ -65,8 +65,8 @@ Attestation %a#onglet-description{ href: url_for(admin_procedure_monavis_path(@procedure)) } - .procedure-list-element{ class: ('active' if active == 'Mon avis') } - Mon avis + .procedure-list-element{ class: ('active' if active == 'MonAvis') } + MonAvis .split-hr-left From ee8a1092e4eac5ec16d73d2e6268c6459ed4adc1 Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Wed, 17 Jul 2019 17:13:08 +0200 Subject: [PATCH 19/26] extracted MonAvisEmbedValidator --- app/models/procedure.rb | 11 +---------- app/validators/mon_avis_embed_validator.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 app/validators/mon_avis_embed_validator.rb diff --git a/app/models/procedure.rb b/app/models/procedure.rb index e94691871..4f36161dd 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -71,16 +71,7 @@ class Procedure < ApplicationRecord validates :duree_conservation_dossiers_hors_ds, allow_nil: false, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, if: :durees_conservation_required validates :duree_conservation_dossiers_dans_ds, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 1, less_than_or_equal_to: MAX_DUREE_CONSERVATION }, unless: :durees_conservation_required validates :duree_conservation_dossiers_hors_ds, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, unless: :durees_conservation_required - - class MonavisValidator < ActiveModel::Validator - def validate(record) - r = Regexp.new('\s*Je donne mon avis\s*', Regexp::MULTILINE) - if record.monavis_embed.present? && !r.match?(record.monavis_embed) - record.errors[:base] << "Le code fourni ne correspond pas au format des codes Monavis reconnus par la plateforme." - end - end - end - validates_with MonavisValidator + validates_with MonAvisEmbedValidator before_save :update_juridique_required before_save :update_durees_conservation_required before_create :ensure_path_exists diff --git a/app/validators/mon_avis_embed_validator.rb b/app/validators/mon_avis_embed_validator.rb new file mode 100644 index 000000000..ac84bad24 --- /dev/null +++ b/app/validators/mon_avis_embed_validator.rb @@ -0,0 +1,9 @@ +class MonAvisEmbedValidator < ActiveModel::Validator + def validate(record) + # We need to ensure the embed code is not any random string in order to avoid injections + r = Regexp.new('\s*Je donne mon avis\s*', Regexp::MULTILINE) + if record.monavis_embed.present? && !r.match?(record.monavis_embed) + record.errors[:base] << "Le code fourni ne correspond pas au format des codes MonAvis reconnus par la plateforme." + end + end +end From f65dccca15f534d2a5de1f88707bc5df8a1f056e Mon Sep 17 00:00:00 2001 From: clemkeirua Date: Thu, 18 Jul 2019 09:22:01 +0200 Subject: [PATCH 20/26] remove possibility to use node 6.* --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0e33b0be0..d0d84c66b 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,6 @@ "lint:js": "eslint ./app/javascript ./app/assets/javascripts ./config/webpack" }, "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": "8.* || >= 10.*" } } From 37c93e634e8bc5aadbb2266a8501ff7b0137b848 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 14:26:55 +0200 Subject: [PATCH 21/26] emails: clarify the `notify_new_draft` action --- app/views/dossier_mailer/notify_new_draft.html.haml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/views/dossier_mailer/notify_new_draft.html.haml b/app/views/dossier_mailer/notify_new_draft.html.haml index 94bc70119..9c3a63a9a 100644 --- a/app/views/dossier_mailer/notify_new_draft.html.haml +++ b/app/views/dossier_mailer/notify_new_draft.html.haml @@ -2,9 +2,12 @@ Bonjour, %p - Vous pouvez retrouver et compléter le brouillon que vous avez créé pour la démarche - %strong= @dossier.procedure.libelle - à l'adresse suivante : + Vous avez commencé à remplir un dossier pour la démarche « #{@dossier.procedure.libelle} ». + +%p + Vous pouvez + %strong retrouver et compléter votre dossier + à l’adresse suivante : = link_to dossier_url(@dossier), dossier_url(@dossier), target: '_blank', rel: 'noopener' = render partial: "layouts/mailers/signature" From b157d860d2f47f6223eb4ea531fc25e3ee89499b Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 14:12:57 +0200 Subject: [PATCH 22/26] emails: adjust notification footer for dossiers without messagerie --- app/mailers/dossier_mailer.rb | 2 ++ .../layouts/mailers/notification.html.haml | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/mailers/dossier_mailer.rb b/app/mailers/dossier_mailer.rb index c07fed240..53b44f817 100644 --- a/app/mailers/dossier_mailer.rb +++ b/app/mailers/dossier_mailer.rb @@ -1,5 +1,7 @@ # Preview all emails at http://localhost:3000/rails/mailers/dossier_mailer class DossierMailer < ApplicationMailer + helper ServiceHelper + layout 'mailers/layout' def notify_new_draft(dossier) diff --git a/app/views/layouts/mailers/notification.html.haml b/app/views/layouts/mailers/notification.html.haml index b267a0fc5..1441f8508 100644 --- a/app/views/layouts/mailers/notification.html.haml +++ b/app/views/layouts/mailers/notification.html.haml @@ -6,14 +6,12 @@ = image_tag @logo_url, height: "150", style: "display:block; max-height: 150px; max-width: 150px;" - content_for :footer do - - if @dossier.present? - - messagerie_url = messagerie_dossier_url(@dossier) - - else - - messagerie_url = "#" %strong - Merci de ne pas répondre à cet email. Pour vous adresser à votre administration, passez directement par votre - = succeed '.' do - = link_to 'messagerie', messagerie_url, target: '_blank', rel: 'noopener' + Merci de ne pas répondre à cet email. + - if @dossier.present? && @dossier.messagerie_available? + Pour vous adresser à votre administration, passez directement par votre + = succeed '.' do + = link_to 'messagerie', messagerie_dossier_url(@dossier), target: '_blank', rel: 'noopener' - if @service.present? %table{ width: "100%", border: "0", cellspacing: "0", cellpadding: "0", style: "cursor:auto;color:#55575d;font-family:Helvetica, Arial, sans-serif;font-size:11px;line-height:22px;text-align:left;" } @@ -31,7 +29,11 @@ %p %strong Poser une question sur votre dossier : %br - = link_to 'Par la messagerie', messagerie_url, target: '_blank', rel: 'noopener' + - if @dossier.present? && @dossier.messagerie_available? + = link_to 'Par la messagerie', messagerie_dossier_url(@dossier), target: '_blank', rel: 'noopener' + - else + Par email : + = link_to @service.email, "mailto:#{@service.email}" %br Par téléphone : = link_to @service.telephone, "tel:#{@service.telephone}" From 8b80c486792e04b5a21fcf94f4cd25b1dc9ca540 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 12:41:37 +0000 Subject: [PATCH 23/26] emails: use the notification template for more messages This allow to display the procedure logo and contact footer at the bottom of these emails. --- app/mailers/application_mailer.rb | 18 ++++++++++++++++++ app/mailers/dossier_mailer.rb | 10 +++++++++- app/mailers/notification_mailer.rb | 13 +------------ 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index a2612765e..88f1a3353 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -2,4 +2,22 @@ class ApplicationMailer < ActionMailer::Base helper :application # gives access to all helpers defined within `application_helper`. default from: "demarches-simplifiees.fr <#{CONTACT_EMAIL}>" layout 'mailer' + + # Attach the procedure logo to the email (if any). + # Returns the attachment url. + def attach_logo(procedure) + return nil if !procedure.logo? + + begin + logo_filename = procedure.logo.filename + attachments.inline[logo_filename] = procedure.logo.read + attachments[logo_filename].url + + rescue StandardError => e + # A problem occured when reading logo, maybe the logo is missing and we should clean the procedure to remove logo reference ? + Raven.extra_context(procedure_id: procedure.id) + Raven.capture_exception(e) + nil + end + end end diff --git a/app/mailers/dossier_mailer.rb b/app/mailers/dossier_mailer.rb index 53b44f817..8483fde87 100644 --- a/app/mailers/dossier_mailer.rb +++ b/app/mailers/dossier_mailer.rb @@ -6,13 +6,21 @@ class DossierMailer < ApplicationMailer def notify_new_draft(dossier) @dossier = dossier + @service = dossier.procedure.service + @logo_url = attach_logo(dossier.procedure) + subject = "Retrouvez votre brouillon pour la démarche « #{dossier.procedure.libelle} »" - mail(to: dossier.user.email, subject: subject) + mail(to: dossier.user.email, subject: subject) do |format| + format.html { render layout: 'mailers/notification' } + end end def notify_new_answer(dossier) @dossier = dossier + @service = dossier.procedure.service + @logo_url = attach_logo(dossier.procedure) + subject = "Nouveau message pour votre dossier nº #{dossier.id} (#{dossier.procedure.libelle})" mail(to: dossier.user.email, subject: subject) do |format| diff --git a/app/mailers/notification_mailer.rb b/app/mailers/notification_mailer.rb index 2822d405a..87379f6df 100644 --- a/app/mailers/notification_mailer.rb +++ b/app/mailers/notification_mailer.rb @@ -38,20 +38,9 @@ class NotificationMailer < ApplicationMailer create_commentaire_for_notification(dossier, subject, body) - if dossier.procedure.logo? - begin - logo_filename = dossier.procedure.logo.filename - attachments.inline[logo_filename] = dossier.procedure.logo.read - @logo_url = attachments[logo_filename].url - rescue StandardError => e - # A problem occured when reading logo, maybe the logo is missing and we should clean the procedure to remove logo reference ? - Raven.extra_context(procedure_id: dossier.procedure.id) - Raven.capture_exception(e) - end - end - @dossier = dossier @service = dossier.procedure.service + @logo_url = attach_logo(dossier.procedure) mail(subject: subject, to: email) do |format| # rubocop:disable Rails/OutputSafety From 630ae065427dc1ceaeb9b737b1e266342d84149d Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 14:36:46 +0000 Subject: [PATCH 24/26] emails: sign the new answer email as the administration --- app/views/dossier_mailer/notify_new_answer.html.haml | 2 +- app/views/layouts/mailers/_signature.html.haml | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/views/dossier_mailer/notify_new_answer.html.haml b/app/views/dossier_mailer/notify_new_answer.html.haml index 1dac34790..6a1bd4f33 100644 --- a/app/views/dossier_mailer/notify_new_answer.html.haml +++ b/app/views/dossier_mailer/notify_new_answer.html.haml @@ -8,4 +8,4 @@ Pour le consulter, merci de vous rendre sur = link_to messagerie_dossier_url(@dossier), messagerie_dossier_url(@dossier), target: '_blank', rel:'noopener' -= render partial: "layouts/mailers/signature" += render partial: "layouts/mailers/signature", locals: { service: @service } diff --git a/app/views/layouts/mailers/_signature.html.haml b/app/views/layouts/mailers/_signature.html.haml index ca5ad2778..f425b70be 100644 --- a/app/views/layouts/mailers/_signature.html.haml +++ b/app/views/layouts/mailers/_signature.html.haml @@ -1,4 +1,7 @@ %p Bonne journée, %br - L’équipe demarches-simplifiees.fr + - if defined?(service) && service && service.nom.present? + = service.nom + - else + L’équipe demarches-simplifiees.fr From f88d7c28fadfbe63be3f0eae314581664b276c7e Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 16:42:34 +0200 Subject: [PATCH 25/26] emails: add a "Read message" button to the new answer email --- app/helpers/mailer_helper.rb | 5 +++++ app/mailers/dossier_mailer.rb | 1 + app/views/dossier_mailer/notify_new_answer.html.haml | 8 +++++--- app/views/shared/_mailer_round_button.html.haml | 9 +++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 app/helpers/mailer_helper.rb create mode 100644 app/views/shared/_mailer_round_button.html.haml diff --git a/app/helpers/mailer_helper.rb b/app/helpers/mailer_helper.rb new file mode 100644 index 000000000..28767841d --- /dev/null +++ b/app/helpers/mailer_helper.rb @@ -0,0 +1,5 @@ +module MailerHelper + def round_button(text, url) + render 'shared/mailer_round_button', text: text, url: url + end +end diff --git a/app/mailers/dossier_mailer.rb b/app/mailers/dossier_mailer.rb index 8483fde87..613b64775 100644 --- a/app/mailers/dossier_mailer.rb +++ b/app/mailers/dossier_mailer.rb @@ -1,6 +1,7 @@ # Preview all emails at http://localhost:3000/rails/mailers/dossier_mailer class DossierMailer < ApplicationMailer helper ServiceHelper + helper MailerHelper layout 'mailers/layout' diff --git a/app/views/dossier_mailer/notify_new_answer.html.haml b/app/views/dossier_mailer/notify_new_answer.html.haml index 6a1bd4f33..502b5a985 100644 --- a/app/views/dossier_mailer/notify_new_answer.html.haml +++ b/app/views/dossier_mailer/notify_new_answer.html.haml @@ -2,10 +2,12 @@ Bonjour, %p - Un nouveau message est disponible dans votre espace demarches-simplifiees.fr. + L’administration en charge de votre dossier vous a + %strong envoyé un nouveau message. %p - Pour le consulter, merci de vous rendre sur - = link_to messagerie_dossier_url(@dossier), messagerie_dossier_url(@dossier), target: '_blank', rel:'noopener' + Pour le consulter et y répondre, cliquez sur le bouton ci-dessous : + += round_button('Lire le message', messagerie_dossier_url(@dossier)) = render partial: "layouts/mailers/signature", locals: { service: @service } diff --git a/app/views/shared/_mailer_round_button.html.haml b/app/views/shared/_mailer_round_button.html.haml new file mode 100644 index 000000000..18031f176 --- /dev/null +++ b/app/views/shared/_mailer_round_button.html.haml @@ -0,0 +1,9 @@ +/# From https://litmus.com/blog/a-guide-to-bulletproof-buttons-in-email-design +%table{ width: "100%", border: "0", cellspacing:"0", cellpadding:"0" } + %tr + %td + %table{ border:"0", cellspacing:"0", cellpadding:"0", style:"margin: auto" } + %tr + %td{ align:"center", style:"border-radius: 5px;", bgcolor:"#0069cc" } + %a{ href: url, target:"_blank", style:"font-size: 16px; font-family: Helvetica, Arial, sans-serif; color: #ffffff; text-decoration: none; text-decoration: none; border-radius: 5px; padding: 12px 25px; border: 1px solid #0069cc; display: inline-block;" } + = text From 3c0ba5e6987ab845ec97b8e344de3dbaf83048f4 Mon Sep 17 00:00:00 2001 From: Pierre de La Morinerie Date: Wed, 17 Jul 2019 16:49:40 +0200 Subject: [PATCH 26/26] emails: improve wording of the messagerie nudge --- app/views/layouts/mailers/notification.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/mailers/notification.html.haml b/app/views/layouts/mailers/notification.html.haml index 1441f8508..04da35e63 100644 --- a/app/views/layouts/mailers/notification.html.haml +++ b/app/views/layouts/mailers/notification.html.haml @@ -9,9 +9,9 @@ %strong Merci de ne pas répondre à cet email. - if @dossier.present? && @dossier.messagerie_available? - Pour vous adresser à votre administration, passez directement par votre + Pour vous adresser à votre administration, passez directement par la = succeed '.' do - = link_to 'messagerie', messagerie_dossier_url(@dossier), target: '_blank', rel: 'noopener' + = link_to 'messagerie du dossier', messagerie_dossier_url(@dossier), target: '_blank', rel: 'noopener' - if @service.present? %table{ width: "100%", border: "0", cellspacing: "0", cellpadding: "0", style: "cursor:auto;color:#55575d;font-family:Helvetica, Arial, sans-serif;font-size:11px;line-height:22px;text-align:left;" }