shiftregister/shiftregister/app/models.py

123 lines
3.9 KiB
Python

from django.db import models
import secrets
from django.shortcuts import reverse
from datetime import timedelta
from django.utils import timezone
from django.db.models import F, Count, Q, ExpressionWrapper
class Room(models.Model):
name = models.CharField(max_length=200, primary_key=True)
required_helpers = models.IntegerField()
def __str__(self):
return self.name
class Shift(models.Model):
room = models.ForeignKey(Room, on_delete=models.RESTRICT)
start_at = models.DateTimeField()
duration = models.DurationField()
# todo: add helper amount override field
def __str__(self):
return f"{self.room.name}: {self.start_at}"
def has_ended(self):
return (self.start_at + self.duration) < timezone.now()
def is_running(self):
return (self.start_at <= timezone.now()) and (not self.has_ended())
class Helper(models.Model):
# todo: add propper phone number validation, maybe even country code?
phone = models.CharField(max_length=200, primary_key=True, editable=False)
name = models.CharField(max_length=200)
# change this to a generic state variable to allow for number blocking/account deactivation?
number_validated = models.BooleanField(default=False)
def __str__(self):
return self.name
def send_confirmation(self):
(token, created) = LoginToken.objects.get_or_create(helper=self)
token.send()
return token
# current or next shift
def important_shift(self):
ret = (
ShiftRegistration.objects.annotate(
shift_end=ExpressionWrapper(
F("shift__start_at") + F("shift__duration"),
output_field=models.DateTimeField(),
)
)
.filter(helper=self, shift_end__gte=timezone.now())
.order_by("shift__start_at")
.first()
)
if ret:
return ret.shift
class ShiftRegistration(models.Model):
class Meta:
unique_together = (("shift", "helper"),)
# use restrict for now as Model.delete is not called
shift = models.ForeignKey(Shift, on_delete=models.RESTRICT)
helper = models.ForeignKey(Helper, on_delete=models.CASCADE)
reminder_sent = models.BooleanField(default=False)
def can_cancel(self):
return self.shift.start_at > (timezone.now() + timedelta(hours=4))
def send_reminder(self):
text = f"Deine Kontakt-Schicht begint um {self.shift.start_at.strftime('%H:%M')}, bitte komme eine halbe Stunde vorher an den Infopoint."
msg = Message(to=self.helper, text=text)
msg.save()
self.reminder_sent = True
self.save()
def get_unnotified_registrations():
return ShiftRegistration.objects.filter(
reminder_sent=False,
shift__start_at__lte=timezone.now() + timedelta(minutes=60),
)
def __str__(self):
return f"{self.helper.name}: {self.shift}"
class Message(models.Model):
# remove limit and send long messages in multiple messages?
text = models.CharField(max_length=160)
to = models.ForeignKey(Helper, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.to.name}({self.created_at}): {self.text}"
def gen_token():
return secrets.token_urlsafe(20)
class LoginToken(models.Model):
id = models.CharField(
max_length=20, primary_key=True, default=gen_token, editable=False
)
helper = models.ForeignKey(Helper, on_delete=models.CASCADE)
sent_at = models.DateTimeField(auto_now_add=True)
def send(self):
text = f"Hallo {self.helper.name}, hier ist dein Registrierungslink zum Kontaktfestival http://short.url{self.get_absolute_url()}"
msg = Message(to=self.helper, text=text)
msg.save()
self.sent_at = timezone.now()
self.save()
def get_absolute_url(self):
return reverse("token_login", kwargs={"token": self.id})