200 lines
6.8 KiB
Python
200 lines
6.8 KiB
Python
from datetime import timedelta
|
|
|
|
from django.contrib.auth.decorators import login_required
|
|
from django.http import HttpResponse
|
|
from django.shortcuts import redirect, render
|
|
from django.utils import timezone
|
|
|
|
from apps.epic.models import GateSlot, Room, RoomInvite, debit_token, select_token
|
|
from apps.lyric.models import Token
|
|
|
|
|
|
RESERVE_TIMEOUT = timedelta(seconds=60)
|
|
|
|
|
|
def _expire_reserved_slots(room):
|
|
cutoff = timezone.now() - RESERVE_TIMEOUT
|
|
room.gate_slots.filter(
|
|
status=GateSlot.RESERVED,
|
|
reserved_at__lt=cutoff,
|
|
).update(status=GateSlot.EMPTY, gamer=None, reserved_at=None)
|
|
|
|
|
|
def _gate_context(room, user):
|
|
_expire_reserved_slots(room)
|
|
slots = room.gate_slots.order_by("slot_number")
|
|
pending_slot = slots.filter(status=GateSlot.RESERVED).first()
|
|
user_reserved_slot = None
|
|
user_filled_slot = None
|
|
if user.is_authenticated:
|
|
user_reserved_slot = slots.filter(gamer=user, status=GateSlot.RESERVED).first()
|
|
user_filled_slot = slots.filter(gamer=user, status=GateSlot.FILLED).first()
|
|
eligible = (
|
|
user.is_authenticated
|
|
and pending_slot is None
|
|
and user_reserved_slot is None
|
|
and user_filled_slot is None
|
|
)
|
|
token_depleted = eligible and select_token(user) is None
|
|
can_drop = eligible and not token_depleted
|
|
is_last_slot = (
|
|
user_reserved_slot is not None
|
|
and slots.filter(status=GateSlot.EMPTY).count() == 0
|
|
)
|
|
user_can_reject = user_reserved_slot is not None or user_filled_slot is not None
|
|
return {
|
|
"slots": slots,
|
|
"pending_slot": pending_slot,
|
|
"user_reserved_slot": user_reserved_slot,
|
|
"user_filled_slot": user_filled_slot,
|
|
"can_drop": can_drop,
|
|
"token_depleted": token_depleted,
|
|
"is_last_slot": is_last_slot,
|
|
"user_can_reject": user_can_reject,
|
|
}
|
|
|
|
|
|
@login_required
|
|
def create_room(request):
|
|
if request.method == "POST":
|
|
name = request.POST.get("name", "").strip()
|
|
if name:
|
|
room = Room.objects.create(name=name, owner=request.user)
|
|
return redirect("epic:gatekeeper", room_id=room.id)
|
|
return redirect("/gameboard/")
|
|
|
|
|
|
def gatekeeper(request, room_id):
|
|
room = Room.objects.get(id=room_id)
|
|
ctx = _gate_context(room, request.user)
|
|
ctx["room"] = room
|
|
return render(request, "apps/gameboard/room.html", ctx)
|
|
|
|
|
|
@login_required
|
|
def drop_token(request, room_id):
|
|
if request.method == "POST":
|
|
room = Room.objects.get(id=room_id)
|
|
if room.gate_slots.filter(status=GateSlot.RESERVED).exists():
|
|
return redirect("epic:gatekeeper", room_id=room_id)
|
|
if room.gate_slots.filter(gamer=request.user, status=GateSlot.FILLED).exists():
|
|
return redirect("epic:gatekeeper", room_id=room_id)
|
|
token_id = request.POST.get("token_id")
|
|
if token_id:
|
|
token = request.user.tokens.filter(id=token_id).first()
|
|
else:
|
|
token = select_token(request.user)
|
|
if token is None:
|
|
return HttpResponse(status=402)
|
|
slot = room.gate_slots.filter(
|
|
status=GateSlot.EMPTY
|
|
).order_by("slot_number").first()
|
|
if slot:
|
|
slot.gamer = request.user
|
|
slot.status = GateSlot.RESERVED
|
|
slot.reserved_at = timezone.now()
|
|
slot.save()
|
|
request.session["kit_token_id"] = str(token.id)
|
|
return redirect("epic:gatekeeper", room_id=room_id)
|
|
|
|
|
|
@login_required
|
|
def confirm_token(request, room_id):
|
|
if request.method == "POST":
|
|
room = Room.objects.get(id=room_id)
|
|
slot = room.gate_slots.filter(
|
|
gamer=request.user, status=GateSlot.RESERVED
|
|
).first()
|
|
if slot:
|
|
token_id = request.session.pop("kit_token_id", None)
|
|
token = None
|
|
if token_id:
|
|
token = request.user.tokens.filter(id=token_id).first()
|
|
if not token:
|
|
token = select_token(request.user)
|
|
if token:
|
|
debit_token(request.user, slot, token)
|
|
return redirect("epic:gatekeeper", room_id=room_id)
|
|
|
|
|
|
@login_required
|
|
def return_token(request, room_id):
|
|
if request.method == "POST":
|
|
room = Room.objects.get(id=room_id)
|
|
slot = room.gate_slots.filter(
|
|
gamer=request.user,
|
|
status__in=[GateSlot.RESERVED, GateSlot.FILLED],
|
|
).first()
|
|
if slot:
|
|
if slot.status == GateSlot.FILLED:
|
|
if slot.debited_token_type == Token.COIN:
|
|
coin = request.user.tokens.filter(
|
|
token_type=Token.COIN, current_room=room
|
|
).first()
|
|
if coin:
|
|
coin.current_room = None
|
|
coin.next_ready_at = None
|
|
coin.save()
|
|
elif slot.debited_token_type in (Token.FREE, Token.TITHE):
|
|
Token.objects.create(
|
|
user=request.user,
|
|
token_type=slot.debited_token_type,
|
|
expires_at=slot.debited_token_expires_at,
|
|
)
|
|
request.session.pop("kit_token_id", None)
|
|
slot.gamer = None
|
|
slot.status = GateSlot.EMPTY
|
|
slot.reserved_at = None
|
|
slot.filled_at = None
|
|
slot.debited_token_type = None
|
|
slot.debited_token_expires_at = None
|
|
slot.save()
|
|
return redirect("epic:gatekeeper", room_id=room_id)
|
|
|
|
|
|
@login_required
|
|
def invite_gamer(request, room_id):
|
|
if request.method == "POST":
|
|
room = Room.objects.get(id=room_id)
|
|
email = request.POST.get("invitee_email", "").strip()
|
|
if email:
|
|
RoomInvite.objects.get_or_create(
|
|
room=room,
|
|
inviter=request.user,
|
|
invitee_email=email,
|
|
defaults={"status": RoomInvite.PENDING}
|
|
)
|
|
return redirect("epic:gatekeeper", room_id=room_id)
|
|
|
|
|
|
@login_required
|
|
def delete_room(request, room_id):
|
|
if request.method == "POST":
|
|
room = Room.objects.get(id=room_id)
|
|
if request.user == room.owner:
|
|
room.delete()
|
|
return redirect("/gameboard/")
|
|
|
|
|
|
@login_required
|
|
def abandon_room(request, room_id):
|
|
if request.method == "POST":
|
|
room = Room.objects.get(id=room_id)
|
|
room.gate_slots.filter(gamer=request.user).update(
|
|
gamer=None, status="EMPTY", filled_at=None
|
|
)
|
|
room.invites.filter(
|
|
invitee_email=request.user.email,
|
|
status=RoomInvite.PENDING
|
|
).delete()
|
|
return redirect("/gameboard/")
|
|
|
|
|
|
def gate_status(request, room_id):
|
|
room = Room.objects.get(id=room_id)
|
|
if room.gate_status == Room.OPEN:
|
|
return HttpResponse("")
|
|
ctx = _gate_context(room, request.user)
|
|
ctx["room"] = room
|
|
return render(request, "apps/gameboard/_partials/_gatekeeper.html", ctx)
|