Move the parts for using Word documents as Jinja templates into JinjaService

This commit is contained in:
mike cullerton 2021-10-21 10:29:56 -04:00
parent 0db96fbbad
commit 3619240bae
2 changed files with 57 additions and 53 deletions

View File

@ -12,6 +12,7 @@ from crc.models.file import CONTENT_TYPES, FileModel
from crc.models.workflow import WorkflowModel
from crc.scripts.script import Script
from crc.services.file_service import FileService
from crc.services.jinja_service import JinjaService
from crc.services.workflow_processor import WorkflowProcessor
@ -77,7 +78,7 @@ Takes two arguments:
else:
image_file_data = None
return self.make_template(BytesIO(file_data_model.data), task.data, image_file_data)
return JinjaService().make_template(BytesIO(file_data_model.data), task.data, image_file_data)
def get_image_file_data(self, fields_str, task):
image_file_data = []
@ -107,55 +108,3 @@ Takes two arguments:
"be a comma-delimited list of File IDs")
return image_file_data
def make_template(self, binary_stream, context, image_file_data=None):
# TODO: Move this into the jinja_service?
doc = DocxTemplate(binary_stream)
doc_context = copy.deepcopy(context)
doc_context = self.rich_text_update(doc_context)
doc_context = self.append_images(doc, doc_context, image_file_data)
jinja_env = jinja2.Environment(autoescape=True)
try:
doc.render(doc_context, jinja_env)
except Exception as e:
print (e)
target_stream = BytesIO()
doc.save(target_stream)
target_stream.seek(0) # move to the beginning of the stream.
return target_stream
def append_images(self, template, context, image_file_data):
context['images'] = {}
if image_file_data is not None:
for file_data_model in image_file_data:
fm = file_data_model.file_model
if fm is not None:
context['images'][fm.id] = {
'name': fm.name,
'url': '/v1.0/file/%s/data' % fm.id,
'image': self.make_image(file_data_model, template)
}
return context
def make_image(self, file_data_model, template):
return InlineImage(template, BytesIO(file_data_model.data), width=Inches(6.5))
def rich_text_update(self, context):
"""This is a bit of a hack. If we find that /n characters exist in the data, we want
these to come out in the final document without requiring someone to predict it in the
template. Ideally we would use the 'RichText' feature of the python-docx library, but
that requires we both escape it here, and in the Docx template. There is a thing called
a 'listing' in python-docx library that only requires we use it on the way in, and the
template doesn't have to think about it. So running with that for now."""
# loop through the content, identify anything that has a newline character in it, and
# wrap that sucker in a 'listing' function.
if isinstance(context, dict):
for k, v in context.items():
context[k] = self.rich_text_update(v)
elif isinstance(context, list):
for i in range(len(context)):
context[i] = self.rich_text_update(context[i])
elif isinstance(context, str) and '\n' in context:
return Listing(context)
return context

View File

@ -37,3 +37,58 @@ Cool Right?
template = jinja2_env.get_template('main_template')
return template.render(**data)
#
# The rest of this is for using Word documents as Jinja templates
#
def make_template(self, binary_stream, context, image_file_data=None):
# TODO: Move this into the jinja_service?
doc = DocxTemplate(binary_stream)
doc_context = copy.deepcopy(context)
doc_context = self.rich_text_update(doc_context)
doc_context = self.append_images(doc, doc_context, image_file_data)
jinja_env = Environment(autoescape=True)
try:
doc.render(doc_context, jinja_env)
except Exception as e:
print (e)
target_stream = BytesIO()
doc.save(target_stream)
target_stream.seek(0) # move to the beginning of the stream.
return target_stream
def rich_text_update(self, context):
"""This is a bit of a hack. If we find that /n characters exist in the data, we want
these to come out in the final document without requiring someone to predict it in the
template. Ideally we would use the 'RichText' feature of the python-docx library, but
that requires we both escape it here, and in the Docx template. There is a thing called
a 'listing' in python-docx library that only requires we use it on the way in, and the
template doesn't have to think about it. So running with that for now."""
# loop through the content, identify anything that has a newline character in it, and
# wrap that sucker in a 'listing' function.
if isinstance(context, dict):
for k, v in context.items():
context[k] = self.rich_text_update(v)
elif isinstance(context, list):
for i in range(len(context)):
context[i] = self.rich_text_update(context[i])
elif isinstance(context, str) and '\n' in context:
return Listing(context)
return context
def append_images(self, template, context, image_file_data):
context['images'] = {}
if image_file_data is not None:
for file_data_model in image_file_data:
fm = file_data_model.file_model
if fm is not None:
context['images'][fm.id] = {
'name': fm.name,
'url': '/v1.0/file/%s/data' % fm.id,
'image': self.make_image(file_data_model, template)
}
return context
@staticmethod
def make_image(file_data_model, template):
return InlineImage(template, BytesIO(file_data_model.data), width=Inches(6.5))