From d2e6b65a12b482c225f6accf6c59632688a00e39 Mon Sep 17 00:00:00 2001 From: Angelo Rodriguez Date: Tue, 3 Dec 2024 15:15:45 +0100 Subject: [PATCH 01/10] work --- core/migrations/0007_approval.py | 29 +++++++++++++++ .../0008_berichtsheft_needs_rewrite.py | 18 ++++++++++ core/models.py | 7 +++- core/styles.py | 6 ++++ core/templates/index.html | 27 +++++++------- core/templates/report.html | 18 ++++++++++ core/urls.py | 2 +- core/views.py | 35 +++++++++++++++++-- 8 files changed, 123 insertions(+), 19 deletions(-) create mode 100755 core/migrations/0007_approval.py create mode 100755 core/migrations/0008_berichtsheft_needs_rewrite.py create mode 100755 core/styles.py create mode 100755 core/templates/report.html diff --git a/core/migrations/0007_approval.py b/core/migrations/0007_approval.py new file mode 100755 index 0000000..6893d66 --- /dev/null +++ b/core/migrations/0007_approval.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.16 on 2024-12-03 12:41 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0006_berichtsheft_num"), + ] + + operations = [ + migrations.CreateModel( + name="Approval", + fields=[ + ("id", models.AutoField(primary_key=True, serialize=False)), + ("user", models.TextField()), + ( + "report", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="report", + to="core.berichtsheft", + ), + ), + ], + ), + ] diff --git a/core/migrations/0008_berichtsheft_needs_rewrite.py b/core/migrations/0008_berichtsheft_needs_rewrite.py new file mode 100755 index 0000000..8c5ea61 --- /dev/null +++ b/core/migrations/0008_berichtsheft_needs_rewrite.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.16 on 2024-12-03 12:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0007_approval"), + ] + + operations = [ + migrations.AddField( + model_name="berichtsheft", + name="needs_rewrite", + field=models.BooleanField(default=False), + ), + ] diff --git a/core/models.py b/core/models.py index 8a57865..b441b63 100755 --- a/core/models.py +++ b/core/models.py @@ -28,13 +28,18 @@ class Berichtsheft(models.Model): year = models.PositiveIntegerField() week = models.PositiveSmallIntegerField() content = models.JSONField() + needs_rewrite = models.BooleanField(default=False) created = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Berichtsheft: {self.user}, Year: {self.year}, Week: {self.week}" + def is_approved(self): + approvals = Approval.objects.filter(report=self.id) + return len(approvals) >= 2 -class Approval: + +class Approval(models.Model): id = models.AutoField(primary_key=True) user = models.TextField() report = models.ForeignKey( diff --git a/core/styles.py b/core/styles.py new file mode 100755 index 0000000..44d1780 --- /dev/null +++ b/core/styles.py @@ -0,0 +1,6 @@ +# Tailwind Styles + +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": "a4-page bg-white shadow-lg p-6 mx-auto my-10", +} diff --git a/core/templates/index.html b/core/templates/index.html index ab7cf7f..fdf059f 100755 --- a/core/templates/index.html +++ b/core/templates/index.html @@ -1,17 +1,7 @@ Azube - + {{ user.display_name }} @@ -24,11 +14,20 @@ {% endif %} +
{% for report in reports %} -
-

{{ report }}

+ + + {% if forloop.last %} + {% if report.week != week_now %} +
+ + {% endif %} + {% endif %} + {% endfor %} - +
\ No newline at end of file diff --git a/core/templates/report.html b/core/templates/report.html new file mode 100755 index 0000000..d8e9ecc --- /dev/null +++ b/core/templates/report.html @@ -0,0 +1,18 @@ + + + Berichtsheft {{ report.num }} + + +

Berichtsheft {{ report.num }}

+ +

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

+ +

Is Approved ? {{ approved }}

+ + {% for key, value in report.content.items %} + +

{{ key }} : {{ value }}

