plateforme-tfjm2/draw/consumers.py

91 lines
3.9 KiB
Python

import json
from asgiref.sync import sync_to_async
from channels.generic.websocket import AsyncJsonWebsocketConsumer
from django.utils.translation import gettext_lazy as _
from draw.models import Draw, Round, Pool, TeamDraw
from participation.models import Tournament, Participation
from registration.models import Registration
def ensure_orga(f):
async def func(self, *args, **kwargs):
reg = self.registration
if reg.is_volunteer and not reg.is_admin and self.tournament not in reg.interesting_tournaments \
or not reg.is_volunteer:
return await self.alert(_("You are not an organizer."), 'danger')
return await f(self, *args, **kwargs)
return func
class DrawConsumer(AsyncJsonWebsocketConsumer):
async def connect(self):
tournament_id = self.scope['url_route']['kwargs']['tournament_id']
self.tournament = await sync_to_async(Tournament.objects.get)(pk=tournament_id)
self.participations = await sync_to_async(lambda: list(Participation.objects\
.filter(tournament=self.tournament, valid=True)\
.prefetch_related('team').all()))()
user = self.scope['user']
reg = await sync_to_async(Registration.objects.get)(user=user)
self.registration = reg
if reg.is_volunteer and not reg.is_admin and self.tournament not in reg.interesting_tournaments \
or not reg.is_volunteer and reg.team.participation.tournament != self.tournament:
# This user may not have access to the drawing session
await self.close()
return
await self.accept()
await self.channel_layer.group_add(f"tournament-{self.tournament.id}", self.channel_name)
async def disconnect(self, close_code):
await self.channel_layer.group_discard(f"tournament-{self.tournament.id}", self.channel_name)
async def alert(self, message: str, alert_type: str = 'info'):
return await self.send_json({'type': 'alert', 'alert_type': alert_type, 'message': str(message)})
async def receive_json(self, content, **kwargs):
print(content)
match content['type']:
case 'start_draw':
await self.start_draw(**content)
@ensure_orga
async def start_draw(self, fmt, **kwargs):
print(fmt, kwargs)
try:
fmt = list(map(int, fmt.split('+')))
except ValueError as e:
return await self.alert(_("Invalid format"), 'danger')
print(fmt, sum(fmt), len(self.participations))
if sum(fmt) != len(self.participations):
return await self.alert(
_("The sum must be equal to the number of teams: expected {len}, got {sum}")\
.format(len=len(self.participations), sum=sum(fmt)), 'danger')
draw = await sync_to_async(Draw.objects.create)(tournament=self.tournament)
for i in [1, 2]:
r = await sync_to_async(Round.objects.create)(draw=draw, number=i)
for j, f in enumerate(fmt):
await sync_to_async(Pool.objects.create)(round=r, letter=j + 1, size=f)
for participation in self.participations:
await sync_to_async(TeamDraw.objects.create)(participation=participation)
await self.alert(_("Draw started!"), 'success')
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
{'type': 'draw.start', 'fmt': fmt, 'draw': draw})
async def draw_start(self, content):
await self.alert(_("The draw for the tournament {tournament} will start.")\
.format(tournament=self.tournament.name), 'warning')
await self.send_json({'type': 'draw_start', 'fmt': content['fmt'],
'trigrams': [p.team.trigram for p in self.participations]})