From 9c69dba56d6a3391e62dda77012e52833809c515 Mon Sep 17 00:00:00 2001 From: Tom Irgang Date: Fri, 21 Apr 2023 18:24:31 +0200 Subject: [PATCH] design, rework flow, extend device --- docs/index.md | 54 ++- nginx.default | 3 + rc_hip/rc_hip/urls.py | 1 + rc_hip/repapp/forms.py | 34 +- ..._secret_remove_guest_confirmed_and_more.py | 49 +++ rc_hip/repapp/models.py | 59 +-- rc_hip/repapp/templates/repapp/base.html | 11 +- .../repapp/templates/repapp/device_view.html | 62 +++- rc_hip/repapp/templates/repapp/index.html | 339 +++++++++++++++++- .../mail/mail_register_device_html.html | 20 +- .../mail/mail_register_device_subject.html | 2 +- .../mail/mail_register_device_text.html | 12 +- .../templates/repapp/register_device.html | 25 +- .../repapp/register_device_confirm.html | 12 - .../repapp/register_device_final.html | 24 +- rc_hip/repapp/urls.py | 8 +- rc_hip/repapp/views.py | 300 ++++++++-------- 17 files changed, 712 insertions(+), 303 deletions(-) create mode 100644 rc_hip/repapp/migrations/0012_remove_device_secret_remove_guest_confirmed_and_more.py delete mode 100644 rc_hip/repapp/templates/repapp/register_device_confirm.html diff --git a/docs/index.md b/docs/index.md index 51e8f31..06eda45 100644 --- a/docs/index.md +++ b/docs/index.md @@ -63,6 +63,7 @@ Attribute: - Datum: Datum der Veranstaltung - Ort: Beschreibung wo das Repair-Café stattfindet +- Adresse: Adresse an der das Repair-Café stattfindet Annahmen: @@ -102,7 +103,6 @@ Attribute: - Telefon: Festnetz oder Mobilnummer des Gastes - Wohnort: Wohnort des Gastes - Mail: eMail-Adresse des Gastes für Benachrichtigungen -- Bestätigt: Ein boolesches Flag das anzeigt ob der Gast seine eMail-Adresse bestätigt hat. Technische Attribute: @@ -115,15 +115,18 @@ Ein Gerät ist ein defekter Gegenstand der im Rahmen eines Repair-Cafés reparie Attribute: - Gerät: Bezeichnung des Geräts +- Hersteller: Hersteller des Geräts - Fehler: Beschreibung des Defekts - Folgetermin: Boolesches Flag das anzeigt ob es sich um einen Folgetermin handelt. -- Bestätigt: Ein boolesches Flag das anzeigt ob der Gast die Greäteanmeldung bestätigt hat. +- Foto vom Gerät +- Foto vom Typenschild +- Bestätigung gesendet?: Ein boolesches Flag das anzeigt ob eine eMail als Anmeldebestätigung gesendet wurde. Technische Attribute: - Identifier: SHA256 Hash aus Gerät + Gast + Timestamp -- Geheimnis: SHA256 Hash aus Gerät + Gast + Timestamp + Zufallszahl - Gast: Referenz zum Gast der das Gerät besitzt +- Cafe: Referenz zum Repair-Café für das diese Gerät angemeldet ist ### Termin @@ -192,17 +195,19 @@ URL: cafe/int:cafe/ Name: register_device Diese Seite zeigt das Formular zum anmelden der Geräte. -Das Formular hat die Felder `eMail-Adresse`, `Gerätebezeichnung`, `Fehlerbeschreibung`, eine Kontrollkästchen `Folgetermin` und einen Knopf `Absenden` zum senden des Formulars. +Das Formular hat die Felder `eMail-Adresse`, `Art des Geräts`, `Hersteller & Modell/Typ`, `Fehlerbeschreibung`, `Foto vom Gerät`, `Foto vom Typenschild`, ein Kontrollkästchen `Folgetermin`, ein Kontrollkästchen `Informationen zur Reparaturabwicklung`, ein Kontrollkästchen `Datenschutz` und einen Knopf `Absenden` zum senden des Formulars. Das Repair-Café zu dem die Anmeldung gehört ist über eine ID in der URL der Seite festgelegt. +Die eMail-Benachrichtigung and die Organisatoren und die Bestätigung an den Gast wird beim absenden des Formulars gesendet, falls die eMail Adresse zu einem bekannten Gast gehört. + #### Sicherheit Die Seite ist ohne Zugangsbeschränkung oder Anmeldung erreichbar. ### Gast anmelden (S3) -URL: cafe/int:cafe/device/str:deviceentifier/str:mail/ +URL: cafe/int:cafe/device/str:device_identifier/mail/str:mail/ Name: register_guest @@ -211,37 +216,20 @@ Das Formular hat die Felder `Name`, `Telefon`, `Wohnort` und einen Knopf `Absend Die eMail-Adresse und das Gerät zu dem die Gast-Kontaktdaten gehören ist über IDs in der URL der Seite festgelegt. -#### Sicherheit - -Die Seite ist ohne Zugangsbeschränkung oder Anmeldung erreichbar. - -### Bestätigung gesendet (S4) - -URL: cafe/int:cafe/device/str:deviceentifier/guest/str:guestentifier/ - -Name: register_device_final - -Die Seite Bestätigung gesendet zeigt einen Hinweis dass eine eMail gesendet wurde und die Anmeldung des Gerätes durch einen Klick auf einen Link in der eMail bestätigt werden muss. - -Die eMail-Bestätigung wird während des Aufrufs dieser Seite gesendet. - -Das Repair-Café, der Gast und das Gerät sind über IDs in der URL der Seite festgelegt. +Die eMail-Benachrichtigung and die Organisatoren und die Bestätigung an den Gast wird beim absenden des Formulars gesendet. #### Sicherheit Die Seite ist ohne Zugangsbeschränkung oder Anmeldung erreichbar. - ### Anmeldung bestätigt (S7) -URL: confirm/str:deviceentifier/code/str:device_secret/ +URL: cafe/int:cafe/device/str:device_identifier/confirm/ -Name: register_device_confirm +Name: register_device_final Die Seite Anmeldung bestätigt zeigt einen Hinweis dass die Anmeldung des Gerätes erfolgreich abgeschlossen wurde. -Die eMail-Benachrichtigung and die Organisatoren wird während des Aufrufs dieser Seite gesendet. - Die Geräte ID ist in der URL der Seite festgelegt. #### Sicherheit @@ -250,11 +238,11 @@ Die Seite ist ohne Zugangsbeschränkung oder Anmeldung erreichbar. ### Geräte Detailseite (S5) -URL: device/str:deviceentifier/ +URL: device/str:device_identifier/ Name: view_device -Die Geräte Detailseite zeigt die Informationen `Gerätebezeichnung`, `Fehlerbeschreibung` und `Folgetermin` an. +Die Geräte Detailseite zeigt die Informationen `Art des Geräts`, `Hersteller & Modell/Typ`, `Fehlerbeschreibung`, `Foto vom Gerät`, `Foto vom Typenschild` und `Folgetermin` an. Das Gerät ist über IDs in der URL der Seite festgelegt. @@ -283,16 +271,16 @@ Die Seite enthält persönliche Daten und ist nur nach Anmeldung erreichbar. Als neuer Gast der ein defekten Geräte anmelden möchte, - gehe ich auf die Seite (S1) der Repair-Café Termine. Dort klicke ich auf `Gerät anmelden` bei dem richtigen Repair-Café Termin. Dieser Klick bringt mich auf die nächste Seite. -- Die nächste Seite (S2) enthält ein Formular mit den Feldern `eMail-Adresse`, `Gerätebezeichnung` und `Fehlerbeschreibung` und eine Kontrollkästchen `Folgetermin`. Nachdem ich die Felder ausgefüllt habe klicke auf auf `Absenden`. Dieser Klick bringt mich auf die nächste Seite. +- Die nächste Seite (S2) enthält ein Formular mit den Feldern `eMail-Adresse`, `Art des Geräts`, `Hersteller & Modell/Typ`, `Fehlerbeschreibung`, `Foto vom Gerät`, `Foto vom Typenschild`, ein Kontrollkästchen `Folgetermin`, ein Kontrollkästchen `Informationen zur Reparaturabwicklung` une ein Kontrollkästchen `Datenschutz`. Nachdem ich die Felder ausgefüllt habe klicke auf auf `Absenden`. Dieser Klick bringt mich auf die nächste Seite. - Die nächste Seite (S3) enthält ein Formular mit den Feldern `Name`, `Telefon` und `Wohnort`. Nachdem ich die Felder ausgefüllt habe klicke auf auf `Absenden`. Dieser Klick bringt mich auf die nächste Seite. -- Die nächste Seite (S4) weißt mich darauf hin dass eine eMail gesendet wurde und ich die Anmeldung über einen Klick in der eMail bestätigen muss. -- In meinem eMail Posteingang finde ich eine Bestätigung der Geräteanmeldung die ebenfalls einen Link enthält um die Anmeldung zu bestätigen. Ein Klick auf diesen Link bringt mich auf die Seite Anmeldung bestätigt (S7). +- Die nächste Seite (S5) bestätigt mir die Anmeldung meines Gerätes. +- In meinem eMail Posteingang finde ich ebenfalls eine Bestätigung der Geräteanmeldung. #### Variante: Bekannter Gast (existierende eMail Adresse) Als bekannter Gast der ein defekten Geräte anmelden möchte, - gehe ich auf die Seite (S1) der Repair-Café Termine. Dort klicke ich auf `Gerät anmelden` bei dem richtigen Repair-Café Termin. Dieser Klick bringt mich auf die nächste Seite. -- Die nächste Seite (S2) enthält ein Formular mit den Feldern `eMail-Adresse`, `Gerätebezeichnung` und `Fehlerbeschreibung` und eine Kontrollkästchen `Folgetermin`. Nachdem ich die Felder ausgefüllt habe klicke auf auf `Absenden`. Dieser Klick bringt mich auf die nächste Seite. -- Die nächste Seite (S4) weißt mich darauf hin dass eine eMail gesendet wurde und ich die Anmeldung über einen Klick in der eMail bestätigen muss. -- In meinem eMail Posteingang finde ich eine Bestätigung der Geräteanmeldung die ebenfalls einen Link enthält um die Anmeldung zu bestätigen. Ein Klick auf diesen Link bringt mich auf die Seite Anmeldung bestätigt (S7). +- Die nächste Seite (S2) enthält ein Formular mit den Feldern `eMail-Adresse`, `Art des Geräts`, `Hersteller & Modell/Typ`, `Fehlerbeschreibung`, `Foto vom Gerät`, `Foto vom Typenschild`, ein Kontrollkästchen `Folgetermin`, ein Kontrollkästchen `Informationen zur Reparaturabwicklung` une ein Kontrollkästchen `Datenschutz`. Nachdem ich die Felder ausgefüllt habe klicke auf auf `Absenden`. Dieser Klick bringt mich auf die nächste Seite. +- Die nächste Seite (S5) bestätigt mir die Anmeldung meines Gerätes. +- In meinem eMail Posteingang finde ich ebenfalls eine Bestätigung der Geräteanmeldung. diff --git a/nginx.default b/nginx.default index 1bd3943..aafba40 100644 --- a/nginx.default +++ b/nginx.default @@ -10,4 +10,7 @@ server { location /static { root /opt/app/rc_hip; } + location /media { + root /opt/app/rc_hip; + } } diff --git a/rc_hip/rc_hip/urls.py b/rc_hip/rc_hip/urls.py index 52331bf..bc7b9ae 100644 --- a/rc_hip/rc_hip/urls.py +++ b/rc_hip/rc_hip/urls.py @@ -17,6 +17,7 @@ Including another URLconf from django.contrib import admin from django.urls import path, include + urlpatterns = [ path("", include("repapp.urls")), path('admin/', admin.site.urls), diff --git a/rc_hip/repapp/forms.py b/rc_hip/repapp/forms.py index faa99d8..aabfb76 100644 --- a/rc_hip/repapp/forms.py +++ b/rc_hip/repapp/forms.py @@ -8,9 +8,12 @@ class RegisterDevice(forms.Form): " zur Anfrage verwendet.", max_length=200) device = forms.CharField( - label="Gerätebezeichnung", - help_text="Bitte geben Sie den Hersteller und die" - " Gerätebezeichnung an.", + label="Art des Geräts", + help_text="z.B. Küchenmaschine, Smartphone, Stehlampe, Drucker, ...", + max_length=200 + ) + manufacturer = forms.CharField( + label="Hersteller & Modell/Typ", max_length=200 ) error = forms.CharField( @@ -18,12 +21,33 @@ class RegisterDevice(forms.Form): help_text="Beschreiben Sie hier das Problem ihres Gerätes.", widget=forms.Textarea ) + device_picture = forms.FileField( + label="Foto vom Gerät ", required=False + ) + type_plate_picture = forms.FileField( + label="Foto vom Typenschild ", required=False + ) follow_up = forms.BooleanField( label="Folgetermin", - help_text="Klicken Sie dieses Kästchen an wenn sie mit diesem" - " Gerät bereits bei einem Repair-Café waren.", + help_text="Kreuzen Sie diese Kästchen an wenn sie mit diesem Gerät bereits bei einem Repair-Café Termin waren.", required=False ) + confirm_repair = forms.BooleanField( + label="Informationen zur Reparaturabwicklung", + help_text="Ich bin mit den " + "Allgemeinen Bedingungen zur Reparaturabwicklung einverstanden.", + required=True + ) + confirm_data = forms.BooleanField( + label="Datenschutz", + help_text=" Ich bin mit der Erhebung, Verarbeitung und Speicherung meiner Daten für " + "die Bearbeitung meiner Anfrage gemäß der " + "" + "Datenschutzerklärung einverstanden.", + required=True + ) class RegisterGuest(forms.Form): diff --git a/rc_hip/repapp/migrations/0012_remove_device_secret_remove_guest_confirmed_and_more.py b/rc_hip/repapp/migrations/0012_remove_device_secret_remove_guest_confirmed_and_more.py new file mode 100644 index 0000000..cd4999e --- /dev/null +++ b/rc_hip/repapp/migrations/0012_remove_device_secret_remove_guest_confirmed_and_more.py @@ -0,0 +1,49 @@ +# Generated by Django 4.2 on 2023-04-21 15:21 + +from django.db import migrations, models +import repapp.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('repapp', '0011_rename_cafe_id_appointment_cafe_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='device', + name='secret', + ), + migrations.RemoveField( + model_name='guest', + name='confirmed', + ), + migrations.AddField( + model_name='cafe', + name='address', + field=models.CharField(default='', max_length=200, verbose_name='Ort'), + preserve_default=False, + ), + migrations.AddField( + model_name='device', + name='device_picture', + field=models.FileField(null=True, upload_to=repapp.models.device_directory_path, verbose_name='Foto vom Gerät'), + ), + migrations.AddField( + model_name='device', + name='manufacturer', + field=models.CharField(default='', max_length=200, verbose_name='Hersteller'), + preserve_default=False, + ), + migrations.AddField( + model_name='device', + name='type_plate_picture', + field=models.FileField(null=True, upload_to=repapp.models.device_directory_path, verbose_name='Foto vom Typenschild'), + ), + migrations.AlterField( + model_name='device', + name='confirmed', + field=models.BooleanField(verbose_name='Bestätigung gesendet?'), + ), + ] diff --git a/rc_hip/repapp/models.py b/rc_hip/repapp/models.py index 35ef4dc..0836015 100644 --- a/rc_hip/repapp/models.py +++ b/rc_hip/repapp/models.py @@ -11,6 +11,8 @@ class Cafe(models.Model): """ location = models.CharField( max_length=200, verbose_name=_("Ort")) + address = models.CharField( + max_length=200, verbose_name=_("Adresse")) event_date = models.DateField(verbose_name=_("Datum")) class Meta: @@ -60,7 +62,6 @@ class Guest(models.Model): phone = models.CharField(max_length=200, verbose_name=_("Telefonnummer")) residence = models.CharField(max_length=200, verbose_name=_("Wohnort")) mail = models.CharField(max_length=200, verbose_name=_("eMail")) - confirmed = models.BooleanField(verbose_name=_("Bestätigt"), default=False) class Meta: verbose_name = _('Gast') @@ -70,21 +71,29 @@ class Guest(models.Model): return f'Gast {self.name} (eMail: {self.mail})' +def device_directory_path(instance, filename): + return f'device_{instance.identifier}/{filename}' + + class Device(models.Model): """ A Device is a broken device owned by a guest which shall be repaired during a Repair-Café. """ identifier = models.CharField(max_length=200, verbose_name=_("ID")) - secret = models.CharField( - max_length=200, verbose_name=_("Bestätigungscode"), default="TEST12345") - device = models.CharField(max_length=200, verbose_name=_("Gerät")) - error = models.TextField(verbose_name=_("Fehler")) + device = models.CharField(max_length=200, verbose_name=_("Art des Geräts")) + manufacturer = models.CharField( + max_length=200, verbose_name=_("Hersteller & Modell/Typ")) + error = models.TextField(verbose_name=_("Fehlerbeschreibung")) follow_up = models.BooleanField(verbose_name=_("Folgetermin")) - confirmed = models.BooleanField(verbose_name=_("Bestätigt"), default=False) + device_picture = models.FileField( + upload_to=device_directory_path, null=True, verbose_name=_("Foto vom Gerät")) + type_plate_picture = models.FileField( + upload_to=device_directory_path, null=True, verbose_name=_("Foto vom Typenschild")) guest = models.ForeignKey( Guest, on_delete=models.CASCADE, null=True, verbose_name=_("Gast")) cafe = models.ForeignKey( Cafe, on_delete=models.CASCADE, null=False, verbose_name=_("Repair-Café")) + confirmed = models.BooleanField(verbose_name=_("Bestätigung gesendet?")) class Meta: verbose_name = _('Gerät') @@ -116,25 +125,6 @@ class Appointment(models.Model): return f'Termin {self.cafe.event_date} {self.time} für Gerät {self.device.device}' -class Candidate(models.Model): - """ - A Candidate is a match of a broken Device and a Repair-Café without a fixed timeslot - or pre-assigned Reparateur. - """ - confirmed = models.BooleanField(verbose_name=_("bestätigt")) - cafe = models.ForeignKey( - Cafe, on_delete=models.CASCADE, verbose_name=_("Repair-Café")) - device = models.ForeignKey( - Device, on_delete=models.CASCADE, null=True, verbose_name=_("Gerät")) - - class Meta: - verbose_name = _('Kandidat') - verbose_name_plural = _('Kandidaten') - - def __str__(self): - return f'Kandidat {self.cafe.event_date} für Gerät {self.device.device}' - - class Question(models.Model): """ A Question is a request for information form a Organisator or a Reparateur for a Device. @@ -155,3 +145,22 @@ class Question(models.Model): def __str__(self): return f'Frage vom {self.date} zum Gerät {self.device.device}' + + +class Candidate(models.Model): + """ + A Candidate is a match of a broken Device and a Repair-Café without a fixed timeslot + or pre-assigned Reparateur. + """ + confirmed = models.BooleanField(verbose_name=_("bestätigt")) + cafe = models.ForeignKey( + Cafe, on_delete=models.CASCADE, verbose_name=_("Repair-Café")) + device = models.ForeignKey( + Device, on_delete=models.CASCADE, null=True, verbose_name=_("Gerät")) + + class Meta: + verbose_name = _('Kandidat') + verbose_name_plural = _('Kandidaten') + + def __str__(self): + return f'Kandidat {self.cafe.event_date} für Gerät {self.device.device}' diff --git a/rc_hip/repapp/templates/repapp/base.html b/rc_hip/repapp/templates/repapp/base.html index 115c1d2..acb2fa5 100644 --- a/rc_hip/repapp/templates/repapp/base.html +++ b/rc_hip/repapp/templates/repapp/base.html @@ -2,6 +2,10 @@ + + + {% block head %} + {% endblock head %}
{% if messages %} - {% for message in messages %} - - {% endfor %} + {% for message in messages %}{% endfor %} {% endif %} {% block content %} {% endblock content %} diff --git a/rc_hip/repapp/templates/repapp/device_view.html b/rc_hip/repapp/templates/repapp/device_view.html index e5c67f7..3ffea1d 100644 --- a/rc_hip/repapp/templates/repapp/device_view.html +++ b/rc_hip/repapp/templates/repapp/device_view.html @@ -5,14 +5,56 @@ {% block content %}