+ + {% endfor %} + + \ No newline at end of file diff --git a/core/urls.py b/core/urls.py index 6a9c653..ffbc220 100755 --- a/core/urls.py +++ b/core/urls.py @@ -4,5 +4,5 @@ from . import views urlpatterns = [ path("", views.index, name="index"), path("write", views.write_new_report, name="write"), - path("test", views.test, name="test"), + path("report/", views.report_detail_page, name="report_detail"), ] diff --git a/core/views.py b/core/views.py index 7f760ec..3df9ed1 100755 --- a/core/views.py +++ b/core/views.py @@ -1,10 +1,12 @@ -from django.shortcuts import redirect, render +from django.http import HttpResponse +from django.shortcuts import get_object_or_404, redirect, render from core.forms import extract_post_values from core.report_templates import ReportTemplates from core.util import get_week_range, next_date from .azure_auth import AzureUser from .models import Berichtsheft +from core.styles import STYLE import datetime # Create your views here. @@ -44,10 +46,18 @@ def write_new_report_get(request): # Get the latest year and week latest = user.reports().order_by("-year", "-week").first() + + year_now, week_now, _ = datetime.datetime.today().isocalendar() + + # Report for this week already exists + if latest is not None: + if latest.year == year_now and latest.week == week_now: + return redirect(f"/report/{latest.id}") + if latest is not None: current_year, current_week = next_date(latest.year, latest.week) else: - current_year, current_week, _ = datetime.datetime.today().isocalendar() + current_year, current_week = year_now, week_now start_date, end_date = get_week_range(current_year, current_week) @@ -79,7 +89,26 @@ def index(request): # Get all berichtshefte all_reports = user.reports() - return render(request, "index.html", {"user": user, "reports": all_reports}) + year_now, week_now, _ = datetime.datetime.today().isocalendar() + + return render( + request, + "index.html", + {"user": user, "reports": all_reports, "week_now": week_now, "style": STYLE}, + ) + + +def report_detail_page(request, report_id): + user = AzureUser(request) + + report = get_object_or_404(Berichtsheft, id=report_id) + + if report.user != user.id: + return HttpResponse("Nah", status=401) + + return render( + request, "report.html", {"report": report, "approved": report.is_approved()} + ) def test(request): From 34f3367a08a76bd781327f326871a829842ab113 Mon Sep 17 00:00:00 2001 From: Angelo Rodriguez Date: Wed, 4 Dec 2024 09:37:01 +0100 Subject: [PATCH 02/10] work --- core/azure_auth.py | 13 +- core/forms.py | 5 - core/migrations/0009_berichtsheft_kind.py | 22 + .../0010_berichtsheft_department.py | 18 + core/models.py | 9 + core/report_templates.py | 29 -- core/reports.py | 26 ++ core/styles.py | 2 +- core/templates/index.html | 63 +-- core/templates/report.html | 2 +- core/templates/test.html | 384 ------------------ core/templates/write.html | 56 +-- core/views.py | 65 +-- 13 files changed, 175 insertions(+), 519 deletions(-) delete mode 100755 core/forms.py create mode 100755 core/migrations/0009_berichtsheft_kind.py create mode 100755 core/migrations/0010_berichtsheft_department.py delete mode 100755 core/report_templates.py create mode 100755 core/reports.py delete mode 100755 core/templates/test.html diff --git a/core/azure_auth.py b/core/azure_auth.py index 3797d8a..091cc33 100755 --- a/core/azure_auth.py +++ b/core/azure_auth.py @@ -2,7 +2,7 @@ import json import base64 from core.models import Berichtsheft -from core.report_templates import ReportTemplates +from core.reports import DailyReport, WeeklyReport class AzureUser: @@ -35,6 +35,13 @@ class AzureUser: def reports(self): return Berichtsheft.objects.filter(user=self.id) - def get_report_template(self): + def get_report_kind(self): # TODO : Implement - return ReportTemplates.get_template("weekly") + return "weekly" + + def get_report_kind_form(self, request=None): + match self.get_report_kind(): + case "weekly": + return WeeklyReport(request) + case "daily": + return DailyReport(request) diff --git a/core/forms.py b/core/forms.py deleted file mode 100755 index be9c917..0000000 --- a/core/forms.py +++ /dev/null @@ -1,5 +0,0 @@ -def extract_post_values(post, vars) -> dict: - res = {} - for var in vars: - res[var["name"]] = post.get(var["name"], "") - return res diff --git a/core/migrations/0009_berichtsheft_kind.py b/core/migrations/0009_berichtsheft_kind.py new file mode 100755 index 0000000..004495f --- /dev/null +++ b/core/migrations/0009_berichtsheft_kind.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.16 on 2024-12-03 14:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0008_berichtsheft_needs_rewrite"), + ] + + operations = [ + migrations.AddField( + model_name="berichtsheft", + name="kind", + field=models.CharField( + choices=[("weekly", "Weekly"), ("daily", "Daily")], + default="weekly", + max_length=20, + ), + ), + ] diff --git a/core/migrations/0010_berichtsheft_department.py b/core/migrations/0010_berichtsheft_department.py new file mode 100755 index 0000000..d330c89 --- /dev/null +++ b/core/migrations/0010_berichtsheft_department.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.16 on 2024-12-03 15:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0009_berichtsheft_kind"), + ] + + operations = [ + migrations.AddField( + model_name="berichtsheft", + name="department", + field=models.CharField(default="", max_length=160), + ), + ] diff --git a/core/models.py b/core/models.py index b441b63..ff5c798 100755 --- a/core/models.py +++ b/core/models.py @@ -21,12 +21,21 @@ class Group(BuiltinGroup): proxy = True +class ReportKind(models.TextChoices): + WEEKLY = "weekly" + DAILY = "daily" + + class Berichtsheft(models.Model): id = models.AutoField(primary_key=True) user = models.TextField() + kind = models.CharField( + max_length=20, choices=ReportKind.choices, default=ReportKind.WEEKLY + ) num = models.PositiveBigIntegerField(default=0) year = models.PositiveIntegerField() week = models.PositiveSmallIntegerField() + department = models.CharField(max_length=160, default="") content = models.JSONField() needs_rewrite = models.BooleanField(default=False) created = models.DateTimeField(auto_now_add=True) diff --git a/core/report_templates.py b/core/report_templates.py deleted file mode 100755 index a5f2073..0000000 --- a/core/report_templates.py +++ /dev/null @@ -1,29 +0,0 @@ -class ReportTemplates: - report_global = { - "vars": [ - {"name": "name", "display_name": "Name"}, - {"name": "num_doc", "display_name": "Berichtsheft Nummer"}, - {"name": "year", "display_name": "Jahr"}, - {"name": "week", "display_name": "Kalenderwoche"}, - {"name": "start_date", "display_name": "Von"}, - {"name": "end_date", "display_name": "bis"}, - {"name": "department", "display_name": "Abteilung"}, - ] - } - - def get_template(id) -> dict: - match id: - case "weekly": - weekly = { - "vars": [ - { - "name": "company_text", - "display_name": "Betriebliche Tätigkeiten", - }, - {"name": "week_topic", "display_name": "Thema der Woche"}, - {"name": "school_text", "display_name": "Berufsschule"}, - ] - } - - weekly["vars"].extend(ReportTemplates.report_global["vars"]) - return weekly diff --git a/core/reports.py b/core/reports.py new file mode 100755 index 0000000..3fcd9ff --- /dev/null +++ b/core/reports.py @@ -0,0 +1,26 @@ +from django import forms + + +class WeeklyReport(forms.Form): + department = forms.CharField(label="Abteilung", max_length=150) + company_text = forms.CharField(label="Betriebliche Tätigkeiten", max_length=300) + week_topic = forms.CharField(label="Thema der Woche", max_length=600) + school_text = forms.CharField(label="Berufsschule", max_length=300) + + def content_values(self) -> dict: + if self.is_valid(): + return { + "company_text": self.cleaned_data["company_text"], + "week_topic": self.cleaned_data["week_topic"], + "school_text": self.cleaned_data["school_text"], + } + + +class DailyReport: + department = forms.CharField(label="Abteilung", max_length=150) + week_topic = forms.CharField(label="Thema der Woche", max_length=600) + monday_text = forms.CharField(label="Berufsschule", max_length=300) + tuesday_text = forms.CharField(label="Dienstag", max_length=300) + wednesday_text = forms.CharField(label="Mittwoch", max_length=300) + thursday_text = forms.CharField(label="Donnerstag", max_length=300) + friday_text = forms.CharField(label="Freitag", max_length=300) diff --git a/core/styles.py b/core/styles.py index 44d1780..a996d57 100755 --- a/core/styles.py +++ b/core/styles.py @@ -2,5 +2,5 @@ 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": "a4-page bg-white shadow-lg p-6 mx-auto my-10", + "card": "bg-white drop-shadow-md p-6 mx-auto my-10 aspect-[2/3] hover:drop-shadow-xl hover:scale-[0.95] scale-[0.9] transition-all duration-50 transform ease-in-out", } diff --git a/core/templates/index.html b/core/templates/index.html index fdf059f..e3d44e5 100755 --- a/core/templates/index.html +++ b/core/templates/index.html @@ -1,33 +1,44 @@ - - Azube - - - - {{ user.display_name }} + + Azube + + + + {{ user.display_name }} -

Deine Berichtshefte

+
+

Deine Berichtshefte

- {% if reports|length == 0 %} - - {% endif %} + {% if reports|length == 0 %} -
+

wau, such empty!

+ + + {% else %} + +
{% for report in reports %} - - {% if forloop.last %} - {% if report.week != week_now %} + + {% if approved %} +
+ ✓ +
+ {% endif %} {{ report }} +
+ + {% if forloop.last %} {% if report.week != week_now %} + + {% endif %} {% endif %} {% endfor %} {% endif %} +
- - {% endif %} - {% endif %} - - {% endfor %} -
- - \ No newline at end of file + + diff --git a/core/templates/report.html b/core/templates/report.html index d8e9ecc..f9feea1 100755 --- a/core/templates/report.html +++ b/core/templates/report.html @@ -15,4 +15,4 @@ {% endfor %} - \ No newline at end of file + diff --git a/core/templates/test.html b/core/templates/test.html deleted file mode 100755 index 31ea0fc..0000000 --- a/core/templates/test.html +++ /dev/null @@ -1,384 +0,0 @@ - - - Test - - - - - - - -

Deine Berichtshefte

- - - - - - \ No newline at end of file diff --git a/core/templates/write.html b/core/templates/write.html index 7d3ccbe..22bcc7c 100755 --- a/core/templates/write.html +++ b/core/templates/write.html @@ -1,50 +1,20 @@ - - Neues Berichtsheft - - -

Neues Berichtsheft

+ + Neues Berichtsheft + + +

Neues Berichtsheft

-

Berichtsheft {{ year }} / {{ week }}

+

{{ user.display_name }}

+

Berichtsheft {{ year }} / {{ week }}

