generate pdfs from images
This commit is contained in:
@@ -8,6 +8,15 @@ class SubmissionsDownloadController < ApplicationController
|
||||
|
||||
Submissions::GenerateResultAttachments.call(submitter) if submitter.documents.blank?
|
||||
|
||||
render json: submitter.documents.map { |e| helpers.rails_blob_url(e) }
|
||||
original_documents = submitter.submission.template.documents.preload(:blob)
|
||||
is_more_than_two_images = original_documents.count(&:image?) > 1
|
||||
|
||||
urls = submitter.documents.preload(:blob).filter_map do |attachment|
|
||||
next if is_more_than_two_images && original_documents.find { |a| a.uuid == attachment.uuid }&.image?
|
||||
|
||||
helpers.rails_blob_url(attachment)
|
||||
end
|
||||
|
||||
render json: urls
|
||||
end
|
||||
end
|
||||
|
||||
@@ -18,20 +18,27 @@ export default targetable(class extends HTMLElement {
|
||||
this.toggleState()
|
||||
|
||||
fetch(this.dataset.src).then((response) => response.json()).then((urls) => {
|
||||
urls.forEach((url) => {
|
||||
fetch(url).then(async (resp) => {
|
||||
const blobUrl = URL.createObjectURL(await resp.blob())
|
||||
const link = document.createElement('a')
|
||||
const fileRequests = urls.map((url) => {
|
||||
return () => {
|
||||
return fetch(url).then(async (resp) => {
|
||||
const blobUrl = URL.createObjectURL(await resp.blob())
|
||||
const link = document.createElement('a')
|
||||
|
||||
link.href = blobUrl
|
||||
link.setAttribute('download', resp.headers.get('content-disposition').split('"')[1])
|
||||
link.href = blobUrl
|
||||
link.setAttribute('download', decodeURI(resp.headers.get('content-disposition').split('"')[1]))
|
||||
|
||||
link.click()
|
||||
link.click()
|
||||
|
||||
URL.revokeObjectURL(url)
|
||||
})
|
||||
URL.revokeObjectURL(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
}).finally(() => {
|
||||
|
||||
fileRequests.reduce(
|
||||
(prevPromise, request) => prevPromise.then(() => request()),
|
||||
Promise.resolve()
|
||||
)
|
||||
|
||||
this.toggleState()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -90,20 +90,27 @@ export default {
|
||||
this.isDownloading = true
|
||||
|
||||
fetch(`/submitters/${this.submitterSlug}/download`).then((response) => response.json()).then((urls) => {
|
||||
urls.forEach((url) => {
|
||||
fetch(url).then(async (resp) => {
|
||||
const blobUrl = URL.createObjectURL(await resp.blob())
|
||||
const link = document.createElement('a')
|
||||
const fileRequests = urls.map((url) => {
|
||||
return () => {
|
||||
return fetch(url).then(async (resp) => {
|
||||
const blobUrl = URL.createObjectURL(await resp.blob())
|
||||
const link = document.createElement('a')
|
||||
|
||||
link.href = blobUrl
|
||||
link.setAttribute('download', resp.headers.get('content-disposition').split('"')[1])
|
||||
link.href = blobUrl
|
||||
link.setAttribute('download', decodeURI(resp.headers.get('content-disposition').split('"')[1]))
|
||||
|
||||
link.click()
|
||||
link.click()
|
||||
|
||||
URL.revokeObjectURL(url)
|
||||
})
|
||||
URL.revokeObjectURL(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
}).finally(() => {
|
||||
|
||||
fileRequests.reduce(
|
||||
(prevPromise, request) => prevPromise.then(() => request()),
|
||||
Promise.resolve()
|
||||
)
|
||||
|
||||
this.isDownloading = false
|
||||
})
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
:field="currentField"
|
||||
:attachments-index="attachmentsIndex"
|
||||
:submitter-slug="submitterSlug"
|
||||
@attached="attachments.push($event)"
|
||||
@attached="[attachments.push($event), $refs.areas.scrollIntoField(currentField)]"
|
||||
/>
|
||||
<SignatureStep
|
||||
v-else-if="currentField.type === 'signature'"
|
||||
@@ -208,7 +208,7 @@
|
||||
:field="currentField"
|
||||
:attachments-index="attachmentsIndex"
|
||||
:submitter-slug="submitterSlug"
|
||||
@attached="attachments.push($event)"
|
||||
@attached="[attachments.push($event), $refs.areas.scrollIntoField(currentField)]"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-8">
|
||||
|
||||
@@ -5,6 +5,8 @@ module Submissions
|
||||
FONT_SIZE = 11
|
||||
FONT_NAME = 'Helvetica'
|
||||
|
||||
A4_SIZE = [595, 842].freeze
|
||||
|
||||
module_function
|
||||
|
||||
# rubocop:disable Metrics
|
||||
@@ -126,42 +128,101 @@ module Submissions
|
||||
end
|
||||
end
|
||||
|
||||
template.schema.map do |item|
|
||||
template.documents.find { |a| a.uuid == item['attachment_uuid'] }
|
||||
image_pdfs = []
|
||||
original_documents = template.documents.preload(:blob)
|
||||
|
||||
io = StringIO.new
|
||||
results =
|
||||
template.schema.map do |item|
|
||||
pdf = pdfs_index[item['attachment_uuid']]
|
||||
|
||||
pdf = pdfs_index[item['attachment_uuid']]
|
||||
attachment = save_signed_pdf(pdf:, submitter:, cert:, uuid: item['attachment_uuid'], name: item['name'])
|
||||
|
||||
pdf.sign(io, reason: "Signed by #{submitter.email}",
|
||||
certificate: OpenSSL::X509::Certificate.new(cert['cert']),
|
||||
key: OpenSSL::PKey::RSA.new(cert['key']),
|
||||
certificate_chain: [OpenSSL::X509::Certificate.new(cert['sub_ca']),
|
||||
OpenSSL::X509::Certificate.new(cert['root_ca'])])
|
||||
image_pdfs << pdf if original_documents.find { |a| a.uuid == item['attachment_uuid'] }.image?
|
||||
|
||||
ActiveStorage::Attachment.create!(
|
||||
uuid: item['attachment_uuid'],
|
||||
blob: ActiveStorage::Blob.create_and_upload!(
|
||||
io: StringIO.new(io.string), filename: "#{item['name']}.pdf"
|
||||
),
|
||||
name: 'documents',
|
||||
record: submitter
|
||||
attachment
|
||||
end
|
||||
|
||||
return results 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_result =
|
||||
save_signed_pdf(
|
||||
pdf: images_pdf,
|
||||
submitter:,
|
||||
cert:,
|
||||
uuid: images_pdf_uuid(original_documents.select(&:image?)),
|
||||
name: template.name
|
||||
)
|
||||
end
|
||||
|
||||
results + [images_pdf_result]
|
||||
end
|
||||
# rubocop:enable Metrics
|
||||
|
||||
def save_signed_pdf(pdf:, submitter:, cert:, uuid:, name:)
|
||||
io = StringIO.new
|
||||
|
||||
pdf.sign(io, reason: "Signed by #{submitter.email}",
|
||||
certificate: OpenSSL::X509::Certificate.new(cert['cert']),
|
||||
key: OpenSSL::PKey::RSA.new(cert['key']),
|
||||
certificate_chain: [OpenSSL::X509::Certificate.new(cert['sub_ca']),
|
||||
OpenSSL::X509::Certificate.new(cert['root_ca'])])
|
||||
|
||||
ActiveStorage::Attachment.create!(
|
||||
uuid:,
|
||||
blob: ActiveStorage::Blob.create_and_upload!(
|
||||
io: StringIO.new(io.string), filename: "#{name}.pdf"
|
||||
),
|
||||
name: 'documents',
|
||||
record: submitter
|
||||
)
|
||||
end
|
||||
|
||||
def images_pdf_uuid(attachments)
|
||||
Digest::UUID.uuid_v5(Digest::UUID::OID_NAMESPACE, attachments.map(&:uuid).sort.join(':'))
|
||||
end
|
||||
|
||||
def build_pdfs_index(submitter)
|
||||
latest_submitter = submitter.submission.submitters
|
||||
.select { |e| e.id != submitter.id && e.completed_at? }
|
||||
.max_by(&:completed_at)
|
||||
|
||||
documents = latest_submitter&.documents.to_a.presence
|
||||
documents ||= submitter.submission.template.documents
|
||||
documents = latest_submitter&.documents&.preload(:blob).to_a.presence
|
||||
documents ||= submitter.submission.template.documents.preload(:blob)
|
||||
|
||||
documents.to_h do |attachment|
|
||||
[attachment.uuid, HexaPDF::Document.new(io: StringIO.new(attachment.download))]
|
||||
pdf =
|
||||
if attachment.image?
|
||||
build_pdf_from_image(attachment)
|
||||
else
|
||||
HexaPDF::Document.new(io: StringIO.new(attachment.download))
|
||||
end
|
||||
|
||||
[attachment.uuid, pdf]
|
||||
end
|
||||
end
|
||||
|
||||
def build_pdf_from_image(attachment)
|
||||
pdf = HexaPDF::Document.new
|
||||
page = pdf.pages.add
|
||||
|
||||
scale = [A4_SIZE.first / attachment.metadata['width'].to_f,
|
||||
A4_SIZE.last / attachment.metadata['height'].to_f].min
|
||||
|
||||
page.box.width = attachment.metadata['width'] * scale
|
||||
page.box.height = attachment.metadata['height'] * scale
|
||||
|
||||
page.canvas.image(
|
||||
StringIO.new(attachment.download),
|
||||
at: [0, 0],
|
||||
width: page.box.width,
|
||||
height: page.box.height
|
||||
)
|
||||
|
||||
pdf
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user