Gerät: {{ device.device }}


-

Fehler:

-

{{ device.error }}

-

- Folgetermin: - {% if device.follow_up %} - Ja - {% else %} - Nein - {% endif %} -

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Art des Geräts{{ device.device }}
Hersteller & Modell/Typ{{ device.manufacturer }}
Fehlerbeschreibung{{ device.error }}
Folgetermin + {% if device.follow_up %} + Ja + {% else %} + Nein + {% endif %} +
Foto vom Gerät + {% if device.device_picture %} + Foto vom Gerät + {% else %} + kein Bild + {% endif %} +
Foto vom Typenschild + {% if device.device_picture %} + Foto vom Typenschild + {% else %} + kein Bild + {% endif %} +
{% endblock content %} diff --git a/rc_hip/repapp/templates/repapp/index.html b/rc_hip/repapp/templates/repapp/index.html index b8169e0..07d63d7 100644 --- a/rc_hip/repapp/templates/repapp/index.html +++ b/rc_hip/repapp/templates/repapp/index.html @@ -1,19 +1,324 @@ {% extends "repapp/base.html" %} - -{% block title %}- Repair-Cafés{% endblock title %} - +{% block title %} + - Repair-Cafés +{% endblock title %} +{% block head %} + +{% endblock head %} {% block content %} -