+

Von: {{ start_date|date:"d.m.Y" }} bis: {{ end_date|date:"d.m.Y" }}

-
- {% for var in definition.vars %} -
- - + {{ form }} - {% if var.name == "year" %} - value = "{{ year }}" - {% endif %} + - {% if var.name == "start_date" %} - value = "{{ start_date|date:"d.m.Y" }}" - {% endif %} - - {% if var.name == "end_date" %} - value = "{{ end_date|date:"d.m.Y" }}" - {% endif %} - - {% if var.name == "num_doc" %} - value = "{{ current_num }}" - {% endif %} - - {% if var.name == "name" %} - value = "{{ user.display_name }}" - {% endif %} - - > -
- {% endfor %} - - - - {% csrf_token %} + {% csrf_token %}
- - + diff --git a/core/views.py b/core/views.py index 3df9ed1..d2e0ab7 100755 --- a/core/views.py +++ b/core/views.py @@ -1,8 +1,6 @@ from django.http import HttpResponse from django.shortcuts import get_object_or_404, redirect, render -from core.forms import extract_post_values -from core.report_templates import ReportTemplates from core.util import get_week_range, next_date from .azure_auth import AzureUser from .models import Berichtsheft @@ -22,38 +20,30 @@ def write_new_report(request): def write_new_report_post(request): user = AzureUser(request) - definition = user.get_report_template() + report_form = user.get_report_kind_form(request.POST) - values = extract_post_values(request.POST, definition["vars"]) + # TODO : Implement values - # TODO : Input Validation + current_year, current_week, _, _, current_num = get_current_report_values( + user.reports().order_by("-year", "-week").first() + ) report = Berichtsheft( user=user.id, - num=int(values.pop("num_doc", "")), - year=int(values.pop("year", "")), - week=int(values.pop("week", "")), - content=values, + kind=user.get_report_kind(), + num=int(current_num), + year=int(current_year), + week=int(current_week), + department=report_form.cleaned_data["department"], + content=report_form.content_values(), ) report.save() return redirect("/") -def write_new_report_get(request): - user = AzureUser(request) - - definition = user.get_report_template() - - # Get the latest year and week - latest = user.reports().order_by("-year", "-week").first() - +def get_current_report_values(latest): year_now, week_now, _ = datetime.datetime.today().isocalendar() - # Report for this week already exists - if latest is not None: - if latest.year == year_now and latest.week == week_now: - return redirect(f"/report/{latest.id}") - if latest is not None: current_year, current_week = next_date(latest.year, latest.week) else: @@ -66,8 +56,32 @@ def write_new_report_get(request): else: current_num = 1 + return current_year, current_week, start_date, end_date, current_num + + +def write_new_report_get(request): + user = AzureUser(request) + + report_kind = user.get_report_kind() + + # Get the latest year and week + latest = user.reports().order_by("-year", "-week").first() + + year_now, week_now, _ = datetime.datetime.today().isocalendar() + + # Report for this week already exists + if latest is not None: + if latest.year == year_now and latest.week == week_now: + return redirect(f"/report/{latest.id}") + + current_year, current_week, start_date, end_date, current_num = ( + get_current_report_values(latest) + ) + # TODO : Cookies for persistent saves + form = user.get_report_kind_form() + return render( request, "write.html", @@ -78,7 +92,8 @@ def write_new_report_get(request): "start_date": start_date, "end_date": end_date, "current_num": current_num, - "definition": definition, + "report_kind": report_kind, + "form": form, }, ) @@ -109,7 +124,3 @@ def report_detail_page(request, report_id): return render( request, "report.html", {"report": report, "approved": report.is_approved()} ) - - -def test(request): - return render(request, "test.html", {}) From d248c99242ad142839adc84fc180efb590ecc89d Mon Sep 17 00:00:00 2001 From: Angelo Rodriguez Date: Wed, 4 Dec 2024 11:41:57 +0100 Subject: [PATCH 03/10] work+htmx --- core/azure_auth.py | 20 +++++++++++- core/models.py | 1 + core/styles.py | 2 +- core/templates/component/report.html | 9 ++++++ core/templates/head.html | 2 ++ core/templates/htmx/reports.html | 12 +++++++ core/templates/index.html | 47 ++++++++++++++++------------ core/templates/report.html | 3 +- core/templates/write.html | 1 + core/urls.py | 1 + core/views.py | 42 +++++++++++++++++++++---- 11 files changed, 111 insertions(+), 29 deletions(-) create mode 100755 core/templates/component/report.html create mode 100755 core/templates/head.html create mode 100755 core/templates/htmx/reports.html diff --git a/core/azure_auth.py b/core/azure_auth.py index 091cc33..8121de2 100755 --- a/core/azure_auth.py +++ b/core/azure_auth.py @@ -1,8 +1,10 @@ +import datetime import json import base64 from core.models import Berichtsheft from core.reports import DailyReport, WeeklyReport +import core.util class AzureUser: @@ -33,7 +35,7 @@ class AzureUser: self.id = "anon" def reports(self): - return Berichtsheft.objects.filter(user=self.id) + return Berichtsheft.objects.filter(user=self.id).order_by("-year", "-week") def get_report_kind(self): # TODO : Implement @@ -45,3 +47,19 @@ class AzureUser: return WeeklyReport(request) case "daily": return DailyReport(request) + + def latest_report(self): + return self.reports().order_by("-year", "-week").first() + + def late_reports(self) -> int: + year_now, week_now, _ = datetime.datetime.today().isocalendar() + count = 0 + latest = self.latest_report() + + new_year, new_week = (latest.year, latest.week) + + while week_now != new_week or (week_now == new_week and year_now != new_year): + count += 1 + new_year, new_week = core.util.next_date(new_year, new_week) + + return count diff --git a/core/models.py b/core/models.py index ff5c798..08bd28a 100755 --- a/core/models.py +++ b/core/models.py @@ -43,6 +43,7 @@ class Berichtsheft(models.Model): def __str__(self): return f"Berichtsheft: {self.user}, Year: {self.year}, Week: {self.week}" + @property def is_approved(self): approvals = Approval.objects.filter(report=self.id) return len(approvals) >= 2 diff --git a/core/styles.py b/core/styles.py index a996d57..c0a672b 100755 --- a/core/styles.py +++ b/core/styles.py @@ -2,5 +2,5 @@ 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-6 mx-auto my-10 aspect-[2/3] hover:drop-shadow-xl hover:scale-[0.95] scale-[0.9] transition-all duration-50 transform ease-in-out", + "card": "bg-white drop-shadow-md p-6 mx-auto my-10 aspect-[2/3] hover:drop-shadow-xl hover:scale-[0.95] scale-[0.9] transition-all duration-50 transform ease-in-out w-80", } diff --git a/core/templates/component/report.html b/core/templates/component/report.html new file mode 100755 index 0000000..e79c3c1 --- /dev/null +++ b/core/templates/component/report.html @@ -0,0 +1,9 @@ + + {% if report.is_approved %} +
+ ✓ +
+ {% endif %} {{ report }} +
diff --git a/core/templates/head.html b/core/templates/head.html new file mode 100755 index 0000000..078f27d --- /dev/null +++ b/core/templates/head.html @@ -0,0 +1,2 @@ + + diff --git a/core/templates/htmx/reports.html b/core/templates/htmx/reports.html new file mode 100755 index 0000000..dc0fb8f --- /dev/null +++ b/core/templates/htmx/reports.html @@ -0,0 +1,12 @@ +{% if reports|length != 0 %} + {% for report in reports %} + + {% include 'component/report.html' with report=report %} + + {% endfor %} + +
+ + {% endif %} diff --git a/core/templates/index.html b/core/templates/index.html index e3d44e5..2549c47 100755 --- a/core/templates/index.html +++ b/core/templates/index.html @@ -1,43 +1,50 @@ Azube - + {% include 'head.html' %} - {{ user.display_name }} - -
+

