From 696e603476fc6309db2ef13b172f79fd4ab38fa0 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 6 Dec 2024 15:07:03 +0100 Subject: [PATCH] report pdf + export options + work --- core/doc_gen.py | 37 +- core/models.py | 24 + core/styles.py | 2 +- core/templates/component/report.html | 3 +- core/templates/report.html | 9 +- core/templates/report_template/weekly.html | 2464 ++++++++++++++++++++ core/urls.py | 3 + core/views.py | 45 +- requirements.txt | 4 +- 9 files changed, 2579 insertions(+), 12 deletions(-) create mode 100644 core/templates/report_template/weekly.html diff --git a/core/doc_gen.py b/core/doc_gen.py index e6b3040..7999cf8 100644 --- a/core/doc_gen.py +++ b/core/doc_gen.py @@ -1,12 +1,35 @@ import json +from weasyprint import HTML, CSS +from io import BytesIO +from pdf2image import convert_from_bytes +from PIL import Image +from django.conf import settings +from django.template.loader import render_to_string +from .models import Berichtsheft +from io import BytesIO -def gen_doc(template: str, vars: dict) -> str: - definition = json.loads(open(f"{template}.json").read()) - content = open(f"{template}.html").read() +def gen_doc_html(report: Berichtsheft): + return render_to_string(f"report_template/{report.kind}.html", report.vars()) - for var in definition["vars"]: - var_r = var["name"].upper() - content = content.replace(f"[[{var_r}]]", vars[var["name"]]) - return content +def gen_doc_pdf(report: Berichtsheft): + main_content = gen_doc_html(report) + + pdf_buffer = BytesIO() + HTML( + string=main_content, + ).write_pdf(pdf_buffer, stylesheets=[CSS(string="@page { size: A4; margin: 1cm }")]) + pdf_buffer.seek(0) + return pdf_buffer + + +def gen_doc_png(report: Berichtsheft): + pdf_buffer = gen_doc_pdf(report) + pages = convert_from_bytes(pdf_buffer.getvalue(), 300) + + for page in pages: + img_byte_array = BytesIO() + page.save(img_byte_array, format="PNG") + img_byte_array.seek(0) + return img_byte_array diff --git a/core/models.py b/core/models.py index d1421bb..96df7f8 100644 --- a/core/models.py +++ b/core/models.py @@ -1,6 +1,8 @@ from django.db import models from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import Group as BuiltinGroup +from .util import get_week_range +import base64 class User(AbstractUser): @@ -49,6 +51,28 @@ class Berichtsheft(models.Model): approvals = Approval.objects.filter(report=self.id) return len(approvals) >= 2 + def vars(self): + start_date, end_date = get_week_range(self.year, self.week) + + vars = { + "user": self.user, + "kind": self.kind, + "num": self.num, + "year": self.year, + "week": self.week, + "department": self.department, + "start_date": start_date, + "end_date": end_date, + "image": base64.b64encode(self.image).decode("utf-8") + if self.image is not None + else None, + } + + for key, val in self.content.items(): + vars[key] = val + + return vars + class Approval(models.Model): id = models.AutoField(primary_key=True) diff --git a/core/styles.py b/core/styles.py index ea7dce0..7f9ce5a 100644 --- a/core/styles.py +++ b/core/styles.py @@ -2,7 +2,7 @@ STYLE = { "red_btn": "text-white bg-red-700 hover:bg-red-800 focus:outline-none focus:ring-4 focus:ring-red-300 font-medium rounded-full text-sm px-5 py-2.5 text-center me-2 mb-2 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900", - "card": "bg-white drop-shadow-md p-4 mx-auto mt-5 aspect-[2/3] hover:drop-shadow-xl hover:scale-[0.85] scale-[0.8] lg:hover:scale-[0.95] lg:scale-[0.9] transition-all duration-50 transform ease-in-out w-60 sm:w-80 flex items-center justify-center", + "card": "bg-white drop-shadow-md mx-auto mt-5 aspect-[2/3] hover:drop-shadow-xl hover:scale-[0.85] scale-[0.8] lg:hover:scale-[0.95] lg:scale-[0.9] transition-all duration-50 transform ease-in-out w-60 sm:w-80 flex items-center justify-center", "text-input": "w-full p-2 border border-gray-300 rounded-lg focus:ring focus:ring-blue-400 mb-5", } diff --git a/core/templates/component/report.html b/core/templates/component/report.html index 1bac2d5..331469c 100644 --- a/core/templates/component/report.html +++ b/core/templates/component/report.html @@ -8,5 +8,6 @@ hx-get="/report/{{ report.id }}" hx-target="#main_content" hx-push-url="true" hx > ✓ - {% endif %} {{ report }} + {% endif %} + diff --git a/core/templates/report.html b/core/templates/report.html index f8fff7a..f47c82f 100644 --- a/core/templates/report.html +++ b/core/templates/report.html @@ -1,7 +1,8 @@ {{ title|safe }}
-
+
+

Berichtsheft {{ report.year }} / {{ report.week }}

