Adding PDF submissions

pull/668/head
Eros Stein 2 months ago
parent c843b8ef75
commit 9bc624d550

@ -14,55 +14,43 @@ module Submissions
template = nil
attrs = params.to_h.with_indifferent_access
validate_attrs!(attrs)
template = build_template_with_documents(user, attrs)
submission = create_submission(template, user, attrs)
clone_documents_to_submission(template, submission)
enqueue_events(submission)
submission
rescue Templates::CreateAttachments::PdfEncrypted
raise Error, 'PDF encrypted'
rescue DownloadUtils::UnableToDownload => e
raise Error, e.message
rescue HexaPDF::Error, Pdfium::PdfiumError => e
raise Error, "Invalid PDF: #{e.message}"
ensure
archive_template(template) if template&.persisted? && template.archived_at.blank?
end
def validate_attrs!(attrs)
raise Error, 'documents are required' if attrs[:documents].blank?
raise Error, 'submitters are required' if attrs[:submitters].blank?
raise Error, 'template_ids are not supported by this endpoint yet' if attrs[:template_ids].present?
end
def build_template_with_documents(user, attrs)
template = build_template(user, attrs)
documents_attrs = sorted_documents_attrs(attrs[:documents])
documents_info = attach_documents(template, documents_attrs, attrs)
documents = documents_info.pluck(:attachment)
template.schema = documents.map.with_index do |document, index|
{
attachment_uuid: document.uuid,
name: documents_attrs[index][:name].presence || document.filename.base
}
end
template.schema = build_schema(documents_info, documents_attrs)
template.submitters = build_template_submitters(attrs)
template.fields = build_fields(template, documents_info)
raise Error, 'PDF does not contain fields' if template.fields.blank?
template.save!
submissions = Submissions.create_from_submitters(
template: template,
user: user,
source: :api,
with_template: false,
submitters_order: attrs[:order] || attrs[:submitters_order] ||
Submissions::DEFAULT_SUBMITTERS_ORDER,
submissions_attrs: [submission_attrs(attrs)]
)
submissions.each { |submission| clone_documents_to_submission(template, submission) }
WebhookUrls.enqueue_events(submissions, 'submission.created')
Submissions.send_signature_requests(submissions)
SearchEntries.enqueue_reindex(submissions)
template.update!(archived_at: Time.current)
submissions.first
rescue Templates::CreateAttachments::PdfEncrypted
raise Error, 'PDF encrypted'
rescue DownloadUtils::UnableToDownload => e
raise Error, e.message
rescue HexaPDF::Error, Pdfium::PdfiumError => e
raise Error, "Invalid PDF: #{e.message}"
ensure
archive_template(template) if template&.persisted? && template.archived_at.blank?
template.tap(&:save!)
end
def build_template(user, attrs)
@ -78,6 +66,36 @@ module Submissions
)
end
def build_schema(documents_info, documents_attrs)
documents_info.pluck(:attachment).map.with_index do |document, index|
{
attachment_uuid: document.uuid,
name: documents_attrs[index][:name].presence || document.filename.base
}
end
end
def create_submission(template, user, attrs)
Submissions.create_from_submitters(
template: template,
user: user,
source: :api,
with_template: false,
submitters_order: submitters_order(attrs),
submissions_attrs: [submission_attrs(attrs)]
).first
end
def submitters_order(attrs)
attrs[:order] || attrs[:submitters_order] || Submissions::DEFAULT_SUBMITTERS_ORDER
end
def enqueue_events(submission)
WebhookUrls.enqueue_events([submission], 'submission.created')
Submissions.send_signature_requests([submission])
SearchEntries.enqueue_reindex([submission])
end
def attach_documents(template, documents_attrs, params)
documents_attrs.map do |document_attrs|
file, text_tags = build_uploaded_file(document_attrs, remove_tags: remove_tags?(params))
@ -139,9 +157,10 @@ module Submissions
def build_template_submitters(attrs)
attrs[:submitters].map.with_index do |submitter_attrs, index|
name = submitter_attrs[:role].presence || submitter_attrs[:name].presence || default_submitter_name(index)
{
'name' => submitter_attrs[:role].presence || submitter_attrs[:name].presence ||
default_submitter_name(index),
'name' => name,
'uuid' => SecureRandom.uuid,
'order' => submitter_attrs[:order]
}.compact

@ -49,19 +49,21 @@ module Templates
end
def group_text_nodes_by_line(text_nodes)
text_nodes.each_with_object([]) do |node, lines|
line = lines.find { |items| same_line?(items.first, node) }
lines = text_nodes.each_with_object([]) do |node, items|
line = items.find { |line_items| same_line?(line_items.first, node) }
if line
line << node
else
lines << [node]
items << [node]
end
end.map { |line| line.sort_by(&:x) }
end
lines.map { |line| line.sort_by(&:x) }
end
def same_line?(a, b)
(a.endy - b.endy).abs < [a.h, b.h].max
def same_line?(first_node, second_node)
(first_node.endy - second_node.endy).abs < [first_node.h, second_node.h].max
end
def parse_tag(text)

@ -11,25 +11,37 @@ module Templates
pdf = HexaPDF::Document.new(io: StringIO.new(data))
cover_tags(pdf, tags)
write_pdf(pdf)
end
def cover_tags(pdf, tags)
tags.group_by { |tag| tag[:area]['page'] }.each do |page_index, page_tags|
page = pdf.pages[page_index]
next unless page
canvas = page.canvas(type: :overlay)
box = page.box
page_tags.each { |tag| cover_tag(page, tag) }
end
end
def cover_tag(page, tag)
page.canvas(type: :overlay)
.fill_color('white')
.rectangle(*tag_rect(page.box, tag[:area]))
.fill
end
page_tags.each do |tag|
area = tag[:area]
x = [(area['x'] - PADDING) * box.width, 0].max
y = box.height - ((area['y'] + area['h'] + PADDING) * box.height)
w = [(area['w'] + (PADDING * 2)) * box.width, box.width - x].min
h = (area['h'] + (PADDING * 2)) * box.height
def tag_rect(box, area)
x = [(area['x'] - PADDING) * box.width, 0].max
y = box.height - ((area['y'] + area['h'] + PADDING) * box.height)
w = [(area['w'] + (PADDING * 2)) * box.width, box.width - x].min
h = (area['h'] + (PADDING * 2)) * box.height
canvas.fill_color('white').rectangle(x, y, w, h).fill
end
end
[x, y, w, h]
end
def write_pdf(pdf)
io = StringIO.new
pdf.write(io, incremental: false, validate: false)

Loading…
Cancel
Save