Deine Berichtshefte

+ {% if late_reports > 1 %} + + + {% endif %} + {% if reports|length == 0 %} -

wau, such empty!

+

wau, such empty!

- {% else %}
{% for report in reports %} - - {% if approved %} -
- ✓ -
- {% endif %} {{ report }} + {% if forloop.first %} {% if report.week != week_now %} +
+ + + {% endif %} {% endif %} + + {% include 'component/report.html' with report=report %} + + {% endfor %} + +
+ + {% endif %} - {% if forloop.last %} {% if report.week != week_now %} - - {% endif %} {% endif %} {% endfor %} {% endif %}
diff --git a/core/templates/report.html b/core/templates/report.html index f9feea1..5f93e64 100755 --- a/core/templates/report.html +++ b/core/templates/report.html @@ -1,13 +1,14 @@ Berichtsheft {{ report.num }} + {% include 'head.html' %}

Berichtsheft {{ report.num }}

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

-

Is Approved ? {{ approved }}

+

Is Approved ? {{ report.is_approved }}

{% for key, value in report.content.items %} diff --git a/core/templates/write.html b/core/templates/write.html index 22bcc7c..98966c2 100755 --- a/core/templates/write.html +++ b/core/templates/write.html @@ -1,6 +1,7 @@ Neues Berichtsheft + {% include 'head.html' %}

Neues Berichtsheft

diff --git a/core/urls.py b/core/urls.py index ffbc220..0253d91 100755 --- a/core/urls.py +++ b/core/urls.py @@ -5,4 +5,5 @@ urlpatterns = [ path("", views.index, name="index"), path("write", views.write_new_report, name="write"), path("report/", views.report_detail_page, name="report_detail"), + path("reports", views.reports_list, name="reports_list"), ] diff --git a/core/views.py b/core/views.py index d2e0ab7..c95bfe2 100755 --- a/core/views.py +++ b/core/views.py @@ -4,6 +4,7 @@ from django.shortcuts import get_object_or_404, redirect, render from core.util import get_week_range, next_date from .azure_auth import AzureUser from .models import Berichtsheft +from django.core.paginator import Paginator from core.styles import STYLE import datetime @@ -22,6 +23,9 @@ def write_new_report_post(request): report_form = user.get_report_kind_form(request.POST) + if not report_form.is_valid(): + return HttpResponse("Bad Request", status=400) + # TODO : Implement values current_year, current_week, _, _, current_num = get_current_report_values( @@ -65,7 +69,7 @@ def write_new_report_get(request): report_kind = user.get_report_kind() # Get the latest year and week - latest = user.reports().order_by("-year", "-week").first() + latest = user.latest_report() year_now, week_now, _ = datetime.datetime.today().isocalendar() @@ -102,14 +106,42 @@ def index(request): user = AzureUser(request) # Get all berichtshefte - all_reports = user.reports() + reports = Paginator(user.reports(), 30).get_page(1) year_now, week_now, _ = datetime.datetime.today().isocalendar() return render( request, "index.html", - {"user": user, "reports": all_reports, "week_now": week_now, "style": STYLE}, + { + "user": user, + "reports": reports, + "week_now": week_now, + "late_reports": user.late_reports(), + "style": STYLE, + }, + ) + + +def reports_list(request): + user = AzureUser(request) + + p = Paginator(user.reports(), 30) + + try: + page_num = int(request.GET.get("page")) + except: + return HttpResponse("Page should be a number", 400) + + if p.num_pages >= page_num: + objs = p.get_page(page_num) + else: + objs = [] + + return render( + request, + "htmx/reports.html", + {"reports": objs, "next": page_num + 1, "style": STYLE}, ) @@ -121,6 +153,4 @@ def report_detail_page(request, report_id): if report.user != user.id: return HttpResponse("Nah", status=401) - return render( - request, "report.html", {"report": report, "approved": report.is_approved()} - ) + return render(request, "report.html", {"report": report}) From 4b496a7d4f35d1f9ee6f42d5605ea1ba03ef8ce9 Mon Sep 17 00:00:00 2001 From: Angelo Rodriguez Date: Wed, 4 Dec 2024 14:04:12 +0100 Subject: [PATCH 04/10] work --- core/styles.py | 2 +- core/templates/head.html | 1 + core/templates/index.html | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/core/styles.py b/core/styles.py index c0a672b..37615c7 100755 --- a/core/styles.py +++ b/core/styles.py @@ -2,5 +2,5 @@ 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-6 mx-auto my-10 aspect-[2/3] hover:drop-shadow-xl hover:scale-[0.95] scale-[0.9] transition-all duration-50 transform ease-in-out w-80", + "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", } diff --git a/core/templates/head.html b/core/templates/head.html index 078f27d..e1d2240 100755 --- a/core/templates/head.html +++ b/core/templates/head.html @@ -1,2 +1,3 @@ + diff --git a/core/templates/index.html b/core/templates/index.html index 2549c47..c23d056 100755 --- a/core/templates/index.html +++ b/core/templates/index.html @@ -25,7 +25,7 @@ {% else %}
{% for report in reports %} From 43fe9aea31df1f0c93a294c545e8fb1be9b530f8 Mon Sep 17 00:00:00 2001 From: Angelo Rodriguez Date: Wed, 4 Dec 2024 16:36:57 +0100 Subject: [PATCH 05/10] work done --- core/reports.py | 49 +++++++++++++++++++++++++++++--- core/styles.py | 4 +++ core/templates/header.html | 5 ++++ core/templates/htmx/reports.html | 2 +- core/templates/index.html | 7 +++-- core/templates/report.html | 45 ++++++++++++++++++++--------- core/templates/write.html | 43 +++++++++++++++++++++------- 7 files changed, 125 insertions(+), 30 deletions(-) create mode 100755 core/templates/header.html diff --git a/core/reports.py b/core/reports.py index 3fcd9ff..3dfbffa 100755 --- a/core/reports.py +++ b/core/reports.py @@ -1,11 +1,52 @@ from django import forms +from core.styles import label_span + class WeeklyReport(forms.Form): - department = forms.CharField(label="Abteilung", max_length=150) - company_text = forms.CharField(label="Betriebliche Tätigkeiten", max_length=300) - week_topic = forms.CharField(label="Thema der Woche", max_length=600) - school_text = forms.CharField(label="Berufsschule", max_length=300) + department = forms.CharField( + label=label_span("Abteilung"), + max_length=150, + widget=forms.TextInput( + attrs={ + "placeholder": "Abteilung", + "class": "w-full p-2 border border-gray-300 rounded-lg focus:ring focus:ring-blue-400 mb-5", + } + ), + ) + company_text = forms.CharField( + label=label_span("Betriebliche Tätigkeiten"), + max_length=300, + widget=forms.Textarea( + attrs={ + "class": "w-full p-2 border border-gray-300 rounded-lg focus:ring focus:ring-blue-400 mb-5", + "rows": 10, + "placeholder": "Betriebliche Tätigkeiten", + } + ), + ) + week_topic = forms.CharField( + label=label_span("Thema der Woche"), + max_length=600, + widget=forms.Textarea( + attrs={ + "class": "w-full p-2 border border-gray-300 rounded-lg focus:ring focus:ring-blue-400 mb-5", + "rows": 8, + "placeholder": "Thema der Woche", + } + ), + ) + school_text = forms.CharField( + label=label_span("Berufsschule"), + max_length=300, + widget=forms.Textarea( + attrs={ + "class": "w-full p-2 border border-gray-300 rounded-lg focus:ring focus:ring-blue-400 mb-5", + "rows": 5, + "placeholder": "Berufsschule", + } + ), + ) def content_values(self) -> dict: if self.is_valid(): diff --git a/core/styles.py b/core/styles.py index 37615c7..088b45d 100755 --- a/core/styles.py +++ b/core/styles.py @@ -4,3 +4,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", } + + +def label_span(txt): + return f'{txt}' diff --git a/core/templates/header.html b/core/templates/header.html new file mode 100755 index 0000000..1a2dd41 --- /dev/null +++ b/core/templates/header.html @@ -0,0 +1,5 @@ +
+
+

