Skip to content

Commit

Permalink
refactor(contact): form is persisted in db before pushed to HS
Browse files Browse the repository at this point in the history
  • Loading branch information
colinux committed Jul 31, 2024
1 parent ad87036 commit 132e00d
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 274 deletions.
57 changes: 20 additions & 37 deletions app/controllers/support_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,31 @@ class SupportController < ApplicationController
invisible_captcha only: [:create], on_spam: :redirect_to_root

def index
@form = Helpscout::Form.new(tags: tags_from_query_params, dossier_id: dossier&.id, current_user:)
@form = ContactForm.new(tags: support_form_params.fetch(:tags, []), dossier_id: dossier&.id)
@form.user = current_user
end

def admin
@form = Helpscout::Form.new(tags: tags_from_query_params, current_user:, for_admin: true)
@form = ContactForm.new(tags: support_form_params.fetch(:tags, []), for_admin: true)
@form.user = current_user

Check warning on line 11 in app/controllers/support_controller.rb

View check run for this annotation

Codecov / codecov/patch

app/controllers/support_controller.rb#L10-L11

Added lines #L10 - L11 were not covered by tests
end

def create
if direct_message? && create_commentaire
if direct_message?
create_commentaire!
flash.notice = "Votre message a été envoyé sur la messagerie de votre dossier."

redirect_to messagerie_dossier_path(dossier)
return
end

@form = Helpscout::Form.new(support_form_params.except(:piece_jointe).merge(current_user:))
form_params = support_form_params
@form = ContactForm.new(form_params.except(:piece_jointe))
@form.piece_jointe.attach(form_params[:piece_jointe]) if form_params[:piece_jointe].present?
@form.user = current_user

if @form.valid?
create_conversation_later(@form)
if @form.save
@form.create_conversation_later
flash.notice = "Votre message a été envoyé."

redirect_to root_path
Expand All @@ -32,29 +38,7 @@ def create

private

def create_conversation_later(form)
if support_form_params[:piece_jointe].present?
blob = ActiveStorage::Blob.create_and_upload!(
io: support_form_params[:piece_jointe].tempfile,
filename: support_form_params[:piece_jointe].original_filename,
content_type: support_form_params[:piece_jointe].content_type,
identify: false
).tap(&:scan_for_virus_later)
end

HelpscoutCreateConversationJob.perform_later(
blob_id: blob&.id,
subject: form.subject,
email: current_user&.email || form.email,
phone: form.phone,
text: form.text,
dossier_id: form.dossier_id,
browser: browser_name,
tags: form.tags_array
)
end

