Refactor mailers directory structure (#4128)

Simplification de la hiérarchie de vue des emails
This commit is contained in:
Pierre de La Morinerie 2019-07-23 16:00:43 +02:00 committed by GitHub
commit f633e3b774
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 131 additions and 108 deletions

View file

@ -8,8 +8,9 @@ module NewAdministrateur
@service = procedure.service @service = procedure.service
mail_template = find_mail_template_by_slug(params[:id]) mail_template = find_mail_template_by_slug(params[:id])
@rendered_template = sanitize(mail_template.body)
render(html: sanitize(mail_template.body), layout: 'mailers/notification') render(template: 'notification_mailer/send_notification', layout: 'mailers/notifications_layout')
end end
private private

View file

@ -13,7 +13,7 @@ class DossierMailer < ApplicationMailer
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) do |format| mail(to: dossier.user.email, subject: subject) do |format|
format.html { render layout: 'mailers/notification' } format.html { render layout: 'mailers/notifications_layout' }
end end
end end
@ -25,7 +25,7 @@ class DossierMailer < ApplicationMailer
subject = "Nouveau message pour votre dossier nº #{dossier.id} (#{dossier.procedure.libelle})" subject = "Nouveau message pour votre dossier nº #{dossier.id} (#{dossier.procedure.libelle})"
mail(to: dossier.user.email, subject: subject) do |format| mail(to: dossier.user.email, subject: subject) do |format|
format.html { render layout: 'mailers/notification' } format.html { render layout: 'mailers/notifications_layout' }
end end
end end

View file

@ -6,8 +6,12 @@
# The subject and body of a Notification can be customized by each demarche. # The subject and body of a Notification can be customized by each demarche.
# #
class NotificationMailer < ApplicationMailer class NotificationMailer < ApplicationMailer
include ActionView::Helpers::SanitizeHelper
helper ServiceHelper helper ServiceHelper
layout 'mailers/notifications_layout'
def send_dossier_received(dossier) def send_dossier_received(dossier)
send_notification(dossier, dossier.procedure.received_mail_template) send_notification(dossier, dossier.procedure.received_mail_template)
end end
@ -41,12 +45,9 @@ class NotificationMailer < ApplicationMailer
@dossier = dossier @dossier = dossier
@service = dossier.procedure.service @service = dossier.procedure.service
@logo_url = attach_logo(dossier.procedure) @logo_url = attach_logo(dossier.procedure)
@rendered_template = sanitize(body)
mail(subject: subject, to: email) do |format| mail(subject: subject, to: email, template_name: 'send_notification')
# rubocop:disable Rails/OutputSafety
format.html { render(html: body.html_safe, layout: 'mailers/notification') }
# rubocop:enable Rails/OutputSafety
end
end end
def create_commentaire_for_notification(dossier, subject, body) def create_commentaire_for_notification(dossier, subject, body)

View file

@ -12,9 +12,9 @@ module Mails
def self.default_template_name_for_procedure(procedure) def self.default_template_name_for_procedure(procedure)
attestation_template = procedure.attestation_template attestation_template = procedure.attestation_template
if attestation_template&.activated? if attestation_template&.activated?
"notification_mailer/closed_mail_with_attestation" "notification_mailer/default_templates/closed_mail_with_attestation"
else else
"notification_mailer/closed_mail" "notification_mailer/default_templates/closed_mail"
end end
end end
end end

View file

@ -5,7 +5,7 @@ module Mails
belongs_to :procedure belongs_to :procedure
SLUG = "initiated_mail" SLUG = "initiated_mail"
DEFAULT_TEMPLATE_NAME = "notification_mailer/initiated_mail" DEFAULT_TEMPLATE_NAME = "notification_mailer/default_templates/initiated_mail"
DISPLAYED_NAME = 'Accusé de réception' DISPLAYED_NAME = 'Accusé de réception'
DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- a bien été reçu (--libellé démarche--)' DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- a bien été reçu (--libellé démarche--)'
DOSSIER_STATE = Dossier.states.fetch(:en_construction) DOSSIER_STATE = Dossier.states.fetch(:en_construction)

View file

@ -5,7 +5,7 @@ module Mails
belongs_to :procedure belongs_to :procedure
SLUG = "received_mail" SLUG = "received_mail"
DEFAULT_TEMPLATE_NAME = "notification_mailer/received_mail" DEFAULT_TEMPLATE_NAME = "notification_mailer/default_templates/received_mail"
DISPLAYED_NAME = 'Accusé de passage en instruction' DISPLAYED_NAME = 'Accusé de passage en instruction'
DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- va être instruit (--libellé démarche--)' DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- va être instruit (--libellé démarche--)'
DOSSIER_STATE = Dossier.states.fetch(:en_instruction) DOSSIER_STATE = Dossier.states.fetch(:en_instruction)