{{ title }}

+
+
diff --git a/core/templates/htmx/reports.html b/core/templates/htmx/reports.html index dc0fb8f..aee0210 100755 --- a/core/templates/htmx/reports.html +++ b/core/templates/htmx/reports.html @@ -3,7 +3,7 @@ {% include 'component/report.html' with report=report %} - {% endfor %} + {% endfor %}
Azube {% include 'head.html' %} - + + + {% include 'header.html' with title="Deine Berichtshefte" center=False %} +
-

Deine Berichtshefte

{% if late_reports > 1 %} +
- + + {% load set_content %} + {% load access %} + {% for field in form %}
- {{ field }} + + {% if field.id_for_label == "id_department" %} + + {{ field|set_content:draft.department}} + + {%else%} + {% with content=draft.content|access:field.id_for_label %} + {{ field|set_content:content }} + {% endwith %} +{%endif%} {% if field.errors %}

{{ field.errors|join:", " }}

{% endif %} @@ -39,6 +51,81 @@ Submit + + + diff --git a/core/templatetags/access.py b/core/templatetags/access.py new file mode 100644 index 0000000..1cd9369 --- /dev/null +++ b/core/templatetags/access.py @@ -0,0 +1,13 @@ +from django import template + +register = template.Library() + + +@register.filter(name="access") +def access(value, arg): + if value == None: + return "" + try: + return value[arg] + except: + return "" diff --git a/core/templatetags/add_attr.py b/core/templatetags/add_attr.py new file mode 100644 index 0000000..51e77b7 --- /dev/null +++ b/core/templatetags/add_attr.py @@ -0,0 +1,25 @@ +from django import template + +register = template.Library() + + +@register.filter(name="add_attr") +def add_attr(field, css): + """Adds custom attributes (like class) to form fields without overwriting existing attributes.""" + # Retrieve existing attributes (if any) + attrs = field.field.widget.attrs.copy() + + # Split the CSS string into key-value pairs + definition = css.split(",") + + for d in definition: + if ":" not in d: + # If no key-value pair is provided, default to 'class' + attrs["class"] = f"{attrs.get('class', '')} {d}".strip() + else: + # If a key-value pair is provided (e.g., 'data-test:123'), add it + key, val = d.split(":") + attrs[key.strip()] = val.strip() + + # Return the widget with the updated attributes + return field.as_widget(attrs=attrs) diff --git a/core/templatetags/set_content.py b/core/templatetags/set_content.py new file mode 100644 index 0000000..0c5dc22 --- /dev/null +++ b/core/templatetags/set_content.py @@ -0,0 +1,27 @@ +from django import template +from django import forms + +register = template.Library() + + +@register.filter(name="set_content") +def set_content(field, content): + """Sets the content of input and textarea fields, and custom attributes like class, without overwriting existing attributes.""" + + # Retrieve existing attributes (if any) + attrs = field.field.widget.attrs.copy() + + # Check if the field is a text input or textarea + is_input_or_textarea = isinstance( + field.field.widget, (forms.widgets.TextInput, forms.widgets.Textarea) + ) + + # If the field is an input or textarea, set the content as value or text + if is_input_or_textarea: + attrs["value"] = content.strip() # Set the value to the provided content + + if isinstance(field.field.widget, forms.widgets.Textarea): + field.initial = content.strip() + + # Return the widget with the updated attributes + return field.as_widget(attrs=attrs) diff --git a/core/tests.py b/core/tests.py old mode 100755 new mode 100644 diff --git a/core/urls.py b/core/urls.py old mode 100755 new mode 100644 index 0253d91..6c33d88 --- a/core/urls.py +++ b/core/urls.py @@ -6,4 +6,5 @@ urlpatterns = [ path("write", views.write_new_report, name="write"), path("report/", views.report_detail_page, name="report_detail"), path("reports", views.reports_list, name="reports_list"), + path("draft", views.report_draft_update, name="report_draft_update"), ] diff --git a/core/util.py b/core/util.py old mode 100755 new mode 100644 diff --git a/core/views.py b/core/views.py old mode 100755 new mode 100644 index c95bfe2..980b5fc --- a/core/views.py +++ b/core/views.py @@ -7,6 +7,7 @@ from .models import Berichtsheft from django.core.paginator import Paginator from core.styles import STYLE import datetime +import json # Create your views here. @@ -78,11 +79,15 @@ def write_new_report_get(request): if latest.year == year_now and latest.week == week_now: return redirect(f"/report/{latest.id}") - current_year, current_week, start_date, end_date, current_num = ( - get_current_report_values(latest) - ) + ( + current_year, + current_week, + start_date, + end_date, + current_num, + ) = get_current_report_values(latest) - # TODO : Cookies for persistent saves + draft = BerichtsheftDraft.objects.filter(user=user.id).first() form = user.get_report_kind_form() @@ -98,6 +103,7 @@ def write_new_report_get(request): "current_num": current_num, "report_kind": report_kind, "form": form, + "draft": draft, }, ) @@ -154,3 +160,37 @@ def report_detail_page(request, report_id): return HttpResponse("Nah", status=401) return render(request, "report.html", {"report": report}) + + +from django.shortcuts import get_object_or_404 +from django.http import JsonResponse +from .models import BerichtsheftDraft + + +def report_draft_update(request): + if request.method == "POST": + user = AzureUser(request) + + data = json.loads(request.body) + + department = "" + content = {} + + for key, val in data.items(): + if key == "id_department": + department = val + continue + content[key] = val + + draft, created = BerichtsheftDraft.objects.update_or_create( + user=user.id, defaults={"department": department, "content": content} + ) + + return JsonResponse( + { + "status": "success", + "message": "Draft updated" if not created else "Draft created", + } + ) + + return JsonResponse({"error": "Invalid request method"}, status=400) diff --git a/manage.py b/manage.py old mode 100755 new mode 100644 diff --git a/requirements.txt b/requirements.txt old mode 100755 new mode 100644 From 73e019de9a7e623b8f3cb19f89a3d598873a2dd4 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Thu, 5 Dec 2024 17:03:42 +0100 Subject: [PATCH 07/10] htmx single page application + work --- core/templates/component/report.html | 7 ++- core/templates/header.html | 5 --- core/templates/index.html | 19 +++----- core/templates/report.html | 22 +++------ core/templates/shell.html | 67 ++++++++++++++++++++++++++++ core/templates/write.html | 26 ++++------- core/templatetags/markdown.py | 10 +++++ core/util.py | 36 +++++++++++++++ core/views.py | 12 +++-- requirements.txt | 4 +- 10 files changed, 150 insertions(+), 58 deletions(-) delete mode 100644 core/templates/header.html create mode 100644 core/templates/shell.html create mode 100644 core/templatetags/markdown.py diff --git a/core/templates/component/report.html b/core/templates/component/report.html index e79c3c1..05d8bd4 100644 --- a/core/templates/component/report.html +++ b/core/templates/component/report.html @@ -1,4 +1,7 @@ - + diff --git a/core/templates/header.html b/core/templates/header.html deleted file mode 100644 index 567861a..0000000 --- a/core/templates/header.html +++ /dev/null @@ -1,5 +0,0 @@ -
-
-

