design, rework flow, extend device
This commit is contained in:
parent
673be80284
commit
9c69dba56d
17 changed files with 712 additions and 303 deletions
|
|
@ -63,6 +63,7 @@ Attribute:
|
||||||
|
|
||||||
- Datum: Datum der Veranstaltung
|
- Datum: Datum der Veranstaltung
|
||||||
- Ort: Beschreibung wo das Repair-Café stattfindet
|
- Ort: Beschreibung wo das Repair-Café stattfindet
|
||||||
|
- Adresse: Adresse an der das Repair-Café stattfindet
|
||||||
|
|
||||||
Annahmen:
|
Annahmen:
|
||||||
|
|
||||||
|
|
@ -102,7 +103,6 @@ Attribute:
|
||||||
- Telefon: Festnetz oder Mobilnummer des Gastes
|
- Telefon: Festnetz oder Mobilnummer des Gastes
|
||||||
- Wohnort: Wohnort des Gastes
|
- Wohnort: Wohnort des Gastes
|
||||||
- Mail: eMail-Adresse des Gastes für Benachrichtigungen
|
- 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:
|
Technische Attribute:
|
||||||
|
|
||||||
|
|
@ -115,15 +115,18 @@ Ein Gerät ist ein defekter Gegenstand der im Rahmen eines Repair-Cafés reparie
|
||||||
Attribute:
|
Attribute:
|
||||||
|
|
||||||
- Gerät: Bezeichnung des Geräts
|
- Gerät: Bezeichnung des Geräts
|
||||||
|
- Hersteller: Hersteller des Geräts
|
||||||
- Fehler: Beschreibung des Defekts
|
- Fehler: Beschreibung des Defekts
|
||||||
- Folgetermin: Boolesches Flag das anzeigt ob es sich um einen Folgetermin handelt.
|
- 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:
|
Technische Attribute:
|
||||||
|
|
||||||
- Identifier: SHA256 Hash aus Gerät + Gast + Timestamp
|
- 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
|
- Gast: Referenz zum Gast der das Gerät besitzt
|
||||||
|
- Cafe: Referenz zum Repair-Café für das diese Gerät angemeldet ist
|
||||||
|
|
||||||
### Termin
|
### Termin
|
||||||
|
|
||||||
|
|
@ -192,17 +195,19 @@ URL: cafe/int:cafe/
|
||||||
Name: register_device
|
Name: register_device
|
||||||
|
|
||||||
Diese Seite zeigt das Formular zum anmelden der Geräte.
|
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.
|
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
|
#### Sicherheit
|
||||||
|
|
||||||
Die Seite ist ohne Zugangsbeschränkung oder Anmeldung erreichbar.
|
Die Seite ist ohne Zugangsbeschränkung oder Anmeldung erreichbar.
|
||||||
|
|
||||||
### Gast anmelden (S3)
|
### 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
|
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.
|
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 eMail-Benachrichtigung and die Organisatoren und die Bestätigung an den Gast wird beim absenden des Formulars gesendet.
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
#### Sicherheit
|
#### Sicherheit
|
||||||
|
|
||||||
Die Seite ist ohne Zugangsbeschränkung oder Anmeldung erreichbar.
|
Die Seite ist ohne Zugangsbeschränkung oder Anmeldung erreichbar.
|
||||||
|
|
||||||
|
|
||||||
### Anmeldung bestätigt (S7)
|
### 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 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.
|
Die Geräte ID ist in der URL der Seite festgelegt.
|
||||||
|
|
||||||
#### Sicherheit
|
#### Sicherheit
|
||||||
|
|
@ -250,11 +238,11 @@ Die Seite ist ohne Zugangsbeschränkung oder Anmeldung erreichbar.
|
||||||
|
|
||||||
### Geräte Detailseite (S5)
|
### Geräte Detailseite (S5)
|
||||||
|
|
||||||
URL: device/str:deviceentifier/
|
URL: device/str:device_identifier/
|
||||||
|
|
||||||
Name: view_device
|
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.
|
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,
|
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.
|
- 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 (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.
|
- Die nächste Seite (S5) bestätigt mir die Anmeldung meines Gerätes.
|
||||||
- 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).
|
- In meinem eMail Posteingang finde ich ebenfalls eine Bestätigung der Geräteanmeldung.
|
||||||
|
|
||||||
#### Variante: Bekannter Gast (existierende eMail Adresse)
|
#### Variante: Bekannter Gast (existierende eMail Adresse)
|
||||||
|
|
||||||
Als bekannter Gast der ein defekten Geräte anmelden möchte,
|
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.
|
- 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 (S4) weißt mich darauf hin dass eine eMail gesendet wurde und ich die Anmeldung über einen Klick in der eMail bestätigen muss.
|
- Die nächste Seite (S5) bestätigt mir die Anmeldung meines Gerätes.
|
||||||
- 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).
|
- In meinem eMail Posteingang finde ich ebenfalls eine Bestätigung der Geräteanmeldung.
|
||||||
|
|
|
||||||
|
|
@ -10,4 +10,7 @@ server {
|
||||||
location /static {
|
location /static {
|
||||||
root /opt/app/rc_hip;
|
root /opt/app/rc_hip;
|
||||||
}
|
}
|
||||||
|
location /media {
|
||||||
|
root /opt/app/rc_hip;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ Including another URLconf
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", include("repapp.urls")),
|
path("", include("repapp.urls")),
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,12 @@ class RegisterDevice(forms.Form):
|
||||||
" zur Anfrage verwendet.",
|
" zur Anfrage verwendet.",
|
||||||
max_length=200)
|
max_length=200)
|
||||||
device = forms.CharField(
|
device = forms.CharField(
|
||||||
label="Gerätebezeichnung",
|
label="Art des Geräts",
|
||||||
help_text="Bitte geben Sie den Hersteller und die"
|
help_text="z.B. Küchenmaschine, Smartphone, Stehlampe, Drucker, ...",
|
||||||
" Gerätebezeichnung an.",
|
max_length=200
|
||||||
|
)
|
||||||
|
manufacturer = forms.CharField(
|
||||||
|
label="Hersteller & Modell/Typ",
|
||||||
max_length=200
|
max_length=200
|
||||||
)
|
)
|
||||||
error = forms.CharField(
|
error = forms.CharField(
|
||||||
|
|
@ -18,12 +21,33 @@ class RegisterDevice(forms.Form):
|
||||||
help_text="Beschreiben Sie hier das Problem ihres Gerätes.",
|
help_text="Beschreiben Sie hier das Problem ihres Gerätes.",
|
||||||
widget=forms.Textarea
|
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(
|
follow_up = forms.BooleanField(
|
||||||
label="Folgetermin",
|
label="Folgetermin",
|
||||||
help_text="Klicken Sie dieses Kästchen an wenn sie mit diesem"
|
help_text="Kreuzen Sie diese Kästchen an wenn sie mit diesem Gerät bereits bei einem Repair-Café Termin waren.",
|
||||||
" Gerät bereits bei einem Repair-Café waren.",
|
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
confirm_repair = forms.BooleanField(
|
||||||
|
label="Informationen zur Reparaturabwicklung",
|
||||||
|
help_text="Ich bin mit den <a href="
|
||||||
|
"\"https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/images/"
|
||||||
|
"repaircafe-hilpoltstein.de/docs/Infos_Reparatur-Abwicklung_v2_2023-02.pdf\">"
|
||||||
|
"Allgemeinen Bedingungen zur Reparaturabwicklung</a> 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 "
|
||||||
|
"<a href=\"https://www.repaircafe-hilpoltstein.de/impressum#c1375\">"
|
||||||
|
"Datenschutzerklärung</a> einverstanden.",
|
||||||
|
required=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RegisterGuest(forms.Form):
|
class RegisterGuest(forms.Form):
|
||||||
|
|
|
||||||
|
|
@ -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?'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -11,6 +11,8 @@ class Cafe(models.Model):
|
||||||
"""
|
"""
|
||||||
location = models.CharField(
|
location = models.CharField(
|
||||||
max_length=200, verbose_name=_("Ort"))
|
max_length=200, verbose_name=_("Ort"))
|
||||||
|
address = models.CharField(
|
||||||
|
max_length=200, verbose_name=_("Adresse"))
|
||||||
event_date = models.DateField(verbose_name=_("Datum"))
|
event_date = models.DateField(verbose_name=_("Datum"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
@ -60,7 +62,6 @@ class Guest(models.Model):
|
||||||
phone = models.CharField(max_length=200, verbose_name=_("Telefonnummer"))
|
phone = models.CharField(max_length=200, verbose_name=_("Telefonnummer"))
|
||||||
residence = models.CharField(max_length=200, verbose_name=_("Wohnort"))
|
residence = models.CharField(max_length=200, verbose_name=_("Wohnort"))
|
||||||
mail = models.CharField(max_length=200, verbose_name=_("eMail"))
|
mail = models.CharField(max_length=200, verbose_name=_("eMail"))
|
||||||
confirmed = models.BooleanField(verbose_name=_("Bestätigt"), default=False)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Gast')
|
verbose_name = _('Gast')
|
||||||
|
|
@ -70,21 +71,29 @@ class Guest(models.Model):
|
||||||
return f'Gast {self.name} (eMail: {self.mail})'
|
return f'Gast {self.name} (eMail: {self.mail})'
|
||||||
|
|
||||||
|
|
||||||
|
def device_directory_path(instance, filename):
|
||||||
|
return f'device_{instance.identifier}/{filename}'
|
||||||
|
|
||||||
|
|
||||||
class Device(models.Model):
|
class Device(models.Model):
|
||||||
"""
|
"""
|
||||||
A Device is a broken device owned by a guest which shall be repaired during a Repair-Café.
|
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"))
|
identifier = models.CharField(max_length=200, verbose_name=_("ID"))
|
||||||
secret = models.CharField(
|
device = models.CharField(max_length=200, verbose_name=_("Art des Geräts"))
|
||||||
max_length=200, verbose_name=_("Bestätigungscode"), default="TEST12345")
|
manufacturer = models.CharField(
|
||||||
device = models.CharField(max_length=200, verbose_name=_("Gerät"))
|
max_length=200, verbose_name=_("Hersteller & Modell/Typ"))
|
||||||
error = models.TextField(verbose_name=_("Fehler"))
|
error = models.TextField(verbose_name=_("Fehlerbeschreibung"))
|
||||||
follow_up = models.BooleanField(verbose_name=_("Folgetermin"))
|
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 = models.ForeignKey(
|
||||||
Guest, on_delete=models.CASCADE, null=True, verbose_name=_("Gast"))
|
Guest, on_delete=models.CASCADE, null=True, verbose_name=_("Gast"))
|
||||||
cafe = models.ForeignKey(
|
cafe = models.ForeignKey(
|
||||||
Cafe, on_delete=models.CASCADE, null=False, verbose_name=_("Repair-Café"))
|
Cafe, on_delete=models.CASCADE, null=False, verbose_name=_("Repair-Café"))
|
||||||
|
confirmed = models.BooleanField(verbose_name=_("Bestätigung gesendet?"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _('Gerät')
|
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}'
|
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):
|
class Question(models.Model):
|
||||||
"""
|
"""
|
||||||
A Question is a request for information form a Organisator or a Reparateur for a Device.
|
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):
|
def __str__(self):
|
||||||
return f'Frage vom {self.date} zum Gerät {self.device.device}'
|
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}'
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@
|
||||||
<html lang="de">
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
<meta name="description"
|
||||||
|
content="{% block description %} {% endblock description %}" />
|
||||||
|
<meta name="keywords"
|
||||||
|
content="{% block keywords %} {% endblock keywords %}" />
|
||||||
<meta name="viewport"
|
<meta name="viewport"
|
||||||
content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||||
<link rel="stylesheet"
|
<link rel="stylesheet"
|
||||||
|
|
@ -15,16 +19,15 @@
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% endblock title %}
|
{% endblock title %}
|
||||||
</title>
|
</title>
|
||||||
|
{% block head %}
|
||||||
|
{% endblock head %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-8">
|
<div class="col-8">
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
{% for message in messages %}
|
{% for message in messages %}<div class="alert alert-primary" role="alert">{{ message }}</div>{% endfor %}
|
||||||
<div class="alert {% if message.tags %}alert-{{ message.tags }}{% else %}alert-primary{% endif %}"
|
|
||||||
role="alert">{{ message }}</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,56 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 class="mt-2">Gerät: {{ device.device }}</h1>
|
<h1 class="mt-2">Gerät: {{ device.device }}</h1>
|
||||||
<hr class="mt-0 mb-4">
|
<hr class="mt-0 mb-4">
|
||||||
<p>Fehler:</p>
|
<table class="table">
|
||||||
<p>{{ device.error }}</p>
|
<tbody>
|
||||||
<p>
|
<tr>
|
||||||
Folgetermin:
|
<th scope="row">Art des Geräts</th>
|
||||||
{% if device.follow_up %}
|
<td>{{ device.device }}</td>
|
||||||
Ja
|
</tr>
|
||||||
{% else %}
|
<tr>
|
||||||
Nein
|
<th scope="row">Hersteller & Modell/Typ</th>
|
||||||
{% endif %}
|
<td>{{ device.manufacturer }}</td>
|
||||||
</p>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Fehlerbeschreibung</th>
|
||||||
|
<td>{{ device.error }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Folgetermin</th>
|
||||||
|
<td>
|
||||||
|
{% if device.follow_up %}
|
||||||
|
Ja
|
||||||
|
{% else %}
|
||||||
|
Nein
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Foto vom Gerät</th>
|
||||||
|
<td>
|
||||||
|
{% if device.device_picture %}
|
||||||
|
<img alt="Foto vom Gerät"
|
||||||
|
height="100%"
|
||||||
|
width="50%"
|
||||||
|
src="/media/{{ device.device_picture }}" />
|
||||||
|
{% else %}
|
||||||
|
kein Bild
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Foto vom Typenschild</th>
|
||||||
|
<td>
|
||||||
|
{% if device.device_picture %}
|
||||||
|
<img alt="Foto vom Typenschild"
|
||||||
|
height="100%"
|
||||||
|
width="50%"
|
||||||
|
src="/media/{{ device.type_plate_picture }}" />
|
||||||
|
{% else %}
|
||||||
|
kein Bild
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,324 @@
|
||||||
{% extends "repapp/base.html" %}
|
{% extends "repapp/base.html" %}
|
||||||
|
{% block title %}
|
||||||
{% block title %}- Repair-Cafés{% endblock title %}
|
- Repair-Cafés
|
||||||
|
{% endblock title %}
|
||||||
|
{% block head %}
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family:'Source Sans Pro';
|
||||||
|
font-style:normal;
|
||||||
|
font-weight:300;
|
||||||
|
src:url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-300.eot');
|
||||||
|
/* IE9 Compat Modes */
|
||||||
|
src:local('Source Sans Pro Light'), local('SourceSansPro-Light'),
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-300.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-300.woff2') format('woff2'), /* Super Modern Browsers */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-300.woff') format('woff'), /* Modern Browsers */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-300.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-300.svg#SourceSansPro') format('svg');/* Legacy iOS */;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family:'Source Sans Pro';
|
||||||
|
font-style:normal;
|
||||||
|
font-weight:400;
|
||||||
|
src:url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-regular.eot');
|
||||||
|
/* IE9 Compat Modes */
|
||||||
|
src:local('Source Sans Pro Regular'), local('SourceSansPro-Regular'),
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-regular.woff') format('woff'), /* Modern Browsers */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-regular.svg#SourceSansPro') format('svg');/* Legacy iOS */;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family:'Source Sans Pro';
|
||||||
|
font-style:normal;
|
||||||
|
font-weight:700;
|
||||||
|
src:url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-700.eot');
|
||||||
|
/* IE9 Compat Modes */
|
||||||
|
src:local('Source Sans Pro Bold'), local('SourceSansPro-Bold'),
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-700.woff2') format('woff2'), /* Super Modern Browsers */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-700.woff') format('woff'), /* Modern Browsers */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-700.ttf') format('truetype'), /* Safari, Android, iOS */
|
||||||
|
url('https://www.repaircafe-hilpoltstein.de/fileadmin/repaircafe-hilpoltstein/default/templates/fonts/source-sans-pro-v11-latin-700.svg#SourceSansPro') format('svg');/* Legacy iOS */;
|
||||||
|
}
|
||||||
|
@media all{
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame > :last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame {
|
||||||
|
position: relative;
|
||||||
|
padding-top: 2rem;
|
||||||
|
padding-bottom: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 576px){
|
||||||
|
.frame {
|
||||||
|
padding-top: 2.5rem;
|
||||||
|
padding-bottom: 2.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px){
|
||||||
|
.frame {
|
||||||
|
padding-top: 3rem;
|
||||||
|
padding-bottom: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 992px){
|
||||||
|
.frame {
|
||||||
|
padding-top: 3.5rem;
|
||||||
|
padding-bottom: 3.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1200px){
|
||||||
|
.frame {
|
||||||
|
padding-top: 3.5rem;
|
||||||
|
padding-bottom: 3.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all{
|
||||||
|
.frame-space-before-none {
|
||||||
|
margin-top: 0rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame-space-after-none {
|
||||||
|
margin-bottom: 0rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1200px){
|
||||||
|
.frame {
|
||||||
|
padding-top: 2.5rem;
|
||||||
|
padding-bottom: 2.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all{
|
||||||
|
.col-md-8 {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
padding-right: 20px;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px){
|
||||||
|
.col-md-8 {
|
||||||
|
flex: 0 0 66.6666666667%;
|
||||||
|
max-width: 66.6666666667%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 992px){
|
||||||
|
.col-md-8 {
|
||||||
|
padding-right: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all{
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-right: -20px;
|
||||||
|
margin-left: -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
padding-right: 20px;
|
||||||
|
padding-left: 20px;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 576px){
|
||||||
|
.container {
|
||||||
|
max-width: 540px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 768px){
|
||||||
|
.container {
|
||||||
|
max-width: 720px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 992px){
|
||||||
|
.container {
|
||||||
|
max-width: 960px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1200px){
|
||||||
|
.container {
|
||||||
|
max-width: 1140px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all{
|
||||||
|
.section {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1200px){
|
||||||
|
.section {
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all{
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: "Source Sans Pro", sans-serif;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #2b2b2b;
|
||||||
|
text-align: left;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
line-height: 1.15;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.news-list-view {
|
||||||
|
padding-right: 20px;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,:before,:after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:selection {
|
||||||
|
background-color: darkred;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article {
|
||||||
|
padding: 30px 0;
|
||||||
|
border-bottom: 2px solid #cccccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article:last-child {
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article.event {
|
||||||
|
padding: 0 0 30px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dtdate {
|
||||||
|
font-size: 21px;
|
||||||
|
color: #FFFFFF;
|
||||||
|
background: darkred;
|
||||||
|
padding: 0 5px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article.event .ort {
|
||||||
|
margin-top: 5px;
|
||||||
|
font-size: 19px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teaser-text {
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 30px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.article.event .teaser-text {
|
||||||
|
padding-top: 20px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: darkred;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: darkblue;
|
||||||
|
border-bottom: 1px solid;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #FFFFFF;
|
||||||
|
text-decoration: underline;
|
||||||
|
background: darkred;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
background: darkblue;
|
||||||
|
color: #ffffff!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
{% endblock head %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 class="mt-2">Repair-Cafés</h1>
|
<h1 class="mt-2">Repair-Cafés</h1>
|
||||||
<hr class="mt-0 mb-4">
|
<hr class="mt-0 mb-4">
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
{% for cafe in object_list %}
|
{% for cafe in object_list %}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
<a href="{% url 'register_device' cafe.id %}">
|
<div class="news-list-view eventhome snipcss-aSNzE" id="news-container-82">
|
||||||
<button type="button" class="btn btn-primary">Repair-Café am {{ cafe.event_date|date }}, {{ cafe.location }}</button>
|
<div class="rc-date">
|
||||||
</a>
|
<div class="article event rc-date "
|
||||||
</li>
|
itemscope="itemscope"
|
||||||
{% empty %}
|
itemtype="http://schema.org/Article">
|
||||||
<li class="list-group-item">Es gibt keine geplanten Repair-Cafés.</li>
|
<div class="dtdate">
|
||||||
{% endfor %}
|
<time itemprop="datePublished" datetime="13.05.2023">
|
||||||
</ul>
|
{{ cafe.event_date|date:"l" }}, {{ cafe.event_date|date }}, 14.00 - 17.00 Uhr
|
||||||
{% endblock content %}
|
</time>
|
||||||
|
</div>
|
||||||
|
<div class="ort">
|
||||||
|
{{ cafe.location }}
|
||||||
|
<br>
|
||||||
|
{{ cafe.address }}
|
||||||
|
</div>
|
||||||
|
<div class="teaser-text">
|
||||||
|
<div itemprop="description">
|
||||||
|
<p>
|
||||||
|
<strong>
|
||||||
|
Nur per Voranmeldung.
|
||||||
|
<a href="{% url 'register_device' cafe.id %}">Zum Anmeldeformular</a>
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% empty %}
|
||||||
|
<li class="list-group-item">Es gibt keine geplanten Repair-Cafés.</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,22 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="de">
|
<html lang="de">
|
||||||
<body>
|
<body>
|
||||||
<p>Hallo {{ guest.name }},</p>
|
<p>Guten Tag,</p>
|
||||||
<p>
|
<p>
|
||||||
Ihre Anmeldung von {{ device.device }} für das Repair-Café am {{ cafe.event_date|date }}
|
dies ist eine automatische Nachricht, die du erhältst, nachdem du unser Anmeldeformular abgesendet hast und deine Angaben in unserer Datenbank gespeichert wurden.
|
||||||
ist bei uns angekommen.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Bitte bestätigen sie ihre Anmeldung in dem Sie
|
Vielen Dank für die Anmeldung des Geräts {{ device.device }} - {{ device.manufacturer }} zur Reparatur im Repair-Café am {{ cafe.event_date|date }}.
|
||||||
<a href="https://repapp.rc-hip.de/confirm/{{ device.identifier }}/code/{{ device.secret }}">hier</a>
|
|
||||||
klicken.
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Viele Grüße,
|
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.
|
||||||
<br>
|
|
||||||
Ihr Repair-Café
|
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Falls du in der Zwischenzeit Rückfragen hast oder deinen Wunschtermin doch nicht wahrnehmen kannst, antworte bitte einfach auf diese Nachricht.
|
||||||
|
</p>
|
||||||
|
<p>Herzliche Grüße sendet dir das Organisationsteam vom Repair-Café Hilpoltstein!</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</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
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
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 https://repapp.rc-hip.de/confirm/{{ device.identifier }}/code/{{ device.secret }} in ihrem Web-Browser aufrufen.
|
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,
|
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.
|
||||||
Ihr Repair-Café
|
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!
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
{% extends "repapp/base.html" %}
|
{% extends "repapp/base.html" %}
|
||||||
|
|
||||||
{% load crispy_forms_tags %}
|
{% load crispy_forms_tags %}
|
||||||
|
{% block title %}
|
||||||
{% block title %}- Gerät anmelden{% endblock title %}
|
- Gerät anmelden
|
||||||
|
{% endblock title %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 class="mt-2">Gerät anmelden</h1>
|
<h1 class="mt-2">Gerät anmelden</h1>
|
||||||
<hr class="mt-0 mb-4">
|
<hr class="mt-0 mb-4">
|
||||||
<form action="{% url 'register_device' cafe.id %}" method="post">
|
<form action="{% url 'register_device' cafe.id %}"
|
||||||
{% csrf_token %}
|
method="post"
|
||||||
{{ form|crispy }}
|
enctype="multipart/form-data">
|
||||||
<button type="submit" class="btn btn-primary">Absenden</button>
|
{% csrf_token %}
|
||||||
</form>
|
{{ form|crispy }}
|
||||||
{% endblock content %}
|
<button type="submit" class="btn btn-primary">Absenden</button>
|
||||||
|
</form>
|
||||||
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
{% extends "repapp/base.html" %}
|
|
||||||
{% block title %}
|
|
||||||
{% endblock title %}
|
|
||||||
{% block content %}
|
|
||||||
<h1 class="mt-2">Anmeldung abgeschlossen</h1>
|
|
||||||
<hr class="mt-0 mb-4">
|
|
||||||
<p>Ihr Gerät ist erfolgreich angemeldet!</p>
|
|
||||||
<p>
|
|
||||||
Wir versuchen für sie einen Termin bei einem geeigneten Reparateur zu finden.
|
|
||||||
Wenn wir einen Termin gefunden haben werden Sie per eMail benachrichtigt.
|
|
||||||
</p>
|
|
||||||
{% endblock content %}
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
{% extends "repapp/base.html" %}
|
{% extends "repapp/base.html" %}
|
||||||
|
{% block title %}
|
||||||
{% block title %}{% endblock title %}
|
{% endblock title %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1 class="mt-2">Bestätigung ihrer Daten</h1>
|
<h1 class="mt-2">Anmeldung erfolgreich!</h1>
|
||||||
<hr class="mt-0 mb-4">
|
<hr class="mt-0 mb-4">
|
||||||
<p>
|
<p>
|
||||||
Wir haben ihnen eine eMail mit ihren Daten gesendet. Bitte bestätigen
|
Vielen Dank für die Anmeldung des Geräts {{ device.device }} - {{ device.manufacturer }} zur Reparatur im Repair-Café am {{ cafe.event_date|date }}.
|
||||||
Sie ihre Anmeldung durch Klick auf den Link in der eMail.
|
</p>
|
||||||
</p>
|
<p>
|
||||||
{% endblock content %}
|
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.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,12 @@ urlpatterns = [
|
||||||
name="register_device"
|
name="register_device"
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
"cafe/<int:cafe>/device/<str:deviceentifier>/<str:mail>/",
|
"cafe/<int:cafe>/device/<str:device_identifier>/mail/<str:mail>/",
|
||||||
views.RegisterGuestFormView.as_view(),
|
views.RegisterGuestFormView.as_view(),
|
||||||
name="register_guest"
|
name="register_guest"
|
||||||
),
|
),
|
||||||
path("cafe/<int:cafe>/device/<str:deviceentifier>/guest/<str:guestentifier>/",
|
path("cafe/<int:cafe>/device/<str:device_identifier>/confirm/",
|
||||||
views.register_device_final, name="register_device_final"),
|
views.register_device_final, name="register_device_final"),
|
||||||
path("confirm/<str:deviceentifier>/code/<str:device_secret>/",
|
path("device/<str:device_identifier>/",
|
||||||
views.register_device_confirm, name="register_device_confirm"),
|
|
||||||
path("device/<str:deviceentifier>/",
|
|
||||||
views.device_view, name="view_device"),
|
views.device_view, name="view_device"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,11 @@ Views of RepApp.
|
||||||
"""
|
"""
|
||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
import random
|
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.shortcuts import get_object_or_404, render
|
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.contrib import messages
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.template.loader import render_to_string
|
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())
|
return Cafe.objects.filter(event_date__gte=datetime.date.today())
|
||||||
|
|
||||||
|
|
||||||
class RegisterDeviceFormView(generic.edit.FormView):
|
def send_confirmation_mails(device, guest, cafe, request):
|
||||||
template_name = "repapp/register_device.html"
|
organizers = []
|
||||||
form_class = RegisterDevice
|
for organizer in Organisator.objects.all():
|
||||||
|
organizers.append(organizer.mail)
|
||||||
|
|
||||||
def form_valid(self, form):
|
text = render_to_string('repapp/mail/notice_new_device.html', {
|
||||||
cafe = self.kwargs['cafe']
|
'guest': device.guest,
|
||||||
cafe = get_object_or_404(Cafe, pk=cafe)
|
'device': device,
|
||||||
|
'cafe': device.cafe,
|
||||||
|
})
|
||||||
|
|
||||||
mail = form.cleaned_data['mail']
|
send_mail(
|
||||||
device = form.cleaned_data['device']
|
subject=f"Neues Gerät { device.device }",
|
||||||
identifier = sha256(
|
message=text,
|
||||||
f'{device}{mail}{datetime.datetime.now()}'.encode('utf-8')
|
from_email=os.getenv("DJANGO_SENDER_ADDRESS", ""),
|
||||||
).hexdigest()
|
recipient_list=organizers,
|
||||||
secret = sha256(
|
fail_silently=True
|
||||||
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)
|
|
||||||
|
|
||||||
subject = render_to_string('repapp/mail/mail_register_device_subject.html', {
|
subject = render_to_string('repapp/mail/mail_register_device_subject.html', {
|
||||||
'guest': guest,
|
'guest': guest,
|
||||||
|
|
@ -168,58 +72,144 @@ def register_device_final(request, cafe, deviceentifier, guestentifier):
|
||||||
)
|
)
|
||||||
|
|
||||||
if ok > 0:
|
if ok > 0:
|
||||||
messages.add_message(request, messages.INFO,
|
device.confirmed = True
|
||||||
'Die Bestätigungs-eMail wurde erfolgreich gesendet.')
|
device.save()
|
||||||
else:
|
else:
|
||||||
messages.add_message(request, messages.ERROR,
|
messages.add_message(request, messages.ERROR,
|
||||||
'Fehler beim senden der Bestätigungs-eMail!')
|
'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(
|
return render(
|
||||||
request,
|
request,
|
||||||
"repapp/register_device_final.html",
|
"repapp/register_device_final.html",
|
||||||
{},
|
{"device": device, 'cafe': cafe},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def register_device_confirm(request, deviceentifier, device_secret):
|
def device_view(request, device_identifier):
|
||||||
device = get_object_or_404(Device, identifier=deviceentifier)
|
device = get_object_or_404(Device, identifier=device_identifier)
|
||||||
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)
|
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
|
|
|
||||||
Reference in a new issue