Repair-Cafés

-
- -{% endblock content %} \ No newline at end of file +

Repair-Cafés

+
+
    + {% for cafe in object_list %} +
  • +
    +
    +
    +
    + +
    +
    + {{ cafe.location }} +
    + {{ cafe.address }} +
    +
    +
    +

    + + Nur per Voranmeldung. + Zum Anmeldeformular + +

    +
    +
    +
    +
    +
    +
  • + {% empty %} +
  • Es gibt keine geplanten Repair-Cafés.
  • + {% endfor %} +
+{% endblock content %} diff --git a/rc_hip/repapp/templates/repapp/mail/mail_register_device_html.html b/rc_hip/repapp/templates/repapp/mail/mail_register_device_html.html index 69e5b75..99b3537 100644 --- a/rc_hip/repapp/templates/repapp/mail/mail_register_device_html.html +++ b/rc_hip/repapp/templates/repapp/mail/mail_register_device_html.html @@ -1,20 +1,22 @@ -

Hallo {{ guest.name }},

+

Guten Tag,

- Ihre Anmeldung von {{ device.device }} für das Repair-Café am {{ cafe.event_date|date }} - ist bei uns angekommen. + dies ist eine automatische Nachricht, die du erhältst, nachdem du unser Anmeldeformular abgesendet hast und deine Angaben in unserer Datenbank gespeichert wurden.

