shiftregister/shiftregister/app/views.py

271 lines
8.8 KiB
Python

from django.shortcuts import render, redirect, get_object_or_404
from .models import Shift, LoginToken, Helper, ShiftRegistration
from django.db import transaction
from django.db.models import F, Count, Q, ExpressionWrapper
from .forms import RegisterForm, EmptyForm, AstaForm
from django.db.models.fields import DateTimeField
from datetime import timedelta
from django.utils import timezone
from django.conf import settings
from django.contrib import messages
import datetime
from .decorators import event_state
from dynamic_preferences.registries import global_preferences_registry
import math
global_preferences = global_preferences_registry.manager()
@event_state
def index(request):
if request.session.get("last_seen_shift"):
del request.session["last_seen_shift"]
context = {
"days": Shift.objects.datetimes("start_at", "day"),
}
if request.helper:
context["my_future_shifts"] = list(
reg.shift
for reg in request.helper.shiftregistration_set.filter(
shift__start_at__gt=timezone.now(),
state__in=[
ShiftRegistration.RegState.REGISTERED,
ShiftRegistration.RegState.CHECKED_IN,
],
).order_by("shift__start_at")
)
imp_shift = request.helper.important_shift()
if imp_shift and imp_shift.is_running():
context["current_shift"] = imp_shift
help_wanted = Q(required_helpers__gt=F("reg_count")) | Q(required_helpers=0) & Q(
room__required_helpers__gt=F("reg_count")
)
# dont show shifts starting in <60 minutes?
# currently only sorts by date
free_shifts = (
Shift.with_reg_count()
.filter(
help_wanted,
start_at__gte=day + timedelta(hours=6),
start_at__lte=day + timedelta(hours=30),
start_at__gt=timezone.now(),
deleted=False,
)
.order_by("start_at")
for day in Shift.objects.datetimes("start_at", "day")
)
if request.helper:
free_shifts = (
day.filter(~Q(shiftregistration__helper=request.helper))
for day in free_shifts
)
context["free_shifts"] = list(
map(lambda qs: list(qs), filter(lambda qs: qs.exists(), free_shifts))
)
return render(request, "shiftlist.html", context)
def login(request, token):
tk = get_object_or_404(LoginToken, pk=token)
if not tk.helper.number_validated:
tk.helper.number_validated = True
tk.helper.save()
messages.add_message(
request,
messages.SUCCESS,
"Nummer bestätigt, du kannst dich jetzt für Schichten anmelden.",
)
request.session["token"] = token
# if the user was viewing a single shift before registering, they probably want to register for that
# shift so we redirect them there.
if request.session.get("last_seen_shift"):
return redirect("shift", shiftid=request.session["last_seen_shift"])
return redirect("index")
def logout(request):
if request.session.get("token"):
del request.session["token"]
return redirect("index")
def register(request):
if global_preferences["helper__event_state"] == "AFTER":
return render(request, "event_after.html", {})
if request.helper:
if request.session.get("last_seen_shift"):
return redirect("shift", shiftid=request.session["last_seen_shift"])
return redirect("index")
context = {}
if request.method == "POST":
form = RegisterForm(request.POST)
if not form.is_valid():
context["form"] = form
return render(request, "register.html", context)
helper = Helper.objects.filter(phone=form.cleaned_data["phone"]).first()
if helper:
token = helper.logintoken_set.first()
messages.add_message(
request,
messages.INFO,
f"Du hast einen Login-Link an deine Telefonnummer erhalten. Falls du die SMS nicht erhalten hast, probiere es in 15 Minuten noch ein mal.",
)
if settings.DEBUG:
messages.add_message(
request,
messages.INFO,
f"DEBUG:{token.get_absolute_url()}",
)
if token.sent_at < (
timezone.now()
- datetime.timedelta(minutes=math.pow(10, token.send_count))
):
token.send()
return render(request, "wait_confirmation.html", context)
helper = Helper(
name=form.cleaned_data["name"], phone=form.cleaned_data["phone"]
)
with transaction.atomic():
helper.save()
token = helper.send_confirmation()
request.session["token"] = token.pk
if settings.DEBUG:
messages.add_message(
request,
messages.INFO,
f"DEBUG: login token: {token.get_absolute_url()}",
)
return render(request, "wait_confirmation.html", {"helper": helper})
context["form"] = RegisterForm()
return render(request, "register.html", context)
@event_state
def shift(request, shiftid):
shift = get_object_or_404(Shift, pk=shiftid)
helper = request.helper
context = {
"can_register": False,
"is_registered": False,
"can_cancel": False,
"shift": shift,
"shift_form": EmptyForm,
}
# this currently ignores date/time
request.session["last_seen_shift"] = shiftid
if (
shift.required_helpers > shift.registration_count()
or shift.required_helpers == 0
and shift.room.required_helpers > shift.registration_count()
):
context["can_register"] = True
if helper:
context["helper"] = helper
reg = ShiftRegistration.objects.filter(shift=shift, helper=helper)
if reg:
context["is_registered"] = True
context["can_register"] = False
if reg[0].can_cancel():
context["can_cancel"] = True
if request.method == "POST":
if EmptyForm(request.POST).is_valid():
if not helper:
messages.add_message(
request,
messages.WARNING,
"Bitte registriere dich, bevor du dich zu Schichten anmeldest",
)
return redirect("register")
if not helper.number_validated:
messages.add_message(
request,
messages.WARNING,
"Bitte bestätige zuerst deine Telefonnummer",
)
return redirect("shift", shiftid=shift.pk)
if shift.deleted:
messages.add_message(
request,
messages.ERROR,
"Diese Schicht wurde gelöscht.",
)
return redirect("index")
if context["can_register"]:
s = ShiftRegistration(helper=helper, shift=shift)
s.save()
messages.add_message(
request,
messages.SUCCESS,
"Erfolgreich angemeldet, bitte komme eine halbe Stunde vor deiner Schicht an den Infopoint",
)
# redirect so page can be reloaded without resending post data
return redirect("shift", shiftid=shift.pk)
return render(request, "shift.html", context)
def cancel(request, shiftid):
if request.method != "POST":
return redirect("shift", shiftid=shiftid)
if not EmptyForm(request.POST).is_valid():
return redirect("shift", shiftid=shiftid)
if not request.session.get("token"):
return redirect("shift", shiftid=shiftid)
shift = get_object_or_404(Shift, pk=shiftid)
reg = get_object_or_404(ShiftRegistration, helper=request.helper, shift=shift)
if reg.can_cancel():
reg.delete()
messages.add_message(
request,
messages.SUCCESS,
"Erfolgreich abgemeldet",
)
else:
messages.add_message(
request,
messages.WARNING,
"Abmeldung nicht (mehr) möglich, bitte wende dich an den Infopoint",
)
return redirect("shift", shiftid=shiftid)
def asta(request):
if not request.helper:
return redirect("index")
form = AstaForm()
if request.method == "POST":
form = AstaForm(request.POST)
if AstaForm(request.POST).is_valid():
request.helper.asta_confirmed = True
request.helper.save()
messages.add_message(
request,
messages.SUCCESS,
"Deine AStA-Mitgliedschaft wurde gespeichert",
)
return redirect("index")
return render(request, "asta.html", {"form": form})