Files
docuseal/lib/submissions/generate_preview_attachments.rb
T

168 lines
6.9 KiB
Ruby
Raw Normal View History

2024-10-15 19:16:09 +03:00
# frozen_string_literal: true
module Submissions
module GeneratePreviewAttachments
module_function
# rubocop:disable Metrics
2026-01-11 11:01:20 +02:00
def call(submission, values_hash: nil, submitter: nil, merge: false)
2024-12-01 00:10:07 +02:00
values_hash ||= if submitter
build_submitter_values_hash(submitter)
else
build_values_hash(submission)
end
2024-10-15 19:16:09 +03:00
2024-10-21 14:34:11 +03:00
configs = submission.account.account_configs.where(key: [AccountConfig::FLATTEN_RESULT_PDF_KEY,
2025-07-10 20:47:52 +03:00
AccountConfig::WITH_SIGNATURE_ID,
2025-07-18 10:30:37 +03:00
AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY,
2026-02-17 17:45:46 +02:00
AccountConfig::WITH_TIMESTAMP_SECONDS_KEY,
2026-04-21 12:35:00 +03:00
AccountConfig::ROTATE_INCREMENTAL_PDF_KEY,
2025-09-09 09:53:21 +03:00
AccountConfig::WITH_FILE_LINKS_KEY,
2026-07-14 12:47:38 +03:00
AccountConfig::WITH_SIGNATURE_ID_REASON_KEY,
AccountConfig::WITH_SIGNATURE_ID_COMPLETED_AT_KEY])
2024-10-15 19:16:09 +03:00
2024-10-21 14:34:11 +03:00
with_signature_id = configs.find { |c| c.key == AccountConfig::WITH_SIGNATURE_ID }&.value == true
2025-09-09 09:53:21 +03:00
with_file_links = configs.find { |c| c.key == AccountConfig::WITH_FILE_LINKS_KEY }&.value == true
2024-10-21 14:34:11 +03:00
is_flatten = configs.find { |c| c.key == AccountConfig::FLATTEN_RESULT_PDF_KEY }&.value != false
2026-04-21 12:35:00 +03:00
is_rotate_incremental = configs.find { |c| c.key == AccountConfig::ROTATE_INCREMENTAL_PDF_KEY }&.value == true
2025-07-10 20:47:52 +03:00
with_submitter_timezone = configs.find { |c| c.key == AccountConfig::WITH_SUBMITTER_TIMEZONE_KEY }&.value == true
2026-02-17 17:45:46 +02:00
with_timestamp_seconds = configs.find { |c| c.key == AccountConfig::WITH_TIMESTAMP_SECONDS_KEY }&.value == true
2025-07-18 10:30:37 +03:00
with_signature_id_reason =
configs.find { |c| c.key == AccountConfig::WITH_SIGNATURE_ID_REASON_KEY }&.value != false
2026-07-14 12:47:38 +03:00
with_signature_id_completed_at =
configs.find { |c| c.key == AccountConfig::WITH_SIGNATURE_ID_COMPLETED_AT_KEY }&.value == true
2024-10-15 19:16:09 +03:00
2026-05-27 22:19:18 +03:00
file_links_expire_at = Accounts.link_expires_at(submission.account) if with_file_links
2026-04-21 12:35:00 +03:00
pdfs_index = GenerateResultAttachments.build_pdfs_index(submission, flatten: is_flatten,
incremental: is_rotate_incremental)
2024-10-15 19:16:09 +03:00
2024-12-01 00:10:07 +02:00
submitters = if submitter
submission.submitters.where(id: submitter.id)
else
submission.submitters.where(completed_at: nil)
end
2024-12-23 22:58:24 +02:00
submitters.preload(attachments_attachments: :blob).each_with_index do |s, index|
2024-12-01 00:10:07 +02:00
GenerateResultAttachments.fill_submitter_fields(s, submission.account, pdfs_index,
2025-07-10 20:47:52 +03:00
with_signature_id:, is_flatten:, with_headings: index.zero?,
2025-09-09 09:53:21 +03:00
with_submitter_timezone:, with_file_links:,
2026-05-27 22:19:18 +03:00
file_links_expire_at:, with_signature_id_reason:,
2026-07-14 12:47:38 +03:00
with_timestamp_seconds:, with_signature_id_completed_at:)
2024-10-15 19:16:09 +03:00
end
template = submission.template
2026-01-11 11:01:20 +02:00
if merge
result = HexaPDF::Document.new
2024-10-15 19:16:09 +03:00
2026-01-11 11:01:20 +02:00
(submission.template_schema || template.schema).each do |item|
2024-10-15 19:16:09 +03:00
pdf = pdfs_index[item['attachment_uuid']]
2026-01-11 11:01:20 +02:00
next unless pdf
2024-12-07 01:35:59 +02:00
2026-01-11 11:01:20 +02:00
pdf.dispatch_message(:complete_objects)
2024-10-15 19:16:09 +03:00
2026-01-11 11:01:20 +02:00
pdf.pages.each { |page| result.pages << result.import(page) }
2024-10-15 19:16:09 +03:00
end
2026-01-11 11:01:20 +02:00
attachment = build_pdf_attachment(
pdf: result,
2024-10-15 19:16:09 +03:00
submission:,
values_hash:,
2026-01-11 11:01:20 +02:00
name: 'preview_merged_document',
2026-06-23 08:48:49 +03:00
filename: "#{submission.name || template&.name}.pdf"
2024-10-15 19:16:09 +03:00
)
2026-01-11 11:01:20 +02:00
ApplicationRecord.no_touching { attachment.save! }
[attachment]
else
image_pdfs = []
original_documents = submission.schema_documents.preload(:blob)
result_attachments =
(submission.template_schema || template.schema).filter_map do |item|
pdf = pdfs_index[item['attachment_uuid']]
next if pdf.nil?
if original_documents.find { |a| a.uuid == item['attachment_uuid'] }.image?
pdf = GenerateResultAttachments.normalize_image_pdf(pdf)
image_pdfs << pdf
end
build_pdf_attachment(pdf:, submission:, submitter:,
uuid: item['attachment_uuid'],
values_hash:,
filename: "#{item['name']}.pdf")
end
return ApplicationRecord.no_touching { result_attachments.map { |e| e.tap(&:save!) } } if image_pdfs.size < 2
images_pdf =
image_pdfs.each_with_object(HexaPDF::Document.new) do |pdf, doc|
pdf.pages.each { |page| doc.pages << doc.import(page) }
end
images_pdf = GenerateResultAttachments.normalize_image_pdf(images_pdf)
images_pdf_attachment =
build_pdf_attachment(
pdf: images_pdf,
submission:,
submitter:,
uuid: GenerateResultAttachments.images_pdf_uuid(original_documents.select(&:image?)),
values_hash:,
2026-06-23 08:48:49 +03:00
filename: "#{submission.name || template&.name}.pdf"
2026-01-11 11:01:20 +02:00
)
ApplicationRecord.no_touching do
(result_attachments + [images_pdf_attachment]).map { |e| e.tap(&:save!) }
end
2024-10-15 19:16:09 +03:00
end
end
def build_values_hash(submission)
2024-12-01 11:41:19 +02:00
Digest::MD5.hexdigest(
submission.submitters.reduce({}) { |acc, s| acc.merge(s.values) }.to_json
)
2024-10-15 19:16:09 +03:00
end
2024-12-01 00:10:07 +02:00
def build_submitter_values_hash(submitter)
submission = submitter.submission
2024-12-01 11:41:19 +02:00
Digest::MD5.hexdigest(
submission.submitters.where.not(completed_at: nil).or(submission.submitters.where(id: submitter.id))
.reduce({}) { |acc, s| acc.merge(s.values) }.to_json
)
2024-12-01 00:10:07 +02:00
end
2026-01-11 11:01:20 +02:00
def build_pdf_attachment(pdf:, submission:, filename:, values_hash:, submitter: nil, uuid: nil,
name: 'preview_documents')
2024-10-15 19:16:09 +03:00
io = StringIO.new
begin
pdf.write(io, incremental: true, validate: false)
rescue HexaPDF::MalformedPDFError => e
Rollbar.error(e) if defined?(Rollbar)
pdf.write(io, incremental: false, validate: false)
end
ActiveStorage::Attachment.new(
2026-01-11 11:01:20 +02:00
blob: ActiveStorage::Blob.create_and_upload!(io: io.tap(&:rewind), filename:),
2024-12-01 00:10:07 +02:00
io_data: io.string,
2024-10-15 19:16:09 +03:00
metadata: { original_uuid: uuid,
values_hash:,
analyzed: true,
2026-01-11 11:01:20 +02:00
sha256: Base64.urlsafe_encode64(Digest::SHA256.digest(io.string)) }.compact,
name: name,
2024-12-01 00:10:07 +02:00
record: submitter || submission
2024-10-15 19:16:09 +03:00
)
end
# rubocop:enable Metrics
end
end