def create_commentaire
def create_commentaire!
attributes = {
piece_jointe: support_form_params[:piece_jointe],
body: "[#{support_form_params[:subject]}]<br><br>#{support_form_params[:text]}"
Expand All @@ -68,12 +52,11 @@ def browser_name
end
end

def tags_from_query_params
support_form_params[:tags]&.join(",") || ""
end

def direct_message?
user_signed_in? && support_form_params[:type] == Helpscout::Form::TYPE_INSTRUCTION && dossier.present? && dossier.messagerie_available?
return false unless user_signed_in?
return false unless support_form_params[:question_type] == ContactForm::TYPE_INSTRUCTION

dossier&.messagerie_available?
end

def dossier
Expand All @@ -85,9 +68,9 @@ def redirect_to_root
end

def support_form_params
keys = [:email, :subject, :text, :type, :dossier_id, :piece_jointe, :phone, :tags, :for_admin]
if params.key?(:helpscout_form) # submitting form
params.require(:helpscout_form).permit(*keys)
keys = [:email, :subject, :text, :question_type, :dossier_id, :piece_jointe, :phone, :for_admin, tags: []]
if params.key?(:contact_form) # submitting form
params.require(:contact_form).permit(*keys)
else
params.permit(:dossier_id, tags: []) # prefilling form
end
Expand Down
36 changes: 22 additions & 14 deletions app/jobs/helpscout_create_conversation_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,49 @@ class FileNotScannedYetError < StandardError

retry_on FileNotScannedYetError, wait: :exponentially_longer, attempts: 10

attr_reader :contact_form
attr_reader :api

def perform(blob_id: nil, **params)
if blob_id.present?
blob = ActiveStorage::Blob.find(blob_id)
raise FileNotScannedYetError if blob.virus_scanner.pending?
def perform(contact_form)
@contact_form = contact_form

blob = nil unless blob.virus_scanner.safe?
if contact_form.piece_jointe.attached?
raise FileNotScannedYetError if contact_form.piece_jointe.virus_scanner.pending?
end

@api = Helpscout::API.new

create_conversation(params, blob)
create_conversation

contact_form.destroy
end

private

def create_conversation(params, blob)
def create_conversation
response = api.create_conversation(
params[:email],
params[:subject],
params[:text],
blob
contact_form.email,
contact_form.subject,
contact_form.text,
safe_blob
)

if response.success?
conversation_id = response.headers['Resource-ID']

if params[:phone].present?
api.add_phone_number(params[:email], params[:phone])
if contact_form.phone.present?
api.add_phone_number(contact_form.email, contact_form.phone)
end

api.add_tags(conversation_id, params[:tags])
api.add_tags(conversation_id, contact_form.tags)
else
fail "Error while creating conversation: #{response.response_code} '#{response.body}'"
end
end

def safe_blob
return if !contact_form.piece_jointe.virus_scanner&.safe?

contact_form.piece_jointe
end
end
78 changes: 0 additions & 78 deletions app/lib/helpscout/form.rb

This file was deleted.

78 changes: 78 additions & 0 deletions app/models/contact_form.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,80 @@
class ContactForm < ApplicationRecord
attr_accessor :user
attr_reader :options

after_initialize :set_options
before_validation :normalize_strings
before_validation :sanitize_email
before_save :add_default_tags

validates :email, presence: true, strict_email: true, if: :require_email?
validates :subject, presence: true
validates :text, presence: true
validates :question_type, presence: true

has_one_attached :piece_jointe

TYPE_INFO = 'procedure_info'
TYPE_PERDU = 'lost_user'
TYPE_INSTRUCTION = 'instruction_info'
TYPE_AMELIORATION = 'product'
TYPE_AUTRE = 'other'

ADMIN_TYPE_RDV = 'admin_demande_rdv'
ADMIN_TYPE_QUESTION = 'admin_question'
ADMIN_TYPE_SOUCIS = 'admin_soucis'
ADMIN_TYPE_PRODUIT = 'admin_suggestion_produit'
ADMIN_TYPE_DEMANDE_COMPTE = 'admin_demande_compte'
ADMIN_TYPE_AUTRE = 'admin_autre'

def self.default_options
[
[I18n.t(:question, scope: [:support, :index, TYPE_INFO]), TYPE_INFO, I18n.t("links.common.faq.contacter_service_en_charge_url")],
[I18n.t(:question, scope: [:support, :index, TYPE_PERDU]), TYPE_PERDU, LISTE_DES_DEMARCHES_URL],
[I18n.t(:question, scope: [:support, :index, TYPE_INSTRUCTION]), TYPE_INSTRUCTION, I18n.t("links.common.faq.ou_en_est_mon_dossier_url")],
[I18n.t(:question, scope: [:support, :index, TYPE_AMELIORATION]), TYPE_AMELIORATION, FEATURE_UPVOTE_URL],
[I18n.t(:question, scope: [:support, :index, TYPE_AUTRE]), TYPE_AUTRE]
]
end

def self.admin_options
[
[I18n.t(:question, scope: [:support, :admin, ADMIN_TYPE_QUESTION], app_name: Current.application_name), ADMIN_TYPE_QUESTION],
[I18n.t(:question, scope: [:support, :admin, ADMIN_TYPE_RDV], app_name: Current.application_name), ADMIN_TYPE_RDV],
[I18n.t(:question, scope: [:support, :admin, ADMIN_TYPE_SOUCIS], app_name: Current.application_name), ADMIN_TYPE_SOUCIS],
[I18n.t(:question, scope: [:support, :admin, ADMIN_TYPE_PRODUIT]), ADMIN_TYPE_PRODUIT],
[I18n.t(:question, scope: [:support, :admin, ADMIN_TYPE_DEMANDE_COMPTE]), ADMIN_TYPE_DEMANDE_COMPTE],
[I18n.t(:question, scope: [:support, :admin, ADMIN_TYPE_AUTRE]), ADMIN_TYPE_AUTRE]
]
end

def for_admin=(value)
super(value)
set_options
end

def create_conversation_later
HelpscoutCreateConversationJob.perform_later(self)
end

def require_email? = user.blank?

private

def normalize_strings
self.subject = subject&.strip
self.text = text&.strip
end

def sanitize_email
self.email = EmailSanitizableConcern::EmailSanitizer.sanitize(email) if email.present?
end

def add_default_tags
self.tags = tags.push('contact form', question_type).uniq
end

def set_options
@options = for_admin? ? self.class.admin_options : self.class.default_options
end
end
19 changes: 10 additions & 9 deletions app/views/support/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@

- if form.require_email?
= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { autocomplete: 'email' }) do |c|
- c.with_label { Helpscout::Form.human_attribute_name(form.for_admin? ? :email_pro : :email) }
- c.with_label { ContactForm.human_attribute_name(form.for_admin? ? :email_pro : :email) }

