Browse Source

DIV-1031 - Convert uploaded images to PDF

pull/169/head
Michael Olund 5 years ago
parent
commit
98170c572c
7 changed files with 133 additions and 4 deletions
  1. +40
    -0
      edivorce/apps/core/templates/pdf/images_to_pdf.html
  2. +16
    -0
      edivorce/apps/core/templatetags/format_utils.py
  3. +2
    -1
      edivorce/apps/core/urls.py
  4. +38
    -2
      edivorce/apps/core/views/api.py
  5. +33
    -1
      edivorce/apps/core/views/pdf.py
  6. +1
    -0
      requirements.txt
  7. +3
    -0
      vue/src/components/Uploader/Uploader.vue

+ 40
- 0
edivorce/apps/core/templates/pdf/images_to_pdf.html View File

@ -0,0 +1,40 @@
{% load static %}
{% load format_utils %}
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>{{ form }}</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="{{ css_root }}/static/css/weasyprint.css" />
{% include 'partials/gtm_head.html' %}
<style type="text/css">
@page {
margin: 0.25cm;
@bottom-right {
content: none
}
}
</style>
</head>
<body>
<div class="print-wrapper">
{% for image in images %}
<img src="{{ css_root }}/api/documents/{{ image.file }}/{{ image.rotation }}/" style="{{ image|css_rotate }}">
{% if not forloop.last %}
<p style="page-break-before: always" ></p>
{% endif %}
{% endfor %}
</div>
</body>
</html>

+ 16
- 0
edivorce/apps/core/templatetags/format_utils.py View File

@ -191,3 +191,19 @@ def agreed_child_support_amount(context, claimant_id, line_breaks=True):
return context.get('amount_income_over_high_income_limit_{}'.format(claimant_id), '')
else:
return linebreaksli(context.get('amount_income_over_high_income_limit_{}'.format(claimant_id), ''))
@register.filter
def css_rotate(image):
""" Gets extra CSS needed for image rotation when generating PDFs """
if image.rotation == 90 or image.rotation == 270:
height = image.width
width = image.height
else:
height = image.height
width = image.width
if width == 0 or height/width < 1.3:
return 'width: 100%'
else:
return 'height: 26.7cm'

+ 2
- 1
edivorce/apps/core/urls.py View File

