diff --git a/app/assets/images/faq/usager-confirm-update-email.png b/app/assets/images/faq/usager-confirm-update-email.png
new file mode 100644
index 000000000..b93ff5680
Binary files /dev/null and b/app/assets/images/faq/usager-confirm-update-email.png differ
diff --git a/app/assets/images/faq/usager-dropdown.png b/app/assets/images/faq/usager-dropdown.png
new file mode 100644
index 000000000..6fd5f65a2
Binary files /dev/null and b/app/assets/images/faq/usager-dropdown.png differ
diff --git a/app/assets/images/faq/usager-edit-email.png b/app/assets/images/faq/usager-edit-email.png
new file mode 100644
index 000000000..6a8b0b48d
Binary files /dev/null and b/app/assets/images/faq/usager-edit-email.png differ
diff --git a/app/assets/stylesheets/markdown-content.scss b/app/assets/stylesheets/markdown-content.scss
new file mode 100644
index 000000000..c166078e8
--- /dev/null
+++ b/app/assets/stylesheets/markdown-content.scss
@@ -0,0 +1,20 @@
+.markdown-content {
+ img {
+ max-width: 100%;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
+
+ display: block;
+
+ // In markdown img are always wrapped in p,
+ // which already contains vertical margin.
+ // We only add margin when there are siblings.
+ // NOTE: CSS consider the img is only-child even
+ // when there are only text node siblings, but it's still fine for us.
+ margin: 1.5rem auto;
+
+ &:only-child {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+ }
+}
diff --git a/app/controllers/faq_controller.rb b/app/controllers/faq_controller.rb
index a6b28d7ed..6c28f2725 100644
--- a/app/controllers/faq_controller.rb
+++ b/app/controllers/faq_controller.rb
@@ -8,9 +8,7 @@ class FAQController < ApplicationController
end
def show
- @renderer = Redcarpet::Markdown.new(
- Redcarpet::BareRenderer.new(class_names_map: { list: 'fr-ol-content--override' })
- )
+ @renderer = Redcarpet::Markdown.new(Redcarpet::TrustedRenderer.new(view_context), autolink: true)
@siblings = loader_service.faqs_for_category(@metadata[:category])
end
diff --git a/app/lib/redcarpet/bare_renderer.rb b/app/lib/redcarpet/bare_renderer.rb
index d8944374c..39bfc9342 100644
--- a/app/lib/redcarpet/bare_renderer.rb
+++ b/app/lib/redcarpet/bare_renderer.rb
@@ -33,7 +33,7 @@ module Redcarpet
when :url
link(link, nil, link)
when :email
- # NOTE: As of Redcarpet 3.6.0, autolinking email containing is broken https://github.com/vmg/redcarpet/issues/402
+ # NOTE: As of Redcarpet 3.6.0, autolinking email containing underscore is broken https://github.com/vmg/redcarpet/issues/402
content_tag(:a, link, { href: "mailto:#{link}" })
else
link
diff --git a/app/lib/redcarpet/trusted_renderer.rb b/app/lib/redcarpet/trusted_renderer.rb
new file mode 100644
index 000000000..f0ee50129
--- /dev/null
+++ b/app/lib/redcarpet/trusted_renderer.rb
@@ -0,0 +1,41 @@
+module Redcarpet
+ class TrustedRenderer < Redcarpet::Render::HTML
+ include ActionView::Helpers::TagHelper
+ include Sprockets::Rails::Helper
+ include ApplicationHelper
+
+ attr_reader :view_context
+
+ def initialize(view_context, extensions = {})
+ @view_context = view_context
+
+ super extensions
+ end
+
+ def link(href, title, content)
+ html_options = {
+ href: href
+ }
+
+ unless href.starts_with?('/')
+ html_options.merge!(title: new_tab_suffix(title), **external_link_attributes)
+ end
+
+ content_tag(:a, content, html_options, false)
+ end
+
+ def autolink(link, link_type)
+ case link_type
+ when :url
+ link(link, nil, link)
+ when :email
+ # NOTE: As of Redcarpet 3.6.0, autolinking email containing underscore is broken https://github.com/vmg/redcarpet/issues/402
+ content_tag(:a, link, { href: "mailto:#{link}" })
+ end
+ end
+
+ def image(link, title, alt)
+ view_context.image_tag(link, title:, alt:, loading: :lazy)
+ end
+ end
+end
diff --git a/app/views/faq/show.html.haml b/app/views/faq/show.html.haml
index b72b8c8f0..cca79a4f0 100644
--- a/app/views/faq/show.html.haml
+++ b/app/views/faq/show.html.haml
@@ -5,4 +5,5 @@
.fr-col-12.fr-col-md-4
= render partial: "sidebar", locals: { faqs: @siblings, current: @metadata }
.fr-col-12.fr-col-md-8.fr-py-12v
- = @renderer.render(@content).html_safe
+ .markdown-content
+ = @renderer.render(@content).html_safe
diff --git a/doc/faqs/usager/je-veux-changer-mon-adresse-email.fr.md b/doc/faqs/usager/je-veux-changer-mon-adresse-email.fr.md
new file mode 100644
index 000000000..eb0ab61b9
--- /dev/null
+++ b/doc/faqs/usager/je-veux-changer-mon-adresse-email.fr.md
@@ -0,0 +1,41 @@
+
+---
+category: "usager"
+subcategory: "account"
+slug: "je-veux-changer-mon-adresse-email"
+locale: "fr"
+keywords: "adresse email, compte usager, sécurité, changement, profil"
+title: "Je veux changer mon adresse email"
+---
+
+# Je veux changer mon adresse email
+
+Si vous disposez d’un compte usager sur demarches.gouv.fr, il est possible de changer l’adresse email associée à celui-ci.
+
+**Attention** : pour des raisons de sécurité, les comptes instructeur et administrateur sur demarches.gouv.fr doivent nous contacter à contact@demarches.gouv.fr pour demander ce changement.
+
+Cette adresse correspond à l’identifiant avec lequel vous vous connectez à demarches.gouv.fr. C’est également à cette adresse que nous envoyons les messages concernant l’avancement de votre dossier.
+
+## Changer mon adresse email
+
+Pour changer l’adresse email associée à votre compte, suivez les étapes suivantes :
+
+1. [Connectez-vous](/users/sign_in) à votre compte sur demarches.gouv.fr ;
+2. Cliquez sur le menu contenant votre adresse email en haut à droite de la page, puis sur _« Voir mon profil »_, ou [suivez directement ce lien si vous êtes déjà connecté(e)](/profil).
+![Menu Usager avec lien Voir mon profil](faq/usager-dropdown.png)
+
+3. Dans l’encadré _« Coordonnées »_, renseignez la nouvelle adresse email que vous souhaitez utiliser. Puis cliquez sur _« Changer mon adresse »_. **Attention** : Cette adresse ne doit pas être déjà utilisée par un autre compte sur demarches.gouv.fr.
+![Section Coordonées avec formulaire de modification d’email](faq/usager-edit-email.png)
+
+4. Ouvrez la boîte email de votre nouvelle adresse, et cliquez sur le lien de confirmation que nous vous avons envoyé.
+ ![Capture d’écran de l’email de confirmation de changement d’adresse email](faq/usager-confirm-update-email.png)
+
+## Si l’adresse est déjà utilisée par un autre compte
+
+La nouvelle adresse email ne doit pas être déjà utilisée par un compte existant sur demarches.gouv.fr.
+
+**Si la nouvelle adresse est déjà utilisée, vous recevrez un email vous informant que le changement d’adresse ne peut pas être pris en compte.**
+
+Dans ce cas, revenez sur la page _« Profil »_, et choisissez une autre adresse email disponible.
+
+Par ailleurs, vous pouvez également transférer plusieurs dossiers depuis votre profil, cela vous permet tout de même de conserver votre compte.
diff --git a/spec/lib/redcarpet/trusted_renderer_spec.rb b/spec/lib/redcarpet/trusted_renderer_spec.rb
new file mode 100644
index 000000000..046472026
--- /dev/null
+++ b/spec/lib/redcarpet/trusted_renderer_spec.rb
@@ -0,0 +1,35 @@
+RSpec.describe Redcarpet::TrustedRenderer do
+ let(:view_context) { ActionController::Base.new.view_context }
+ subject(:renderer) { Redcarpet::Markdown.new(described_class.new(view_context), autolink: true) }
+
+ context 'when rendering links' do
+ it 'renders internal links without target and rel attributes' do
+ markdown = "[Click here](/internal)"
+ expect(renderer.render(markdown)).to include('Click here')
+ end
+
+ it 'renders external links with target="_blank" and rel="noopener noreferrer"' do
+ markdown = "[Visit](http://example.com)"
+ expect(renderer.render(markdown)).to include('Visit')
+ end
+ end
+
+ context 'when rendering images' do
+ it 'renders an image tag with lazy loading' do
+ markdown = "![A cute cat](http://example.com/cat.jpg)"
+ expect(renderer.render(markdown)).to include('')
+ end
+ end
+
+ context 'when autolinking' do
+ it 'autolinks URLs' do
+ markdown = "Visit http://example.com"
+ expect(renderer.render(markdown)).to include('Visit http://example.com')
+ end
+
+ it 'autolinks email addresses with mailto' do
+ markdown = "Email user@example.com"
+ expect(renderer.render(markdown)).to include('user@example.com')
+ end
+ end
+end