Skip to content

Commit

Permalink
testing fix
Browse files Browse the repository at this point in the history
  • Loading branch information
maximz committed Feb 6, 2016
1 parent 69ef95b commit d97c9f0
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 46 deletions.
130 changes: 85 additions & 45 deletions course_selection/pdf.py
Original file line number Diff line number Diff line change
@@ -1,76 +1,112 @@
# retrieved from: https://gist.github.com/zyegfryed/918403
# retrieved from: https://gist.github.com/zyegfryed/918403, https://gist.github.com/grantmcconnaughey/ce90a689050c07c61c96
# used for creating pdf files to be served using django

# -*- coding: utf-8 -*-
import codecs
import subprocess
from fdfgen import forge_fdf
from django.core.exceptions import ImproperlyConfigured
from django.template import engines
from django.template.backends.base import BaseEngine
from django.template.engine import Engine, _dirs_undefined

from django.template import Template, loader
from django.template.loader import get_template as gtl, LoaderOrigin


class PdfTemplateError(Exception):
pass

class PdftkEngine(BaseEngine):

class PdfTemplate(Template):
# Going ahead and defining this, but really PDFs should still be placed
# in the templates directory of an app because the loader checks templates
app_dirname = 'pdfs'

def __init__(self, template_string, origin=None, name='<Unknown Template>'):
self.origin = origin
def __init__(self, params):
params = params.copy()
options = params.pop('OPTIONS').copy()
super(PdftkEngine, self).__init__(params)
self.engine = self._Engine(self.dirs, self.app_dirs, **options)

def get_template(self, template_name, dirs=_dirs_undefined):
return PdfTemplate(self.engine.get_template(template_name, dirs))

class _Engine(Engine):
def make_origin(self, display_name, loader, name, dirs):
# Always return an Origin object, because PDFTemplate need it to
# render the PDF Form file.
from django.template.loader import LoaderOrigin
return LoaderOrigin(display_name, loader, name, dirs)


class PdfTemplate(object):
pdftk_bin = None

def __init__(self, template):
self.template = template
self.set_pdftk_bin()

@property
def origin(self):
return self.template.origin

def render(self, context=None, request=None):
if context is None:
context = {}

def render(self, context):
context = context.items()
output, err = self.fill_form(context, self.origin.name)
if err:
raise PdfTemplateError(err)
return output

def fill_form(self, fields, src, pdftk_bin=None):
if pdftk_bin is None:
from django.conf import settings
assert hasattr(settings, 'PDFTK_BIN'), "PDF generation requires pdftk (http://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/). Edit your PDFTK_BIN settings accordingly."
assert len(settings.PDFTK_BIN) > 0
pdftk_bin = settings.PDFTK_BIN

fdf_stream = forge_fdf(fdf_data_strings=fields)

cmd = [
pdftk_bin,
src,
'fill_form',
'-',
'output',
'-',
'flatten',
]
cmd = [self.pdftk_bin, src, 'fill_form', '-', 'output', '-', 'flatten']
cmd = ' '.join(cmd)

return self.run_cmd(cmd, fdf_stream)

def dump_data_fields(self):
cmd = [self.pdftk_bin, self.origin.name, 'dump_data_fields']
cmd = ' '.join(cmd)

output, err = self.run_cmd(cmd, None)
if err:
raise PdfTemplateError(err)
return output

def run_cmd(self, cmd, input_data):
try:
process = subprocess.Popen(cmd, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, shell=True)
return process.communicate(input=fdf_stream)
except OSError:
return None


def get_template_from_string(source, origin=None, name=None):
"""
Returns a compiled Template object for the given template code,
handling template inheritance recursively.
"""
if name and name.endswith('.pdf'):
return PdfTemplate('pdf', origin, name)
return Template(source, origin, name)
loader.get_template_from_string = get_template_from_string
if input_data:
return process.communicate(input=input_data)
else:
return process.communicate()
except OSError, e:
return None, e

def set_pdftk_bin(self):
if self.pdftk_bin is None:
from django.conf import settings
if not hasattr(settings, 'PDFTK_BIN'):
msg = "PDF generation requires pdftk " \
"(http://www.pdflabs.com/tools/pdftk-the-pdf-toolkit). " \
"Edit your PDFTK_BIN settings accordingly."
raise ImproperlyConfigured(msg)
self.pdftk_bin = settings.PDFTK_BIN

return self.pdftk_bin

def make_origin(display_name, loader, name, dirs):
# Always return an Origin object, because PDFTemplate need it to render
# the PDF Form file.
return LoaderOrigin(display_name, loader, name, dirs)
loader.make_origin = make_origin
def version(self):
cmd = [self.pdftk_bin, '--version']
cmd = ' '.join(cmd)

output, err = self.run_cmd(cmd, None)
if err:
raise PdfTemplateError(err)
return output

def get_template(template_name):
"""
Expand All @@ -87,9 +123,13 @@ def fake_strict_errors(exception):
# Loading hacks
# Ignore UnicodeError, due to PDF file read
codecs.register_error('strict', fake_strict_errors)
# --//--
template = gtl(template_name)

if template_name.endswith('.pdf'):
template = engines['pdf'].get_template(template_name)
else:
template = engines['django'].get_template(template_name)

# Loading hacks
codecs.register_error('strict', strict_errors)
# --//--
return template

return template
2 changes: 1 addition & 1 deletion course_selection/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ def mobile_logged_in(request):
# course enrollment form generation
#############################################################################

from pdf import get_template
def get_worksheet_pdf(request, schedule_id, template_name='course_enrollment_worksheet.pdf', **kwargs):
from pdf import get_template

"""
returns a filled out course enrollment form
Expand Down
12 changes: 12 additions & 0 deletions settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@
TEMPLATE_DIRS = [normpath(join(DJANGO_ROOT, 'course_selection', 'templates')),
]

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
},
{
'BACKEND': 'course_selection.pdf.PdftkEngine',
'APP_DIRS': True,
},
]


CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # overwritten in prod.py
Expand Down

0 comments on commit d97c9f0

Please sign in to comment.