View file

@ -5,7 +5,7 @@ module Mails
belongs_to :procedure belongs_to :procedure
SLUG = "refused_mail" SLUG = "refused_mail"
DEFAULT_TEMPLATE_NAME = "notification_mailer/refused_mail" DEFAULT_TEMPLATE_NAME = "notification_mailer/default_templates/refused_mail"
DISPLAYED_NAME = 'Accusé de rejet du dossier' DISPLAYED_NAME = 'Accusé de rejet du dossier'
DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- a été refusé (--libellé démarche--)' DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- a été refusé (--libellé démarche--)'
DOSSIER_STATE = Dossier.states.fetch(:refuse) DOSSIER_STATE = Dossier.states.fetch(:refuse)

View file

@ -5,7 +5,7 @@ module Mails
belongs_to :procedure belongs_to :procedure
SLUG = "without_continuation" SLUG = "without_continuation"
DEFAULT_TEMPLATE_NAME = "notification_mailer/without_continuation_mail" DEFAULT_TEMPLATE_NAME = "notification_mailer/default_templates/without_continuation_mail"
DISPLAYED_NAME = 'Accusé de classement sans suite' DISPLAYED_NAME = 'Accusé de classement sans suite'
DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- a été classé sans suite (--libellé démarche--)' DEFAULT_SUBJECT = 'Votre dossier nº --numéro du dossier-- a été classé sans suite (--libellé démarche--)'
DOSSIER_STATE = Dossier.states.fetch(:sans_suite) DOSSIER_STATE = Dossier.states.fetch(:sans_suite)

View file

@ -1,3 +1,6 @@
- content_for :procedure_logo do
= render 'layouts/mailers/logo', url: @logo_url
%p %p
Bonjour, Bonjour,
@ -10,4 +13,7 @@
= round_button('Lire le message', messagerie_dossier_url(@dossier)) = round_button('Lire le message', messagerie_dossier_url(@dossier))
= render partial: "layouts/mailers/signature", locals: { service: @service } = render 'layouts/mailers/signature', service: @service
- content_for :footer do
= render 'layouts/mailers/service_footer', service: @service, dossier: @dossier

View file

@ -1,3 +1,6 @@
- content_for :procedure_logo do
= render 'layouts/mailers/logo', url: @logo_url
%p %p
Bonjour, Bonjour,
@ -10,4 +13,7 @@
à ladresse suivante : à ladresse suivante :
= link_to dossier_url(@dossier), dossier_url(@dossier), target: '_blank', rel: 'noopener' = link_to dossier_url(@dossier), dossier_url(@dossier), target: '_blank', rel: 'noopener'
= render partial: "layouts/mailers/signature" = render 'layouts/mailers/signature'
- content_for :footer do
= render 'layouts/mailers/service_footer', service: @service, dossier: @dossier

View file

@ -0,0 +1,5 @@
- if url.present?
%table{ width: "100%", border: "0", cellspacing: "0", cellpadding: "0" }
%tr
%td{ align: "center" }
= image_tag url, height: "150", style: "display:block; max-height: 150px; max-width: 150px;"

View file

@ -0,0 +1,34 @@
%strong
Merci de ne pas répondre à cet email.
- if dossier.present? && dossier.messagerie_available?
Pour vous adresser à votre administration, passez directement par la
= succeed '.' do
= 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;" }
%tr
%td{ width: "50%", valign: "top" }
%p
%strong Cette démarche est gérée par :
%br
= service.nom
%br
= service.organisme
%br
= service.adresse
%td{ width: "50%", valign: "top" }
%p
%strong Poser une question sur votre dossier :
%br
- 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}"
%br
Horaires : #{ formatted_horaires(service.horaires) }

View file