- Bitte bestätigen sie ihre Anmeldung in dem Sie - hier - klicken. + Vielen Dank für die Anmeldung des Geräts {{ device.device }} - {{ device.manufacturer }} zur Reparatur im Repair-Café am {{ cafe.event_date|date }}.

- Viele Grüße, -
- Ihr Repair-Café + Die Organisation unserer Repair-Cafés beginnt i.a. einige Tage vor dem jeweiligen Termin. Dann erstellen wir anhand der angemeldeten Geräte und der Spezialgebiete der anwesenden Reparateure einen Zeitplan.

+

+ Sobald dieser Zeitplan fertig gestellt ist, erhältst du von einem Mitglied unseres Organisationsteams eine Mail. Diese beinhaltet im Normalfall den Reparaturtermin inkl. der Uhrzeit, für die die Reparatur vorgesehen ist. In Ausnahmefällen (z.B. wenn kein Spezialist für die Gerätegruppe anwesend sein wird oder überbucht ist) ist es aber auch möglich, dass wir deinen gewünschten Termin absagen und dir einen Alternativtermin vorschlagen müssen. +

+

+ Falls du in der Zwischenzeit Rückfragen hast oder deinen Wunschtermin doch nicht wahrnehmen kannst, antworte bitte einfach auf diese Nachricht. +

