diff --git a/draw/consumers.py b/draw/consumers.py
index 4843a9b..31f893f 100644
--- a/draw/consumers.py
+++ b/draw/consumers.py
@@ -42,35 +42,27 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
We accept only if this is a user of a team of the associated tournament, or a volunteer
of the tournament.
"""
- # Get the tournament from the URL
- self.tournament_id = self.scope['url_route']['kwargs']['tournament_id']
- self.tournament = await Tournament.objects.filter(pk=self.tournament_id)\
- .prefetch_related('draw__current_round__current_pool__current_team__participation__team').aget()
-
- # Fetch participations from the tournament
- self.participations = []
- async for participation in self.tournament.participations.filter(valid=True).prefetch_related('team'):
- self.participations.append(participation)
# Fetch the registration of the current user
user = self.scope['user']
reg = await Registration.objects.aget(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
# Accept the connection
await self.accept()
# Register to channel layers to get updates
- await self.channel_layer.group_add(f"tournament-{self.tournament.id}", self.channel_name)
- if not self.registration.is_volunteer:
+ if self.registration.participates:
await self.channel_layer.group_add(f"team-{self.registration.team.trigram}", self.channel_name)
+ participation = reg.team.participation
+ if participation.valid:
+ await self.channel_layer.group_add(f"tournament-{participation.tournament.id}", self.channel_name)
else:
- await self.channel_layer.group_add(f"volunteer-{self.tournament.id}", self.channel_name)
+ tids = [t.id async for t in Tournament.objects.all()] \
+ if reg.is_admin else [t.id for t in reg.interesting_tournaments]
+ for tid in tids:
+ await self.channel_layer.group_add(f"tournament-{tid}", self.channel_name)
+ await self.channel_layer.group_add(f"volunteer-{tid}", self.channel_name)
async def disconnect(self, close_code) -> None:
"""
@@ -78,25 +70,40 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
:param close_code: The error code.
"""
# Unregister from channel layers
- await self.channel_layer.group_discard(f"tournament-{self.tournament.id}", self.channel_name)
if not self.registration.is_volunteer:
await self.channel_layer.group_discard(f"team-{self.registration.team.trigram}", self.channel_name)
+ participation = self.registration.team.participation
+ await self.channel_layer.group_discard(f"tournament-{participation.tournament.id}", self.channel_name)
else:
- await self.channel_layer.group_discard(f"volunteer-{self.tournament.id}", self.channel_name)
+ async for tournament in Tournament.objects.all():
+ await self.channel_layer.group_discard(f"tournament-{tournament.id}", self.channel_name)
+ await self.channel_layer.group_discard(f"volunteer-{tournament.id}", self.channel_name)
- async def alert(self, message: str, alert_type: str = 'info', **kwargs):
+ async def alert(self, message: str, alert_type: str = 'info', tid: int = -1, **kwargs):
"""
Send an alert message to the current user.
:param message: The body of the alert.
:param alert_type: The type of the alert, which is a bootstrap color (success, warning, info, danger,…)
+ :param tid: The tournament id. Default to -1, the current tournament.
"""
- return await self.send_json({'type': 'alert', 'alert_type': alert_type, 'message': str(message)})
+ tid = tid if tid > 0 else self.tournament_id
+ return await self.send_json({'tid': tid, 'type': 'alert', 'alert_type': alert_type, 'message': str(message)})
async def receive_json(self, content, **kwargs):
"""
Called when the client sends us some data, parsed as JSON.
:param content: The sent data, decoded from JSON text. Must content a `type` field.
"""
+ # Get the tournament from the message
+ self.tournament_id = content['tid']
+ self.tournament = await Tournament.objects.filter(pk=self.tournament_id) \
+ .prefetch_related('draw__current_round__current_pool__current_team__participation__team').aget()
+
+ # Fetch participations from the tournament
+ self.participations = []
+ async for participation in self.tournament.participations.filter(valid=True).prefetch_related('team'):
+ self.participations.append(participation)
+
# Refresh tournament
self.tournament = await Tournament.objects.filter(pk=self.tournament_id)\
.prefetch_related('draw__current_round__current_pool__current_team__participation__team').aget()
@@ -176,37 +183,42 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await TeamDraw.objects.acreate(participation=participation, round=r)
# Send to clients the different pools
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.send_poules',
- 'round': r.number,
- 'poules': [
- {
- 'letter': pool.get_letter_display(),
- 'teams': await pool.atrigrams(),
- }
- async for pool in r.pool_set.order_by('letter').all()
- ]})
+ {
+ 'tid': self.tournament_id,
+ 'type': 'draw.send_poules',
+ 'round': r.number,
+ 'poules': [
+ {
+ 'letter': pool.get_letter_display(),
+ 'teams': await pool.atrigrams(),
+ }
+ async for pool in r.pool_set.order_by('letter').all()
+ ]
+ })
draw.current_round = r1
await draw.asave()
# Make dice box visible
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
await self.alert(_("Draw started!"), 'success')
# Update user interface
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.start', 'fmt': fmt, 'draw': draw})
+ {'tid': self.tournament_id, 'type': 'draw.start', 'fmt': fmt, 'draw': draw})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_info',
+ {'tid': self.tournament_id, 'type': 'draw.set_info',
'info': await self.tournament.draw.ainformation()})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_active', 'round': 1})
+ {'tid': self.tournament_id, 'type': 'draw.set_active', 'round': 1})
# Send notification to everyone
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.notify', 'title': 'Tirage au sort du TFJM²',
+ {'tid': self.tournament_id, 'type': 'draw.notify',
+ 'title': 'Tirage au sort du TFJM²',
'body': "Le tirage au sort du tournoi de "
f"{self.tournament.name} a commencé !"})
@@ -216,7 +228,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
"""
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'],
+ await self.send_json({'tid': content['tid'], 'type': 'draw_start', 'fmt': content['fmt'],
'trigrams': [p.team.trigram for p in self.participations]})
@ensure_orga
@@ -231,7 +243,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# All associated data will be deleted by cascade
await self.tournament.draw.adelete()
# Send information to all users
- await self.channel_layer.group_send(f"tournament-{self.tournament.id}", {'type': 'draw_abort'})
+ await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
+ {'tid': self.tournament_id, 'type': 'draw_abort'})
async def draw_abort(self, content) -> None:
"""
@@ -239,7 +252,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
"""
await self.alert(_("The draw for the tournament {tournament} is aborted.")
.format(tournament=self.tournament.name), 'danger')
- await self.send_json({'type': 'abort'})
+ await self.send_json({'tid': content['tid'], 'type': 'abort'})
async def process_dice(self, trigram: str | None = None, **kwargs):
"""
@@ -310,7 +323,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Send the dice result to all users
await self.channel_layer.group_send(
- f"tournament-{self.tournament.id}", {'type': 'draw.dice', 'team': trigram, 'result': res})
+ f"tournament-{self.tournament.id}", {'tid': self.tournament_id, 'type': 'draw.dice',
+ 'team': trigram, 'result': res})
if state == 'DICE_SELECT_POULES' and \
not await TeamDraw.objects.filter(round_id=self.tournament.draw.current_round_id,
@@ -364,19 +378,20 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await dup.asave()
await self.channel_layer.group_send(
f"tournament-{self.tournament.id}",
- {'type': 'draw.dice', 'team': dup.participation.team.trigram, 'result': None})
+ {'tid': self.tournament_id, 'type': 'draw.dice',
+ 'team': dup.participation.team.trigram, 'result': None})
# Send notification to concerned teams
await self.channel_layer.group_send(
f"team-{dup.participation.team.trigram}",
- {'type': 'draw.notify', 'title': 'Tirage au sort du TFJM²',
+ {'tid': self.tournament_id, 'type': 'draw.notify', 'title': 'Tirage au sort du TFJM²',
'body': 'Votre score de dé est identique à celui de une ou plusieurs équipes. '
'Veuillez le relancer.'}
)
# Alert the tournament
await self.channel_layer.group_send(
f"tournament-{self.tournament.id}",
- {'type': 'draw.alert',
+ {'tid': self.tournament_id, 'type': 'draw.alert',
'message': _('Dices from teams {teams} are identical. Please relaunch your dices.').format(
teams=', '.join(td.participation.team.trigram for td in dups)),
'alert_type': 'warning'})
@@ -452,23 +467,26 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
for td in tds:
await self.channel_layer.group_send(
f"tournament-{self.tournament.id}",
- {'type': 'draw.dice', 'team': td.participation.team.trigram, 'result': None})
+ {'tid': self.tournament_id, 'type': 'draw.dice', 'team': td.participation.team.trigram, 'result': None})
# Hide dice interface
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': False})
# Display dice interface only for the teams in the first pool, and for volunteers
async for td in pool.teamdraw_set.prefetch_related('participation__team').all():
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
# First send the second pool to have the good team order
r2 = await self.tournament.draw.round_set.filter(number=2).aget()
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.send_poules',
+ {'tid': self.tournament_id, 'type': 'draw.send_poules',
'round': r2.number,
'poules': [
{
@@ -478,7 +496,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
async for pool in r2.pool_set.order_by('letter').all()
]})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.send_poules',
+ {'tid': self.tournament_id, 'type': 'draw.send_poules',
'round': r.number,
'poules': [
{
@@ -490,10 +508,10 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Update information header and the active team on the recap menu
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_info',
+ {'tid': self.tournament_id, 'type': 'draw.set_info',
'info': await self.tournament.draw.ainformation()})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_active',
+ {'tid': self.tournament_id, 'type': 'draw.set_active',
'round': r.number,
'pool': pool.get_letter_display()})
@@ -521,28 +539,30 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Update information header
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_info',
+ {'tid': self.tournament_id, 'type': 'draw.set_info',
'info': await self.tournament.draw.ainformation()})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_active',
+ {'tid': self.tournament_id, 'type': 'draw.set_active',
'round': r.number,
'pool': pool.get_letter_display(),
'team': pool.current_team.participation.team.trigram})
# Hide dice button to everyone
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': False})
# Display the box button to the first team and to volunteers
trigram = pool.current_team.participation.team.trigram
await self.channel_layer.group_send(f"team-{trigram}",
- {'type': 'draw.box_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.box_visibility', 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.box_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.box_visibility', 'visible': True})
# Notify the team that it can draw a problem
await self.channel_layer.group_send(f"team-{tds[0].participation.team.trigram}",
- {'type': 'draw.notify', 'title': "À votre tour !",
+ {'tid': self.tournament_id, 'type': 'draw.notify',
+ 'title': "À votre tour !",
'body': "C'est à vous de tirer un nouveau problème !"})
async def select_problem(self, **kwargs):
@@ -585,20 +605,25 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Update interface
trigram = td.participation.team.trigram
await self.channel_layer.group_send(f"team-{trigram}",
- {'type': 'draw.box_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.box_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.box_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.box_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"team-{trigram}",
- {'type': 'draw.buttons_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.buttons_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"team-{self.tournament.id}",
- {'type': 'draw.draw_problem', 'team': trigram, 'problem': problem})
+ {'tid': self.tournament_id, 'type': 'draw.draw_problem', 'team': trigram,
+ 'problem': problem})
self.tournament.draw.last_message = ""
await self.tournament.draw.asave()
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_info',
+ {'tid': self.tournament_id, 'type': 'draw.set_info',
'info': await self.tournament.draw.ainformation()})
async def accept_problem(self, **kwargs):
@@ -641,11 +666,13 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Send the accepted problem to the users
await self.channel_layer.group_send(f"team-{trigram}",
- {'type': 'draw.buttons_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.buttons_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_problem',
+ {'tid': self.tournament_id, 'type': 'draw.set_problem',
'round': r.number,
'team': trigram,
'problem': td.accepted})
@@ -659,13 +686,16 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
new_trigram = next_td.participation.team.trigram
await self.channel_layer.group_send(f"team-{new_trigram}",
- {'type': 'draw.box_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.box_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.box_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.box_visibility',
+ 'visible': True})
# Notify the team that it can draw a problem
await self.channel_layer.group_send(f"team-{new_trigram}",
- {'type': 'draw.notify', 'title': "À votre tour !",
+ {'tid': self.tournament_id, 'type': 'draw.notify',
+ 'title': "À votre tour !",
'body': "C'est à vous de tirer un nouveau problème !"})
else:
# Pool is ended
@@ -674,10 +704,10 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
pool = r.current_pool
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_info',
+ {'tid': self.tournament_id, 'type': 'draw.set_info',
'info': await self.tournament.draw.ainformation()})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_active',
+ {'tid': self.tournament_id, 'type': 'draw.set_active',
'round': r.number,
'pool': pool.get_letter_display(),
'team': pool.current_team.participation.team.trigram
@@ -715,6 +745,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Send the reordered pool
await self.channel_layer.group_send(f"tournament-{self.tournament.id}", {
+ 'tid': self.tournament_id,
'type': 'draw.reorder_pool',
'round': r.number,
'pool': pool.get_letter_display(),
@@ -736,14 +767,17 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
async for td in next_pool.team_draws.prefetch_related('participation__team').all():
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
# Notify the team that it can draw a dice
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.notify', 'title': "À votre tour !",
+ {'tid': self.tournament_id, 'type': 'draw.notify',
+ 'title': "À votre tour !",
'body': "C'est à vous de lancer le dé !"})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
else:
# Round is ended
await self.end_round(r)
@@ -766,16 +800,18 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
for participation in self.participations:
await self.channel_layer.group_send(
f"tournament-{self.tournament.id}",
- {'type': 'draw.dice', 'team': participation.team.trigram, 'result': None})
+ {'tid': self.tournament_id, 'type': 'draw.dice',
+ 'team': participation.team.trigram, 'result': None})
# Notify the team that it can draw a dice
await self.channel_layer.group_send(f"team-{participation.team.trigram}",
- {'type': 'draw.notify', 'title': "À votre tour !",
+ {'tid': self.tournament_id, 'type': 'draw.notify',
+ 'title': "À votre tour !",
'body': "C'est à vous de lancer le dé !"})
# Reorder dices
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.send_poules',
+ {'tid': self.tournament_id, 'type': 'draw.send_poules',
'round': r2.number,
'poules': [
{
@@ -793,9 +829,11 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
async for td in p1.teamdraw_set.prefetch_related('participation__team').all():
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
elif r.number == 1 and self.tournament.final:
# For the final tournament, we wait for a manual update between the two rounds.
msg += "
Le tirage au sort du tour 1 est terminé."
@@ -803,7 +841,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await self.tournament.draw.asave()
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.export_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.export_visibility',
+ 'visible': True})
async def reject_problem(self, **kwargs):
"""
@@ -854,11 +893,13 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Update interface
await self.channel_layer.group_send(f"team-{trigram}",
- {'type': 'draw.buttons_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.buttons_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.reject_problem',
+ {'tid': self.tournament_id, 'type': 'draw.reject_problem',
'round': r.number, 'team': trigram, 'rejected': td.rejected})
if already_refused:
@@ -873,22 +914,23 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
new_trigram = next_td.participation.team.trigram
await self.channel_layer.group_send(f"team-{new_trigram}",
- {'type': 'draw.box_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.box_visibility', 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.box_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.box_visibility', 'visible': True})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_info',
+ {'tid': self.tournament_id, 'type': 'draw.set_info',
'info': await self.tournament.draw.ainformation()})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_active',
+ {'tid': self.tournament_id, 'type': 'draw.set_active',
'round': r.number,
'pool': pool.get_letter_display(),
'team': new_trigram})
# Notify the team that it can draw a problem
await self.channel_layer.group_send(f"team-{new_trigram}",
- {'type': 'draw.notify', 'title': "À votre tour !",
+ {'tid': self.tournament_id, 'type': 'draw.notify',
+ 'title': "À votre tour !",
'body': "C'est à vous de tirer un nouveau problème !"})
@ensure_orga
@@ -906,7 +948,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await pool.export()
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.export_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.export_visibility',
+ 'visible': False})
@ensure_orga
async def continue_final(self, **kwargs):
@@ -951,7 +994,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Send pools to users
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.send_poules',
+ {'tid': self.tournament_id, 'type': 'draw.send_poules',
'round': r2.number,
'poules': [
{
@@ -965,27 +1008,31 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
for participation in self.participations:
await self.channel_layer.group_send(
f"tournament-{self.tournament.id}",
- {'type': 'draw.dice', 'team': participation.team.trigram, 'result': None})
+ {'tid': self.tournament_id, 'type': 'draw.dice', 'team': participation.team.trigram, 'result': None})
async for td in r2.current_pool.team_draws.prefetch_related('participation__team'):
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
# Notify the team that it can draw a problem
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.notify', 'title': "À votre tour !",
+ {'tid': self.tournament_id, 'type': 'draw.notify',
+ 'title': "À votre tour !",
'body': "C'est à vous de tirer un nouveau problème !"})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.continue_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.continue_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_info',
+ {'tid': self.tournament_id, 'type': 'draw.set_info',
'info': await self.tournament.draw.ainformation()})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_active',
+ {'tid': self.tournament_id, 'type': 'draw.set_active',
'round': r2.number,
'pool': r2.current_pool.get_letter_display()})
@@ -1014,12 +1061,12 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await self.undo_order_dice()
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_info',
+ {'tid': self.tournament_id, 'type': 'draw.set_info',
'info': await self.tournament.draw.ainformation()})
r = self.tournament.draw.current_round
p = r.current_pool
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_active',
+ {'tid': self.tournament_id, 'type': 'draw.set_active',
'round': r.number,
'pool': p.get_letter_display() if p else None,
'team': p.current_team.participation.team.trigram
@@ -1037,15 +1084,18 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await td.asave()
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.continue_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.continue_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.buttons_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.buttons_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_problem',
+ {'tid': self.tournament_id, 'type': 'draw.set_problem',
'round': r.number,
'team': td.participation.team.trigram,
'problem': td.accepted})
@@ -1061,13 +1111,15 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await td.asave()
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.buttons_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.buttons_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.box_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.box_visibility', 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.box_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.box_visibility', 'visible': True})
async def undo_process_problem(self):
"""
@@ -1115,7 +1167,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await last_td.asave()
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_problem',
+ {'tid': self.tournament_id, 'type': 'draw.set_problem',
'round': r.number,
'team': last_td.participation.team.trigram,
'problem': last_td.accepted})
@@ -1133,7 +1185,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await last_td.asave()
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.reject_problem',
+ {'tid': self.tournament_id, 'type': 'draw.reject_problem',
'round': r.number,
'team': last_td.participation.team.trigram,
'rejected': last_td.rejected})
@@ -1143,9 +1195,11 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await r.current_pool.asave()
await self.channel_layer.group_send(f"team-{last_td.participation.team.trigram}",
- {'type': 'draw.buttons_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.buttons_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': True})
else:
# Return to the dice choice
pool_tds = {td.id: td async for td in p.team_draws.prefetch_related('participation__team')}
@@ -1166,7 +1220,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Reset the dice on the interface
await self.channel_layer.group_send(
- f"tournament-{self.tournament.id}", {'type': 'draw.dice',
+ f"tournament-{self.tournament.id}", {'tid': self.tournament_id, 'type': 'draw.dice',
'team': last_td.participation.team.trigram,
'result': None})
break
@@ -1177,12 +1231,15 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Make dice box visible
for td in pool_tds.values():
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.box_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.box_visibility',
+ 'visible': False})
async def undo_pool_dice(self):
"""
@@ -1217,7 +1274,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Reset the dice on the interface
await self.channel_layer.group_send(
- f"tournament-{self.tournament.id}", {'type': 'draw.dice',
+ f"tournament-{self.tournament.id}", {'tid': self.tournament_id, 'type': 'draw.dice',
'team': last_td.participation.team.trigram,
'result': None})
break
@@ -1236,15 +1293,18 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await td.asave()
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.buttons_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.buttons_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_problem',
+ {'tid': self.tournament_id, 'type': 'draw.set_problem',
'round': r.number,
'team': td.participation.team.trigram,
'problem': td.accepted})
@@ -1258,12 +1318,12 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
async for td in r1.team_draws.prefetch_related('participation__team').all():
await self.channel_layer.group_send(
- f"tournament-{self.tournament.id}", {'type': 'draw.dice',
+ f"tournament-{self.tournament.id}", {'tid': self.tournament_id, 'type': 'draw.dice',
'team': td.participation.team.trigram,
'result': td.choice_dice})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.send_poules',
+ {'tid': self.tournament_id, 'type': 'draw.send_poules',
'round': r1.number,
'poules': [
{
@@ -1281,15 +1341,18 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
await td.asave()
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
- {'type': 'draw.buttons_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.buttons_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.buttons_visibility',
+ 'visible': True})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.set_problem',
+ {'tid': self.tournament_id, 'type': 'draw.set_problem',
'round': r1.number,
'team': td.participation.team.trigram,
'problem': td.accepted})
@@ -1308,14 +1371,16 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
async for td in r1.team_draws.prefetch_related('participation__team').all():
await self.channel_layer.group_send(
- f"tournament-{self.tournament.id}", {'type': 'draw.dice',
+ f"tournament-{self.tournament.id}", {'tid': self.tournament_id, 'type': 'draw.dice',
'team': td.participation.team.trigram,
'result': td.choice_dice})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': False})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': False})
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
- {'type': 'draw.continue_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.continue_visibility',
+ 'visible': True})
else:
# Go to the dice order
async for r0 in self.tournament.draw.round_set.all():
@@ -1349,19 +1414,20 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Reset the dice on the interface
await self.channel_layer.group_send(
- f"tournament-{self.tournament.id}", {'type': 'draw.dice',
+ f"tournament-{self.tournament.id}", {'tid': self.tournament_id, 'type': 'draw.dice',
'team': last_td.participation.team.trigram,
'result': None})
break
async for td in r.team_draws.prefetch_related('participation__team').all():
await self.channel_layer.group_send(
- f"tournament-{self.tournament.id}", {'type': 'draw.dice',
+ f"tournament-{self.tournament.id}", {'tid': self.tournament_id, 'type': 'draw.dice',
'team': td.participation.team.trigram,
'result': td.passage_dice})
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
- {'type': 'draw.dice_visibility', 'visible': True})
+ {'tid': self.tournament_id, 'type': 'draw.dice_visibility',
+ 'visible': True})
async def undo_order_dice(self):
"""
@@ -1393,7 +1459,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# Reset the dice on the interface
await self.channel_layer.group_send(
- f"tournament-{self.tournament.id}", {'type': 'draw.dice',
+ f"tournament-{self.tournament.id}", {'tid': self.tournament_id, 'type': 'draw.dice',
'team': last_td.participation.team.trigram,
'result': None})
break
@@ -1410,55 +1476,57 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
"""
Send a notification (with title and body) to the current user.
"""
- await self.send_json({'type': 'notification', 'title': content['title'], 'body': content['body']})
+ await self.send_json({'tid': content['tid'], 'type': 'notification',
+ 'title': content['title'], 'body': content['body']})
async def draw_set_info(self, content):
"""
Set the information banner to the current user.
"""
- await self.send_json({'type': 'set_info', 'information': content['info']})
+ await self.send_json({'tid': content['tid'], 'type': 'set_info', 'information': content['info']})
async def draw_dice(self, content):
"""
Update the dice of a given team for the current user interface.
"""
- await self.send_json({'type': 'dice', 'team': content['team'], 'result': content['result']})
+ await self.send_json({'tid': content['tid'], 'type': 'dice',
+ 'team': content['team'], 'result': content['result']})
async def draw_dice_visibility(self, content):
"""
Update the visibility of the dice button for the current user.
"""
- await self.send_json({'type': 'dice_visibility', 'visible': content['visible']})
+ await self.send_json({'tid': content['tid'], 'type': 'dice_visibility', 'visible': content['visible']})
async def draw_box_visibility(self, content):
"""
Update the visibility of the box button for the current user.
"""
- await self.send_json({'type': 'box_visibility', 'visible': content['visible']})
+ await self.send_json({'tid': content['tid'], 'type': 'box_visibility', 'visible': content['visible']})
async def draw_buttons_visibility(self, content):
"""
Update the visibility of the accept/reject buttons for the current user.
"""
- await self.send_json({'type': 'buttons_visibility', 'visible': content['visible']})
+ await self.send_json({'tid': content['tid'], 'type': 'buttons_visibility', 'visible': content['visible']})
async def draw_export_visibility(self, content):
"""
Update the visibility of the export button for the current user.
"""
- await self.send_json({'type': 'export_visibility', 'visible': content['visible']})
+ await self.send_json({'tid': content['tid'], 'type': 'export_visibility', 'visible': content['visible']})
async def draw_continue_visibility(self, content):
"""
Update the visibility of the continue button for the current user.
"""
- await self.send_json({'type': 'continue_visibility', 'visible': content['visible']})
+ await self.send_json({'tid': content['tid'], 'type': 'continue_visibility', 'visible': content['visible']})
async def draw_send_poules(self, content):
"""
Send the pools and the teams to the current user to update the interface.
"""
- await self.send_json({'type': 'set_poules', 'round': content['round'],
+ await self.send_json({'tid': content['tid'], 'type': 'set_poules', 'round': content['round'],
'poules': content['poules']})
async def draw_set_active(self, content):
@@ -1466,6 +1534,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
Update the user interface to highlight the current team.
"""
await self.send_json({
+ 'tid': content['tid'],
'type': 'set_active',
'round': content.get('round', None),
'poule': content.get('pool', None),
@@ -1476,20 +1545,20 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
"""
Send the accepted problem of a team to the current user.
"""
- await self.send_json({'type': 'set_problem', 'round': content['round'],
+ await self.send_json({'tid': content['tid'], 'type': 'set_problem', 'round': content['round'],
'team': content['team'], 'problem': content['problem']})
async def draw_reject_problem(self, content):
"""
Send the rejected problems of a team to the current user.
"""
- await self.send_json({'type': 'reject_problem', 'round': content['round'],
+ await self.send_json({'tid': content['tid'], 'type': 'reject_problem', 'round': content['round'],
'team': content['team'], 'rejected': content['rejected']})
async def draw_reorder_pool(self, content):
"""
Send the new order of a pool to the current user.
"""
- await self.send_json({'type': 'reorder_poule', 'round': content['round'],
+ await self.send_json({'tid': content['tid'], 'type': 'reorder_poule', 'round': content['round'],
'poule': content['pool'], 'teams': content['teams'],
'problems': content['problems']})
diff --git a/draw/routing.py b/draw/routing.py
index c060dfa..8ce6085 100644
--- a/draw/routing.py
+++ b/draw/routing.py
@@ -1,7 +1,10 @@
+# Copyright (C) 2023 by Animath
+# SPDX-License-Identifier: GPL-3.0-or-later
+
from django.urls import path
from . import consumers
websocket_urlpatterns = [
- path("ws/draw//", consumers.DrawConsumer.as_asgi()),
+ path("ws/draw/", consumers.DrawConsumer.as_asgi()),
]
diff --git a/draw/static/draw.js b/draw/static/draw.js
index efdf508..0f255f4 100644
--- a/draw/static/draw.js
+++ b/draw/static/draw.js
@@ -7,7 +7,7 @@
const problems_count = JSON.parse(document.getElementById('problems_count').textContent)
const tournaments = JSON.parse(document.getElementById('tournaments_list').textContent)
-const sockets = {}
+let socket = null
const messages = document.getElementById('messages')
@@ -17,7 +17,7 @@ const messages = document.getElementById('messages')
* @param tid The tournament id
*/
function abortDraw(tid) {
- sockets[tid].send(JSON.stringify({'type': 'abort'}))
+ socket.send(JSON.stringify({'tid': tid, 'type': 'abort'}))
}
/**
@@ -26,7 +26,7 @@ function abortDraw(tid) {
* @param tid The tournament id
*/
function cancelLastStep(tid) {
- sockets[tid].send(JSON.stringify({'type': 'cancel'}))
+ socket.send(JSON.stringify({'tid': tid, 'type': 'cancel'}))
}
/**
@@ -36,7 +36,7 @@ function cancelLastStep(tid) {
* @param trigram The trigram of the team that a volunteer wants to force the dice launch (default: null)
*/
function drawDice(tid, trigram = null) {
- sockets[tid].send(JSON.stringify({'type': 'dice', 'trigram': trigram}))
+ socket.send(JSON.stringify({'tid': tid, 'type': 'dice', 'trigram': trigram}))
}
/**
@@ -44,7 +44,7 @@ function drawDice(tid, trigram = null) {
* @param tid The tournament id
*/
function drawProblem(tid) {
- sockets[tid].send(JSON.stringify({'type': 'draw_problem'}))
+ socket.send(JSON.stringify({'tid': tid, 'type': 'draw_problem'}))
}
/**
@@ -52,7 +52,7 @@ function drawProblem(tid) {
* @param tid The tournament id
*/
function acceptProblem(tid) {
- sockets[tid].send(JSON.stringify({'type': 'accept'}))
+ socket.send(JSON.stringify({'tid': tid, 'type': 'accept'}))
}
/**
@@ -60,7 +60,7 @@ function acceptProblem(tid) {
* @param tid The tournament id
*/
function rejectProblem(tid) {
- sockets[tid].send(JSON.stringify({'type': 'reject'}))
+ socket.send(JSON.stringify({'tid': tid, 'type': 'reject'}))
}
/**
@@ -68,7 +68,7 @@ function rejectProblem(tid) {
* @param tid The tournament id
*/
function exportDraw(tid) {
- sockets[tid].send(JSON.stringify({'type': 'export'}))
+ socket.send(JSON.stringify({'tid': tid, 'type': 'export'}))
}
/**
@@ -76,7 +76,7 @@ function exportDraw(tid) {
* @param tid The tournament id
*/
function continueFinal(tid) {
- sockets[tid].send(JSON.stringify({'type': 'continue_final'}))
+ socket.send(JSON.stringify({'tid': tid, 'type': 'continue_final'}))
}
/**
@@ -108,644 +108,671 @@ document.addEventListener('DOMContentLoaded', () => {
elem => elem.addEventListener(
'click', () => document.location.hash = '#' + elem.innerText.toLowerCase()))
- for (let tournament of tournaments) {
- // Open a websocket per tournament
- let socket = new WebSocket(
- (document.location.protocol === 'https:' ? 'wss' : 'ws') + '://' + window.location.host
- + '/ws/draw/' + tournament.id + '/'
- )
- sockets[tournament.id] = socket
+ // Open a global websocket
+ socket = new WebSocket(
+ (document.location.protocol === 'https:' ? 'wss' : 'ws') + '://' + window.location.host
+ + '/ws/draw/'
+ )
- /**
- * Add alert message on the top on the interface.
- * @param message The content of the alert.
- * @param type The alert type, which is a bootstrap color (success, info, warning, danger,…).
- * @param timeout The time (in milliseconds) before the alert is auto-closing. 0 to infinitely, default to 5000 ms.
- */
- function addMessage(message, type, timeout = 5000) {
- const wrapper = document.createElement('div')
- wrapper.innerHTML = [
- `
`,
- `
${message}
`,
- '',
- ].join('\n')
- messages.append(wrapper)
+ /**
+ * Add alert message on the top on the interface.
+ * @param message The content of the alert.
+ * @param type The alert type, which is a bootstrap color (success, info, warning, danger,…).
+ * @param timeout The time (in milliseconds) before the alert is auto-closing. 0 to infinitely, default to 5000 ms.
+ */
+ function addMessage(message, type, timeout = 5000) {
+ const wrapper = document.createElement('div')
+ wrapper.innerHTML = [
+ `
`,
+ `
${message}
`,
+ '',
+ ].join('\n')
+ messages.append(wrapper)
- if (timeout)
- setTimeout(() => wrapper.remove(), timeout)
- }
+ if (timeout)
+ setTimeout(() => wrapper.remove(), timeout)
+ }
- /**
- * Update the information banner.
- * @param info The content to updated
- */
- function setInfo(info) {
- document.getElementById(`messages-${tournament.id}`).innerHTML = info
- }
+ /**
+ * Update the information banner.
+ * @param tid The tournament id
+ * @param info The content to updated
+ */
+ function setInfo(tid, info) {
+ document.getElementById(`messages-${tid}`).innerHTML = info
+ }
- /**
- * Open the draw interface, given the list of teams.
- * @param teams The list of teams (represented by their trigrams) that are present on this draw.
- */
- function drawStart(teams) {
- // Hide the not-started-banner
- document.getElementById(`banner-not-started-${tournament.id}`).classList.add('d-none')
- // Display the full draw interface
- document.getElementById(`draw-content-${tournament.id}`).classList.remove('d-none')
+ /**
+ * Open the draw interface, given the list of teams.
+ * @param tid The tournament id
+ * @param teams The list of teams (represented by their trigrams) that are present on this draw.
+ */
+ function drawStart(tid, teams) {
+ // Hide the not-started-banner
+ document.getElementById(`banner-not-started-${tid}`).classList.add('d-none')
+ // Display the full draw interface
+ document.getElementById(`draw-content-${tid}`).classList.remove('d-none')
- let dicesDiv = document.getElementById(`dices-${tournament.id}`)
- for (let team of teams) {
- // Add empty dice score badge for each team
- let col = document.createElement('div')
- col.classList.add('col-md-1')
- dicesDiv.append(col)
+ let dicesDiv = document.getElementById(`dices-${tid}`)
+ for (let team of teams) {
+ // Add empty dice score badge for each team
+ let col = document.createElement('div')
+ col.classList.add('col-md-1')
+ dicesDiv.append(col)
- let diceDiv = document.createElement('div')
- diceDiv.id = `dice-${tournament.id}-${team}`
- diceDiv.classList.add('badge', 'rounded-pill', 'text-bg-warning')
- if (document.getElementById(`abort-${tournament.id}`) !== null) {
- // Check if this is a volunteer, who can launch a dice for a specific team
- diceDiv.onclick = (e) => drawDice(tournament.id, team)
- }
- diceDiv.textContent = `${team} 🎲 ??`
- col.append(diceDiv)
+ let diceDiv = document.createElement('div')
+ diceDiv.id = `dice-${tid}-${team}`
+ diceDiv.classList.add('badge', 'rounded-pill', 'text-bg-warning')
+ if (document.getElementById(`abort-${tid}`) !== null) {
+ // Check if this is a volunteer, who can launch a die for a specific team
+ diceDiv.onclick = (_) => drawDice(tid, team)
}
+ diceDiv.textContent = `${team} 🎲 ??`
+ col.append(diceDiv)
}
+ }
- /**
- * Abort the current draw, and make all invisible, except the not-started-banner.
- */
- function drawAbort() {
- document.getElementById(`banner-not-started-${tournament.id}`).classList.remove('d-none')
- document.getElementById(`draw-content-${tournament.id}`).classList.add('d-none')
- document.getElementById(`dices-${tournament.id}`).innerHTML = ""
- document.getElementById(`recap-${tournament.id}-round-list`).innerHTML = ""
- document.getElementById(`tables-${tournament.id}`).innerHTML = ""
- updateDiceVisibility(false)
- updateBoxVisibility(false)
- updateButtonsVisibility(false)
- updateExportVisibility(false)
- updateContinueVisibility(false)
+ /**
+ * Abort the current draw, and make all invisible, except the not-started-banner.
+ * @param tid The tournament id
+ */
+ function drawAbort(tid) {
+ document.getElementById(`banner-not-started-${tid}`).classList.remove('d-none')
+ document.getElementById(`draw-content-${tid}`).classList.add('d-none')
+ document.getElementById(`dices-${tid}`).innerHTML = ""
+ document.getElementById(`recap-${tid}-round-list`).innerHTML = ""
+ document.getElementById(`tables-${tid}`).innerHTML = ""
+ updateDiceVisibility(tid, false)
+ updateBoxVisibility(tid, false)
+ updateButtonsVisibility(tid, false)
+ updateExportVisibility(tid, false)
+ updateContinueVisibility(tid, false)
+ }
+
+ /**
+ * This function is triggered after a new dice result. We update the score of the team.
+ * Can be resetted to empty values if the result is null.
+ * @param tid The tournament id
+ * @param trigram The trigram of the team that launched its dice
+ * @param result The result of the dice. null if it is a reset.
+ */
+ function updateDiceInfo(tid, trigram, result) {
+ let elem = document.getElementById(`dice-${tid}-${trigram}`)
+ if (result === null) {
+ elem.classList.remove('text-bg-success')
+ elem.classList.add('text-bg-warning')
+ elem.innerText = `${trigram} 🎲 ??`
}
-
- /**
- * This function is triggered after a new dice result. We update the score of the team.
- * Can be resetted to empty values if the result is null.
- * @param trigram The trigram of the team that launched its dice
- * @param result The result of the dice. null if it is a reset.
- */
- function updateDiceInfo(trigram, result) {
- let elem = document.getElementById(`dice-${tournament.id}-${trigram}`)
- if (result === null) {
- elem.classList.remove('text-bg-success')
- elem.classList.add('text-bg-warning')
- elem.innerText = `${trigram} 🎲 ??`
- }
- else {
- elem.classList.remove('text-bg-warning')
- elem.classList.add('text-bg-success')
- elem.innerText = `${trigram} 🎲 ${result}`
- }
+ else {
+ elem.classList.remove('text-bg-warning')
+ elem.classList.add('text-bg-success')
+ elem.innerText = `${trigram} 🎲 ${result}`
}
+ }
- /**
- * Display or hide the dice button.
- * @param visible The visibility status
- */
- function updateDiceVisibility(visible) {
- let div = document.getElementById(`launch-dice-${tournament.id}`)
+ /**
+ * Display or hide the dice button.
+ * @param tid The tournament id
+ * @param visible The visibility status
+ */
+ function updateDiceVisibility(tid, visible) {
+ let div = document.getElementById(`launch-dice-${tid}`)
+ if (visible)
+ div.classList.remove('d-none')
+ else
+ div.classList.add('d-none')
+ }
+
+ /**
+ * Display or hide the box button.
+ * @param tid The tournament id
+ * @param visible The visibility status
+ */
+ function updateBoxVisibility(tid, visible) {
+ let div = document.getElementById(`draw-problem-${tid}`)
+ if (visible)
+ div.classList.remove('d-none')
+ else
+ div.classList.add('d-none')
+ }
+
+ /**
+ * Display or hide the accept and reject buttons.
+ * @param tid The tournament id
+ * @param visible The visibility status
+ */
+ function updateButtonsVisibility(tid, visible) {
+ let div = document.getElementById(`buttons-${tid}`)
+ if (visible)
+ div.classList.remove('d-none')
+ else
+ div.classList.add('d-none')
+ }
+
+ /**
+ * Display or hide the export button.
+ * @param tid The tournament id
+ * @param visible The visibility status
+ */
+ function updateExportVisibility(tid, visible) {
+ let div = document.getElementById(`export-${tid}`)
+ if (visible)
+ div.classList.remove('d-none')
+ else
+ div.classList.add('d-none')
+ }
+
+ /**
+ * Display or hide the continuation button.
+ * @param tid The tournament id
+ * @param visible The visibility status
+ */
+ function updateContinueVisibility(tid, visible) {
+ let div = document.getElementById(`continue-${tid}`)
+ if (div !== null) {
+ // Only present during the final
if (visible)
div.classList.remove('d-none')
else
div.classList.add('d-none')
}
+ }
- /**
- * Display or hide the box button.
- * @param visible The visibility status
- */
- function updateBoxVisibility(visible) {
- let div = document.getElementById(`draw-problem-${tournament.id}`)
- if (visible)
- div.classList.remove('d-none')
- else
- div.classList.add('d-none')
+ /**
+ * Set the different pools for the given round, and update the interface.
+ * @param tid The tournament id
+ * @param round The round number, as integer (1 or 2)
+ * @param poules The list of poules, which are represented with their letters and trigrams,
+ * [{'letter': 'A', 'teams': ['ABC', 'DEF', 'GHI']}]
+ */
+ function updatePoules(tid, round, poules) {
+ let roundList = document.getElementById(`recap-${tid}-round-list`)
+ let poolListId = `recap-${tid}-round-${round}-pool-list`
+ let poolList = document.getElementById(poolListId)
+ if (poolList === null) {
+ // Add a div for the round in the recap div
+ let div = document.createElement('div')
+ div.id = `recap-${tid}-round-${round}`
+ div.classList.add('col-md-6', 'px-3', 'py-3')
+ div.setAttribute('data-tournament', tid)
+
+ let title = document.createElement('strong')
+ title.textContent = 'Tour ' + round
+
+ poolList = document.createElement('ul')
+ poolList.id = poolListId
+ poolList.classList.add('list-group', 'list-group-flush')
+
+ div.append(title, poolList)
+ roundList.append(div)
}
- /**
- * Display or hide the accept and reject buttons.
- * @param visible The visibility status
- */
- function updateButtonsVisibility(visible) {
- let div = document.getElementById(`buttons-${tournament.id}`)
- if (visible)
- div.classList.remove('d-none')
- else
- div.classList.add('d-none')
- }
+ let c = 1
- /**
- * Display or hide the export button.
- * @param visible The visibility status
- */
- function updateExportVisibility(visible) {
- let div = document.getElementById(`export-${tournament.id}`)
- if (visible)
- div.classList.remove('d-none')
- else
- div.classList.add('d-none')
- }
-
- /**
- * Display or hide the continuation button.
- * @param visible The visibility status
- */
- function updateContinueVisibility(visible) {
- let div = document.getElementById(`continue-${tournament.id}`)
- if (visible)
- div.classList.remove('d-none')
- else
- div.classList.add('d-none')
- }
-
- /**
- * Set the different pools for the given round, and update the interface.
- * @param round The round number, as integer (1 or 2)
- * @param poules The list of poules, which are represented with their letters and trigrams,
- * [{'letter': 'A', 'teams': ['ABC', 'DEF', 'GHI']}]
- */
- function updatePoules(round, poules) {
- let roundList = document.getElementById(`recap-${tournament.id}-round-list`)
- let poolListId = `recap-${tournament.id}-round-${round}-pool-list`
- let poolList = document.getElementById(poolListId)
- if (poolList === null) {
- // Add a div for the round in the recap div
- let div = document.createElement('div')
- div.id = `recap-${tournament.id}-round-${round}`
- div.classList.add('col-md-6', 'px-3', 'py-3')
- div.setAttribute('data-tournament', tournament.id)
+ for (let poule of poules) {
+ let teamListId = `recap-${tid}-round-${round}-pool-${poule.letter}-team-list`
+ let teamList = document.getElementById(teamListId)
+ if (teamList === null) {
+ // Add a div for the pool in the recap div
+ let li = document.createElement('li')
+ li.id = `recap-${tid}-round-${round}-pool-${poule.letter}`
+ li.classList.add('list-group-item', 'px-3', 'py-3')
+ li.setAttribute('data-tournament', tid)
let title = document.createElement('strong')
- title.textContent = 'Tour ' + round
+ title.textContent = 'Poule ' + poule.letter + round
- poolList = document.createElement('ul')
- poolList.id = poolListId
- poolList.classList.add('list-group', 'list-group-flush')
+ teamList = document.createElement('ul')
+ teamList.id = teamListId
+ teamList.classList.add('list-group', 'list-group-flush')
- div.append(title, poolList)
- roundList.append(div)
+ li.append(title, teamList)
+ poolList.append(li)
}
- let c = 1
+ if (poule.teams.length > 0) {
+ // The pool is initialized
+ for (let team of poule.teams) {
+ // Reorder dices
+ let diceDiv = document.getElementById(`dice-${tid}-${team}`)
+ diceDiv.parentElement.style.order = c.toString()
+ c += 1
- for (let poule of poules) {
- let teamListId = `recap-${tournament.id}-round-${round}-pool-${poule.letter}-team-list`
- let teamList = document.getElementById(teamListId)
- if (teamList === null) {
- // Add a div for the pool in the recap div
- let li = document.createElement('li')
- li.id = `recap-${tournament.id}-round-${round}-pool-${poule.letter}`
- li.classList.add('list-group-item', 'px-3', 'py-3')
- li.setAttribute('data-tournament', tournament.id)
+ let teamLiId = `recap-${tid}-round-${round}-team-${team}`
+ let teamLi = document.getElementById(teamLiId)
- let title = document.createElement('strong')
- title.textContent = 'Poule ' + poule.letter + round
+ if (teamLi === null) {
+ // Add a line for the team in the recap
+ teamLi = document.createElement('li')
+ teamLi.id = teamLiId
+ teamLi.classList.add('list-group-item')
+ teamLi.setAttribute('data-tournament', tid)
- teamList = document.createElement('ul')
- teamList.id = teamListId
- teamList.classList.add('list-group', 'list-group-flush')
+ teamList.append(teamLi)
+ }
- li.append(title, teamList)
- poolList.append(li)
- }
+ // Add the accepted problem div (empty for now)
+ let acceptedDivId = `recap-${tid}-round-${round}-team-${team}-accepted`
+ let acceptedDiv = document.getElementById(acceptedDivId)
+ if (acceptedDiv === null) {
+ acceptedDiv = document.createElement('div')
+ acceptedDiv.id = acceptedDivId
+ acceptedDiv.classList.add('badge', 'rounded-pill', 'text-bg-warning')
+ acceptedDiv.textContent = `${team} 📃 ?`
+ teamLi.append(acceptedDiv)
+ }
- if (poule.teams.length > 0) {
- // The pool is initialized
- for (let team of poule.teams) {
- // Reorder dices
- let diceDiv = document.getElementById(`dice-${tournament.id}-${team}`)
- diceDiv.parentElement.style.order = c.toString()
- c += 1
-
- let teamLiId = `recap-${tournament.id}-round-${round}-team-${team}`
- let teamLi = document.getElementById(teamLiId)
-
- if (teamLi === null) {
- // Add a line for the team in the recap
- teamLi = document.createElement('li')
- teamLi.id = teamLiId
- teamLi.classList.add('list-group-item')
- teamLi.setAttribute('data-tournament', tournament.id)
-
- teamList.append(teamLi)
- }
-
- // Add the accepted problem div (empty for now)
- let acceptedDivId = `recap-${tournament.id}-round-${round}-team-${team}-accepted`
- let acceptedDiv = document.getElementById(acceptedDivId)
- if (acceptedDiv === null) {
- acceptedDiv = document.createElement('div')
- acceptedDiv.id = acceptedDivId
- acceptedDiv.classList.add('badge', 'rounded-pill', 'text-bg-warning')
- acceptedDiv.textContent = `${team} 📃 ?`
- teamLi.append(acceptedDiv)
- }
-
- // Add the rejected problems div (empty for now)
- let rejectedDivId = `recap-${tournament.id}-round-${round}-team-${team}-rejected`
- let rejectedDiv = document.getElementById(rejectedDivId)
- if (rejectedDiv === null) {
- rejectedDiv = document.createElement('div')
- rejectedDiv.id = rejectedDivId
- rejectedDiv.classList.add('badge', 'rounded-pill', 'text-bg-danger')
- rejectedDiv.textContent = '🗑️'
- teamLi.append(rejectedDiv)
- }
+ // Add the rejected problems div (empty for now)
+ let rejectedDivId = `recap-${tid}-round-${round}-team-${team}-rejected`
+ let rejectedDiv = document.getElementById(rejectedDivId)
+ if (rejectedDiv === null) {
+ rejectedDiv = document.createElement('div')
+ rejectedDiv.id = rejectedDivId
+ rejectedDiv.classList.add('badge', 'rounded-pill', 'text-bg-danger')
+ rejectedDiv.textContent = '🗑️'
+ teamLi.append(rejectedDiv)
}
}
-
- // Draw tables
- let tablesDiv = document.getElementById(`tables-${tournament.id}`)
- let tablesRoundDiv = document.getElementById(`tables-${tournament.id}-round-${round}`)
- if (tablesRoundDiv === null) {
- // Add the tables div for the current round if necessary
- let card = document.createElement('div')
- card.classList.add('card', 'col-md-6')
- tablesDiv.append(card)
-
- let cardHeader = document.createElement('div')
- cardHeader.classList.add('card-header')
- cardHeader.innerHTML = `
Tour ${round}
`
- card.append(cardHeader)
-
- tablesRoundDiv = document.createElement('div')
- tablesRoundDiv.id = `tables-${tournament.id}-round-${round}`
- tablesRoundDiv.classList.add('card-body', 'd-flex', 'flex-wrap')
- card.append(tablesRoundDiv)
- }
-
- for (let poule of poules) {
- if (poule.teams.length === 0)
- continue
-
- // Display the table for the pool
- updatePouleTable(round, poule)
- }
}
- }
- /**
- * Update the table for the given round and the given pool, where there will be the chosen problems.
- * @param round The round number, as integer (1 or 2)
- * @param poule The current pool, which id represented with its letter and trigrams,
- * {'letter': 'A', 'teams': ['ABC', 'DEF', 'GHI']}
- */
- function updatePouleTable(round, poule) {
- let tablesRoundDiv = document.getElementById(`tables-${tournament.id}-round-${round}`)
- let pouleTable = document.getElementById(`table-${tournament.id}-${round}-${poule.letter}`)
- if (pouleTable === null) {
- // Create table
+ // Draw tables
+ let tablesDiv = document.getElementById(`tables-${tid}`)
+ let tablesRoundDiv = document.getElementById(`tables-${tid}-round-${round}`)
+ if (tablesRoundDiv === null) {
+ // Add the tables div for the current round if necessary
let card = document.createElement('div')
- card.classList.add('card', 'w-100', 'my-3', `order-${poule.letter.charCodeAt(0) - 64}`)
- tablesRoundDiv.append(card)
+ card.classList.add('card', 'col-md-6')
+ tablesDiv.append(card)
let cardHeader = document.createElement('div')
cardHeader.classList.add('card-header')
- cardHeader.innerHTML = `
Poule ${poule.letter}${round}
`
+ cardHeader.innerHTML = `
Tour ${round}
`
card.append(cardHeader)
- let cardBody = document.createElement('div')
- cardBody.classList.add('card-body')
- card.append(cardBody)
+ tablesRoundDiv = document.createElement('div')
+ tablesRoundDiv.id = `tables-${tid}-round-${round}`
+ tablesRoundDiv.classList.add('card-body', 'd-flex', 'flex-wrap')
+ card.append(tablesRoundDiv)
+ }
- pouleTable = document.createElement('table')
- pouleTable.id = `table-${tournament.id}-${round}-${poule.letter}`
- pouleTable.classList.add('table', 'table-stripped')
- cardBody.append(pouleTable)
+ for (let poule of poules) {
+ if (poule.teams.length === 0)
+ continue
- let thead = document.createElement('thead')
- pouleTable.append(thead)
+ // Display the table for the pool
+ updatePouleTable(tid, round, poule)
+ }
+ }
+ }
- let phaseTr = document.createElement('tr')
- thead.append(phaseTr)
+ /**
+ * Update the table for the given round and the given pool, where there will be the chosen problems.
+ * @param tid The tournament id
+ * @param round The round number, as integer (1 or 2)
+ * @param poule The current pool, which id represented with its letter and trigrams,
+ * {'letter': 'A', 'teams': ['ABC', 'DEF', 'GHI']}
+ */
+ function updatePouleTable(tid, round, poule) {
+ let tablesRoundDiv = document.getElementById(`tables-${tid}-round-${round}`)
+ let pouleTable = document.getElementById(`table-${tid}-${round}-${poule.letter}`)
+ if (pouleTable === null) {
+ // Create table
+ let card = document.createElement('div')
+ card.classList.add('card', 'w-100', 'my-3', `order-${poule.letter.charCodeAt(0) - 64}`)
+ tablesRoundDiv.append(card)
- let teamTh = document.createElement('th')
- teamTh.classList.add('text-center')
- teamTh.rowSpan = poule.teams.length === 5 ? 3 : 2
- teamTh.textContent = "Équipe"
- phaseTr.append(teamTh)
+ let cardHeader = document.createElement('div')
+ cardHeader.classList.add('card-header')
+ cardHeader.innerHTML = `
Poule ${poule.letter}${round}
`
+ card.append(cardHeader)
- // Add columns
- for (let i = 1; i <= (poule.teams.length === 4 ? 4 : 3); ++i) {
- let phaseTh = document.createElement('th')
- phaseTh.classList.add('text-center')
- if (poule.teams.length === 5 && i < 3)
- phaseTh.colSpan = 2
- phaseTh.textContent = `Phase ${i}`
- phaseTr.append(phaseTh)
+ let cardBody = document.createElement('div')
+ cardBody.classList.add('card-body')
+ card.append(cardBody)
+
+ pouleTable = document.createElement('table')
+ pouleTable.id = `table-${tid}-${round}-${poule.letter}`
+ pouleTable.classList.add('table', 'table-stripped')
+ cardBody.append(pouleTable)
+
+ let thead = document.createElement('thead')
+ pouleTable.append(thead)
+
+ let phaseTr = document.createElement('tr')
+ thead.append(phaseTr)
+
+ let teamTh = document.createElement('th')
+ teamTh.classList.add('text-center')
+ teamTh.rowSpan = poule.teams.length === 5 ? 3 : 2
+ teamTh.textContent = "Équipe"
+ phaseTr.append(teamTh)
+
+ // Add columns
+ for (let i = 1; i <= (poule.teams.length === 4 ? 4 : 3); ++i) {
+ let phaseTh = document.createElement('th')
+ phaseTh.classList.add('text-center')
+ if (poule.teams.length === 5 && i < 3)
+ phaseTh.colSpan = 2
+ phaseTh.textContent = `Phase ${i}`
+ phaseTr.append(phaseTh)
+ }
+
+ if (poule.teams.length === 5) {
+ let roomTr = document.createElement('tr')
+ thead.append(roomTr)
+
+ for (let i = 0; i < 5; ++i) {
+ let roomTh = document.createElement('th')
+ roomTh.classList.add('text-center')
+ roomTh.textContent = `Salle ${1 + (i % 2)}`
+ roomTr.append(roomTh)
}
+ }
- if (poule.teams.length === 5) {
- let roomTr = document.createElement('tr')
- thead.append(roomTr)
+ let problemTr = document.createElement('tr')
+ thead.append(problemTr)
- for (let i = 0; i < 5; ++i) {
- let roomTh = document.createElement('th')
- roomTh.classList.add('text-center')
- roomTh.textContent = `Salle ${1 + (i % 2)}`
- roomTr.append(roomTh)
+ for (let team of poule.teams) {
+ let problemTh = document.createElement('th')
+ problemTh.classList.add('text-center')
+ // Problem is unknown for now
+ problemTh.innerHTML = `Pb. ?`
+ problemTr.append(problemTh)
+ }
+
+ // Add body
+ let tbody = document.createElement('tbody')
+ pouleTable.append(tbody)
+
+ for (let i = 0; i < poule.teams.length; ++i) {
+ let team = poule.teams[i]
+
+ let teamTr = document.createElement('tr')
+ tbody.append(teamTr)
+
+ // First create cells, then we will add them in the table
+ let teamTd = document.createElement('td')
+ teamTd.classList.add('text-center')
+ teamTd.innerText = team
+ teamTr.append(teamTd)
+
+ let defenderTd = document.createElement('td')
+ defenderTd.classList.add('text-center')
+ defenderTd.innerText = 'Déf'
+
+ let opponentTd = document.createElement('td')
+ opponentTd.classList.add('text-center')
+ opponentTd.innerText = 'Opp'
+
+ let reporterTd = document.createElement('td')
+ reporterTd.classList.add('text-center')
+ reporterTd.innerText = 'Rap'
+
+ // Put the cells in their right places, according to the pool size and the row number.
+ if (poule.teams.length === 3) {
+ switch (i) {
+ case 0:
+ teamTr.append(defenderTd, reporterTd, opponentTd)
+ break
+ case 1:
+ teamTr.append(opponentTd, defenderTd, reporterTd)
+ break
+ case 2:
+ teamTr.append(reporterTd, opponentTd, defenderTd)
+ break
}
}
-
- let problemTr = document.createElement('tr')
- thead.append(problemTr)
-
- for (let team of poule.teams) {
- let problemTh = document.createElement('th')
- problemTh.classList.add('text-center')
- // Problem is unknown for now
- problemTh.innerHTML = `Pb. ?`
- problemTr.append(problemTh)
+ else if (poule.teams.length === 4) {
+ let emptyTd = document.createElement('td')
+ switch (i) {
+ case 0:
+ teamTr.append(defenderTd, emptyTd, reporterTd, opponentTd)
+ break
+ case 1:
+ teamTr.append(opponentTd, defenderTd, emptyTd, reporterTd)
+ break
+ case 2:
+ teamTr.append(reporterTd, opponentTd, defenderTd, emptyTd)
+ break
+ case 3:
+ teamTr.append(emptyTd, reporterTd, opponentTd, defenderTd)
+ break
+ }
}
-
- // Add body
- let tbody = document.createElement('tbody')
- pouleTable.append(tbody)
-
- for (let i = 0; i < poule.teams.length; ++i) {
- let team = poule.teams[i]
-
- let teamTr = document.createElement('tr')
- tbody.append(teamTr)
-
- // First create cells, then we will add them in the table
- let teamTd = document.createElement('td')
- teamTd.classList.add('text-center')
- teamTd.innerText = team
- teamTr.append(teamTd)
-
- let defenderTd = document.createElement('td')
- defenderTd.classList.add('text-center')
- defenderTd.innerText = 'Déf'
-
- let opponentTd = document.createElement('td')
- opponentTd.classList.add('text-center')
- opponentTd.innerText = 'Opp'
-
- let reporterTd = document.createElement('td')
- reporterTd.classList.add('text-center')
- reporterTd.innerText = 'Rap'
-
- // Put the cells in their right places, according to the pool size and the row number.
- if (poule.teams.length === 3) {
- switch (i) {
- case 0:
- teamTr.append(defenderTd, reporterTd, opponentTd)
- break
- case 1:
- teamTr.append(opponentTd, defenderTd, reporterTd)
- break
- case 2:
- teamTr.append(reporterTd, opponentTd, defenderTd)
- break
- }
- }
- else if (poule.teams.length === 4) {
- let emptyTd = document.createElement('td')
- switch (i) {
- case 0:
- teamTr.append(defenderTd, emptyTd, reporterTd, opponentTd)
- break
- case 1:
- teamTr.append(opponentTd, defenderTd, emptyTd, reporterTd)
- break
- case 2:
- teamTr.append(reporterTd, opponentTd, defenderTd, emptyTd)
- break
- case 3:
- teamTr.append(emptyTd, reporterTd, opponentTd, defenderTd)
- break
- }
- }
- else if (poule.teams.length === 5) {
- let emptyTd = document.createElement('td')
- let emptyTd2 = document.createElement('td')
- switch (i) {
- case 0:
- teamTr.append(defenderTd, emptyTd, opponentTd, reporterTd, emptyTd2)
- break
- case 1:
- teamTr.append(emptyTd, defenderTd, reporterTd, emptyTd2, opponentTd)
- break
- case 2:
- teamTr.append(opponentTd, emptyTd, defenderTd, emptyTd2, reporterTd)
- break
- case 3:
- teamTr.append(reporterTd, opponentTd, emptyTd, defenderTd, emptyTd2)
- break
- case 4:
- teamTr.append(emptyTd, reporterTd, emptyTd2, opponentTd, defenderTd)
- break
- }
+ else if (poule.teams.length === 5) {
+ let emptyTd = document.createElement('td')
+ let emptyTd2 = document.createElement('td')
+ switch (i) {
+ case 0:
+ teamTr.append(defenderTd, emptyTd, opponentTd, reporterTd, emptyTd2)
+ break
+ case 1:
+ teamTr.append(emptyTd, defenderTd, reporterTd, emptyTd2, opponentTd)
+ break
+ case 2:
+ teamTr.append(opponentTd, emptyTd, defenderTd, emptyTd2, reporterTd)
+ break
+ case 3:
+ teamTr.append(reporterTd, opponentTd, emptyTd, defenderTd, emptyTd2)
+ break
+ case 4:
+ teamTr.append(emptyTd, reporterTd, emptyTd2, opponentTd, defenderTd)
+ break
}
}
}
}
+ }
- /**
- * Highligh the team that is currently choosing its problem.
- * @param round The current round number, as integer (1 or 2)
- * @param pool The current pool letter (A, B, C or D) (null if non-relevant)
- * @param team The current team trigram (null if non-relevant)
- */
- function updateActiveRecap(round, pool, team) {
- // Remove the previous highlights
- document.querySelectorAll(`div.text-bg-secondary[data-tournament="${tournament.id}"]`)
- .forEach(elem => elem.classList.remove('text-bg-secondary'))
- document.querySelectorAll(`li.list-group-item-success[data-tournament="${tournament.id}"]`)
- .forEach(elem => elem.classList.remove('list-group-item-success'))
- document.querySelectorAll(`li.list-group-item-info[data-tournament="${tournament.id}"]`)
- .forEach(elem => elem.classList.remove('list-group-item-info'))
+ /**
+ * Highlight the team that is currently choosing its problem.
+ * @param tid The tournament id
+ * @param round The current round number, as integer (1 or 2)
+ * @param pool The current pool letter (A, B, C or D) (null if non-relevant)
+ * @param team The current team trigram (null if non-relevant)
+ */
+ function updateActiveRecap(tid, round, pool, team) {
+ // Remove the previous highlights
+ document.querySelectorAll(`div.text-bg-secondary[data-tournament="${tid}"]`)
+ .forEach(elem => elem.classList.remove('text-bg-secondary'))
+ document.querySelectorAll(`li.list-group-item-success[data-tournament="${tid}"]`)
+ .forEach(elem => elem.classList.remove('list-group-item-success'))
+ document.querySelectorAll(`li.list-group-item-info[data-tournament="${tid}"]`)
+ .forEach(elem => elem.classList.remove('list-group-item-info'))
- // Highlight current round, if existing
- let roundDiv = document.getElementById(`recap-${tournament.id}-round-${round}`)
- if (roundDiv !== null)
- roundDiv.classList.add('text-bg-secondary')
+ // Highlight current round, if existing
+ let roundDiv = document.getElementById(`recap-${tid}-round-${round}`)
+ if (roundDiv !== null)
+ roundDiv.classList.add('text-bg-secondary')
- // Highlight current pool, if existing
- let poolLi = document.getElementById(`recap-${tournament.id}-round-${round}-pool-${pool}`)
- if (poolLi !== null)
- poolLi.classList.add('list-group-item-success')
+ // Highlight current pool, if existing
+ let poolLi = document.getElementById(`recap-${tid}-round-${round}-pool-${pool}`)
+ if (poolLi !== null)
+ poolLi.classList.add('list-group-item-success')
- // Highlight current team, if existing
- let teamLi = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}`)
- if (teamLi !== null)
- teamLi.classList.add('list-group-item-info')
+ // Highlight current team, if existing
+ let teamLi = document.getElementById(`recap-${tid}-round-${round}-team-${team}`)
+ if (teamLi !== null)
+ teamLi.classList.add('list-group-item-info')
+ }
+
+ /**
+ * Update the recap and the table when a team accepts a problem.
+ * @param tid The tournament id
+ * @param round The current round, as integer (1 or 2)
+ * @param team The current team trigram
+ * @param problem The accepted problem, as integer
+ */
+ function setProblemAccepted(tid, round, team, problem) {
+ // Update recap
+ let recapDiv = document.getElementById(`recap-${tid}-round-${round}-team-${team}-accepted`)
+ if (problem !== null) {
+ recapDiv.classList.remove('text-bg-warning')
+ recapDiv.classList.add('text-bg-success')
}
-
- /**
- * Update the recap and the table when a team accepts a problem.
- * @param round The current round, as integer (1 or 2)
- * @param team The current team trigram
- * @param problem The accepted problem, as integer
- */
- function setProblemAccepted(round, team, problem) {
- // Update recap
- let recapDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-accepted`)
- if (problem !== null) {
- recapDiv.classList.remove('text-bg-warning')
- recapDiv.classList.add('text-bg-success')
- }
- else {
- recapDiv.classList.add('text-bg-warning')
- recapDiv.classList.remove('text-bg-success')
- }
- recapDiv.textContent = `${team} 📃 ${problem ? problem : '?'}`
-
- // Update table
- let tableSpan = document.getElementById(`table-${tournament.id}-round-${round}-problem-${team}`)
- tableSpan.textContent = problem ? problem : '?'
+ else {
+ recapDiv.classList.add('text-bg-warning')
+ recapDiv.classList.remove('text-bg-success')
}
+ recapDiv.textContent = `${team} 📃 ${problem ? problem : '?'}`
- /**
- * Update the recap when a team rejects a problem.
- * @param round The current round, as integer (1 or 2)
- * @param team The current team trigram
- * @param rejected The full list of rejected problems
- */
- function setProblemRejected(round, team, rejected) {
- // Update recap
- let recapDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-rejected`)
- recapDiv.textContent = `🗑️ ${rejected.join(', ')}`
+ // Update table
+ let tableSpan = document.getElementById(`table-${tid}-round-${round}-problem-${team}`)
+ tableSpan.textContent = problem ? problem : '?'
+ }
- let penaltyDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-penalty`)
- if (rejected.length > problems_count - 5) {
- // If more than P - 5 problems were rejected, add a penalty of 0.5 of the coefficient of the oral defender
- if (penaltyDiv === null) {
- penaltyDiv = document.createElement('div')
- penaltyDiv.id = `recap-${tournament.id}-round-${round}-team-${team}-penalty`
- penaltyDiv.classList.add('badge', 'rounded-pill', 'text-bg-info')
- recapDiv.parentNode.append(penaltyDiv)
- }
- penaltyDiv.textContent = `❌ ${0.5 * (rejected.length - (problems_count - 5))}`
- }
- else {
- // Eventually remove this div
- if (penaltyDiv !== null)
- penaltyDiv.remove()
+ /**
+ * Update the recap when a team rejects a problem.
+ * @param tid The tournament id
+ * @param round The current round, as integer (1 or 2)
+ * @param team The current team trigram
+ * @param rejected The full list of rejected problems
+ */
+ function setProblemRejected(tid, round, team, rejected) {
+ // Update recap
+ let recapDiv = document.getElementById(`recap-${tid}-round-${round}-team-${team}-rejected`)
+ recapDiv.textContent = `🗑️ ${rejected.join(', ')}`
+
+ let penaltyDiv = document.getElementById(`recap-${tid}-round-${round}-team-${team}-penalty`)
+ if (rejected.length > problems_count - 5) {
+ // If more than P - 5 problems were rejected, add a penalty of 0.5 of the coefficient of the oral defender
+ if (penaltyDiv === null) {
+ penaltyDiv = document.createElement('div')
+ penaltyDiv.id = `recap-${tid}-round-${round}-team-${team}-penalty`
+ penaltyDiv.classList.add('badge', 'rounded-pill', 'text-bg-info')
+ recapDiv.parentNode.append(penaltyDiv)
}
+ penaltyDiv.textContent = `❌ ${0.5 * (rejected.length - (problems_count - 5))}`
}
-
- /**
- * For a 5-teams pool, we may reorder the pool if two teams select the same problem.
- * Then, we redraw the table and set the accepted problems.
- * @param round The current round, as integer (1 or 2)
- * @param poule The pool represented by its letter
- * @param teams The teams list represented by their trigrams, ["ABC", "DEF", "GHI", "JKL", "MNO"]
- * @param problems The accepted problems in the same order than the teams, [1, 1, 2, 2, 3]
- */
- function reorderPoule(round, poule, teams, problems) {
- // Redraw the pool table
- let table = document.getElementById(`table-${tournament.id}-${round}-${poule}`)
- table.parentElement.parentElement.remove()
-
- updatePouleTable(round, {'letter': poule, 'teams': teams})
-
- // Put the problems in the table
- for (let i = 0; i < teams.length; ++i) {
- let team = teams[i]
- let problem = problems[i]
-
- setProblemAccepted(round, team, problem)
- }
+ else {
+ // Eventually remove this div
+ if (penaltyDiv !== null)
+ penaltyDiv.remove()
}
+ }
- // Listen on websockets and process messages from the server
- socket.addEventListener('message', e => {
- // Parse received data as JSON
- const data = JSON.parse(e.data)
+ /**
+ * For a 5-teams pool, we may reorder the pool if two teams select the same problem.
+ * Then, we redraw the table and set the accepted problems.
+ * @param tid The tournament id
+ * @param round The current round, as integer (1 or 2)
+ * @param poule The pool represented by its letter
+ * @param teams The teams list represented by their trigrams, ["ABC", "DEF", "GHI", "JKL", "MNO"]
+ * @param problems The accepted problems in the same order than the teams, [1, 1, 2, 2, 3]
+ */
+ function reorderPoule(tid, round, poule, teams, problems) {
+ // Redraw the pool table
+ let table = document.getElementById(`table-${tid}-${round}-${poule}`)
+ table.parentElement.parentElement.remove()
- switch (data.type) {
- case 'alert':
- // Add alert message
- addMessage(data.message, data.alert_type)
- break
- case 'notification':
- // Add notification
- showNotification(data.title, data.body)
- break
- case 'set_info':
- // Update information banner
- setInfo(data.information)
- break
- case 'draw_start':
- // Start the draw and update the interface
- drawStart(data.trigrams)
- break
- case 'abort':
- // Abort the current draw
- drawAbort()
- break
- case 'dice':
- // Update the interface after a dice launch
- updateDiceInfo(data.team, data.result)
- break
- case 'dice_visibility':
- // Update the dice button visibility
- updateDiceVisibility(data.visible)
- break
- case 'box_visibility':
- // Update the box button visibility
- updateBoxVisibility(data.visible)
- break
- case 'buttons_visibility':
- // Update the accept/reject buttons visibility
- updateButtonsVisibility(data.visible)
- break
- case 'export_visibility':
- // Update the export button visibility
- updateExportVisibility(data.visible)
- break
- case 'continue_visibility':
- // Update the continue button visibility for the final tournament
- updateContinueVisibility(data.visible)
- break
- case 'set_poules':
- // Set teams order and pools and update the interface
- updatePoules(data.round, data.poules)
- break
- case 'set_active':
- // Highlight the team that is selecting a problem
- updateActiveRecap(data.round, data.poule, data.team)
- break
- case 'set_problem':
- // Mark a problem as accepted and update the interface
- setProblemAccepted(data.round, data.team, data.problem)
- break
- case 'reject_problem':
- // Mark a problem as rejected and update the interface
- setProblemRejected(data.round, data.team, data.rejected)
- break
- case 'reorder_poule':
- // Reorder a pool and redraw the associated table
- reorderPoule(data.round, data.poule, data.teams, data.problems)
- break
- }
- })
+ updatePouleTable(tid, round, {'letter': poule, 'teams': teams})
- // Manage errors
- socket.addEventListener('close', e => {
- console.error('Chat socket closed unexpectedly')
- })
+ // Put the problems in the table
+ for (let i = 0; i < teams.length; ++i) {
+ let team = teams[i]
+ let problem = problems[i]
- // When the socket is opened, set the language in order to receive alerts in the good language
- socket.addEventListener('open', e => {
- socket.send(JSON.stringify({
- 'type': 'set_language',
- 'language': document.getElementsByName('language')[0].value,
- }))
- })
+ setProblemAccepted(tid, round, team, problem)
+ }
+ }
+ /**
+ * Process the received data from the server.
+ * @param tid The tournament id
+ * @param data The received message
+ */
+ function processMessage(tid, data) {
+ switch (data.type) {
+ case 'alert':
+ // Add alert message
+ addMessage(data.message, data.alert_type)
+ break
+ case 'notification':
+ // Add notification
+ showNotification(data.title, data.body)
+ break
+ case 'set_info':
+ // Update information banner
+ setInfo(tid, data.information)
+ break
+ case 'draw_start':
+ // Start the draw and update the interface
+ drawStart(tid, data.trigrams)
+ break
+ case 'abort':
+ // Abort the current draw
+ drawAbort(tid)
+ break
+ case 'dice':
+ // Update the interface after a dice launch
+ updateDiceInfo(tid, data.team, data.result)
+ break
+ case 'dice_visibility':
+ // Update the dice button visibility
+ updateDiceVisibility(tid, data.visible)
+ break
+ case 'box_visibility':
+ // Update the box button visibility
+ updateBoxVisibility(tid, data.visible)
+ break
+ case 'buttons_visibility':
+ // Update the accept/reject buttons visibility
+ updateButtonsVisibility(tid, data.visible)
+ break
+ case 'export_visibility':
+ // Update the export button visibility
+ updateExportVisibility(tid, data.visible)
+ break
+ case 'continue_visibility':
+ // Update the continue button visibility for the final tournament
+ updateContinueVisibility(tid, data.visible)
+ break
+ case 'set_poules':
+ // Set teams order and pools and update the interface
+ updatePoules(tid, data.round, data.poules)
+ break
+ case 'set_active':
+ // Highlight the team that is selecting a problem
+ updateActiveRecap(tid, data.round, data.poule, data.team)
+ break
+ case 'set_problem':
+ // Mark a problem as accepted and update the interface
+ setProblemAccepted(tid, data.round, data.team, data.problem)
+ break
+ case 'reject_problem':
+ // Mark a problem as rejected and update the interface
+ setProblemRejected(tid, data.round, data.team, data.rejected)
+ break
+ case 'reorder_poule':
+ // Reorder a pool and redraw the associated table
+ reorderPoule(tid, data.round, data.poule, data.teams, data.problems)
+ break
+ }
+ }
+
+ // Listen on websockets and process messages from the server
+ socket.addEventListener('message', e => {
+ // Parse received data as JSON
+ const data = JSON.parse(e.data)
+
+ processMessage(data['tid'], data)
+ })
+
+ // Manage errors
+ socket.addEventListener('close', e => {
+ console.error('Chat socket closed unexpectedly')
+ })
+
+ // When the socket is opened, set the language in order to receive alerts in the good language
+ socket.addEventListener('open', e => {
+ socket.send(JSON.stringify({
+ 'tid': tournaments[0].id,
+ 'type': 'set_language',
+ 'language': document.getElementsByName('language')[0].value,
+ }))
+ })
+
+ for (let tournament of tournaments) {
// Manage the start form
let format_form = document.getElementById('format-form-' + tournament.id)
if (format_form !== null) {
@@ -753,6 +780,7 @@ document.addEventListener('DOMContentLoaded', () => {
e.preventDefault()
socket.send(JSON.stringify({
+ 'tid': tournament.id,
'type': 'start_draw',
'fmt': document.getElementById('format-' + tournament.id).value
}))
diff --git a/draw/tests.py b/draw/tests.py
index 3b45cde..69a8f84 100644
--- a/draw/tests.py
+++ b/draw/tests.py
@@ -1,6 +1,6 @@
# Copyright (C) 2023 by Animath
# SPDX-License-Identifier: GPL-3.0-or-later
-
+import asyncio
from random import shuffle
from asgiref.sync import sync_to_async
@@ -48,25 +48,26 @@ class TestDraw(TestCase):
"""
await sync_to_async(self.async_client.force_login)(self.superuser)
+ tid = self.tournament.id
+
resp = await self.async_client.get(reverse('draw:index'))
self.assertEqual(resp.status_code, 200)
# Connect to Websocket
headers = [(b'cookie', self.async_client.cookies.output(header='', sep='; ').encode())]
communicator = WebsocketCommunicator(AuthMiddlewareStack(URLRouter(routing.websocket_urlpatterns)),
- f"/ws/draw/{self.tournament.id}/",
- headers)
+ "/ws/draw/", headers)
connected, subprotocol = await communicator.connect()
self.assertTrue(connected)
# Define language
- await communicator.send_json_to({'type': 'set_language', 'language': 'en'})
+ await communicator.send_json_to({'tid': tid, 'type': 'set_language', 'language': 'en'})
# Ensure that Draw has not started
self.assertFalse(await Draw.objects.filter(tournament=self.tournament).aexists())
# Must be an error since 1+1+1 != 12
- await communicator.send_json_to({'type': 'start_draw', 'fmt': '1+1+1'})
+ await communicator.send_json_to({'tid': tid, 'type': 'start_draw', 'fmt': '1+1+1'})
resp = await communicator.receive_json_from()
self.assertEqual(resp['type'], 'alert')
self.assertEqual(resp['alert_type'], 'danger')
@@ -74,29 +75,30 @@ class TestDraw(TestCase):
self.assertFalse(await Draw.objects.filter(tournament=self.tournament).aexists())
# Now start the draw
- await communicator.send_json_to({'type': 'start_draw', 'fmt': '3+4+5'})
+ await communicator.send_json_to({'tid': tid, 'type': 'start_draw', 'fmt': '3+4+5'})
# Receive data after the start
self.assertEqual((await communicator.receive_json_from())['type'], 'alert')
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'set_poules', 'round': 1,
+ {'tid': tid, 'type': 'set_poules', 'round': 1,
'poules': [{'letter': 'A', 'teams': []},
{'letter': 'B', 'teams': []},
{'letter': 'C', 'teams': []}]})
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'set_poules', 'round': 2,
+ {'tid': tid, 'type': 'set_poules', 'round': 2,
'poules': [{'letter': 'A', 'teams': []},
{'letter': 'B', 'teams': []},
{'letter': 'C', 'teams': []}]})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'dice_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'alert')
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'draw_start', 'fmt': [5, 4, 3],
+ {'tid': tid, 'type': 'draw_start', 'fmt': [5, 4, 3],
'trigrams': ['AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF',
'GGG', 'HHH', 'III', 'JJJ', 'KKK', 'LLL']})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'set_active', 'round': 1, 'poule': None, 'team': None})
+ {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': None, 'team': None})
self.assertEqual((await communicator.receive_json_from())['type'], 'notification')
# Ensure that now tournament has started
@@ -107,7 +109,7 @@ class TestDraw(TestCase):
self.assertEqual(resp.status_code, 200)
# Try to relaunch the draw
- await communicator.send_json_to({'type': 'start_draw', 'fmt': '3+4+5'})
+ await communicator.send_json_to({'tid': tid, 'type': 'start_draw', 'fmt': '3+4+5'})
resp = await communicator.receive_json_from()
self.assertEqual(resp['type'], 'alert')
self.assertEqual(resp['alert_type'], 'danger')
@@ -119,7 +121,7 @@ class TestDraw(TestCase):
for i, team in enumerate(self.teams):
# Launch a new dice
- await communicator.send_json_to({'type': "dice", 'trigram': team.trigram})
+ await communicator.send_json_to({'tid': tid, 'type': "dice", 'trigram': team.trigram})
resp = await communicator.receive_json_from()
self.assertEqual(resp['type'], "dice")
self.assertEqual(resp['team'], team.trigram)
@@ -130,7 +132,7 @@ class TestDraw(TestCase):
self.assertEqual(resp['result'], td.passage_dice)
# Try to relaunch the dice
- await communicator.send_json_to({'type': "dice", 'trigram': team.trigram})
+ await communicator.send_json_to({'tid': tid, 'type': "dice", 'trigram': team.trigram})
resp = await communicator.receive_json_from()
self.assertEqual(resp['type'], 'alert')
self.assertEqual(resp['message'], "You've already launched the dice.")
@@ -151,7 +153,7 @@ class TestDraw(TestCase):
self.assertEqual((await communicator.receive_json_from())['type'], 'alert')
for i in range(dup_count):
- await communicator.send_json_to({'type': "dice", 'trigram': None})
+ await communicator.send_json_to({'tid': tid, 'type': "dice", 'trigram': None})
await communicator.receive_json_from()
# Reset dices
@@ -161,8 +163,10 @@ class TestDraw(TestCase):
self.assertIsNone(resp['result'])
# Hide and re-display the dice
- self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': False})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'dice_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'dice_visibility', 'visible': True})
# Set pools for the two rounds
self.assertEqual((await communicator.receive_json_from())['type'], 'set_poules')
@@ -172,7 +176,7 @@ class TestDraw(TestCase):
# Manage the first pool
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'set_active', 'round': 1, 'poule': 'A', 'team': None})
+ {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'A', 'team': None})
r: Round = await Round.objects.prefetch_related('current_pool__current_team__participation__team')\
.aget(number=1, draw=draw)
p = r.current_pool
@@ -188,7 +192,7 @@ class TestDraw(TestCase):
i = 0
async for td in p.teamdraw_set.prefetch_related('participation__team').all():
# Launch a new dice
- await communicator.send_json_to({'type': "dice", 'trigram': td.participation.team.trigram})
+ await communicator.send_json_to({'tid': tid, 'type': "dice", 'trigram': td.participation.team.trigram})
resp = await communicator.receive_json_from()
self.assertEqual(resp['type'], "dice")
trigram = td.participation.team.trigram
@@ -200,7 +204,7 @@ class TestDraw(TestCase):
self.assertEqual(resp['result'], td.choice_dice)
# Try to relaunch the dice
- await communicator.send_json_to({'type': "dice", 'trigram': trigram})
+ await communicator.send_json_to({'tid': tid, 'type': "dice", 'trigram': trigram})
resp = await communicator.receive_json_from()
self.assertEqual(resp['type'], 'alert')
self.assertEqual(resp['message'], "You've already launched the dice.")
@@ -222,7 +226,7 @@ class TestDraw(TestCase):
self.assertEqual((await communicator.receive_json_from())['type'], 'alert')
for i in range(dup_count):
- await communicator.send_json_to({'type': "dice", 'trigram': None})
+ await communicator.send_json_to({'tid': tid, 'type': "dice", 'trigram': None})
await communicator.receive_json_from()
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
@@ -232,27 +236,32 @@ class TestDraw(TestCase):
td = p.current_team
trigram = td.participation.team.trigram
self.assertEqual(td.choose_index, 0)
- self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'A',
- 'team': td.participation.team.trigram})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'set_active', 'round': 1,
+ 'poule': 'A', 'team': td.participation.team.trigram})
# Dice is hidden for everyone first
- self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'dice_visibility', 'visible': False})
# The draw box is displayed for the current team and for volunteers
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': True})
# Render page
resp = await self.async_client.get(reverse('draw:index'))
self.assertEqual(resp.status_code, 200)
# Try to launch a dice while it is not the time
- await communicator.send_json_to({'type': 'dice', 'trigram': None})
+ await communicator.send_json_to({'tid': tid, 'type': 'dice', 'trigram': None})
resp = await communicator.receive_json_from()
self.assertEqual(resp['type'], 'alert')
self.assertEqual(resp['message'], "This is not the time for this.")
# Draw a problem
- await communicator.send_json_to({'type': 'draw_problem'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': True})
+ await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
@@ -265,17 +274,19 @@ class TestDraw(TestCase):
self.assertEqual(resp.status_code, 200)
# Try to redraw a problem while it is not the time
- await communicator.send_json_to({'type': 'draw_problem'})
+ await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'})
resp = await communicator.receive_json_from()
self.assertEqual(resp['type'], 'alert')
self.assertEqual(resp['message'], "This is not the time for this.")
# Reject the first problem
- await communicator.send_json_to({'type': 'reject'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': False})
+ await communicator.send_json_to({'tid': tid, 'type': 'reject'})
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'reject_problem', 'round': 1, 'team': trigram, 'rejected': [purposed]})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': True})
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'reject_problem', 'round': 1, 'team': trigram, 'rejected': [purposed]})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
self.assertIsNone(td.purposed)
@@ -287,17 +298,19 @@ class TestDraw(TestCase):
td = p.current_team
trigram = td.participation.team.trigram
self.assertEqual(td.choose_index, i + 1)
- self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'A',
- 'team': trigram})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'A', 'team': trigram})
# Render page
resp = await self.async_client.get(reverse('draw:index'))
self.assertEqual(resp.status_code, 200)
# Draw a problem
- await communicator.send_json_to({'type': 'draw_problem'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': True})
+ await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
@@ -313,11 +326,13 @@ class TestDraw(TestCase):
self.assertEqual(resp.status_code, 200)
# Accept the problem
- await communicator.send_json_to({'type': 'accept'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': False})
+ await communicator.send_json_to({'tid': tid, 'type': 'accept'})
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'set_problem', 'round': 1, 'team': trigram, 'problem': 1 + (i % 2)})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': True})
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'set_problem', 'round': 1, 'team': trigram, 'problem': 1 + (i % 2)})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
self.assertIsNone(td.purposed)
@@ -332,15 +347,17 @@ class TestDraw(TestCase):
td = p.current_team
trigram = td.participation.team.trigram
self.assertEqual(td.choose_index, 0)
- self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'A',
- 'team': trigram})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'A', 'team': trigram})
# Draw and reject 100 times a problem
for _i in range(100):
# Draw a problem
- await communicator.send_json_to({'type': 'draw_problem'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': True})
+ await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
@@ -349,10 +366,12 @@ class TestDraw(TestCase):
self.assertIn(td.purposed, range(3, len(settings.PROBLEMS) + 1))
# Reject
- await communicator.send_json_to({'type': 'reject'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': False})
+ await communicator.send_json_to({'tid': tid, 'type': 'reject'})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': False})
self.assertEqual((await communicator.receive_json_from())['type'], 'reject_problem')
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
self.assertIsNone(td.purposed)
@@ -361,8 +380,8 @@ class TestDraw(TestCase):
# Ensures that this is still the first team
p: Pool = await Pool.objects.prefetch_related('current_team__participation__team').aget(round=r, letter=1)
self.assertEqual(p.current_team, td)
- self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'A',
- 'team': trigram})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'A', 'team': trigram})
# Render page
resp = await self.async_client.get(reverse('draw:index'))
@@ -372,9 +391,11 @@ class TestDraw(TestCase):
self.assertGreaterEqual(td.penalty, 1)
# Draw a last problem
- await communicator.send_json_to({'type': 'draw_problem'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': True})
+ await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
@@ -382,19 +403,21 @@ class TestDraw(TestCase):
self.assertIn(td.purposed, range(1, len(settings.PROBLEMS) + 1))
# Accept the problem
- await communicator.send_json_to({'type': 'accept'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': False})
+ await communicator.send_json_to({'tid': tid, 'type': 'accept'})
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'set_problem', 'round': 1, 'team': trigram, 'problem': td.purposed})
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'set_problem', 'round': 1, 'team': trigram, 'problem': td.purposed})
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
self.assertIsNone(td.purposed)
# Reorder the pool since there are 5 teams
self.assertEqual((await communicator.receive_json_from())['type'], 'reorder_poule')
- self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'dice_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'set_active', 'round': 1, 'poule': 'B', 'team': None})
+ {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'B', 'team': None})
# Start pool 2
r: Round = await Round.objects.prefetch_related('current_pool__current_team__participation__team')\
@@ -412,7 +435,7 @@ class TestDraw(TestCase):
i = 0
async for td in p.teamdraw_set.prefetch_related('participation__team').all():
# Launch a new dice
- await communicator.send_json_to({'type': "dice", 'trigram': td.participation.team.trigram})
+ await communicator.send_json_to({'tid': tid, 'type': "dice", 'trigram': td.participation.team.trigram})
await communicator.receive_json_from()
await td.arefresh_from_db()
td.choice_dice = 101 + i # Avoid duplicates
@@ -427,20 +450,24 @@ class TestDraw(TestCase):
td = p.current_team
trigram = td.participation.team.trigram
self.assertEqual(td.choose_index, i)
- self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'B',
- 'team': trigram})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'B', 'team': trigram})
if i == 0:
- self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': False})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'dice_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': True})
# Render page
resp = await self.async_client.get(reverse('draw:index'))
self.assertEqual(resp.status_code, 200)
# Draw a problem
- await communicator.send_json_to({'type': 'draw_problem'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': True})
+ await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
@@ -458,14 +485,17 @@ class TestDraw(TestCase):
self.assertEqual(resp.status_code, 200)
# Accept the problem
- await communicator.send_json_to({'type': 'accept'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': False})
+ await communicator.send_json_to({'tid': tid, 'type': 'accept'})
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'set_problem', 'round': 1, 'team': trigram, 'problem': i + 1})
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'set_problem', 'round': 1, 'team': trigram, 'problem': i + 1})
if i < 3:
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': True})
else:
- self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'dice_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
self.assertIsNone(td.purposed)
@@ -483,8 +513,8 @@ class TestDraw(TestCase):
self.assertEqual(p.size, 3)
self.assertEqual(await p.teamdraw_set.acount(), 3)
self.assertEqual(p.current_team, None)
- self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'C',
- 'team': None})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'C', 'team': None})
# Render page
resp = await self.async_client.get(reverse('draw:index'))
@@ -493,7 +523,7 @@ class TestDraw(TestCase):
i = 0
async for td in p.teamdraw_set.prefetch_related('participation__team').all():
# Launch a new dice
- await communicator.send_json_to({'type': "dice", 'trigram': td.participation.team.trigram})
+ await communicator.send_json_to({'tid': tid, 'type': "dice", 'trigram': td.participation.team.trigram})
await communicator.receive_json_from()
await td.arefresh_from_db()
td.choice_dice = 101 + i # Avoid duplicates
@@ -508,20 +538,24 @@ class TestDraw(TestCase):
td = p.current_team
trigram = td.participation.team.trigram
self.assertEqual(td.choose_index, i)
- self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'C',
- 'team': trigram})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'C', 'team': trigram})
if i == 0:
- self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': False})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'dice_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': True})
# Render page
resp = await self.async_client.get(reverse('draw:index'))
self.assertEqual(resp.status_code, 200)
# Draw a problem
- await communicator.send_json_to({'type': 'draw_problem'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': True})
+ await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
@@ -539,16 +573,18 @@ class TestDraw(TestCase):
self.assertEqual(resp.status_code, 200)
# Accept the problem
- await communicator.send_json_to({'type': 'accept'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': False})
+ await communicator.send_json_to({'tid': tid, 'type': 'accept'})
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'set_problem', 'round': 1, 'team': trigram, 'problem': i + 1})
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'set_problem', 'round': 1, 'team': trigram, 'problem': i + 1})
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
self.assertIsNone(td.purposed)
self.assertEqual(td.accepted, i + 1)
if i == 2:
break
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
# Render page
@@ -572,8 +608,10 @@ class TestDraw(TestCase):
self.assertEqual(resp['type'], 'set_poules')
self.assertEqual(resp['round'], 2)
- self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': True})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'export_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'dice_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'export_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
# Render page
@@ -589,12 +627,12 @@ class TestDraw(TestCase):
self.assertEqual(p.size, 5 - i)
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'set_active', 'round': 2, 'poule': chr(65 + i), 'team': None})
+ {'tid': tid, 'type': 'set_active', 'round': 2, 'poule': chr(65 + i), 'team': None})
j = 0
async for td in p.teamdraw_set.prefetch_related('participation__team').all():
# Launch a new dice
- await communicator.send_json_to({'type': "dice", 'trigram': td.participation.team.trigram})
+ await communicator.send_json_to({'tid': tid, 'type': "dice", 'trigram': td.participation.team.trigram})
await communicator.receive_json_from()
await td.arefresh_from_db()
td.choice_dice = 101 + j # Avoid duplicates
@@ -612,23 +650,24 @@ class TestDraw(TestCase):
trigram = td.participation.team.trigram
self.assertEqual(td.choose_index, j)
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'set_active', 'round': 2, 'poule': chr(65 + i),
+ {'tid': tid, 'type': 'set_active', 'round': 2, 'poule': chr(65 + i),
'team': trigram})
if j == 0:
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'dice_visibility', 'visible': False})
+ {'tid': tid, 'type': 'dice_visibility', 'visible': False})
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'box_visibility', 'visible': True})
+ {'tid': tid, 'type': 'box_visibility', 'visible': True})
# Render page
resp = await self.async_client.get(reverse('draw:index'))
self.assertEqual(resp.status_code, 200)
# Draw a problem
- await communicator.send_json_to({'type': 'draw_problem'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False})
+ await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'})
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'buttons_visibility', 'visible': True})
+ {'tid': tid, 'type': 'box_visibility', 'visible': False})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
@@ -640,44 +679,55 @@ class TestDraw(TestCase):
self.assertNotEqual(td.purposed, old_td.accepted)
# Accept the problem
- await communicator.send_json_to({'type': 'accept'})
+ await communicator.send_json_to({'tid': tid, 'type': 'accept'})
self.assertEqual(await communicator.receive_json_from(),
- {'type': 'buttons_visibility', 'visible': False})
+ {'tid': tid, 'type': 'buttons_visibility', 'visible': False})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_problem')
td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk)
self.assertIsNone(td.purposed)
if j == 4 - i:
break
- self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'box_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
if i == 0:
# Reorder the pool since there are 5 teams
self.assertEqual((await communicator.receive_json_from())['type'], 'reorder_poule')
if i < 2:
- self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'dice_visibility', 'visible': True})
else:
- self.assertEqual(await communicator.receive_json_from(), {'type': 'export_visibility', 'visible': True})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'export_visibility', 'visible': True})
self.assertEqual((await communicator.receive_json_from())['type'], 'set_info')
self.assertEqual((await communicator.receive_json_from())['type'], 'set_active')
# Export the draw
- await communicator.send_json_to({'type': 'export'})
- self.assertEqual(await communicator.receive_json_from(), {'type': 'export_visibility', 'visible': False})
+ await communicator.send_json_to({'tid': tid, 'type': 'export'})
+ self.assertEqual(await communicator.receive_json_from(),
+ {'tid': tid, 'type': 'export_visibility', 'visible': False})
# Cancel all steps and reset all
for i in range(1000):
- await communicator.send_json_to({'type': 'cancel'})
- if not await Draw.objects.filter(tournament=self.tournament).aexists():
+ await communicator.send_json_to({'tid': tid, 'type': 'cancel'})
+
+ # Purge receive queue
+ while True:
+ try:
+ await communicator.receive_json_from()
+ except asyncio.TimeoutError:
break
- else:
- current_state = (await Draw.objects.filter(tournament=self.tournament).prefetch_related(
+
+ if await Draw.objects.filter(tournament_id=tid).aexists():
+ print((await Draw.objects.filter(tournament_id=tid).aexists()))
+ current_state = (await Draw.objects.filter(tournament_id=tid).prefetch_related(
'current_round__current_pool__current_team__participation__team').aget()).get_state()
raise AssertionError("Draw wasn't aborted after 1000 steps, current state: " + current_state)
# Abort while the tournament is already aborted
- await communicator.send_json_to({'type': "abort"})
+ await communicator.send_json_to({'tid': tid, 'type': "abort"})
def test_admin_pages(self):
"""