@ -1,44 +0,0 @@
- if @logo_url.present?
- content_for :procedure_logo do
%table{ width: "100%", border: "0", cellspacing: "0", cellpadding: "0" }
%tr
%td{ align: "center" }
= image_tag @logo_url, height: "150", style: "display:block; max-height: 150px; max-width: 150px;"
- content_for :footer do
%strong
Merci de ne pas répondre à cet email.
- if @dossier.present? && @dossier.messagerie_available?
Pour vous adresser à votre administration, passez directement par la
= succeed '.' do
= 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;" }
%tr
%td{ width: "50%", valign: "top" }
%p
%strong Cette démarche est gérée par :
%br
= @service.nom
%br
= @service.organisme
%br
= @service.adresse
%td{ width: "50%", valign: "top" }
%p
%strong Poser une question sur votre dossier :
%br
- 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}"
%br
Horaires : #{ formatted_horaires(@service.horaires) }
= render template: 'layouts/mailers/notifications_layout'

View file

@ -7,4 +7,4 @@
%p %p
À tout moment, vous pouvez consulter votre dossier et les éventuels messages de l'administration à cette adresse : --lien dossier-- À tout moment, vous pouvez consulter votre dossier et les éventuels messages de l'administration à cette adresse : --lien dossier--
= render partial: "notification_mailer/signature" = render partial: "notification_mailer/default_templates/signature"

View file

@ -10,4 +10,4 @@
%p %p
À tout moment, vous pouvez consulter votre dossier et les éventuels messages de l'administration à cette adresse : --lien dossier-- À tout moment, vous pouvez consulter votre dossier et les éventuels messages de l'administration à cette adresse : --lien dossier--
= render partial: "notification_mailer/signature" = render partial: "notification_mailer/default_templates/signature"

View file

@ -7,4 +7,4 @@
%p %p
À tout moment, vous pouvez consulter votre dossier et les éventuels messages de l'administration à cette adresse : --lien dossier-- À tout moment, vous pouvez consulter votre dossier et les éventuels messages de l'administration à cette adresse : --lien dossier--
= render partial: "notification_mailer/signature" = render partial: "notification_mailer/default_templates/signature"

View file

@ -4,4 +4,4 @@
%p %p
Votre administration vous confirme la bonne réception de votre dossier nº --numéro du dossier--. Celui-ci sera instruit dans le délai légal déclaré par votre interlocuteur. Votre administration vous confirme la bonne réception de votre dossier nº --numéro du dossier--. Celui-ci sera instruit dans le délai légal déclaré par votre interlocuteur.
= render partial: "notification_mailer/signature" = render partial: "notification_mailer/default_templates/signature"

View file

@ -10,4 +10,4 @@
%p %p
Pour en savoir plus sur le motif du refus, vous pouvez consulter votre dossier et les éventuels messages de l'administration à cette adresse : --lien dossier-- Pour en savoir plus sur le motif du refus, vous pouvez consulter votre dossier et les éventuels messages de l'administration à cette adresse : --lien dossier--
= render partial: "notification_mailer/signature" = render partial: "notification_mailer/default_templates/signature"

View file

@ -10,4 +10,4 @@
%p %p
Pour en savoir plus sur les raisons de ce classement sans suite, vous pouvez consulter votre dossier et les éventuels messages de l'administration à cette adresse : --lien dossier-- Pour en savoir plus sur les raisons de ce classement sans suite, vous pouvez consulter votre dossier et les éventuels messages de l'administration à cette adresse : --lien dossier--
= render partial: "notification_mailer/signature" = render partial: "notification_mailer/default_templates/signature"

View file

@ -0,0 +1,7 @@
- content_for :procedure_logo do
= render 'layouts/mailers/logo', url: @logo_url
= @rendered_template
- content_for :footer do
= render 'layouts/mailers/service_footer', service: @service, dossier: @dossier

View file

@ -3,6 +3,12 @@ require "rails_helper"
RSpec.describe DossierMailer, type: :mailer do RSpec.describe DossierMailer, type: :mailer do
let(:to_email) { 'gestionnaire@exemple.gouv.fr' } let(:to_email) { 'gestionnaire@exemple.gouv.fr' }
shared_examples 'a dossier notification' do
it 'includes the contact informations in the footer' do
expect(subject.body).to include('ne pas répondre')
end
end
describe '.notify_new_draft' do describe '.notify_new_draft' do
let(:dossier) { create(:dossier, procedure: build(:simple_procedure)) } let(:dossier) { create(:dossier, procedure: build(:simple_procedure)) }
@ -12,6 +18,8 @@ RSpec.describe DossierMailer, type: :mailer do
it { expect(subject.subject).to include(dossier.procedure.libelle) } it { expect(subject.subject).to include(dossier.procedure.libelle) }
it { expect(subject.body).to include(dossier.procedure.libelle) } it { expect(subject.body).to include(dossier.procedure.libelle) }
it { expect(subject.body).to include(dossier_url(dossier)) } it { expect(subject.body).to include(dossier_url(dossier)) }
it_behaves_like 'a dossier notification'
end end
describe '.notify_new_answer' do describe '.notify_new_answer' do
@ -22,6 +30,8 @@ RSpec.describe DossierMailer, type: :mailer do
it { expect(subject.subject).to include("Nouveau message") } it { expect(subject.subject).to include("Nouveau message") }
it { expect(subject.subject).to include(dossier.id.to_s) } it { expect(subject.subject).to include(dossier.id.to_s) }
it { expect(subject.body).to include(messagerie_dossier_url(dossier)) } it { expect(subject.body).to include(messagerie_dossier_url(dossier)) }
it_behaves_like 'a dossier notification'
end end
describe '.notify_deletion_to_user' do describe '.notify_deletion_to_user' do

