Skip to content
Snippets Groups Projects
Commit 75b36c7f authored by jan.bednarik's avatar jan.bednarik
Browse files

elections2021: Fancy PDF export

parent a0892adf
Branches
No related tags found
2 merge requests!304Release,!303Pdf
Showing
with 198 additions and 39 deletions
......@@ -4,4 +4,4 @@ line_length = 88
multi_line_output = 3
default_section = "THIRDPARTY"
include_trailing_comma = true
known_third_party = arrow,bleach,bs4,captcha,django,environ,faker,ics,markdown,modelcluster,pirates,pytest,pytz,requests,sentry_sdk,snapshottest,taggit,wagtail,wagtailmetadata,weasyprint
known_third_party = PyPDF2,arrow,bleach,bs4,captcha,django,environ,faker,ics,markdown,modelcluster,pirates,pytest,pytz,requests,sentry_sdk,snapshottest,taggit,wagtail,wagtailmetadata,weasyprint
import re
from pathlib import Path
from django.core.management.base import BaseCommand
from django.core.management.base import BaseCommand, CommandError
from django.template.loader import render_to_string
from django.utils import timezone
from weasyprint import CSS, HTML
from PyPDF2 import PdfFileMerger
from weasyprint import CSS, HTML, default_url_fetcher
from weasyprint.fonts import FontConfiguration
from ...constants import BENEFITS_CHOICES, MINISTRY_CHOICES, MINISTRY_CODES
from ...models import Elections2021ProgramPointPage
FORMAT_PDF = "pdf"
FORMAT_HTML = "html"
STATICS_DIR = (Path(__file__).parent / "../../static/elections2021/pdf/").resolve()
def get_ministry_points(ministry):
weight = f"weight_ministry_{MINISTRY_CODES[ministry]}"
return Elections2021ProgramPointPage.filter_by_weights([weight])
def local_fetcher(url):
if url.startswith("file://"):
file = Path(url[7:])
if not file.is_absolute():
file = STATICS_DIR / (url[7:])
return dict(file_obj=file.open(mode="rb"))
return default_url_fetcher(url)
def plain_export(output_file, output_format):
benefits_titles = dict(BENEFITS_CHOICES)
toc = []
body = []
for ministry, title in MINISTRY_CHOICES:
sub_toc = []
points = []
for page in get_ministry_points(ministry):
value = render_to_string(
"elections2021/export_program_point.html",
{"page": page, "benefits_titles": benefits_titles},
)
value = re.sub(r'href="#zdroje"', f'href="#zdroje_{page.id}"', value)
points.append(value)
sub_toc.append({"anchor": page.slug, "title": page.title})
body.append({"anchor": ministry, "title": title, "points": points})
toc.append({"anchor": ministry, "title": title, "sub_toc": sub_toc})
content = render_to_string(
"elections2021/export_program.html",
{
"toc": toc,
"body": body,
"now": timezone.localtime().strftime("%d.%m.%Y %H:%M"),
},
)
if output_format == FORMAT_PDF:
font_config = FontConfiguration()
html = HTML(string=content)
css = CSS(
string="""
@page {
size: A4;
margin: 1cm;
}
@font-face {
font-family: "Roboto Condensed";
src: url("https://github.com/google/fonts/blob/main/apache/roboto/static/RobotoCondensed-Regular.ttf?raw=true");
}
""",
font_config=font_config,
)
html.write_pdf(output_file, stylesheets=[css], font_config=font_config)
elif output_format == FORMAT_HTML:
with open(output_file, "w") as file:
file.write(content)
def fancy_export(output_file):
tmp_file = f"{output_file}.tmp"
benefits_titles = dict(BENEFITS_CHOICES)
points = []
for ministry, title in MINISTRY_CHOICES:
for page in get_ministry_points(ministry):
value = render_to_string(
"elections2021/export_program_point_fancy.html",
{"page": page, "benefits_titles": benefits_titles},
)
value = re.sub(r'href="#', f'href="#{page.id}_', value)
value = re.sub(r'id="', f'id="{page.id}_', value)
points.append(value)
content = render_to_string(
"elections2021/export_program_fancy.html", {"points": points}
)
font_config = FontConfiguration()
html = HTML(string=content, url_fetcher=local_fetcher)
css = CSS(str(STATICS_DIR / "style.css"), font_config=font_config)
document = html.render(stylesheets=[css], font_config=font_config)
document.write_pdf(tmp_file)
merger = PdfFileMerger()
merger.append(str(STATICS_DIR / "beginning.pdf"))
merger.append(tmp_file, pages=(2, len(document.pages)))
merger.append(str(STATICS_DIR / "ending.pdf"))
merger.write(output_file)
merger.close()
Path(tmp_file).unlink()
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument("output", type=str, help=".pdf nebo .html soubor")
parser.add_argument("--fancy", action="store_true")
def handle(self, *args, **options):
benefits_titles = {num: title for num, title in BENEFITS_CHOICES}
toc = []
body = []
for ministry, title in MINISTRY_CHOICES:
sub_toc = []
points = []
for page in get_ministry_points(ministry):
value = render_to_string(
"elections2021/export_program_point.html",
{"page": page, "benefits_titles": benefits_titles},
)
value = re.sub(r'href="#zdroje"', f'href="#zdroje_{page.id}"', value)
points.append(value)
sub_toc.append({"anchor": page.slug, "title": page.title})
body.append({"anchor": ministry, "title": title, "points": points})
toc.append({"anchor": ministry, "title": title, "sub_toc": sub_toc})
content = render_to_string(
"elections2021/export_program.html",
{
"toc": toc,
"body": body,
"now": timezone.localtime().strftime("%d.%m.%Y %H:%M"),
},
)
output_file = options["output"]
if output_file.endswith(".pdf"):
output_format = FORMAT_PDF
elif output_file.endswith(".html"):
output_format = FORMAT_HTML
else:
raise CommandError("Jako výstup zadej soubor .html nebo .pdf")
if options["output"].endswith(".pdf"):
html = HTML(string=content)
css = CSS(string="@page { size: A4; margin: 1cm; }")
html.write_pdf(options["output"], stylesheets=[css])
elif options["output"].endswith(".html"):
with open(options["output"], "w") as file:
file.write(content)
if options["fancy"]:
if output_format != FORMAT_PDF:
raise CommandError("Fancy export lze udělat jen do .pdf")
fancy_export(output_file)
else:
print("ERROR: Jako výstup zadej soubor .html nebo .pdf")
plain_export(output_file, output_format)
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
This diff is collapsed.
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment