2023-04-17 07:41:34 +00:00
|
|
|
"""
|
|
|
|
|
This module implements the models of RepApp.
|
|
|
|
|
"""
|
2023-04-24 06:27:18 +00:00
|
|
|
import django.utils.timezone
|
2023-04-16 11:01:31 +00:00
|
|
|
from django.db import models
|
2023-04-16 18:48:19 +00:00
|
|
|
from django.utils.translation import gettext_lazy as _
|
2023-04-24 16:02:43 +00:00
|
|
|
from django.contrib.auth.models import AbstractUser
|
2023-04-25 12:17:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def device_directory_path(instance, filename):
|
|
|
|
|
"""
|
|
|
|
|
device_directory_path generates a device-specific storage path for file uploads.
|
|
|
|
|
"""
|
|
|
|
|
return f'device_{instance.identifier}/{filename}'
|
2023-04-16 11:01:31 +00:00
|
|
|
|
2023-04-16 17:55:54 +00:00
|
|
|
|
2023-04-25 07:14:26 +00:00
|
|
|
class CustomUser(AbstractUser):
|
|
|
|
|
"""
|
|
|
|
|
Custom user object with unique email.
|
|
|
|
|
"""
|
|
|
|
|
email = models.EmailField(unique=True, verbose_name=_("eMail Adresse"))
|
2023-06-18 07:01:14 +00:00
|
|
|
notifications = models.BooleanField(
|
|
|
|
|
verbose_name=_("Benachrichtigungen"), default=True)
|
2023-04-25 07:14:26 +00:00
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _('Benutzer')
|
|
|
|
|
verbose_name_plural = _('Benutzer')
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f'{self.email}'
|
|
|
|
|
|
|
|
|
|
|
2023-04-16 17:55:54 +00:00
|
|
|
class Cafe(models.Model):
|
2023-04-17 07:41:34 +00:00
|
|
|
"""
|
|
|
|
|
A Cafe is a "Repair-Café event.
|
|
|
|
|
"""
|
2023-04-16 18:48:19 +00:00
|
|
|
location = models.CharField(
|
|
|
|
|
max_length=200, verbose_name=_("Ort"))
|
2023-04-21 16:24:31 +00:00
|
|
|
address = models.CharField(
|
|
|
|
|
max_length=200, verbose_name=_("Adresse"))
|
2023-04-16 18:48:19 +00:00
|
|
|
event_date = models.DateField(verbose_name=_("Datum"))
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _('Repair-Café')
|
|
|
|
|
verbose_name_plural = _('Repair-Cafés')
|
2023-04-16 17:55:54 +00:00
|
|
|
|
2023-04-16 18:13:37 +00:00
|
|
|
def __str__(self):
|
2023-04-16 18:48:19 +00:00
|
|
|
return f'Repair-Café am {self.event_date} (Ort: {self.location})'
|
2023-04-16 18:13:37 +00:00
|
|
|
|
2023-04-16 17:55:54 +00:00
|
|
|
|
|
|
|
|
class Reparateur(models.Model):
|
2023-04-17 07:41:34 +00:00
|
|
|
"""
|
|
|
|
|
A Reparateur is a member of the Repair-Café who supports guests with fixing their devices.
|
|
|
|
|
"""
|
2023-04-16 18:48:19 +00:00
|
|
|
name = models.CharField(max_length=200, verbose_name=_("Name"))
|
|
|
|
|
mail = models.CharField(max_length=200, verbose_name=_("eMail"))
|
2023-06-18 07:44:53 +00:00
|
|
|
cafe = models.ManyToManyField(Cafe)
|
2023-04-16 18:48:19 +00:00
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _('Reparateur')
|
|
|
|
|
verbose_name_plural = _('Reparateure')
|
2023-04-16 17:55:54 +00:00
|
|
|
|
2023-04-16 18:13:37 +00:00
|
|
|
def __str__(self):
|
2023-04-17 07:41:34 +00:00
|
|
|
return f'Reparateur {self.name} (eMail: {self.mail})'
|
2023-04-16 18:13:37 +00:00
|
|
|
|
2023-04-16 17:55:54 +00:00
|
|
|
|
|
|
|
|
class Organisator(models.Model):
|
2023-04-17 07:41:34 +00:00
|
|
|
"""
|
|
|
|
|
A Organisator is a member of the Repair-Café who arranges repair appointments with guests.
|
|
|
|
|
"""
|
2023-04-16 18:48:19 +00:00
|
|
|
name = models.CharField(max_length=200, verbose_name=_("Name"))
|
|
|
|
|
mail = models.CharField(max_length=200, verbose_name=_("eMail"))
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _('Organisator')
|
|
|
|
|
verbose_name_plural = _('Organisatoren')
|
2023-04-16 17:55:54 +00:00
|
|
|
|
2023-04-16 18:13:37 +00:00
|
|
|
def __str__(self):
|
|
|
|
|
return f'Organisator {self.name} (eMail: {self.mail})'
|
|
|
|
|
|
2023-04-16 17:55:54 +00:00
|
|
|
|
2023-04-17 07:41:34 +00:00
|
|
|
class Guest(models.Model):
|
|
|
|
|
"""
|
|
|
|
|
A guest is a owner of a broken device who wants support in context of a Repair-Café.
|
|
|
|
|
"""
|
2023-04-16 18:48:19 +00:00
|
|
|
identifier = models.CharField(max_length=200, verbose_name=_("ID"))
|
2023-04-17 07:41:34 +00:00
|
|
|
name = models.CharField(max_length=200, verbose_name=_("Name"))
|
2023-04-16 19:17:11 +00:00
|
|
|
phone = models.CharField(max_length=200, verbose_name=_("Telefonnummer"))
|
|
|
|
|
residence = models.CharField(max_length=200, verbose_name=_("Wohnort"))
|
2023-04-16 18:48:19 +00:00
|
|
|
mail = models.CharField(max_length=200, verbose_name=_("eMail"))
|
2023-04-25 07:14:26 +00:00
|
|
|
user = models.ForeignKey(
|
|
|
|
|
CustomUser, on_delete=models.CASCADE, null=True, verbose_name=_("Benutzer"))
|
2023-04-17 07:41:34 +00:00
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _('Gast')
|
|
|
|
|
verbose_name_plural = _('Gäste')
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f'Gast {self.name} (eMail: {self.mail})'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Device(models.Model):
|
|
|
|
|
"""
|
|
|
|
|
A Device is a broken device owned by a guest which shall be repaired during a Repair-Café.
|
|
|
|
|
"""
|
2023-06-18 07:44:53 +00:00
|
|
|
STATUS_REJECTED = -1
|
|
|
|
|
STATUS_NEW = 0
|
|
|
|
|
STATUS_ORGA_QUESTION = 1
|
|
|
|
|
STATUS_ORGA_QUESTION_ANSWERED = 2
|
|
|
|
|
STATUS_WAITING_LIST = 3
|
|
|
|
|
STATUS = (
|
|
|
|
|
(STATUS_REJECTED, 'abgelehnt'),
|
|
|
|
|
(STATUS_NEW, 'neu'),
|
|
|
|
|
(STATUS_ORGA_QUESTION, 'in Orga Rückfrage'),
|
|
|
|
|
(STATUS_ORGA_QUESTION_ANSWERED, 'in Orga Rückfrage beantwortet'),
|
|
|
|
|
(STATUS_WAITING_LIST, 'in der Warteliste'),
|
|
|
|
|
)
|
|
|
|
|
|
2023-04-17 07:41:34 +00:00
|
|
|
identifier = models.CharField(max_length=200, verbose_name=_("ID"))
|
2023-04-25 11:56:12 +00:00
|
|
|
date = models.DateField(verbose_name=_(
|
|
|
|
|
"Erstellungsdatum"), default=django.utils.timezone.now)
|
2023-04-21 16:24:31 +00:00
|
|
|
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"))
|
2023-04-16 18:48:19 +00:00
|
|
|
follow_up = models.BooleanField(verbose_name=_("Folgetermin"))
|
2023-04-21 16:24:31 +00:00
|
|
|
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"))
|
2023-04-25 11:56:12 +00:00
|
|
|
confirmed = models.BooleanField(verbose_name=_("Bestätigung gesendet?"))
|
2023-05-29 14:58:36 +00:00
|
|
|
status = models.IntegerField(verbose_name=_("Status"), default=0)
|
2023-04-20 18:52:24 +00:00
|
|
|
guest = models.ForeignKey(
|
2023-06-18 07:44:53 +00:00
|
|
|
Guest, on_delete=models.CASCADE, null=True, verbose_name=_("Gast"), choices=STATUS)
|
2023-04-20 18:52:24 +00:00
|
|
|
cafe = models.ForeignKey(
|
|
|
|
|
Cafe, on_delete=models.CASCADE, null=False, verbose_name=_("Repair-Café"))
|
2023-04-16 18:48:19 +00:00
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _('Gerät')
|
|
|
|
|
verbose_name_plural = _('Geräte')
|
2023-04-16 17:55:54 +00:00
|
|
|
|
2023-04-16 18:13:37 +00:00
|
|
|
def __str__(self):
|
2023-05-29 14:58:36 +00:00
|
|
|
return f'Gerät {self.device} - {self.manufacturer}'
|
2023-04-16 18:13:37 +00:00
|
|
|
|
2023-04-16 17:55:54 +00:00
|
|
|
|
2023-04-16 18:48:19 +00:00
|
|
|
class Appointment(models.Model):
|
2023-04-17 07:41:34 +00:00
|
|
|
"""
|
|
|
|
|
A Appointment is a match of a broken Device and a Reparateur during a Repair-Café
|
|
|
|
|
with a defined time slot.
|
|
|
|
|
"""
|
2023-04-16 18:48:19 +00:00
|
|
|
time = models.TimeField(verbose_name=_("Zeit"))
|
|
|
|
|
confirmed = models.BooleanField(verbose_name=_("bestätigt"))
|
2023-04-20 18:52:24 +00:00
|
|
|
cafe = models.ForeignKey(
|
2023-04-16 18:48:19 +00:00
|
|
|
Cafe, on_delete=models.CASCADE, verbose_name=_("Repair-Café"))
|
2023-04-20 18:52:24 +00:00
|
|
|
reparateur = models.ForeignKey(
|
2023-04-16 18:48:19 +00:00
|
|
|
Reparateur, on_delete=models.CASCADE, verbose_name=_("Reparateur"))
|
2023-04-20 18:52:24 +00:00
|
|
|
device = models.ForeignKey(
|
2023-04-16 18:48:19 +00:00
|
|
|
Device, on_delete=models.CASCADE, null=True, verbose_name=_("Gerät"))
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _('Termin')
|
|
|
|
|
verbose_name_plural = _('Termine')
|
2023-04-16 18:13:37 +00:00
|
|
|
|
|
|
|
|
def __str__(self):
|
2023-04-20 18:52:24 +00:00
|
|
|
return f'Termin {self.cafe.event_date} {self.time} für Gerät {self.device.device}'
|
2023-04-16 17:55:54 +00:00
|
|
|
|
|
|
|
|
|
2023-04-16 18:48:19 +00:00
|
|
|
class Question(models.Model):
|
2023-04-17 07:41:34 +00:00
|
|
|
"""
|
|
|
|
|
A Question is a request for information form a Organisator or a Reparateur for a Device.
|
|
|
|
|
"""
|
2023-04-16 18:48:19 +00:00
|
|
|
question = models.TextField(verbose_name=_("Frage"))
|
2023-05-29 14:58:36 +00:00
|
|
|
answer = models.TextField(verbose_name=_("Antwort"), null=True)
|
2023-04-24 06:27:18 +00:00
|
|
|
date = models.DateField(verbose_name=_(
|
|
|
|
|
"Erstellungsdatum"), default=django.utils.timezone.now)
|
2023-04-20 18:52:24 +00:00
|
|
|
organisator = models.ForeignKey(
|
2023-04-16 18:48:19 +00:00
|
|
|
Organisator, on_delete=models.CASCADE, null=True, verbose_name=_("Organisator"))
|
2023-04-20 18:52:24 +00:00
|
|
|
reparateur = models.ForeignKey(
|
2023-04-16 18:48:19 +00:00
|
|
|
Reparateur, on_delete=models.CASCADE, null=True, verbose_name=_("Reparateur"))
|
2023-04-20 18:52:24 +00:00
|
|
|
device = models.ForeignKey(
|
2023-04-16 18:48:19 +00:00
|
|
|
Device, on_delete=models.CASCADE, verbose_name=_("Gerät"))
|
2023-05-29 14:58:36 +00:00
|
|
|
open = models.BooleanField(verbose_name=_("offen"), default=True)
|
|
|
|
|
sent = models.BooleanField(verbose_name=_("gesendet"), default=False)
|
|
|
|
|
answered = models.BooleanField(
|
|
|
|
|
verbose_name=_("beantwortet"), default=False)
|
2023-04-16 18:48:19 +00:00
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _('Frage')
|
|
|
|
|
verbose_name_plural = _('Fragen')
|
2023-04-16 18:13:37 +00:00
|
|
|
|
|
|
|
|
def __str__(self):
|
2023-04-20 18:52:24 +00:00
|
|
|
return f'Frage vom {self.date} zum Gerät {self.device.device}'
|
2023-04-21 16:24:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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}'
|
2023-04-24 16:02:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class OneTimeLogin(models.Model):
|
|
|
|
|
"""
|
|
|
|
|
A OneTimeLogin is a secret which can be used once to login a user.
|
|
|
|
|
"""
|
|
|
|
|
secret = models.CharField(max_length=200, verbose_name=_(
|
2023-04-25 11:56:12 +00:00
|
|
|
"Geheimnis"), unique=True, null=False)
|
2023-04-24 16:02:43 +00:00
|
|
|
url = models.CharField(max_length=200, verbose_name=_("URL"))
|
|
|
|
|
created = models.DateField(verbose_name=_(
|
|
|
|
|
"Erstellungsdatum"), default=django.utils.timezone.now)
|
|
|
|
|
login_used = models.BooleanField(
|
|
|
|
|
verbose_name=_("Login benutzt?"), default=False)
|
|
|
|
|
login_date = models.DateField(verbose_name=_(
|
|
|
|
|
"Login Datum"), null=True)
|
2023-04-25 11:56:12 +00:00
|
|
|
user = models.ForeignKey(
|
|
|
|
|
CustomUser, on_delete=models.CASCADE, null=False, verbose_name=_("Benutzer"))
|
2023-04-24 16:02:43 +00:00
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _('Einmal-Login')
|
|
|
|
|
verbose_name_plural = _('Einmal-Login')
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f'Einmal-Login {self.user.email}'
|
2023-04-24 17:25:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class Message(models.Model):
|
|
|
|
|
"""
|
|
|
|
|
A Message is a request from a guest.
|
|
|
|
|
"""
|
|
|
|
|
message = models.TextField(verbose_name=_("Nachricht"))
|
|
|
|
|
answer = models.TextField(verbose_name=_("Antwort"))
|
|
|
|
|
date = models.DateField(verbose_name=_(
|
|
|
|
|
"Erstellungsdatum"), default=django.utils.timezone.now)
|
|
|
|
|
guest = models.ForeignKey(
|
|
|
|
|
Guest, on_delete=models.CASCADE, null=True, verbose_name=_("Gast"))
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name = _('Nachricht')
|
|
|
|
|
verbose_name_plural = _('Nachrichten')
|
|
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
|
return f'Nachricht vom {self.date} von {self.guest.mail}'
|