View file

@ -1,58 +1,55 @@
require "spec_helper" require "spec_helper"
RSpec.describe NotificationMailer, type: :mailer do RSpec.describe NotificationMailer, type: :mailer do
shared_examples_for "create a commentaire not notified" do
it do
expect { subject.deliver_now }.to change { Commentaire.count }.by(1)
subject.deliver_now
commentaire = Commentaire.last
expect(commentaire.body).to include(email_template.subject_for_dossier(dossier), email_template.body_for_dossier(dossier))
expect(commentaire.dossier).to eq(dossier)
end
end
let(:user) { create(:user) } let(:user) { create(:user) }
let(:dossier) { create(:dossier, :with_service, :en_construction, user: user) } let(:procedure) { create(:simple_procedure) }
let(:dossier) { create(:dossier, :en_construction, :for_individual, :with_service, user: user, procedure: procedure) }
describe '.send_notification' do
let(:email_template) { instance_double('email_template', subject_for_dossier: 'subject', body_for_dossier: 'body') }
subject(:mail) do
klass = Class.new(described_class) do
# Were testing the (private) method `NotificationMailer#send_notification`.
#
# The standard trick to test a private method would be to `send(:send_notification)`, but doesnt work here,
# because ActionMailer does some magic to expose public instance methods as class methods.
# So, we use inheritance instead to make the private method public for testing purposes.
def send_notification(dossier, template)
super
end
end
klass.send_notification(dossier, email_template)
end
it { expect(mail.subject).to eq(email_template.subject_for_dossier) }
it { expect(mail.body).to include(email_template.body_for_dossier) }
it { expect(mail.body).to have_link('messagerie') }
it_behaves_like "create a commentaire not notified"
end
describe '.send_dossier_received' do describe '.send_dossier_received' do
subject(:mail) { described_class.send_dossier_received(dossier) } let(:email_template) { create(:received_mail, subject: 'Email subject', body: 'Your dossier was processed. Thanks.') }
let(:email_template) { create(:received_mail) }
before do before do
dossier.procedure.received_mail = email_template dossier.procedure.received_mail = email_template
end end
it do subject(:mail) { described_class.send_dossier_received(dossier) }
expect(mail.subject).to eq(email_template.subject)
expect(mail.body).to include(email_template.body) it 'creates a commentaire in the messagerie' do
expect { subject.deliver_now }.to change { Commentaire.count }.by(1)
commentaire = Commentaire.last
expect(commentaire.body).to include(email_template.subject_for_dossier(dossier), email_template.body_for_dossier(dossier))
expect(commentaire.dossier).to eq(dossier)
end
it 'renders the template' do
expect(mail.subject).to eq('Email subject')
expect(mail.body).to include('Your dossier was processed')
expect(mail.body).to have_link('messagerie') expect(mail.body).to have_link('messagerie')
end end
it_behaves_like "create a commentaire not notified" context 'when the template body contains tags' do
let(:email_template) { create(:received_mail, subject: 'Email subject', body: 'Hello --nom--, your dossier --lien dossier-- was processed.') }
it 'replaces value tags with the proper value' do
expect(mail.body).to have_content(dossier.individual.nom)
end
it 'replaces link tags with a clickable link' do
expect(mail.body).to have_link(dossier_url(dossier))
end
end
context 'when the template body contains HTML' do
let(:email_template) { create(:received_mail, body: 'Your <b>dossier</b> was processed. <iframe src="#">Foo</iframe>') }
it 'allows basic formatting tags' do
expect(mail.body).to include('<b>dossier</b>')
end
it 'sanitizes sensitive content' do
expect(mail.body).not_to include('iframe')
end
end
end end
end end