Skip to content

Commit

Permalink
feat: Support generating multi set pdf report
Browse files Browse the repository at this point in the history
  • Loading branch information
ronisaha committed Mar 13, 2024
1 parent 94b0af7 commit d7608f7
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 31 deletions.
24 changes: 13 additions & 11 deletions weasyprint_rest/print/weasyprinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,29 @@ def create_directory_if_not_present(file_path):
os.makedirs(directory)


def encrypt_pdf(pdf_bytes, password=None):
if password is None:
return pdf_bytes

out_file = io.BytesIO()
encrypt(io.BytesIO(pdf_bytes), password, out_file)

return out_file.getvalue()


class WeasyPrinter:

def __init__(self, html=None, url=None, template=None):
self.html = html
self.url = url
self.template = template if template is not None else Template()

def write(self, password=None, driver=None, options=None):
def write(self, driver=None, options=None):

if driver == 'wk':
pdf_bytes = self._write_with_pdfkit(options)
return self._write_with_pdfkit(options)
else:
pdf_bytes = self._write_with_weasyprint()

if password is None:
return pdf_bytes

out_file = io.BytesIO()
encrypt(io.BytesIO(pdf_bytes), password, out_file)

return out_file.getvalue()
return self._write_with_weasyprint()

def _write_with_pdfkit(self, options):
verbose = None
Expand Down
81 changes: 61 additions & 20 deletions weasyprint_rest/web/rest/print.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@
# -*- coding: utf-8 -*-
import io
import json
import logging
import os

from flask import request, abort, make_response, render_template
from flask_restful import Resource
from pypdf import PdfMerger
from werkzeug.datastructures import FileStorage

from ..util import authenticate
from ...print.template import Template
from ...print.template_loader import TemplateLoader
from ...print.weasyprinter import WeasyPrinter
from ...print.weasyprinter import WeasyPrinter, encrypt_pdf


def _get_request_list_or_value(request_dict, name):
return request_dict.getlist(name) if name.endswith("[]") else request_dict[name]


def _get_request_argument(name, default=None):
form = request.form
args = request.args
Expand Down Expand Up @@ -70,6 +71,35 @@ def _build_template():
return Template(styles=styles, assets=assets, base_template=base_template)


def convert_html2pdf(driver, html, template, url):
printer = WeasyPrinter(html=html, url=url, template=template)
options = None
if driver == 'wk':
options = json.loads(_parse_request_argument("options", '{}'))
pdf_bytes = printer.write(driver=driver, options=options)
return pdf_bytes


def render_report_template(report, **data):
content = render_template(report, **data)
return FileStorage(
stream=io.BytesIO(bytes(content, encoding='utf8')),
content_type="text/html"
)


def get_multi_report_pdf(driver, optimize_images, report, template, data_arr):
merger = PdfMerger()
for data in data_arr:
h = render_report_template(report, **data)
pdf_bytes = convert_html2pdf(driver, h, optimize_images, template, None)
merger.append(io.BytesIO(pdf_bytes))
bytes_stream = io.BytesIO()
merger.write(bytes_stream)

return bytes_stream.getvalue()


class PrintAPI(Resource):
decorators = [authenticate]

Expand All @@ -81,43 +111,54 @@ def post(self):
driver = _parse_request_argument("driver", 'weasy')
url = _parse_request_argument("url", None)
report = _parse_request_argument("report", None)
data_set = _parse_request_argument("data_set", None)

if driver not in['weasy', 'wk']:
if driver not in ['weasy', 'wk']:
return abort(422, description="Invalid value for driver! only wk or weasy supported")

html = None
pdf_bytes = None
template = _build_template()

if report is not None:
if report is not None and data_set is not None:

try:
data_arr = json.loads(_parse_request_argument("data_set", '[]'))
except (ValueError, TypeError) as te:
logging.error(te)
return abort(400, description="Invalid data provided")
except Exception as te:
logging.error(te)
return abort(400, description="Unknown error occurred")

if not isinstance(data_arr, list) or len(data_arr) == 0:
return abort(400, description="Unknown error occurred")

pdf_bytes = get_multi_report_pdf(driver, report, template, data_arr)
elif report is not None:
try:
data = json.loads(_parse_request_argument("data", '{}'))
content = render_template(report, **data)
html = FileStorage(
stream=io.BytesIO(bytes(content, encoding='utf8')),
content_type="text/html"
)
except (ValueError, TypeError):
html = render_report_template(report, **(json.loads(_parse_request_argument("data", '{}'))))
except (ValueError, TypeError) as te:
logging.error(te)
return abort(400, description="Invalid data provided")
except Exception as te:
return abort(400, description=te)
logging.error(te)
return abort(400, description="Unknown error occurred")

elif url is None:
html = _parse_request_argument("html", None, "file", {
"content_type": "text/html"
})

if html is None and url is None:
if html is None and url is None and pdf_bytes is None:
return abort(422, description="Required argument 'html' or 'url' or report is missing.")

template = _build_template()
printer = WeasyPrinter(html=html, url=url, template=template)
if pdf_bytes is None:
pdf_bytes = convert_html2pdf(driver, html, template, url)

password = _parse_request_argument("password", None)

options = None
if driver == 'wk':
options = json.loads(_parse_request_argument("options", '{}'))

content = printer.write(password=password, driver=driver, options=options)
content = encrypt_pdf(pdf_bytes, password=password)

# build response
response = make_response(content)
Expand Down

0 comments on commit d7608f7

Please sign in to comment.