@ -7,7 +7,7 @@ urlpatterns = [
# url(r'^guide$', styleguide.guide),
url(r'^api/response$', api.UserResponseHandler.as_view()),
url(r'^api/documents/$', api.DocumentCreateView.as_view(), name='documents'),
path('api/documents/<file_key>/', api.get_document_file_by_key, name='file_by_key'),
path('api/documents/<file_key>/<int:rotation>/', api.get_document_file_by_key, name='document_by_key'),
# we add an extra 'x' to the file extension so the siteminder proxy doesn't treat it as an image
path('api/documents/<doc_type>/<int:party_code>/<filename>x/<int:size>/', api.DocumentView.as_view(), name='document'),
@ -32,6 +32,7 @@ urlpatterns = [
# url(r'^headers$', system.headers),
url(r'^pdf-form(?P<form_number>[0-9]{1,3}(_we|_claimant1|_claimant2)?)$', pdf.form, name="pdf_form"),
path('pdf-images/<doc_type>/<int:party_code>/', pdf.images_to_pdf, name='pdf_images'),
url(r'^prequalification/step_(?P<step>[0-9]{2})$', main.prequalification, name="prequalification"),
url(r'^question/(?P<step>.*)/(?P<sub_step>.*)/$', main.question, name="question_steps"),
url(r'^question/(?P<step>.*)$', main.question, name="question_steps"),


+ 38
- 2
edivorce/apps/core/views/api.py View File

@ -5,6 +5,7 @@ from rest_framework import permissions, status
from rest_framework.generics import CreateAPIView, ListAPIView, RetrieveUpdateDestroyAPIView
from rest_framework.views import APIView
from rest_framework.response import Response
from PIL import Image
from ..models import Document, Question
from ..serializer import CreateDocumentSerializer, DocumentMetadataSerializer, UserResponseSerializer
@ -87,9 +88,44 @@ class DocumentView(RetrieveUpdateDestroyAPIView):
return HttpResponse(file_contents, content_type=content_type)
def get_document_file_by_key(request, file_key):
def get_document_file_by_key(request, file_key, rotation):
file = Document.get_file(file_key)
if not file:
return HttpResponseNotFound()
content_type = Document.content_type_from_filename(file.name)
return HttpResponse(file, content_type=content_type)
# if it's a PDF or it doesn't require rotation
if content_type == 'application/pdf' or rotation == 0:
try:
return HttpResponse(file, content_type=content_type)
except TypeError:
raise Http404("File not found")
# if the file needs to be rotated
rot_img = __rotate_image(file, rotation)
extension = __get_file_extension(file)
try:
response = HttpResponse(content_type=content_type)
rot_img.save(response, extension)
return response
except TypeError:
raise Http404("File not found")
def __get_file_extension(file):
extension = re.split(r'[\._]', file.name.upper())[-1]
if extension == "JPG" or extension == "JPE":
return "JPEG"
return extension
def __rotate_image(file, rotation):
im = Image.open(file)
if rotation == 90:
return im.transpose(Image.ROTATE_270)
elif rotation == 270:
return im.transpose(Image.ROTATE_90)
else:
return im.transpose(Image.ROTATE_180)

+ 33
- 1
edivorce/apps/core/views/pdf.py View File

@ -9,6 +9,7 @@ from django.template.loader import render_to_string
import requests
from ..decorators import bceid_required
from ..models import Document
from ..utils.derived import get_derived_data
from ..utils.user_response import get_data_for_user
@ -66,8 +67,12 @@ def __render_form(request, form_name, context):
if output_as_html:
context['css_root'] = settings.FORCE_SCRIPT_NAME[:-1]
template_name = form_name
if not form_name.startswith('form'):
template_name = 'images_to_pdf'
# render to form as HTML
rendered_html = render_to_string('pdf/' + form_name + '.html',
rendered_html = render_to_string('pdf/' + template_name + '.html',
context=context, request=request)
# if '?html' is in the querystring, then return the plain html
@ -93,3 +98,30 @@ def __add_claimant_info(responses, claimant):
claimant_info[claimant_key] = responses[key]
responses.update(claimant_info)
return responses
@bceid_required
def images_to_pdf(request, doc_type, party_code):
documents = Document.objects.filter(
bceid_user=request.user, doc_type=doc_type, party_code=party_code)
if not documents:
return HttpResponse(status=204)
if party_code == 1:
form_name = doc_type + "_claimant1"
elif party_code == 2:
form_name = doc_type + "_claimant2"
else:
form_name = doc_type
if documents[0].filename.endswith(('.pdf', '.PDF')):
response = HttpResponse(documents[0].file.read(), content_type='application/pdf')
response['Content-Disposition'] = 'inline;filename=' + form_name + '.pdf'
return response
return __render_form(request, form_name, {
'css_root': settings.WEASYPRINT_CSS_LOOPBACK,
'images': documents,
'form': form_name
})

+ 1
- 0
requirements.txt View File

@ -19,6 +19,7 @@ gunicorn==20.0.4
idna==2.10
libsass==0.20.0
marshmallow==3.7.1
Pillow==7.2.0
promise==2.3
psycopg2==2.8.5
python-dotenv==0.14.0


+ 3
- 0
vue/src/components/Uploader/Uploader.vue View File

@ -98,6 +98,9 @@
<div class="pull-right" v-if="!tooBig">
<em>(Maximum {{ maxMegabytes }} MB)</em>
</div>
<a v-if="files.length" :href="pdfURL" target="_blank">{{ pdfURL }}</a>
<modal ref="warningModal" class="warning-modal" v-model="showWarning">
{{ warningText }}
</modal>


Loading…
Cancel
Save