Files
intranet/worker/pdf_python/create_pdf.py
T

349 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#! /usr/bin/env python3
from calendar import monthrange
from fpdf import FPDF
import datetime
from datetime import datetime as datelul
from bs4 import BeautifulSoup
import requests
import os
def is_invalid_date(date_str):
try:
datelul.strptime(date_str, "%Y-%m-%d")
return False
except ValueError:
return True
def pdf_safe(text):
if text is None:
return ""
text = str(text)
replacements = {
"„": '"',
"“": '"',
"‚": "'",
"‘": "'",
"’": "'",
"–": "-",
"—": "-",
"…": "...",
"\xa0": " ",
}
for old, new in replacements.items():
text = text.replace(old, new)
# Alles, was nicht latin-1-kompatibel ist, verwerfen
return text.encode("latin-1", "replace").decode("latin-1")
#### GENERAL DATE CONFIGURATION ####
months_numeric = ["JANUAR", "FEBRUAR", "MÄRZ", "APRIL", "MAI", "JUNI", "JULI", "AUGUST", "SEPTEMBER", "OKTOBER", "NOVEMBER", "DEZEMBER"]
months_numeric_lower = ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"]
date = datetime.datetime.now()
month_range = monthrange(date.year, date.month)
month = months_numeric[date.month - 1]
weekdays_list = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
counter = 2
actual_day = datetime.date.today()
first_day = actual_day.replace(day=1)
weekday = first_day.weekday()
#### URL HTML PARSING ####
url = os.environ.get("CKAL_CALENDAR_URL")
if not url:
raise RuntimeError("CKAL_CALENDAR_URL ist nicht gesetzt.")
result = requests.get(url, timeout=30)
result.raise_for_status()
doc = BeautifulSoup(result.text, "html.parser")
table = doc.find_all("tbody")[0]
tablerows = table.find_all("tr")
#### PDF GENERATING PROGRESS ####
pdf = FPDF("P", "mm", "A4")
pdf.set_auto_page_break(auto=True, margin=15)
pdf.add_page()
# Header
pdf.set_font("helvetica", "B", 16)
pdf.cell(160, 7, pdf_safe("Terminübersicht: " + str(month) + " " + str(date.year)), 0, 1)
path = os.path.join(os.path.dirname(__file__), "nak_logo.png")
assert os.path.isfile(path)
pdf.image(path, 188, 9.5, 11)
pdf.set_font("helvetica", "", 10)
pdf.cell(160, 5, pdf_safe("der Gemeinde Berlin-Reinickendorf"), 0, 1)
pdf.cell(0, 2, " ", 0, 1)
# Tablehead
pdf.set_font("helvetica", "B", 10)
pdf.cell(20, 5, "Datum", 1, 0, "C")
pdf.cell(15, 5, "Tag", 1, 0, "C")
pdf.cell(20, 5, "Uhrzeit", 1, 0, "C")
pdf.cell(75, 5, "Veranstaltung", 1, 0)
pdf.cell(60, 5, "Ort", 1, 1, "C")
pdf.set_font("helvetica", "", 8)
# Startposition (heutiges Datum) suchen
iStart = None
jStart = None
for i in range(len(tablerows)):
table_cells = tablerows[i].find_all("td")
for j in range(len(table_cells)):
table_dates = table_cells[j].get("data-date", "")
date_for_table = str(table_dates).split("-")
if len(date_for_table) == 3:
if (
date_for_table[0] == str(date.strftime("%Y"))
and date_for_table[1] == str(date.strftime("%m"))
and date_for_table[2] == str(date.strftime("%d"))
):
iStart = i
jStart = j
break
if jStart is not None:
break
if jStart is None:
raise RuntimeError("Heutiges Datum wurde im Kalender nicht gefunden.")
j = jStart
for i in range(len(tablerows)):
table_cells = tablerows[i].find_all("td")
table_dates = table_cells[j].get("data-date", "")
date_for_table = str(table_dates).split("-")
if len(date_for_table) != 3:
break
if is_invalid_date(date_for_table[0] + "-" + date_for_table[1] + "-" + date_for_table[2]):
break
# Trennlinie
pdf.set_fill_color(130)
pdf.cell(0, 0.3, " ", 0, 1, fill=True)
# Wochentag korrigieren
if weekday == 7:
weekday = 0
# Zeilenfarbe
if counter % 2 == 0:
pdf.set_fill_color(255, 255, 255)
else:
pdf.set_fill_color(220)
# Samstag/Sonntag hervorheben
pdf.set_font("helvetica", "", 8)
if weekday == 2 or weekday == 6:
pdf.set_font("helvetica", "B", 8)
if weekday == 6:
pdf.set_fill_color(170, 210, 255)
# Heutigen Tag gelb markieren
if (
date_for_table[0] == str(date.strftime("%Y"))
and date_for_table[1] == str(date.strftime("%m"))
and date_for_table[2] == str(date.strftime("%d"))
):
pdf.set_fill_color(255, 255, 0)
pdf.cell(20, 4, pdf_safe(date_for_table[2] + "." + date_for_table[1] + "." + date_for_table[0]), 0, 0, "C", fill=True)
event_full_block = table_cells[j].find_all("div", class_="calEventBox")
events = table_cells[j].find_all(
style=lambda style: style
and "margin-right:.2em" in style.replace(" ", "")
)
pdf.cell(15, 4, pdf_safe(weekdays_list[weekday]), 0, 0, "C", fill=True)
if len(events) == 0:
pdf.cell(0, 4, " ", 0, 1, fill=True)
for k in range(len(events)):
if k > 0:
pdf.cell(35, 4, " ", 0, 0, fill=True)
event_place = "--"
pdf.cell(20, 4, " ", 0, 0, "C", fill=True)
if k < len(event_full_block):
event_time = event_full_block[k].find_all(style="font-weight:normal")
else:
event_time = []
if len(event_time) > 0:
try:
elements = str(event_time[0]).split("<")
except Exception:
print("error1")
else:
if len(elements) > 1 and ">" in elements[1]:
time_text = elements[1].split(">")[1]
if ":" in str(time_text):
pdf.set_x(pdf.get_x() - 20)
pdf.cell(20, 4, pdf_safe(time_text), 0, 0, "C", fill=True)
if len(elements) > 2 and ">" in elements[2]:
place_text = elements[2].split(">")[1]
if place_text == "":
event_place = "--"
else:
if str(place_text).startswith(","):
event_place = str(place_text)[2:]
else:
event_place = str(place_text)
event_name = events[k].get_text(strip=True) if len(events) > 0 else ""
pdf.cell(75, 4, pdf_safe(event_name), 0, 0, fill=True)
pdf.cell(60, 4, pdf_safe(event_place), 0, 1, "C", fill=True)
counter += 1
weekday += 1
# Fußzeile
pdf.set_font("helvetica", "", 8)
pdf.cell(0, 1, " ", 0, 1)
pdf.cell(0, 0.1, " ", 1, 1)
pdf.cell(0, 1, " ", 0, 1)
pdf.cell(153, 3, pdf_safe("gemeindeleitung@nak-reinickendorf.de"), 0, 0)
pdf.cell(30, 3, pdf_safe("Klixstraße 17, 13403 Berlin"), 0, 1)
pdf.set_font("helvetica", "I", 8)
pdf.cell(153, 3, pdf_safe("Berlin, " + str(date.strftime("%d.%m.%Y %H:%M"))), 0, 0)
pdf.set_font("helvetica", "", 8)
pdf.cell(30, 3, pdf_safe("nak-reinickendorf.de"), 0, 1)
# Zweite Monats-Spalte / Folgemonat
if jStart + 1 < 12:
pdf.cell(0, 4, " ", 0, 1)
pdf.cell(0, 2, " ", 0, 1)
pdf.set_font("helvetica", "B", 16)
pdf.cell(160, 7, pdf_safe("Terminübersicht: " + str(months_numeric[date.month] + " " + str(date.year))), 0, 1)
pdf.set_font("helvetica", "", 10)
pdf.cell(
160,
5,
pdf_safe("Die Termine für " + str(months_numeric_lower[date.month]) + " befinden sich noch in Planung und können sich ändern."),
0,
1,
)
pdf.cell(0, 2, " ", 0, 1)
# Tablehead
pdf.set_font("helvetica", "B", 10)
pdf.cell(20, 5, "Datum", 1, 0, "C")
pdf.cell(15, 5, "Tag", 1, 0, "C")
pdf.cell(20, 5, "Uhrzeit", 1, 0, "C")
pdf.cell(75, 5, "Veranstaltung", 1, 0)
pdf.cell(60, 5, "Ort", 1, 1, "C")
j = jStart + 1
for i in range(len(tablerows)):
table_cells = tablerows[i].find_all("td")
table_dates = table_cells[j].get("data-date", "")
date_for_table = str(table_dates).split("-")
if len(date_for_table) != 3:
break
if is_invalid_date(date_for_table[0] + "-" + date_for_table[1] + "-" + date_for_table[2]):
break
pdf.set_fill_color(130)
pdf.cell(0, 0.3, " ", 0, 1, fill=True)
if weekday == 7:
weekday = 0
if counter % 2 == 0:
pdf.set_fill_color(255, 255, 255)
else:
pdf.set_fill_color(220)
pdf.set_font("helvetica", "", 8)
if weekday == 2 or weekday == 6:
pdf.set_font("helvetica", "B", 8)
if weekday == 6:
pdf.set_fill_color(170, 210, 255)
pdf.cell(20, 4, pdf_safe(date_for_table[2] + "." + date_for_table[1] + "." + date_for_table[0]), 0, 0, "C", fill=True)
event_full_block = table_cells[j].find_all("div", class_="calEventBox")
events = table_cells[j].find_all(style="margin-right:.2em")
pdf.cell(15, 4, pdf_safe(weekdays_list[weekday]), 0, 0, "C", fill=True)
if len(events) == 0:
pdf.cell(0, 4, " ", 0, 1, fill=True)
for k in range(len(events)):
if k > 0:
pdf.cell(35, 4, " ", 0, 0, fill=True)
event_place = "--"
pdf.cell(20, 4, " ", 0, 0, "C", fill=True)
if k < len(event_full_block):
event_time = event_full_block[k].find_all(style="font-weight:normal")
else:
event_time = []
if len(event_time) > 0:
try:
elements = str(event_time[0]).split("<")
except Exception:
print("error3")
else:
if len(elements) > 1 and ">" in elements[1]:
time_text = elements[1].split(">")[1]
if ":" in str(time_text):
pdf.set_x(pdf.get_x() - 20)
pdf.cell(20, 4, pdf_safe(time_text), 0, 0, "C", fill=True)
if len(elements) > 2 and ">" in elements[2]:
place_text = elements[2].split(">")[1]
if place_text == "":
event_place = "--"
else:
if str(place_text).startswith(","):
event_place = str(place_text)[2:]
else:
event_place = str(place_text)
event_name = events[k].get_text(strip=True) if len(events) > 0 else ""
pdf.cell(75, 4, pdf_safe(event_name), 0, 0, fill=True)
pdf.cell(60, 4, pdf_safe(event_place), 0, 1, "C", fill=True)
counter += 1
weekday += 1
# Fußzeile
pdf.set_font("helvetica", "", 8)
pdf.cell(0, 1, " ", 0, 1)
pdf.cell(0, 0.1, " ", 1, 1)
pdf.cell(0, 1, " ", 0, 1)
pdf.cell(153, 3, pdf_safe("gemeindeleitung@nak-reinickendorf.de"), 0, 0)
pdf.cell(30, 3, pdf_safe("Klixstraße 17, 13403 Berlin"), 0, 1)
pdf.set_font("helvetica", "I", 8)
pdf.cell(153, 3, pdf_safe("Berlin, " + str(date.strftime("%d.%m.%Y %H:%M"))), 0, 0)
pdf.set_font("helvetica", "", 8)
pdf.cell(30, 3, pdf_safe("nak-reinickendorf.de"), 0, 1)
#### PDF ERZEUGEN ####
output_path = os.environ.get("PDF_OUTPUT", "/data/pdf/terminuebersicht.pdf")
os.makedirs(os.path.dirname(output_path), exist_ok=True)
pdf.output(output_path)