You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
docuseal/lib/submissions/upload_to_paperless.rb

130 lines
3.8 KiB

# frozen_string_literal: true
module Submissions
module UploadToPaperless
UploadError = Class.new(StandardError)
BOUNDARY_PREFIX = '----DocuSealPaperlessUpload'
module_function
def call(submission)
return unless configured?
submission.submitters.load unless submission.submitters.loaded?
title = build_title(submission)
created = completed_date(submission)
results = documents_to_upload(submission, title).map do |attachment, doc_title|
upload_document(attachment, title: doc_title, created:)
end
results.compact.presence
end
def configured?
ENV['PAPERLESS_NGX_URL'].present? && ENV['PAPERLESS_NGX_TOKEN'].present?
end
def documents_to_upload(submission, title)
documents = []
if submission.combined_document.attached?
documents << [submission.combined_document, title]
else
submission.submitters.select(&:completed_at?).each do |submitter|
submitter.documents.each do |doc|
documents << [doc, title]
end
end
end
documents << [submission.audit_trail, "#{title} - Audit Trail"] if submission.audit_trail.attached?
documents
end
def build_title(submission)
submitter_names = submission.submitters
.select(&:completed_at?)
.sort_by(&:completed_at)
.filter_map(&:name)
.join(', ')
template_name = submission.template&.name || 'Document'
if submitter_names.present?
"#{template_name} - #{submitter_names}"
else
template_name
end
end
def completed_date(submission)
last_completed = submission.submitters.filter_map(&:completed_at).max
last_completed&.strftime('%Y-%m-%d')
end
def upload_document(attachment, title:, created:)
blob = attachment.blob
filename = sanitize_filename(blob.filename.to_s)
boundary = "#{BOUNDARY_PREFIX}#{SecureRandom.hex(16)}"
blob.open do |tempfile|
body = build_multipart_body(tempfile, filename:, title:, created:, boundary:)
response = connection.post('/api/documents/post_document/') do |req|
req.headers['Authorization'] = "Token #{ENV['PAPERLESS_NGX_TOKEN']}" # rubocop:disable Style/FetchEnvVar
req.headers['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
req.body = body
req.options.read_timeout = 30
req.options.open_timeout = 10
end
if response.status >= 400
body_preview = response.body.to_s.truncate(200)
raise UploadError, "Paperless-ngx upload failed (HTTP #{response.status}): #{body_preview}"
end
response.body.to_s.delete('"').strip
end
end
def sanitize_filename(filename)
filename.gsub(/["\r\n\\]/, '_')
end
def build_multipart_body(tempfile, filename:, title:, created:, boundary:)
parts = []
parts << "--#{boundary}\r\n"
parts << "Content-Disposition: form-data; name=\"document\"; filename=\"#{filename}\"\r\n"
parts << "Content-Type: application/pdf\r\n\r\n"
parts << tempfile.read
parts << "\r\n"
parts << "--#{boundary}\r\n"
parts << "Content-Disposition: form-data; name=\"title\"\r\n\r\n"
parts << title
parts << "\r\n"
if created
parts << "--#{boundary}\r\n"
parts << "Content-Disposition: form-data; name=\"created\"\r\n\r\n"
parts << created
parts << "\r\n"
end
parts << "--#{boundary}--\r\n"
parts.join
end
def connection
Faraday.new(url: ENV['PAPERLESS_NGX_URL']) do |f| # rubocop:disable Style/FetchEnvVar
f.adapter Faraday.default_adapter
end
end
end
end