+

Herzliche Grüße sendet dir das Organisationsteam vom Repair-Café Hilpoltstein!

diff --git a/rc_hip/repapp/templates/repapp/mail/mail_register_device_subject.html b/rc_hip/repapp/templates/repapp/mail/mail_register_device_subject.html index 7268866..cc948cb 100644 --- a/rc_hip/repapp/templates/repapp/mail/mail_register_device_subject.html +++ b/rc_hip/repapp/templates/repapp/mail/mail_register_device_subject.html @@ -1 +1 @@ -Anmeldung von {{ device.device }} für das Repair-Café am {{ cafe.event_date|date }} +Repair-Café Hilpoltstein am {{ cafe.event_date|date }} - Geräteanmeldung diff --git a/rc_hip/repapp/templates/repapp/mail/mail_register_device_text.html b/rc_hip/repapp/templates/repapp/mail/mail_register_device_text.html index 053c2f9..30110e2 100644 --- a/rc_hip/repapp/templates/repapp/mail/mail_register_device_text.html +++ b/rc_hip/repapp/templates/repapp/mail/mail_register_device_text.html @@ -1,5 +1,7 @@ -Hallo {{ guest.name }}, -Ihre Anmeldung von {{ device.device }} für das Repair-Café am {{ cafe.event_date|date }} ist bei uns angekommen. -Bitte bestätigen sie ihre Anmeldung in dem Sie https://repapp.rc-hip.de/confirm/{{ device.identifier }}/code/{{ device.secret }} in ihrem Web-Browser aufrufen. -Viele Grüße, -Ihr Repair-Café +Guten Tag, +dies ist eine automatische Nachricht, die du erhältst, nachdem du unser Anmeldeformular abgesendet hast und deine Angaben in unserer Datenbank gespeichert wurden. +Vielen Dank für die Anmeldung des Geräts {{ device.device }} - {{ device.manufacturer }} zur Reparatur im Repair-Café am {{ cafe.event_date|date }}. +Die Organisation unserer Repair-Cafés beginnt i.a. einige Tage vor dem jeweiligen Termin. Dann erstellen wir anhand der angemeldeten Geräte und der Spezialgebiete der anwesenden Reparateure einen Zeitplan. +Sobald dieser Zeitplan fertig gestellt ist, erhältst du von einem Mitglied unseres Organisationsteams eine Mail. Diese beinhaltet im Normalfall den Reparaturtermin inkl. der Uhrzeit, für die die Reparatur vorgesehen ist. In Ausnahmefällen (z.B. wenn kein Spezialist für die Gerätegruppe anwesend sein wird oder überbucht ist) ist es aber auch möglich, dass wir deinen gewünschten Termin absagen und dir einen Alternativtermin vorschlagen müssen. +Falls du in der Zwischenzeit Rückfragen hast oder deinen Wunschtermin doch nicht wahrnehmen kannst, antworte bitte einfach auf diese Nachricht. +Herzliche Grüße sendet dir das Organisationsteam vom Repair-Café Hilpoltstein! diff --git a/rc_hip/repapp/templates/repapp/register_device.html b/rc_hip/repapp/templates/repapp/register_device.html index e52e45f..4c71c79 100644 --- a/rc_hip/repapp/templates/repapp/register_device.html +++ b/rc_hip/repapp/templates/repapp/register_device.html @@ -1,15 +1,16 @@ {% extends "repapp/base.html" %} - {% load crispy_forms_tags %} - -{% block title %}- Gerät anmelden{% endblock title %} - +{% block title %} + - Gerät anmelden +{% endblock title %} {% block content %} -