@@ -12,6 +13,12 @@

+ +

Content:

diff --git a/core/templates/report_template/weekly.html b/core/templates/report_template/weekly.html new file mode 100644 index 0000000..6c05a5c --- /dev/null +++ b/core/templates/report_template/weekly.html @@ -0,0 +1,2464 @@ +{% load markdown %} + + + + + + + + + + + + + + + + + + + + +
+ +

 

+ +

 

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

 

+
+

 

+
+

Name: {{ user }}

+
+

Ausbildungsnachweis Nr. {{ num }}

+
+

 

+
+

 

+
+

 

+
+

 

+
+

Ausbildungsjahr: {{ year }}

+
+

Firma:

+
+

Ausbildungsabteilung: {{ department }}

+
+

 

+
+

 

+
+

 

+
+

 

+
+

CANCOM GmbH

+
+

 

+
+

Woche: {{ week }}

+
+

Messerschmittstr. 20

+
+

 

+
+

 

+
+

89343 Jettingen-Scheppach

+
+

 

+
+

 

+
+

 

+
+

 

+
+

vom: {{ start_date }} bis: {{ end_date }}

+
+

 

+
+

 

+
+

 

+
+

Betriebliche + Tätigkeit (bitte + Ausbildungsverlauf mit der zeitlichen und sachlichen Gliederung abgleichen):

+

 

+

 

+

{{ company_text|markdown|safe }}        

+

 

+

 

+

 

+
+

Stunden

+
+

Thema der Woche:

+

  {{ week_topic|markdown|safe }}

+

 

+

 

+

 

+
+

 

+
+

 

+
+

 

+
+

Berufsschule (Themen des + Unterrichts)

+

 

+

{{ school_text|markdown|safe }}

+

 

+

 

+

 

+
+

 

+
+

 

+
+

 

+
+

8

+
+

Gesamtstunden

+
+

40

+
+

 

+
+

 

+
+

 

+
+

Für + die

+
+

                   

+
+

 

+
+

 

+
+

 

+
+

Richtigkeit

+
+

____________________

+
+

____________________

+
+

____________________

+
+

____________________

+
+

 

+
+

Datum

+
+

Auszubildender

+
+

Datum

+
+

Ausbilder

+
+

 

+
+

 

+
+

 

+
+ +
+ +

 

+ +
+ + + + diff --git a/core/urls.py b/core/urls.py index dcab3cb..4e7c018 100644 --- a/core/urls.py +++ b/core/urls.py @@ -5,6 +5,9 @@ urlpatterns = [ path("", views.index, name="index"), path("write", views.write_new_report, name="write"), path("report/", views.report_detail_page, name="report_detail"), + path("report//pdf", views.report_pdf_route, name="report_pdf"), + path("report//html", views.report_html_route, name="report_html"), + path("report//png", views.report_png_route, name="report_png"), path("reports", views.reports_list, name="reports_list"), path("draft", views.report_draft_update, name="report_draft_update"), path("settings", views.settings_page, name="settings"), diff --git a/core/views.py b/core/views.py index 6144704..a477744 100644 --- a/core/views.py +++ b/core/views.py @@ -9,6 +9,7 @@ from django.template.loader import render_to_string from core.styles import STYLE from .util import is_htmx_request, title, htmx_request from .reports import choose_report_kind +from .doc_gen import gen_doc_html, gen_doc_pdf, gen_doc_png import datetime import json @@ -176,7 +177,7 @@ def report_detail_page(request, report_id): return htmx_request( request, "report.html", - {"report": report, "form": form}, + {"report": report, "form": form, "STYLE": STYLE}, f"Berichtsheft {report.num}", ) @@ -224,3 +225,45 @@ def settings_page(request): {"user": user}, "Einstellungen", ) + + +def report_pdf_route(request, report_id): + user = AzureUser(request) + + report = get_object_or_404(Berichtsheft, id=report_id) + form = choose_report_kind(report.kind) + + if report.user != user.id: + return HttpResponse("Nah", status=401) + + pdf_buffer = gen_doc_pdf(report) + response = HttpResponse(pdf_buffer, content_type="application/pdf") + return response + + +def report_html_route(request, report_id): + user = AzureUser(request) + + report = get_object_or_404(Berichtsheft, id=report_id) + form = choose_report_kind(report.kind) + + if report.user != user.id: + return HttpResponse("Nah", status=401) + + html = gen_doc_html(report) + response = HttpResponse(html) + return response + + +def report_png_route(request, report_id): + user = AzureUser(request) + + report = get_object_or_404(Berichtsheft, id=report_id) + form = choose_report_kind(report.kind) + + if report.user != user.id: + return HttpResponse("Nah", status=401) + + png = gen_doc_png(report) + response = HttpResponse(png, content_type="image/png") + return response diff --git a/requirements.txt b/requirements.txt index d8344af..5b5aab3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,6 @@ Django~=4.2.11 psycopg2 markdown bleach -pillow \ No newline at end of file +pillow +weasyprint +pdf2image \ No newline at end of file