shiftregister/shiftregister/app/models.py

136 lines
4.4 KiB
Python
Raw Normal View History

2022-04-12 00:18:51 +02:00
from django.db import models
2022-04-12 16:09:17 +02:00
import secrets
from django.shortcuts import reverse
from datetime import timedelta
from django.utils import timezone
2022-04-20 18:39:33 +02:00
from django.db.models import F, Count, Q, ExpressionWrapper
2022-04-27 15:07:43 +02:00
from phonenumber_field.modelfields import PhoneNumberField
2022-04-27 17:45:34 +02:00
from dynamic_preferences.registries import global_preferences_registry
global_preferences = global_preferences_registry.manager()
2022-04-15 16:20:13 +02:00
2022-04-12 14:41:01 +02:00
class Room(models.Model):
name = models.CharField(max_length=200, primary_key=True)
required_helpers = models.IntegerField()
2022-04-15 16:20:13 +02:00
2022-04-12 14:41:01 +02:00
def __str__(self):
return self.name
2022-04-15 16:20:13 +02:00
2022-04-12 14:41:01 +02:00
class Shift(models.Model):
room = models.ForeignKey(Room, on_delete=models.RESTRICT)
start_at = models.DateTimeField()
duration = models.DurationField()
required_helpers = models.IntegerField(
default=0, help_text="When this is set to zero, the room value is used instead."
)
2022-04-23 14:36:47 +02:00
deleted = models.BooleanField(default=False)
2022-04-12 14:41:01 +02:00
def __str__(self):
return f"{self.room.name}: {self.start_at}"
2022-04-20 18:57:04 +02:00
def has_ended(self):
return (self.start_at + self.duration) < timezone.now()
2022-04-20 18:57:04 +02:00
2022-04-20 18:39:33 +02:00
def is_running(self):
2022-04-20 18:57:04 +02:00
return (self.start_at <= timezone.now()) and (not self.has_ended())
2022-04-12 14:41:01 +02:00
2022-04-15 16:20:13 +02:00
2022-04-12 14:41:01 +02:00
class Helper(models.Model):
phone = PhoneNumberField(unique=True, editable=False)
2022-04-12 14:41:01 +02:00
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)
2022-04-15 16:20:13 +02:00
2022-04-12 14:41:01 +02:00
def __str__(self):
return self.name
2022-04-15 16:20:13 +02:00
2022-04-12 17:04:47 +02:00
def send_confirmation(self):
(token, created) = LoginToken.objects.get_or_create(helper=self)
token.send()
2022-04-12 17:04:47 +02:00
return token
2022-04-20 18:57:04 +02:00
2022-04-20 18:39:33 +02:00
# current or next shift
def important_shift(self):
2022-04-20 18:57:04 +02:00
ret = (
ShiftRegistration.objects.annotate(
2022-04-20 18:39:33 +02:00
shift_end=ExpressionWrapper(
F("shift__start_at") + F("shift__duration"),
output_field=models.DateTimeField(),
2022-04-20 18:57:04 +02:00
)
)
2022-04-27 20:24:00 +02:00
.filter(helper=self, shift_end__gte=timezone.now(), shift__deleted=False)
2022-04-20 18:57:04 +02:00
.order_by("shift__start_at")
.first()
)
2022-04-20 18:39:33 +02:00
if ret:
return ret.shift
2022-04-12 14:41:01 +02:00
class ShiftRegistration(models.Model):
class Meta:
2022-04-15 16:20:13 +02:00
unique_together = (("shift", "helper"),)
2022-04-12 14:41:01 +02:00
# 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)
2022-04-15 16:20:13 +02:00
def can_cancel(self):
2022-04-27 17:45:34 +02:00
return self.shift.start_at > (
timezone.now()
+ global_preferences_registry.manager()["helper__min_cancel_time"]
2022-04-27 17:45:34 +02:00
)
2022-04-15 16:20:13 +02:00
def send_reminder(self):
text = f"Deine kontakt-Schicht beginnt um {self.shift.start_at.strftime('%H:%M')}, bitte komm eine halbe Stunde vorher an den Infopoint."
msg = Message(to=self.helper, text=text)
msg.save()
self.reminder_sent = True
self.save()
def __str__(self):
return f"{self.helper.name}: {self.shift}"
2022-04-12 14:41:01 +02:00
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)
sent_at = models.DateTimeField(null=True)
2022-04-15 16:20:13 +02:00
2022-04-12 14:41:01 +02:00
def __str__(self):
return f"{self.to.name}({self.created_at}): {self.text}"
2022-04-12 14:41:01 +02:00
2022-04-15 16:20:13 +02:00
2022-04-12 14:41:01 +02:00
def gen_token():
2022-04-25 23:35:13 +02:00
return secrets.token_urlsafe(
15
) # returns 15 bytes Base64-encoded (times 1.333...) = 20 characters
2022-04-12 14:41:01 +02:00
2022-04-15 16:20:13 +02:00
2022-04-12 14:41:01 +02:00
class LoginToken(models.Model):
2022-04-15 16:20:13 +02:00
id = models.CharField(
max_length=20, primary_key=True, default=gen_token, editable=False
)
2022-04-12 16:09:17 +02:00
helper = models.ForeignKey(Helper, on_delete=models.CASCADE)
sent_at = models.DateTimeField(auto_now_add=True)
send_count = models.IntegerField(default=0)
def send(self):
text = f"Dein Registrierungslink zum Helfer*innensystem: https://kontakt.rocks{self.get_absolute_url()}\nWenn du dich nicht registriert hast, ignoriere diese SMS."
msg = Message(to=self.helper, text=text)
msg.save()
self.sent_at = timezone.now()
self.send_count += 1
self.save()
# import here to break import cycle
from .tasks import send_message
2022-04-27 22:34:26 +02:00
send_message.delay(msg.pk)
2022-04-15 16:20:13 +02:00
2022-04-12 16:09:17 +02:00
def get_absolute_url(self):
2022-04-15 16:20:13 +02:00
return reverse("token_login", kwargs={"token": self.id})