1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-02-26 22:26:28 +00:00

Compare commits

...

4 Commits

Author SHA1 Message Date
Emmy D'Anello
b38302449c
Don't manage pools of the second day with the dices of the first day since we consider the scores of the first day
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2023-05-11 17:28:05 +02:00
Emmy D'Anello
feee5069b1
Add notification when the draw of the final is resumed
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2023-05-11 17:15:50 +02:00
Emmy D'Anello
6b962a74b3
Auto-restart the draw socket on close
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2023-05-11 17:13:52 +02:00
Emmy D'Anello
0c80385958
Use a unique socket for the drawing system
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
2023-05-11 17:07:53 +02:00
5 changed files with 1006 additions and 843 deletions

View File

@ -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'})
@ -415,24 +430,27 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
# This also determines the passage order, in the natural order this time.
# If there is a 5-teams pool, we force the last team to be in the first pool,
# which is this specific pool since they are ordered by decreasing size.
tds_copy = tds.copy()
round2 = await self.tournament.draw.round_set.filter(number=2).aget()
round2_pools = [p async for p in Pool.objects.filter(round__draw__tournament=self.tournament, round=round2)
.order_by('letter').all()]
current_pool_id, current_passage_index = 0, 0
for i, td in enumerate(tds_copy):
if i == len(tds) - 1 and round2_pools[0].size == 5:
current_pool_id = 0
current_passage_index = 4
# This is not true for the final tournament, which considers the scores of the
# first round.
if not self.tournament.final:
tds_copy = tds.copy()
round2 = await self.tournament.draw.round_set.filter(number=2).aget()
round2_pools = [p async for p in Pool.objects.filter(round__draw__tournament=self.tournament, round=round2)
.order_by('letter').all()]
current_pool_id, current_passage_index = 0, 0
for i, td in enumerate(tds_copy):
if i == len(tds) - 1 and round2_pools[0].size == 5:
current_pool_id = 0
current_passage_index = 4
td2 = await TeamDraw.objects.filter(participation=td.participation, round=round2).aget()
td2.pool = round2_pools[current_pool_id]
td2.passage_index = current_passage_index
current_pool_id += 1
if current_pool_id == len(round2_pools):
current_pool_id = 0
current_passage_index += 1
await td2.asave()
td2 = await TeamDraw.objects.filter(participation=td.participation, round=round2).aget()
td2.pool = round2_pools[current_pool_id]
td2.passage_index = current_passage_index
current_pool_id += 1
if current_pool_id == len(round2_pools):
current_pool_id = 0
current_passage_index += 1
await td2.asave()
# The current pool is the first pool of the current (first) round
pool = await Pool.objects.filter(round=self.tournament.draw.current_round, letter=1).aget()
@ -452,23 +470,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 +499,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 +511,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 +542,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 +608,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 +669,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 +689,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 +707,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 +748,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 +770,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 +803,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 +832,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 += "<br><br>Le tirage au sort du tour 1 est terminé."
@ -803,7 +844,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 +896,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 +917,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 +951,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):
@ -926,6 +972,12 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
self.tournament.draw.last_message = msg
await self.tournament.draw.asave()
# Send notification to everyone
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
{'tid': self.tournament_id, 'type': 'draw.notify',
'title': 'Tirage au sort du TFJM²',
'body': "Le tirage au sort pour le second tour de la finale a commencé !"})
# Set the first pool of the second round as the active pool
pool = await Pool.objects.filter(round=self.tournament.draw.current_round, letter=1).aget()
r2.current_pool = pool
@ -951,7 +1003,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 +1017,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 +1070,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 +1093,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 +1120,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 +1176,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 +1194,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 +1204,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 +1229,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 +1240,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 +1283,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 +1302,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 +1327,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 +1350,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 +1380,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 +1423,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 +1468,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 +1485,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 +1543,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 +1554,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']})

View File

@ -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/<int:tournament_id>/", consumers.DrawConsumer.as_asgi()),
path("ws/draw/", consumers.DrawConsumer.as_asgi()),
]

File diff suppressed because it is too large Load Diff

View File

@ -351,7 +351,7 @@
{% trans "Are you sure you want to abort this draw?" %}
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-danger" onclick="abortDraw({{ tournament.id }})">{% trans "Abort" %}</button>
<button type="submit" class="btn btn-danger" data-bs-dismiss="modal" onclick="abortDraw({{ tournament.id }})">{% trans "Abort" %}</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Close" %}</button>
</div>
</div>

View File

@ -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):
"""