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