Gerät anmelden

-
-
- {% csrf_token %} - {{ form|crispy }} - -
-{% endblock content %} \ No newline at end of file +

Gerät anmelden

+
+
+ {% csrf_token %} + {{ form|crispy }} + +
+{% endblock content %} diff --git a/rc_hip/repapp/templates/repapp/register_device_confirm.html b/rc_hip/repapp/templates/repapp/register_device_confirm.html deleted file mode 100644 index e181974..0000000 --- a/rc_hip/repapp/templates/repapp/register_device_confirm.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "repapp/base.html" %} -{% block title %} -{% endblock title %} -{% block content %} -

Anmeldung abgeschlossen

-
-

Ihr Gerät ist erfolgreich angemeldet!

-

- Wir versuchen für sie einen Termin bei einem geeigneten Reparateur zu finden. - Wenn wir einen Termin gefunden haben werden Sie per eMail benachrichtigt. -

-{% endblock content %} diff --git a/rc_hip/repapp/templates/repapp/register_device_final.html b/rc_hip/repapp/templates/repapp/register_device_final.html index a2a11bf..c53eaa5 100644 --- a/rc_hip/repapp/templates/repapp/register_device_final.html +++ b/rc_hip/repapp/templates/repapp/register_device_final.html @@ -1,12 +1,16 @@ {% extends "repapp/base.html" %} - -{% block title %}{% endblock title %} - +{% block title %} +{% endblock title %} {% block content %} -

Bestätigung ihrer Daten

-
-

-Wir haben ihnen eine eMail mit ihren Daten gesendet. Bitte bestätigen -Sie ihre Anmeldung durch Klick auf den Link in der eMail. -

-{% endblock content %} \ No newline at end of file +

Anmeldung erfolgreich!

+
+

+ Vielen Dank für die Anmeldung des Geräts {{ device.device }} - {{ device.manufacturer }} zur Reparatur im Repair-Café am {{ cafe.event_date|date }}. +

+

+ Die Organisation unserer Repair-Cafés beginnt i.a. einige Tage vor dem jeweiligen Termin. Dann erstellen wir anhand der angemeldeten Geräte und der Spezialgebiete der anwesenden Reparateure einen Zeitplan. +

+

+ Sobald dieser Zeitplan fertig gestellt ist, erhältst du von einem Mitglied unseres Organisationsteams eine Mail. Diese beinhaltet im Normalfall den Reparaturtermin inkl. der Uhrzeit, für die die Reparatur vorgesehen ist. In Ausnahmefällen (z.B. wenn kein Spezialist für die Gerätegruppe anwesend sein wird oder überbucht ist) ist es aber auch möglich, dass wir deinen gewünschten Termin absagen und dir einen Alternativtermin vorschlagen müssen. +