{{ title }}

-
-
diff --git a/core/templates/index.html b/core/templates/index.html index 888542e..5e0bfc9 100644 --- a/core/templates/index.html +++ b/core/templates/index.html @@ -1,13 +1,4 @@ - - - Azube - {% include 'head.html' %} - - - - {% include 'header.html' with title="Deine Berichtshefte" center=False %} - -
+ {{ title|safe }} {% if late_reports > 1 %} @@ -33,9 +24,11 @@ {% for report in reports %} {% if forloop.first %} {% if report.week != week_now %} - + {% endif %} {% endif %} {% include 'component/report.html' with report=report %} @@ -50,5 +43,3 @@
- - diff --git a/core/templates/report.html b/core/templates/report.html index 04db2cb..de52a08 100644 --- a/core/templates/report.html +++ b/core/templates/report.html @@ -1,14 +1,5 @@ - - - Berichtsheft {{ report.num }} - {% include 'head.html' %} - - - - {% with title="Berichtsheft "|add:report.num %} - {% include 'header.html' with title="Berichtsheft" %} -{% endwith %} - +{{ title|safe }} +

@@ -25,14 +16,13 @@

Content:

+ {% load markdown %} {% for key, value in report.content.items %} -
-
{{ key }}
-
{{ value }}
+
+

{{ key }}

+ {{ value|markdown|safe }}
{% endfor %}
- - diff --git a/core/templates/shell.html b/core/templates/shell.html new file mode 100644 index 0000000..0c35906 --- /dev/null +++ b/core/templates/shell.html @@ -0,0 +1,67 @@ + + + {{ title }} + {% include 'head.html' %} + + + + +
+
+ + +

{{ title }}

+
+ + +
+ +
+
    +
  • + +
  • +
+
+ + +
+ {{ main_content|safe }} +
+
+
+ + + + + + diff --git a/core/templates/write.html b/core/templates/write.html index 3bff28f..62e1b84 100644 --- a/core/templates/write.html +++ b/core/templates/write.html @@ -1,13 +1,7 @@ - - - Neues Berichtsheft - {% include 'head.html' %} - - - - {% include 'header.html' with title="Neues Berichtsheft" %} -
+ + {{ title|safe }} +

{{ user.display_name }}

@@ -20,8 +14,7 @@

- {% load set_content %} - {% load access %} + {% load access set_content %} {% for field in form %}
@@ -31,13 +24,13 @@ {% if field.id_for_label == "id_department" %} - {{ field|set_content:draft.department}} + {{ field|set_content:draft.department }} - {%else%} + {% else %} {% with content=draft.content|access:field.id_for_label %} {{ field|set_content:content }} {% endwith %} -{%endif%} +{% endif %} {% if field.errors %}

{{ field.errors|join:", " }}