%fieldset.fr-fieldset{ name: "type" }
%fieldset.fr-fieldset{ name: "question_type" }
%legend.fr-fieldset__legend.fr-fieldset__legend--regular
= t('.your_question')
= render EditableChamp::AsteriskMandatoryComponent.new
.fr-fieldset__content
- form.options.each do |(question, question_type, link)|
.fr-radio-group
= f.radio_button :type, question_type, required: true, data: {"support-target": "inputRadio" }, checked: question_type == form.type
= f.label "type_#{question_type}", { 'aria-controls': link ? "card-#{question_type}" : nil, class: 'fr-label' } do
= f.radio_button :question_type, question_type, required: true, data: {"support-target": "inputRadio" }, checked: question_type == form.question_type
= f.label "question_type_#{question_type}", { 'aria-controls': link ? "card-#{question_type}" : nil, class: 'fr-label' } do
= question

- if link.present?
.fr-ml-3w{ id: "card-#{question_type}",
class: class_names('hidden' => question_type != form.type),
"aria-hidden": question_type != form.type,
class: class_names('hidden' => question_type != form.question_type),
"aria-hidden": question_type != form.question_type,
data: { "support-target": "content" } }
= render Dsfr::CalloutComponent.new(title: t('.our_answer')) do |c|
- c.with_html_body do
Expand All @@ -43,13 +43,14 @@
%span.fr-hint-text
= t('.notice_upload_group')

%p.notice.hidden{ data: { 'contact-type-only': Helpscout::Form::TYPE_AMELIORATION } }
%p.notice.hidden{ data: { 'contact-type-only': ContactForm::TYPE_AMELIORATION } }
= t('.notice_pj_product')
%p.notice.hidden{ data: { 'contact-type-only': Helpscout::Form::TYPE_AUTRE } }
%p.notice.hidden{ data: { 'contact-type-only': ContactForm::TYPE_AUTRE } }
= t('.notice_pj_other')
= f.file_field :piece_jointe, class: 'fr-upload', accept: '.jpg, .jpeg, .png, .pdf'

= f.hidden_field :tags
- f.object.tags.each do |tag|
= f.hidden_field "tags[]", value: tag
= f.hidden_field :for_admin

= invisible_captcha
Expand Down
Loading

0 comments on commit 132e00d

Please sign in to comment.