demarches-normaliennes/app/models/attestation_template.rb
2024-12-09 10:06:13 +01:00

251 lines
7.1 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# frozen_string_literal: true
class AttestationTemplate < ApplicationRecord
include ActionView::Helpers::NumberHelper
include TagsSubstitutionConcern
belongs_to :procedure, inverse_of: :attestation_template
has_one_attached :logo
has_one_attached :signature
enum state: {
draft: 'draft',
published: 'published'
}
validates :title, tags: true, if: -> { procedure.present? && version == 1 }
validates :body, tags: true, if: -> { procedure.present? && version == 1 }
validates :json_body, tags: true, if: -> { procedure.present? && version == 2 }
validates :footer, length: { maximum: 190 }
FILE_MAX_SIZE = 1.megabytes
validates :logo, content_type: ['image/png', 'image/jpg', 'image/jpeg'], size: { less_than: FILE_MAX_SIZE }
validates :signature, content_type: ['image/png', 'image/jpg', 'image/jpeg'], size: { less_than: FILE_MAX_SIZE }
DOSSIER_STATE = Dossier.states.fetch(:accepte)
scope :v1, -> { where(version: 1) }
scope :v2, -> { where(version: 2) }
TIPTAP_BODY_DEFAULT = {
"type" => "doc",
"content" => [
{
"type" => "header",
"content" => [
{
"type" => "headerColumn",
"content" => [
{
"type" => "paragraph",
"attrs" => { "textAlign" => "left" },
"content" => [{ "type" => "mention", "attrs" => { "id" => "dossier_service_name", "label" => "nom du service" } }]
}
]
},
{
"type" => "headerColumn",
"content" => [
{
"type" => "paragraph",
"attrs" => { "textAlign" => "left" },
"content" => [
{ "text" => "Fait le ", "type" => "text" },
{ "type" => "mention", "attrs" => { "id" => "dossier_processed_at", "label" => "date de décision" } }
]
}
]
}
]
},
{ "type" => "title", "attrs" => { "textAlign" => "center" }, "content" => [{ "text" => "Titre de lattestation", "type" => "text" }] },
{
"type" => "paragraph",
"attrs" => { "textAlign" => "left" },
"content" => [
{
"text" => "Vous pouvez éditer ce texte pour personnaliser votre attestation. Pour ajouter du contenu issu du dossier, utilisez les balises situées sous cette zone de saisie.",
"type" => "text"
}
]
}
]
}.freeze
def attestation_for(dossier)
attestation = Attestation.new
attestation.title = replace_tags(title, dossier, escape: false) if version == 1
attestation.pdf.attach(
io: StringIO.new(build_pdf(dossier)),
filename: "attestation-dossier-#{dossier.id}.pdf",
content_type: 'application/pdf',
# we don't want to run virus scanner on this file
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
)
attestation
end
def unspecified_champs_for_dossier(dossier)
types_de_champ_by_tag_id = dossier.revision.types_de_champ.index_by { "tdc#{_1.stable_id}" }
used_tags.filter_map do |used_tag|
corresponding_type_de_champ = types_de_champ_by_tag_id[used_tag]
if corresponding_type_de_champ && dossier.project_champ(corresponding_type_de_champ).blank?
corresponding_type_de_champ
end
end
end
def dup
attestation_template = super
ClonePiecesJustificativesService.clone_attachments(self, attestation_template)
attestation_template
end
def logo_url
if logo.attached?
logo_variant = logo.variant(resize_to_limit: [400, 400])
logo_variant.key.present? ? logo_variant.processed.url : Rails.application.routes.url_helpers.url_for(logo)
end
end
def signature_url
if signature.attached?
Rails.application.routes.url_helpers.url_for(signature)
end
end
def render_attributes_for(params = {})
groupe_instructeur = params[:groupe_instructeur]
groupe_instructeur ||= params[:dossier]&.groupe_instructeur
base_attributes = {
created_at: Time.current,
footer: params.fetch(:footer, footer),
signature: signature_to_render(groupe_instructeur)
}
if version == 2
render_attributes_for_v2(params, base_attributes)
else
render_attributes_for_v1(params, base_attributes)
end
end
def logo_checksum
logo.attached? ? logo.checksum : nil
end
def signature_checksum
signature.attached? ? signature.checksum : nil
end
def logo_filename
logo.attached? ? logo.filename : nil
end
def signature_filename
signature.attached? ? signature.filename : nil
end
def tiptap_body
json_body&.to_json
end
def tiptap_body=(json)
self.json_body = JSON.parse(json)
end
private
def render_attributes_for_v1(params, base_attributes)
attributes = base_attributes.merge(
logo: params.fetch(:logo, logo.attached? ? logo : nil)
)
dossier = params[:dossier]
if dossier.present?
attributes.merge(
title: replace_tags(title, dossier, escape: false),
body: replace_tags(body, dossier, escape: false)
)
else
attributes.merge(
title: params.fetch(:title, title),
body: params.fetch(:body, body)
)
end
end
def render_attributes_for_v2(params, base_attributes)
dossier = params[:dossier]
json = json_body&.deep_symbolize_keys
tiptap = TiptapService.new
if dossier.present?
# 2x faster this way than with `replace_tags` which would reparse text
used_tags = TiptapService.used_tags_and_libelle_for(json.deep_symbolize_keys)
substitutions = tags_substitutions(used_tags, dossier, escape: false)
body = tiptap.to_html(json, substitutions)
attributes.merge(
body:
)
else
attributes.merge(
body: params.fetch(:body) { tiptap.to_html(json) }
)
end
end
def signature_to_render(groupe_instructeur)
if groupe_instructeur&.signature&.attached?
groupe_instructeur.signature
else
signature
end
end
def used_tags
if version == 2
json = json_body&.deep_symbolize_keys
TiptapService.used_tags_and_libelle_for(json.deep_symbolize_keys).map(&:first)
else
used_tags_for(title) + used_tags_for(body)
end
end
def build_pdf(dossier)
if version == 2
build_v2_pdf(dossier)
else
build_v1_pdf(dossier)
end
end
def build_v1_pdf(dossier)
attestation = render_attributes_for(dossier: dossier)
ApplicationController.render(
template: 'administrateurs/attestation_templates/show',
formats: :pdf,
assigns: { attestation: attestation }
)
end
def build_v2_pdf(dossier)
body = render_attributes_for(dossier:).fetch(:body)
html = ApplicationController.render(
template: '/administrateurs/attestation_template_v2s/show',
formats: [:html],
layout: 'attestation',
assigns: { attestation_template: self, body: body }
)
WeasyprintService.generate_pdf(html, { procedure_id: procedure.id, dossier_id: dossier.id })
end
end