{% endif %} @@ -45,6 +38,7 @@ {% endfor %} {% csrf_token %} +
- - diff --git a/core/templatetags/markdown.py b/core/templatetags/markdown.py new file mode 100644 index 0000000..c6bea54 --- /dev/null +++ b/core/templatetags/markdown.py @@ -0,0 +1,10 @@ +from django import template +import markdown +import bleach + +register = template.Library() + + +@register.filter(name="markdown") +def markdown_tag(value): + return markdown.markdown(bleach.clean(value, tags=[], attributes=[])) diff --git a/core/util.py b/core/util.py index c93ebe8..b383732 100644 --- a/core/util.py +++ b/core/util.py @@ -1,5 +1,9 @@ import datetime +from django.template.loader import render_to_string +from django.shortcuts import render +from django.http import HttpResponse + def next_date(year: int, week: int) -> (int, int): if week >= 52: @@ -30,3 +34,35 @@ def get_week_range(p_year, p_week): ).date() lastdayofweek = firstdayofweek + datetime.timedelta(days=6.9) return firstdayofweek, lastdayofweek + + +def is_htmx_request(request) -> bool: + return request.headers.get("HX-Request") is not None + + +def title(t): + return f""" + + """ + + +def htmx_request(request, content_template, vars, page_title): + vars["title"] = title(page_title) + vars["htmx"] = is_htmx_request(request) + + main_content = render_to_string(content_template, vars, request=request) + + if is_htmx_request(request): + return HttpResponse(main_content, content_type="text/html") + else: + return render( + request, + "shell.html", + { + "title": page_title, + "main_content": main_content, + }, + ) diff --git a/core/views.py b/core/views.py index 980b5fc..e7b122c 100644 --- a/core/views.py +++ b/core/views.py @@ -5,7 +5,9 @@ from core.util import get_week_range, next_date from .azure_auth import AzureUser from .models import Berichtsheft from django.core.paginator import Paginator +from django.template.loader import render_to_string from core.styles import STYLE +from .util import is_htmx_request, title, htmx_request import datetime import json @@ -91,7 +93,7 @@ def write_new_report_get(request): form = user.get_report_kind_form() - return render( + return htmx_request( request, "write.html", { @@ -105,6 +107,7 @@ def write_new_report_get(request): "form": form, "draft": draft, }, + "Neues Berichtsheft", ) @@ -116,7 +119,7 @@ def index(request): year_now, week_now, _ = datetime.datetime.today().isocalendar() - return render( + return htmx_request( request, "index.html", { @@ -126,6 +129,7 @@ def index(request): "late_reports": user.late_reports(), "style": STYLE, }, + "Berichtshefte", ) @@ -159,7 +163,9 @@ def report_detail_page(request, report_id): if report.user != user.id: return HttpResponse("Nah", status=401) - return render(request, "report.html", {"report": report}) + return htmx_request( + request, "report.html", {"report": report}, f"Berichtsheft {report.num}" + ) from django.shortcuts import get_object_or_404 diff --git a/requirements.txt b/requirements.txt index 7a4844b..f19d158 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ Django~=4.2.11 -psycopg2 \ No newline at end of file +psycopg2 +markdown +bleach \ No newline at end of file From d64efb663a52773042d122bb7ad7a545421afd2f Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 6 Dec 2024 12:10:30 +0100 Subject: [PATCH 08/10] image feature + refactor --- core/azure_auth.py | 10 +- core/migrations/0012_berichtsheft_image.py | 17 +++ core/models.py | 1 + core/reports.py | 155 +++++++++++++++++++-- core/styles.py | 1 + core/templates/index.html | 2 +- core/templates/report.html | 21 ++- core/templates/shell.html | 10 +- core/templates/write.html | 6 +- core/templatetags/b64.py | 11 ++ core/templatetags/markdown.py | 4 +- core/views.py | 17 ++- requirements.txt | 3 +- 13 files changed, 221 insertions(+), 37 deletions(-) create mode 100644 core/migrations/0012_berichtsheft_image.py create mode 100644 core/templatetags/b64.py diff --git a/core/azure_auth.py b/core/azure_auth.py index 8121de2..64ad1f5 100644 --- a/core/azure_auth.py +++ b/core/azure_auth.py @@ -3,7 +3,7 @@ import json import base64 from core.models import Berichtsheft -from core.reports import DailyReport, WeeklyReport +from core.reports import DailyReport, WeeklyReport, choose_report_kind import core.util @@ -41,12 +41,8 @@ class AzureUser: # TODO : Implement return "weekly" - def get_report_kind_form(self, request=None): - match self.get_report_kind(): - case "weekly": - return WeeklyReport(request) - case "daily": - return DailyReport(request) + def get_report_kind_form(self, request=None, files=None): + return choose_report_kind(self.get_report_kind(), request, files) def latest_report(self): return self.reports().order_by("-year", "-week").first() diff --git a/core/migrations/0012_berichtsheft_image.py b/core/migrations/0012_berichtsheft_image.py new file mode 100644 index 0000000..b6e5aed --- /dev/null +++ b/core/migrations/0012_berichtsheft_image.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.17 on 2024-12-06 09:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0011_berichtsheftdraft"), + ] + + operations = [ + migrations.AddField( + model_name="berichtsheft", + name="image", + field=models.BinaryField(blank=True, null=True), + ), + ] diff --git a/core/models.py b/core/models.py index 67b831d..d1421bb 100644 --- a/core/models.py +++ b/core/models.py @@ -39,6 +39,7 @@ class Berichtsheft(models.Model): content = models.JSONField() needs_rewrite = models.BooleanField(default=False) created = models.DateTimeField(auto_now_add=True) + image = models.BinaryField(null=True, blank=True) def __str__(self): return f"Berichtsheft: {self.user}, Year: {self.year}, Week: {self.week}" diff --git a/core/reports.py b/core/reports.py index 4c9328d..fa637af 100644 --- a/core/reports.py +++ b/core/reports.py @@ -1,6 +1,6 @@ from django import forms -from core.styles import label_span +from core.styles import label_span, STYLE class WeeklyReport(forms.Form): @@ -10,7 +10,7 @@ class WeeklyReport(forms.Form): widget=forms.TextInput( attrs={ "placeholder": "Abteilung", - "class": "w-full p-2 border border-gray-300 rounded-lg focus:ring focus:ring-blue-400 mb-5", + "class": STYLE["text-input"], } ), ) @@ -19,7 +19,7 @@ class WeeklyReport(forms.Form): max_length=300, widget=forms.Textarea( attrs={ - "class": "w-full p-2 border border-gray-300 rounded-lg focus:ring focus:ring-blue-400 mb-5", + "class": STYLE["text-input"], "rows": 5, "placeholder": "Betriebliche Tätigkeiten", } @@ -30,7 +30,7 @@ class WeeklyReport(forms.Form): max_length=600, widget=forms.Textarea( attrs={ - "class": "w-full p-2 border border-gray-300 rounded-lg focus:ring focus:ring-blue-400 mb-5", + "class": STYLE["text-input"], "rows": 10, "placeholder": "Thema der Woche", } @@ -41,12 +41,31 @@ class WeeklyReport(forms.Form): max_length=300, widget=forms.Textarea( attrs={ - "class": "w-full p-2 border border-gray-300 rounded-lg focus:ring focus:ring-blue-400 mb-5", + "class": STYLE["text-input"], "rows": 5, "placeholder": "Berufsschule", } ), ) + img = forms.ImageField( + label=label_span("Bild"), + required=False, + widget=forms.ClearableFileInput( + attrs={ + "class": "block w-full p-2 text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400", + "accept": "image/*", + } + ), + ) + + @property + def display_names(self): + return { + "department": self.fields["department"].label, + "company_text": self.fields["company_text"].label, + "week_topic": self.fields["week_topic"].label, + "school_text": self.fields["school_text"].label, + } def content_values(self) -> dict: if self.is_valid(): @@ -57,11 +76,121 @@ class WeeklyReport(forms.Form): } -class DailyReport: - department = forms.CharField(label="Abteilung", max_length=150) - week_topic = forms.CharField(label="Thema der Woche", max_length=600) - monday_text = forms.CharField(label="Berufsschule", max_length=300) - tuesday_text = forms.CharField(label="Dienstag", max_length=300) - wednesday_text = forms.CharField(label="Mittwoch", max_length=300) - thursday_text = forms.CharField(label="Donnerstag", max_length=300) - friday_text = forms.CharField(label="Freitag", max_length=300) +class DailyReport(forms.Form): + department = forms.CharField( + label=label_span("Abteilung"), + max_length=150, + widget=forms.TextInput( + attrs={ + "placeholder": "Abteilung", + "class": STYLE["text-input"], + } + ), + ) + week_topic = forms.CharField( + label=label_span("Thema der Woche"), + max_length=600, + widget=forms.Textarea( + attrs={ + "class": STYLE["text-input"], + "rows": 5, + "placeholder": "Thema der Woche", + } + ), + ) + monday_text = forms.CharField( + label=label_span("Montag"), + max_length=300, + widget=forms.Textarea( + attrs={ + "class": STYLE["text-input"], + "rows": 5, + "placeholder": "Montag", + } + ), + ) + tuesday_text = forms.CharField( + label=label_span("Dienstag"), + max_length=300, + widget=forms.Textarea( + attrs={ + "class": STYLE["text-input"], + "rows": 5, + "placeholder": "Dienstag", + } + ), + ) + wednesday_text = forms.CharField( + label=label_span("Mittwoch"), + max_length=300, + widget=forms.Textarea( + attrs={ + "class": STYLE["text-input"], + "rows": 5, + "placeholder": "Mittwoch,", + } + ), + ) + thursday_text = forms.CharField( + label=label_span("Donnerstag"), + max_length=300, + widget=forms.Textarea( + attrs={ + "class": STYLE["text-input"], + "rows": 5, + "placeholder": "Donnerstag", + } + ), + ) + friday_text = forms.CharField( + label=label_span("Freitag"), + max_length=300, + widget=forms.Textarea( + attrs={ + "class": STYLE["text-input"], + "rows": 5, + "placeholder": "Freitag", + } + ), + ) + img = forms.ImageField( + label=label_span("Bild"), + required=False, + widget=forms.ClearableFileInput( + attrs={ + "class": "block w-full p-2 text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400", + "accept": "image/*", + } + ), + ) + + @property + def display_names(self) -> dict: + return { + "department": self.fields["department"].label, + "week_topic": self.fields["week_topic"].label, + "monday_text": self.fields["monday_text"].label, + "tuesday_text": self.fields["tuesday_text"].label, + "wednesday_text": self.fields["wednesday_text"].label, + "thursday_text": self.fields["thursday_text"].label, + "friday_text": self.fields["friday_text"].label, + } + + def content_values(self) -> dict: + if self.is_valid(): + return { + "week_topic": self.cleaned_data["week_topic"], + "monday_text": self.cleaned_data["monday_text"], + "tuesday_text": self.cleaned_data["tuesday_text"], + "wednesday_text": self.cleaned_data["wednesday_text"], + "thursday_text": self.cleaned_data["thursday_text"], + "friday_text": self.cleaned_data["friday_text"], + } + + +def choose_report_kind(kind, request=None, files=None): + match kind: + case "weekly": + return WeeklyReport(request, files) + case "daily": + return DailyReport(request, files) diff --git a/core/styles.py b/core/styles.py index 088b45d..1600293 100644 --- a/core/styles.py +++ b/core/styles.py @@ -3,6 +3,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", + "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/index.html b/core/templates/index.html index 5e0bfc9..ade5705 100644 --- a/core/templates/index.html +++ b/core/templates/index.html @@ -2,7 +2,7 @@ {% if late_reports > 1 %} - - +

Content:

- {% load markdown %} +
+
+ {% load access markdown %} {% for key, value in report.content.items %}
-

{{ key }}

- {{ value|markdown|safe }} +

{{ form.display_names|access:key|safe }}

+
{{ value|markdown|safe }}
{% endfor %} +
+ + {% if report.image is not None %} + {% load b64 %} +
+ +
+ {% endif %} + +
diff --git a/core/templates/shell.html b/core/templates/shell.html index 0c35906..b1a26fb 100644 --- a/core/templates/shell.html +++ b/core/templates/shell.html @@ -8,7 +8,7 @@
- @@ -38,11 +38,9 @@
- diff --git a/core/templates/write.html b/core/templates/write.html index 62e1b84..3ec6783 100644 --- a/core/templates/write.html +++ b/core/templates/write.html @@ -12,7 +12,7 @@

- + {% load access set_content %} @@ -24,7 +24,11 @@ {% if field.id_for_label == "id_department" %} + {% if draft is not None %} {{ field|set_content:draft.department }} + {% else %} + {{ field }} + {% endif %} {% else %} {% with content=draft.content|access:field.id_for_label %} diff --git a/core/templatetags/b64.py b/core/templatetags/b64.py new file mode 100644 index 0000000..6c82718 --- /dev/null +++ b/core/templatetags/b64.py @@ -0,0 +1,11 @@ +from django import template +import base64 + +register = template.Library() + + +@register.filter(name="b64") +def b64(value): + if value is None: + return "" + return base64.b64encode(value).decode("utf-8") diff --git a/core/templatetags/markdown.py b/core/templatetags/markdown.py index c6bea54..3728b52 100644 --- a/core/templatetags/markdown.py +++ b/core/templatetags/markdown.py @@ -7,4 +7,6 @@ register = template.Library() @register.filter(name="markdown") def markdown_tag(value): - return markdown.markdown(bleach.clean(value, tags=[], attributes=[])) + return markdown.markdown( + bleach.clean(value, tags=[], attributes=[]), extensions=["nl2br"] + ) diff --git a/core/views.py b/core/views.py index e7b122c..33ac90d 100644 --- a/core/views.py +++ b/core/views.py @@ -8,6 +8,7 @@ from django.core.paginator import Paginator 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 import datetime import json @@ -24,7 +25,7 @@ def write_new_report(request): def write_new_report_post(request): user = AzureUser(request) - report_form = user.get_report_kind_form(request.POST) + report_form = user.get_report_kind_form(request.POST, request.FILES) if not report_form.is_valid(): return HttpResponse("Bad Request", status=400) @@ -35,6 +36,9 @@ def write_new_report_post(request): user.reports().order_by("-year", "-week").first() ) + upload = report_form.cleaned_data["img"] + img = upload.read() if upload is not None else None + report = Berichtsheft( user=user.id, kind=user.get_report_kind(), @@ -43,8 +47,13 @@ def write_new_report_post(request): week=int(current_week), department=report_form.cleaned_data["department"], content=report_form.content_values(), + image=img, ) report.save() + + # Clear draft + BerichtsheftDraft.objects.filter(user=user.id).delete() + return redirect("/") @@ -159,12 +168,16 @@ def report_detail_page(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) return htmx_request( - request, "report.html", {"report": report}, f"Berichtsheft {report.num}" + request, + "report.html", + {"report": report, "form": form}, + f"Berichtsheft {report.num}", ) diff --git a/requirements.txt b/requirements.txt index f19d158..d8344af 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ Django~=4.2.11 psycopg2 markdown -bleach \ No newline at end of file +bleach +pillow \ No newline at end of file From 3caecf63f69ac6e7ee7a8acf6a64318fd9c305cb Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 6 Dec 2024 14:04:17 +0100 Subject: [PATCH 09/10] work+roles --- core/azure_auth.py | 12 ++++++++++++ core/styles.py | 2 +- core/templates/component/report.html | 6 +++--- core/templates/index.html | 6 +++--- core/templates/settings.html | 8 ++++++++ core/templates/shell.html | 13 ++++++++++--- core/urls.py | 1 + core/views.py | 11 +++++++++++ 8 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 core/templates/settings.html diff --git a/core/azure_auth.py b/core/azure_auth.py index 64ad1f5..2dee84e 100644 --- a/core/azure_auth.py +++ b/core/azure_auth.py @@ -5,6 +5,13 @@ import base64 from core.models import Berichtsheft from core.reports import DailyReport, WeeklyReport, choose_report_kind import core.util +from enum import Enum + + +class Roles(Enum): + TRAINEE = "trainee" + MANAGER = "manager" + ADMIN = "admin" class AzureUser: @@ -59,3 +66,8 @@ class AzureUser: new_year, new_week = core.util.next_date(new_year, new_week) return count + + @property + def role(self) -> Roles: + # TODO : Implement + return Roles.TRAINEE diff --git a/core/styles.py b/core/styles.py index 1600293..ea7dce0 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", + "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", "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 05d8bd4..1bac2d5 100644 --- a/core/templates/component/report.html +++ b/core/templates/component/report.html @@ -1,5 +1,5 @@ -
{% endif %} {{ report }} - + diff --git a/core/templates/index.html b/core/templates/index.html index ade5705..7655f66 100644 --- a/core/templates/index.html +++ b/core/templates/index.html @@ -24,11 +24,11 @@ {% for report in reports %} {% if forloop.first %} {% if report.week != week_now %} - + {% endif %} {% endif %} {% include 'component/report.html' with report=report %} diff --git a/core/templates/settings.html b/core/templates/settings.html new file mode 100644 index 0000000..9d14eb4 --- /dev/null +++ b/core/templates/settings.html @@ -0,0 +1,8 @@ +{{ title|safe }} + +

+ Benutzer: +

+ +

{{ user.display_name }}

+

{{ user.role.value|capfirst }}

diff --git a/core/templates/shell.html b/core/templates/shell.html index b1a26fb..a4402a5 100644 --- a/core/templates/shell.html +++ b/core/templates/shell.html @@ -8,7 +8,7 @@
- @@ -21,11 +21,18 @@
diff --git a/core/urls.py b/core/urls.py index 6c33d88..dcab3cb 100644 --- a/core/urls.py +++ b/core/urls.py @@ -7,4 +7,5 @@ urlpatterns = [ path("report/", views.report_detail_page, name="report_detail"), 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 33ac90d..6144704 100644 --- a/core/views.py +++ b/core/views.py @@ -213,3 +213,14 @@ def report_draft_update(request): ) return JsonResponse({"error": "Invalid request method"}, status=400) + + +def settings_page(request): + user = AzureUser(request) + + return htmx_request( + request, + "settings.html", + {"user": user}, + "Einstellungen", + ) From 696e603476fc6309db2ef13b172f79fd4ab38fa0 Mon Sep 17 00:00:00 2001 From: JMARyA Date: Fri, 6 Dec 2024 15:07:03 +0100 Subject: [PATCH 10/10] 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