+{% endblock content %} diff --git a/rc_hip/repapp/urls.py b/rc_hip/repapp/urls.py index 77eb6dd..f56ab76 100644 --- a/rc_hip/repapp/urls.py +++ b/rc_hip/repapp/urls.py @@ -13,14 +13,12 @@ urlpatterns = [ name="register_device" ), path( - "cafe//device///", + "cafe//device//mail//", views.RegisterGuestFormView.as_view(), name="register_guest" ), - path("cafe//device//guest//", + path("cafe//device//confirm/", views.register_device_final, name="register_device_final"), - path("confirm//code//", - views.register_device_confirm, name="register_device_confirm"), - path("device//", + path("device//", views.device_view, name="view_device"), ] diff --git a/rc_hip/repapp/views.py b/rc_hip/repapp/views.py index 23d944f..1a4b75a 100644 --- a/rc_hip/repapp/views.py +++ b/rc_hip/repapp/views.py @@ -3,12 +3,11 @@ Views of RepApp. """ import datetime import os -import random from hashlib import sha256 from django.views import generic from django.urls import reverse_lazy from django.shortcuts import get_object_or_404, render -from django.http import HttpResponseRedirect, Http404 +from django.http import HttpResponseRedirect from django.contrib import messages from django.core.mail import send_mail from django.template.loader import render_to_string @@ -28,119 +27,24 @@ class IndexView(generic.ListView): return Cafe.objects.filter(event_date__gte=datetime.date.today()) -class RegisterDeviceFormView(generic.edit.FormView): - template_name = "repapp/register_device.html" - form_class = RegisterDevice +def send_confirmation_mails(device, guest, cafe, request): + organizers = [] + for organizer in Organisator.objects.all(): + organizers.append(organizer.mail) - def form_valid(self, form): - cafe = self.kwargs['cafe'] - cafe = get_object_or_404(Cafe, pk=cafe) + text = render_to_string('repapp/mail/notice_new_device.html', { + 'guest': device.guest, + 'device': device, + 'cafe': device.cafe, + }) - mail = form.cleaned_data['mail'] - device = form.cleaned_data['device'] - identifier = sha256( - f'{device}{mail}{datetime.datetime.now()}'.encode('utf-8') - ).hexdigest() - secret = sha256( - f'{device}{mail}{datetime.datetime.now()}{random.randint(0, 999999)}'.encode( - 'utf-8') - ).hexdigest() - device = Device( - identifier=identifier, - secret=secret, - device=device, - error=form.cleaned_data['error'], - follow_up=form.cleaned_data['follow_up'], - cafe=cafe, - ) - device.save() - - guest = Guest.objects.filter(mail=mail).first() - - if guest: - device.guest = guest - device.save() - return HttpResponseRedirect( - reverse_lazy('register_device_final', kwargs={ - 'cafe': cafe.pk, - 'deviceentifier': device.identifier, - 'guestentifier': guest.identifier}) - ) - else: - return HttpResponseRedirect( - reverse_lazy('register_guest', kwargs={ - 'cafe': cafe.pk, - 'deviceentifier': device.identifier, - 'mail': mail}) - ) - - def get_context_data(self, **kwargs): - cafe = self.kwargs['cafe'] - cafe = get_object_or_404(Cafe, pk=cafe) - - context = super(RegisterDeviceFormView, self).get_context_data( - **kwargs - ) - context["cafe"] = cafe - return context - - -class RegisterGuestFormView(generic.edit.FormView): - template_name = "repapp/register_guest.html" - form_class = RegisterGuest - - def form_valid(self, form): - cafe = self.kwargs['cafe'] - cafe = get_object_or_404(Cafe, pk=cafe) - - deviceentifier = self.kwargs['deviceentifier'] - device = get_object_or_404(Device, identifier=deviceentifier) - - name = form.cleaned_data['name'] - residence = form.cleaned_data['residence'] - identifier = sha256( - f'{name}{residence}{datetime.datetime.now()}'.encode('utf-8') - ).hexdigest() - guest = Guest( - identifier=identifier, - name=name, - phone=form.cleaned_data['phone'], - residence=residence, - mail=self.kwargs['mail'], - ) - guest.save() - - device.guest = guest - device.save() - - return HttpResponseRedirect( - reverse_lazy('register_device_final', kwargs={ - 'cafe': cafe.pk, - 'deviceentifier': device.identifier, - 'guestentifier': guest.identifier}) - ) - - def get_context_data(self, **kwargs): - cafe = self.kwargs['cafe'] - cafe = get_object_or_404(Cafe, pk=cafe) - - deviceentifier = self.kwargs['deviceentifier'] - device = get_object_or_404(Device, identifier=deviceentifier) - - context = super(RegisterGuestFormView, self).get_context_data( - **kwargs - ) - context["cafe"] = cafe - context["device"] = device - context["mail"] = self.kwargs['mail'] - - return context - - -def register_device_final(request, cafe, deviceentifier, guestentifier): - cafe = get_object_or_404(Cafe, pk=cafe) - device = get_object_or_404(Device, identifier=deviceentifier) - guest = get_object_or_404(Guest, identifier=guestentifier) + send_mail( + subject=f"Neues Gerät { device.device }", + message=text, + from_email=os.getenv("DJANGO_SENDER_ADDRESS", ""), + recipient_list=organizers, + fail_silently=True + ) subject = render_to_string('repapp/mail/mail_register_device_subject.html', { 'guest': guest, @@ -168,58 +72,144 @@ def register_device_final(request, cafe, deviceentifier, guestentifier): ) if ok > 0: - messages.add_message(request, messages.INFO, - 'Die Bestätigungs-eMail wurde erfolgreich gesendet.') + device.confirmed = True + device.save() else: messages.add_message(request, messages.ERROR, 'Fehler beim senden der Bestätigungs-eMail!') + +class RegisterDeviceFormView(generic.edit.FormView): + template_name = "repapp/register_device.html" + form_class = RegisterDevice + + def form_valid(self, form): + cafe = self.kwargs['cafe'] + cafe = get_object_or_404(Cafe, pk=cafe) + mail = form.cleaned_data['mail'] + device = form.cleaned_data['device'] + identifier = sha256( + f'{device}{mail}{datetime.datetime.now()}'.encode('utf-8') + ).hexdigest() + device = Device( + identifier=identifier, + device=device, + manufacturer=form.cleaned_data['manufacturer'], + error=form.cleaned_data['error'], + follow_up=form.cleaned_data['follow_up'], + device_picture=self.request.FILES.get("device_picture", None), + type_plate_picture=self.request.FILES.get( + "type_plate_picture", None), + cafe=cafe, + confirmed=False, + ) + device.save() + + guest = Guest.objects.filter(mail=mail).first() + + print(f'Register: Dev: {device}, Guest: {guest}') + + if guest: + print('Guest already known') + device.guest = guest + device.save() + + send_confirmation_mails(device, guest, cafe, self.request) + + print('Mails sent') + + resp = HttpResponseRedirect( + reverse_lazy('register_device_final', kwargs={ + 'cafe': cafe.pk, + 'device_identifier': device.identifier}) + ) + print(resp) + return resp + else: + return HttpResponseRedirect( + reverse_lazy('register_guest', kwargs={ + 'cafe': cafe.pk, + 'device_identifier': device.identifier, + 'mail': mail}) + ) + + def get_context_data(self, **kwargs): + cafe = self.kwargs['cafe'] + cafe = get_object_or_404(Cafe, pk=cafe) + + context = super(RegisterDeviceFormView, self).get_context_data( + **kwargs + ) + context["cafe"] = cafe + return context + + +class RegisterGuestFormView(generic.edit.FormView): + template_name = "repapp/register_guest.html" + form_class = RegisterGuest + + def form_valid(self, form): + cafe = self.kwargs['cafe'] + cafe = get_object_or_404(Cafe, pk=cafe) + + device_identifier = self.kwargs['device_identifier'] + device = get_object_or_404(Device, identifier=device_identifier) + + name = form.cleaned_data['name'] + residence = form.cleaned_data['residence'] + identifier = sha256( + f'{name}{residence}{datetime.datetime.now()}'.encode('utf-8') + ).hexdigest() + guest = Guest( + identifier=identifier, + name=name, + phone=form.cleaned_data['phone'], + residence=residence, + mail=self.kwargs['mail'], + ) + guest.save() + + device.guest = guest + device.save() + + send_confirmation_mails(device, guest, cafe, self.request) + + return HttpResponseRedirect( + reverse_lazy('register_device_final', kwargs={ + 'cafe': cafe.pk, + 'device_identifier': device.identifier}) + ) + + def get_context_data(self, **kwargs): + cafe = self.kwargs['cafe'] + cafe = get_object_or_404(Cafe, pk=cafe) + + device_identifier = self.kwargs['device_identifier'] + device = get_object_or_404(Device, identifier=device_identifier) + + context = super(RegisterGuestFormView, self).get_context_data( + **kwargs + ) + context["cafe"] = cafe + context["device"] = device + context["mail"] = self.kwargs['mail'] + + return context + + +def register_device_final(request, cafe, device_identifier): + cafe = get_object_or_404(Cafe, pk=cafe) + device = get_object_or_404(Device, identifier=device_identifier) + return render( request, "repapp/register_device_final.html", - {}, + {"device": device, 'cafe': cafe}, ) -def register_device_confirm(request, deviceentifier, device_secret): - device = get_object_or_404(Device, identifier=deviceentifier) - if not device.guest: - raise Http404('Unknown guest!') - - device.confirmed = True - device.save() - - if not device.guest.confirmed: - device.guest.confirmed = True - device.guest.save() - - text = render_to_string('repapp/mail/notice_new_device.html', { - 'guest': device.guest, - 'device': device, - 'cafe': device.cafe, - }) - - organizers = [] - for organizer in Organisator.objects.all(): - organizers.append(organizer.mail) - - send_mail( - subject=f"Neues Gerät { device.device }", - message=text, - from_email=os.getenv("DJANGO_SENDER_ADDRESS", ""), - recipient_list=organizers, - fail_silently=True - ) - - return render( - request, - "repapp/register_device_confirm.html", - {"device": device, "guest": device.guest, "cafe": device.cafe}, - ) - - -def device_view(request, deviceentifier): - device = get_object_or_404(Device, identifier=deviceentifier) +def device_view(request, device_identifier): + device = get_object_or_404(Device, identifier=device_identifier) return render( request,