91 lines
3.9 KiB
Python
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]})
|