mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-10-31 15:00:00 +01:00 
			
		
		
		
	Use a unique socket for the drawing system
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
		| @@ -42,8 +42,60 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         We accept only if this is a user of a team of the associated tournament, or a volunteer |         We accept only if this is a user of a team of the associated tournament, or a volunteer | ||||||
|         of the tournament. |         of the tournament. | ||||||
|         """ |         """ | ||||||
|         # Get the tournament from the URL |  | ||||||
|         self.tournament_id = self.scope['url_route']['kwargs']['tournament_id'] |         # Fetch the registration of the current user | ||||||
|  |         user = self.scope['user'] | ||||||
|  |         reg = await Registration.objects.aget(user=user) | ||||||
|  |         self.registration = reg | ||||||
|  |  | ||||||
|  |         # Accept the connection | ||||||
|  |         await self.accept() | ||||||
|  |  | ||||||
|  |         # Register to channel layers to get updates | ||||||
|  |         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: | ||||||
|  |             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: | ||||||
|  |         """ | ||||||
|  |         Called when the websocket got disconnected, for any reason. | ||||||
|  |         :param close_code: The error code. | ||||||
|  |         """ | ||||||
|  |         # Unregister from channel layers | ||||||
|  |         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: | ||||||
|  |             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', 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. | ||||||
|  |         """ | ||||||
|  |         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) \ |         self.tournament = await Tournament.objects.filter(pk=self.tournament_id) \ | ||||||
|             .prefetch_related('draw__current_round__current_pool__current_team__participation__team').aget() |             .prefetch_related('draw__current_round__current_pool__current_team__participation__team').aget() | ||||||
|  |  | ||||||
| @@ -52,51 +104,6 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         async for participation in self.tournament.participations.filter(valid=True).prefetch_related('team'): |         async for participation in self.tournament.participations.filter(valid=True).prefetch_related('team'): | ||||||
|             self.participations.append(participation) |             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: |  | ||||||
|             await self.channel_layer.group_add(f"team-{self.registration.team.trigram}", self.channel_name) |  | ||||||
|         else: |  | ||||||
|             await self.channel_layer.group_add(f"volunteer-{self.tournament.id}", self.channel_name) |  | ||||||
|  |  | ||||||
|     async def disconnect(self, close_code) -> None: |  | ||||||
|         """ |  | ||||||
|         Called when the websocket got disconnected, for any reason. |  | ||||||
|         :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) |  | ||||||
|         else: |  | ||||||
|             await self.channel_layer.group_discard(f"volunteer-{self.tournament.id}", self.channel_name) |  | ||||||
|  |  | ||||||
|     async def alert(self, message: str, alert_type: str = 'info', **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,…) |  | ||||||
|         """ |  | ||||||
|         return await self.send_json({'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. |  | ||||||
|         """ |  | ||||||
|         # Refresh tournament |         # Refresh tournament | ||||||
|         self.tournament = await Tournament.objects.filter(pk=self.tournament_id)\ |         self.tournament = await Tournament.objects.filter(pk=self.tournament_id)\ | ||||||
|             .prefetch_related('draw__current_round__current_pool__current_team__participation__team').aget() |             .prefetch_related('draw__current_round__current_pool__current_team__participation__team').aget() | ||||||
| @@ -176,7 +183,9 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|                 await TeamDraw.objects.acreate(participation=participation, round=r) |                 await TeamDraw.objects.acreate(participation=participation, round=r) | ||||||
|             # Send to clients the different pools |             # Send to clients the different pools | ||||||
|             await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |             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, |                                                     'round': r.number, | ||||||
|                                                     'poules': [ |                                                     'poules': [ | ||||||
|                                                         { |                                                         { | ||||||
| @@ -184,29 +193,32 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|                                                             'teams': await pool.atrigrams(), |                                                             'teams': await pool.atrigrams(), | ||||||
|                                                         } |                                                         } | ||||||
|                                                         async for pool in r.pool_set.order_by('letter').all() |                                                         async for pool in r.pool_set.order_by('letter').all() | ||||||
|                                                  ]}) |                                                     ] | ||||||
|  |                                                 }) | ||||||
|  |  | ||||||
|         draw.current_round = r1 |         draw.current_round = r1 | ||||||
|         await draw.asave() |         await draw.asave() | ||||||
|  |  | ||||||
|         # Make dice box visible |         # Make dice box visible | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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') |         await self.alert(_("Draw started!"), 'success') | ||||||
|  |  | ||||||
|         # Update user interface |         # Update user interface | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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}", |         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()}) |                                              'info': await self.tournament.draw.ainformation()}) | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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 |         # Send notification to everyone | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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 " |                                              'body': "Le tirage au sort du tournoi de " | ||||||
|                                                      f"{self.tournament.name} a commencé !"}) |                                                      f"{self.tournament.name} a commencé !"}) | ||||||
|  |  | ||||||
| @@ -216,7 +228,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         """ |         """ | ||||||
|         await self.alert(_("The draw for the tournament {tournament} will start.") |         await self.alert(_("The draw for the tournament {tournament} will start.") | ||||||
|                          .format(tournament=self.tournament.name), 'warning') |                          .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]}) |                               'trigrams': [p.team.trigram for p in self.participations]}) | ||||||
|  |  | ||||||
|     @ensure_orga |     @ensure_orga | ||||||
| @@ -231,7 +243,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         # All associated data will be deleted by cascade |         # All associated data will be deleted by cascade | ||||||
|         await self.tournament.draw.adelete() |         await self.tournament.draw.adelete() | ||||||
|         # Send information to all users |         # 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: |     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.") |         await self.alert(_("The draw for the tournament {tournament} is aborted.") | ||||||
|                          .format(tournament=self.tournament.name), 'danger') |                          .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): |     async def process_dice(self, trigram: str | None = None, **kwargs): | ||||||
|         """ |         """ | ||||||
| @@ -310,7 +323,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|         # Send the dice result to all users |         # Send the dice result to all users | ||||||
|         await self.channel_layer.group_send( |         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 \ |         if state == 'DICE_SELECT_POULES' and \ | ||||||
|                 not await TeamDraw.objects.filter(round_id=self.tournament.draw.current_round_id, |                 not await TeamDraw.objects.filter(round_id=self.tournament.draw.current_round_id, | ||||||
| @@ -364,19 +378,20 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|                     await dup.asave() |                     await dup.asave() | ||||||
|                     await self.channel_layer.group_send( |                     await self.channel_layer.group_send( | ||||||
|                         f"tournament-{self.tournament.id}", |                         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 |                     # Send notification to concerned teams | ||||||
|                     await self.channel_layer.group_send( |                     await self.channel_layer.group_send( | ||||||
|                         f"team-{dup.participation.team.trigram}", |                         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. ' |                          'body': 'Votre score de dé est identique à celui de une ou plusieurs équipes. ' | ||||||
|                                  'Veuillez le relancer.'} |                                  'Veuillez le relancer.'} | ||||||
|                     ) |                     ) | ||||||
|                 # Alert the tournament |                 # Alert the tournament | ||||||
|                 await self.channel_layer.group_send( |                 await self.channel_layer.group_send( | ||||||
|                     f"tournament-{self.tournament.id}", |                     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( |                      'message': _('Dices from teams {teams} are identical. Please relaunch your dices.').format( | ||||||
|                          teams=', '.join(td.participation.team.trigram for td in dups)), |                          teams=', '.join(td.participation.team.trigram for td in dups)), | ||||||
|                      'alert_type': 'warning'}) |                      'alert_type': 'warning'}) | ||||||
| @@ -452,23 +467,26 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         for td in tds: |         for td in tds: | ||||||
|             await self.channel_layer.group_send( |             await self.channel_layer.group_send( | ||||||
|                 f"tournament-{self.tournament.id}", |                 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 |         # Hide dice interface | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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 |         # 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(): |         async for td in pool.teamdraw_set.prefetch_related('participation__team').all(): | ||||||
|             await self.channel_layer.group_send(f"team-{td.participation.team.trigram}", |             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}", |         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 |         # First send the second pool to have the good team order | ||||||
|         r2 = await self.tournament.draw.round_set.filter(number=2).aget() |         r2 = await self.tournament.draw.round_set.filter(number=2).aget() | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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, |                                              'round': r2.number, | ||||||
|                                              'poules': [ |                                              'poules': [ | ||||||
|                                                  { |                                                  { | ||||||
| @@ -478,7 +496,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|                                                  async for pool in r2.pool_set.order_by('letter').all() |                                                  async for pool in r2.pool_set.order_by('letter').all() | ||||||
|                                              ]}) |                                              ]}) | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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, |                                              'round': r.number, | ||||||
|                                              'poules': [ |                                              'poules': [ | ||||||
|                                                  { |                                                  { | ||||||
| @@ -490,10 +508,10 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|         # Update information header and the active team on the recap menu |         # Update information header and the active team on the recap menu | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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()}) |                                              'info': await self.tournament.draw.ainformation()}) | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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, |                                              'round': r.number, | ||||||
|                                              'pool': pool.get_letter_display()}) |                                              'pool': pool.get_letter_display()}) | ||||||
|  |  | ||||||
| @@ -521,28 +539,30 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|         # Update information header |         # Update information header | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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()}) |                                              'info': await self.tournament.draw.ainformation()}) | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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, |                                              'round': r.number, | ||||||
|                                              'pool': pool.get_letter_display(), |                                              'pool': pool.get_letter_display(), | ||||||
|                                              'team': pool.current_team.participation.team.trigram}) |                                              'team': pool.current_team.participation.team.trigram}) | ||||||
|  |  | ||||||
|         # Hide dice button to everyone |         # Hide dice button to everyone | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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 |         # Display the box button to the first team and to volunteers | ||||||
|         trigram = pool.current_team.participation.team.trigram |         trigram = pool.current_team.participation.team.trigram | ||||||
|         await self.channel_layer.group_send(f"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}", |         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 |         # Notify the team that it can draw a problem | ||||||
|         await self.channel_layer.group_send(f"team-{tds[0].participation.team.trigram}", |         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 !"}) |                                              'body': "C'est à vous de tirer un nouveau problème !"}) | ||||||
|  |  | ||||||
|     async def select_problem(self, **kwargs): |     async def select_problem(self, **kwargs): | ||||||
| @@ -585,20 +605,25 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         # Update interface |         # Update interface | ||||||
|         trigram = td.participation.team.trigram |         trigram = td.participation.team.trigram | ||||||
|         await self.channel_layer.group_send(f"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}", |         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}", |         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}", |         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}", |         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 = "" |         self.tournament.draw.last_message = "" | ||||||
|         await self.tournament.draw.asave() |         await self.tournament.draw.asave() | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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()}) |                                              'info': await self.tournament.draw.ainformation()}) | ||||||
|  |  | ||||||
|     async def accept_problem(self, **kwargs): |     async def accept_problem(self, **kwargs): | ||||||
| @@ -641,11 +666,13 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|         # Send the accepted problem to the users |         # Send the accepted problem to the users | ||||||
|         await self.channel_layer.group_send(f"team-{trigram}", |         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}", |         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}", |         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, |                                              'round': r.number, | ||||||
|                                              'team': trigram, |                                              'team': trigram, | ||||||
|                                              'problem': td.accepted}) |                                              'problem': td.accepted}) | ||||||
| @@ -659,13 +686,16 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|             new_trigram = next_td.participation.team.trigram |             new_trigram = next_td.participation.team.trigram | ||||||
|             await self.channel_layer.group_send(f"team-{new_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}", |             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 |             # Notify the team that it can draw a problem | ||||||
|             await self.channel_layer.group_send(f"team-{new_trigram}", |             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 !"}) |                                                  'body': "C'est à vous de tirer un nouveau problème !"}) | ||||||
|         else: |         else: | ||||||
|             # Pool is ended |             # Pool is ended | ||||||
| @@ -674,10 +704,10 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|             pool = r.current_pool |             pool = r.current_pool | ||||||
|  |  | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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()}) |                                              'info': await self.tournament.draw.ainformation()}) | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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, |                                              'round': r.number, | ||||||
|                                              'pool': pool.get_letter_display(), |                                              'pool': pool.get_letter_display(), | ||||||
|                                              'team': pool.current_team.participation.team.trigram |                                              'team': pool.current_team.participation.team.trigram | ||||||
| @@ -715,6 +745,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|             # Send the reordered pool |             # Send the reordered pool | ||||||
|             await self.channel_layer.group_send(f"tournament-{self.tournament.id}", { |             await self.channel_layer.group_send(f"tournament-{self.tournament.id}", { | ||||||
|  |                 'tid': self.tournament_id, | ||||||
|                 'type': 'draw.reorder_pool', |                 'type': 'draw.reorder_pool', | ||||||
|                 'round': r.number, |                 'round': r.number, | ||||||
|                 'pool': pool.get_letter_display(), |                 '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(): |             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}", |                 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 |                 # Notify the team that it can draw a dice | ||||||
|                 await self.channel_layer.group_send(f"team-{td.participation.team.trigram}", |                 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é !"}) |                                                      'body': "C'est à vous de lancer le dé !"}) | ||||||
|  |  | ||||||
|             await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |             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: |         else: | ||||||
|             # Round is ended |             # Round is ended | ||||||
|             await self.end_round(r) |             await self.end_round(r) | ||||||
| @@ -766,16 +800,18 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|             for participation in self.participations: |             for participation in self.participations: | ||||||
|                 await self.channel_layer.group_send( |                 await self.channel_layer.group_send( | ||||||
|                     f"tournament-{self.tournament.id}", |                     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 |                 # Notify the team that it can draw a dice | ||||||
|                 await self.channel_layer.group_send(f"team-{participation.team.trigram}", |                 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é !"}) |                                                      'body': "C'est à vous de lancer le dé !"}) | ||||||
|  |  | ||||||
|             # Reorder dices |             # Reorder dices | ||||||
|             await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |             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, |                                                  'round': r2.number, | ||||||
|                                                  'poules': [ |                                                  'poules': [ | ||||||
|                                                      { |                                                      { | ||||||
| @@ -793,9 +829,11 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|             async for td in p1.teamdraw_set.prefetch_related('participation__team').all(): |             async for td in p1.teamdraw_set.prefetch_related('participation__team').all(): | ||||||
|                 await self.channel_layer.group_send(f"team-{td.participation.team.trigram}", |                 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}", |             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: |         elif r.number == 1 and self.tournament.final: | ||||||
|             # For the final tournament, we wait for a manual update between the two rounds. |             # 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é." |             msg += "<br><br>Le tirage au sort du tour 1 est terminé." | ||||||
| @@ -803,7 +841,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|             await self.tournament.draw.asave() |             await self.tournament.draw.asave() | ||||||
|  |  | ||||||
|         await self.channel_layer.group_send(f"volunteer-{self.tournament.id}", |         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): |     async def reject_problem(self, **kwargs): | ||||||
|         """ |         """ | ||||||
| @@ -854,11 +893,13 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|         # Update interface |         # Update interface | ||||||
|         await self.channel_layer.group_send(f"team-{trigram}", |         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}", |         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}", |         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}) |                                              'round': r.number, 'team': trigram, 'rejected': td.rejected}) | ||||||
|  |  | ||||||
|         if already_refused: |         if already_refused: | ||||||
| @@ -873,22 +914,23 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|         new_trigram = next_td.participation.team.trigram |         new_trigram = next_td.participation.team.trigram | ||||||
|         await self.channel_layer.group_send(f"team-{new_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}", |         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}", |         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()}) |                                              'info': await self.tournament.draw.ainformation()}) | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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, |                                              'round': r.number, | ||||||
|                                              'pool': pool.get_letter_display(), |                                              'pool': pool.get_letter_display(), | ||||||
|                                              'team': new_trigram}) |                                              'team': new_trigram}) | ||||||
|  |  | ||||||
|         # Notify the team that it can draw a problem |         # Notify the team that it can draw a problem | ||||||
|         await self.channel_layer.group_send(f"team-{new_trigram}", |         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 !"}) |                                              'body': "C'est à vous de tirer un nouveau problème !"}) | ||||||
|  |  | ||||||
|     @ensure_orga |     @ensure_orga | ||||||
| @@ -906,7 +948,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|                     await pool.export() |                     await pool.export() | ||||||
|  |  | ||||||
|         await self.channel_layer.group_send(f"volunteer-{self.tournament.id}", |         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 |     @ensure_orga | ||||||
|     async def continue_final(self, **kwargs): |     async def continue_final(self, **kwargs): | ||||||
| @@ -951,7 +994,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|         # Send pools to users |         # Send pools to users | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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, |                                              'round': r2.number, | ||||||
|                                              'poules': [ |                                              'poules': [ | ||||||
|                                                  { |                                                  { | ||||||
| @@ -965,27 +1008,31 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         for participation in self.participations: |         for participation in self.participations: | ||||||
|             await self.channel_layer.group_send( |             await self.channel_layer.group_send( | ||||||
|                 f"tournament-{self.tournament.id}", |                 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'): |         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}", |             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 |             # Notify the team that it can draw a problem | ||||||
|             await self.channel_layer.group_send(f"team-{td.participation.team.trigram}", |             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 !"}) |                                                  'body': "C'est à vous de tirer un nouveau problème !"}) | ||||||
|  |  | ||||||
|         await self.channel_layer.group_send(f"volunteer-{self.tournament.id}", |         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}", |         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}", |         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()}) |                                              'info': await self.tournament.draw.ainformation()}) | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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, |                                              'round': r2.number, | ||||||
|                                              'pool': r2.current_pool.get_letter_display()}) |                                              'pool': r2.current_pool.get_letter_display()}) | ||||||
|  |  | ||||||
| @@ -1014,12 +1061,12 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|             await self.undo_order_dice() |             await self.undo_order_dice() | ||||||
|  |  | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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()}) |                                              'info': await self.tournament.draw.ainformation()}) | ||||||
|         r = self.tournament.draw.current_round |         r = self.tournament.draw.current_round | ||||||
|         p = r.current_pool |         p = r.current_pool | ||||||
|         await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |         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, |                                              'round': r.number, | ||||||
|                                              'pool': p.get_letter_display() if p else None, |                                              'pool': p.get_letter_display() if p else None, | ||||||
|                                              'team': p.current_team.participation.team.trigram |                                              'team': p.current_team.participation.team.trigram | ||||||
| @@ -1037,15 +1084,18 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         await td.asave() |         await td.asave() | ||||||
|  |  | ||||||
|         await self.channel_layer.group_send(f"volunteer-{self.tournament.id}", |         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}", |         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}", |         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}", |         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, |                                              'round': r.number, | ||||||
|                                              'team': td.participation.team.trigram, |                                              'team': td.participation.team.trigram, | ||||||
|                                              'problem': td.accepted}) |                                              'problem': td.accepted}) | ||||||
| @@ -1061,13 +1111,15 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         await td.asave() |         await td.asave() | ||||||
|  |  | ||||||
|         await self.channel_layer.group_send(f"team-{td.participation.team.trigram}", |         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}", |         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}", |         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}", |         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): |     async def undo_process_problem(self): | ||||||
|         """ |         """ | ||||||
| @@ -1115,7 +1167,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|                     await last_td.asave() |                     await last_td.asave() | ||||||
|  |  | ||||||
|                     await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |                     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, |                                                          'round': r.number, | ||||||
|                                                          'team': last_td.participation.team.trigram, |                                                          'team': last_td.participation.team.trigram, | ||||||
|                                                          'problem': last_td.accepted}) |                                                          'problem': last_td.accepted}) | ||||||
| @@ -1133,7 +1185,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|                     await last_td.asave() |                     await last_td.asave() | ||||||
|  |  | ||||||
|                     await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |                     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, |                                                          'round': r.number, | ||||||
|                                                          'team': last_td.participation.team.trigram, |                                                          'team': last_td.participation.team.trigram, | ||||||
|                                                          'rejected': last_td.rejected}) |                                                          'rejected': last_td.rejected}) | ||||||
| @@ -1143,9 +1195,11 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|             await r.current_pool.asave() |             await r.current_pool.asave() | ||||||
|  |  | ||||||
|             await self.channel_layer.group_send(f"team-{last_td.participation.team.trigram}", |             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}", |             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: |         else: | ||||||
|             # Return to the dice choice |             # Return to the dice choice | ||||||
|             pool_tds = {td.id: td async for td in p.team_draws.prefetch_related('participation__team')} |             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 |                     # Reset the dice on the interface | ||||||
|                     await self.channel_layer.group_send( |                     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, |                                                              'team': last_td.participation.team.trigram, | ||||||
|                                                              'result': None}) |                                                              'result': None}) | ||||||
|                     break |                     break | ||||||
| @@ -1177,12 +1231,15 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|             # Make dice box visible |             # Make dice box visible | ||||||
|             for td in pool_tds.values(): |             for td in pool_tds.values(): | ||||||
|                 await self.channel_layer.group_send(f"team-{td.participation.team.trigram}", |                 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}", |             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}", |         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): |     async def undo_pool_dice(self): | ||||||
|         """ |         """ | ||||||
| @@ -1217,7 +1274,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|                     # Reset the dice on the interface |                     # Reset the dice on the interface | ||||||
|                     await self.channel_layer.group_send( |                     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, |                                                              'team': last_td.participation.team.trigram, | ||||||
|                                                              'result': None}) |                                                              'result': None}) | ||||||
|                     break |                     break | ||||||
| @@ -1236,15 +1293,18 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|                 await td.asave() |                 await td.asave() | ||||||
|  |  | ||||||
|                 await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |                 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}", |                 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}", |                 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}", |                 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, |                                                      'round': r.number, | ||||||
|                                                      'team': td.participation.team.trigram, |                                                      'team': td.participation.team.trigram, | ||||||
|                                                      'problem': td.accepted}) |                                                      'problem': td.accepted}) | ||||||
| @@ -1258,12 +1318,12 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|                     async for td in r1.team_draws.prefetch_related('participation__team').all(): |                     async for td in r1.team_draws.prefetch_related('participation__team').all(): | ||||||
|                         await self.channel_layer.group_send( |                         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, |                                                                  'team': td.participation.team.trigram, | ||||||
|                                                                  'result': td.choice_dice}) |                                                                  'result': td.choice_dice}) | ||||||
|  |  | ||||||
|                     await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |                     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, |                                                          'round': r1.number, | ||||||
|                                                          'poules': [ |                                                          'poules': [ | ||||||
|                                                              { |                                                              { | ||||||
| @@ -1281,15 +1341,18 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|                     await td.asave() |                     await td.asave() | ||||||
|  |  | ||||||
|                     await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |                     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}", |                     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}", |                     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}", |                     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, |                                                          'round': r1.number, | ||||||
|                                                          'team': td.participation.team.trigram, |                                                          'team': td.participation.team.trigram, | ||||||
|                                                          'problem': td.accepted}) |                                                          'problem': td.accepted}) | ||||||
| @@ -1308,14 +1371,16 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|                     async for td in r1.team_draws.prefetch_related('participation__team').all(): |                     async for td in r1.team_draws.prefetch_related('participation__team').all(): | ||||||
|                         await self.channel_layer.group_send( |                         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, |                                                                  'team': td.participation.team.trigram, | ||||||
|                                                                  'result': td.choice_dice}) |                                                                  'result': td.choice_dice}) | ||||||
|  |  | ||||||
|                     await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |                     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}", |                     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: |             else: | ||||||
|                 # Go to the dice order |                 # Go to the dice order | ||||||
|                 async for r0 in self.tournament.draw.round_set.all(): |                 async for r0 in self.tournament.draw.round_set.all(): | ||||||
| @@ -1349,19 +1414,20 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|                         # Reset the dice on the interface |                         # Reset the dice on the interface | ||||||
|                         await self.channel_layer.group_send( |                         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, |                                                                  'team': last_td.participation.team.trigram, | ||||||
|                                                                  'result': None}) |                                                                  'result': None}) | ||||||
|                         break |                         break | ||||||
|  |  | ||||||
|                 async for td in r.team_draws.prefetch_related('participation__team').all(): |                 async for td in r.team_draws.prefetch_related('participation__team').all(): | ||||||
|                     await self.channel_layer.group_send( |                     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, |                                                              'team': td.participation.team.trigram, | ||||||
|                                                              'result': td.passage_dice}) |                                                              'result': td.passage_dice}) | ||||||
|  |  | ||||||
|                 await self.channel_layer.group_send(f"tournament-{self.tournament.id}", |                 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): |     async def undo_order_dice(self): | ||||||
|         """ |         """ | ||||||
| @@ -1393,7 +1459,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|  |  | ||||||
|                     # Reset the dice on the interface |                     # Reset the dice on the interface | ||||||
|                     await self.channel_layer.group_send( |                     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, |                                                              'team': last_td.participation.team.trigram, | ||||||
|                                                              'result': None}) |                                                              'result': None}) | ||||||
|                     break |                     break | ||||||
| @@ -1410,55 +1476,57 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         """ |         """ | ||||||
|         Send a notification (with title and body) to the current user. |         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): |     async def draw_set_info(self, content): | ||||||
|         """ |         """ | ||||||
|         Set the information banner to the current user. |         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): |     async def draw_dice(self, content): | ||||||
|         """ |         """ | ||||||
|         Update the dice of a given team for the current user interface. |         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): |     async def draw_dice_visibility(self, content): | ||||||
|         """ |         """ | ||||||
|         Update the visibility of the dice button for the current user. |         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): |     async def draw_box_visibility(self, content): | ||||||
|         """ |         """ | ||||||
|         Update the visibility of the box button for the current user. |         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): |     async def draw_buttons_visibility(self, content): | ||||||
|         """ |         """ | ||||||
|         Update the visibility of the accept/reject buttons for the current user. |         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): |     async def draw_export_visibility(self, content): | ||||||
|         """ |         """ | ||||||
|         Update the visibility of the export button for the current user. |         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): |     async def draw_continue_visibility(self, content): | ||||||
|         """ |         """ | ||||||
|         Update the visibility of the continue button for the current user. |         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): |     async def draw_send_poules(self, content): | ||||||
|         """ |         """ | ||||||
|         Send the pools and the teams to the current user to update the interface. |         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']}) |                               'poules': content['poules']}) | ||||||
|  |  | ||||||
|     async def draw_set_active(self, content): |     async def draw_set_active(self, content): | ||||||
| @@ -1466,6 +1534,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         Update the user interface to highlight the current team. |         Update the user interface to highlight the current team. | ||||||
|         """ |         """ | ||||||
|         await self.send_json({ |         await self.send_json({ | ||||||
|  |             'tid': content['tid'], | ||||||
|             'type': 'set_active', |             'type': 'set_active', | ||||||
|             'round': content.get('round', None), |             'round': content.get('round', None), | ||||||
|             'poule': content.get('pool', None), |             'poule': content.get('pool', None), | ||||||
| @@ -1476,20 +1545,20 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): | |||||||
|         """ |         """ | ||||||
|         Send the accepted problem of a team to the current user. |         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']}) |                               'team': content['team'], 'problem': content['problem']}) | ||||||
|  |  | ||||||
|     async def draw_reject_problem(self, content): |     async def draw_reject_problem(self, content): | ||||||
|         """ |         """ | ||||||
|         Send the rejected problems of a team to the current user. |         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']}) |                               'team': content['team'], 'rejected': content['rejected']}) | ||||||
|  |  | ||||||
|     async def draw_reorder_pool(self, content): |     async def draw_reorder_pool(self, content): | ||||||
|         """ |         """ | ||||||
|         Send the new order of a pool to the current user. |         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'], |                               'poule': content['pool'], 'teams': content['teams'], | ||||||
|                               'problems': content['problems']}) |                               'problems': content['problems']}) | ||||||
|   | |||||||
| @@ -1,7 +1,10 @@ | |||||||
|  | # Copyright (C) 2023 by Animath | ||||||
|  | # SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  |  | ||||||
| from django.urls import path | from django.urls import path | ||||||
|  |  | ||||||
| from . import consumers | from . import consumers | ||||||
|  |  | ||||||
| websocket_urlpatterns = [ | websocket_urlpatterns = [ | ||||||
|     path("ws/draw/<int:tournament_id>/", consumers.DrawConsumer.as_asgi()), |     path("ws/draw/", consumers.DrawConsumer.as_asgi()), | ||||||
| ] | ] | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
| const problems_count = JSON.parse(document.getElementById('problems_count').textContent) | const problems_count = JSON.parse(document.getElementById('problems_count').textContent) | ||||||
|  |  | ||||||
| const tournaments = JSON.parse(document.getElementById('tournaments_list').textContent) | const tournaments = JSON.parse(document.getElementById('tournaments_list').textContent) | ||||||
| const sockets = {} | let socket = null | ||||||
|  |  | ||||||
| const messages = document.getElementById('messages') | const messages = document.getElementById('messages') | ||||||
|  |  | ||||||
| @@ -17,7 +17,7 @@ const messages = document.getElementById('messages') | |||||||
|  * @param tid The tournament id |  * @param tid The tournament id | ||||||
|  */ |  */ | ||||||
| function abortDraw(tid) { | 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 |  * @param tid The tournament id | ||||||
|  */ |  */ | ||||||
| function cancelLastStep(tid) { | 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) |  * @param trigram The trigram of the team that a volunteer wants to force the dice launch (default: null) | ||||||
|  */ |  */ | ||||||
| function drawDice(tid, trigram = 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 |  * @param tid The tournament id | ||||||
|  */ |  */ | ||||||
| function drawProblem(tid) { | 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 |  * @param tid The tournament id | ||||||
|  */ |  */ | ||||||
| function acceptProblem(tid) { | 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 |  * @param tid The tournament id | ||||||
|  */ |  */ | ||||||
| function rejectProblem(tid) { | 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 |  * @param tid The tournament id | ||||||
|  */ |  */ | ||||||
| function exportDraw(tid) { | 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 |  * @param tid The tournament id | ||||||
|  */ |  */ | ||||||
| function continueFinal(tid) { | function continueFinal(tid) { | ||||||
|     sockets[tid].send(JSON.stringify({'type': 'continue_final'})) |     socket.send(JSON.stringify({'tid': tid, 'type': 'continue_final'})) | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -108,13 +108,11 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|         elem => elem.addEventListener( |         elem => elem.addEventListener( | ||||||
|             'click', () => document.location.hash = '#' + elem.innerText.toLowerCase())) |             'click', () => document.location.hash = '#' + elem.innerText.toLowerCase())) | ||||||
|  |  | ||||||
|     for (let tournament of tournaments) { |     // Open a global websocket | ||||||
|         // Open a websocket per tournament |     socket = new WebSocket( | ||||||
|         let socket = new WebSocket( |  | ||||||
|         (document.location.protocol === 'https:' ? 'wss' : 'ws') + '://' + window.location.host |         (document.location.protocol === 'https:' ? 'wss' : 'ws') + '://' + window.location.host | ||||||
|             + '/ws/draw/' + tournament.id + '/' |         + '/ws/draw/' | ||||||
|     ) |     ) | ||||||
|         sockets[tournament.id] = socket |  | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Add alert message on the top on the interface. |      * Add alert message on the top on the interface. | ||||||
| @@ -137,23 +135,25 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Update the information banner. |      * Update the information banner. | ||||||
|  |      * @param tid The tournament id | ||||||
|      * @param info The content to updated |      * @param info The content to updated | ||||||
|      */ |      */ | ||||||
|         function setInfo(info) { |     function setInfo(tid, info) { | ||||||
|             document.getElementById(`messages-${tournament.id}`).innerHTML = info |         document.getElementById(`messages-${tid}`).innerHTML = info | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Open the draw interface, given the list of teams. |      * 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. |      * @param teams The list of teams (represented by their trigrams) that are present on this draw. | ||||||
|      */ |      */ | ||||||
|         function drawStart(teams) { |     function drawStart(tid, teams) { | ||||||
|         // Hide the not-started-banner |         // Hide the not-started-banner | ||||||
|             document.getElementById(`banner-not-started-${tournament.id}`).classList.add('d-none') |         document.getElementById(`banner-not-started-${tid}`).classList.add('d-none') | ||||||
|         // Display the full draw interface |         // Display the full draw interface | ||||||
|             document.getElementById(`draw-content-${tournament.id}`).classList.remove('d-none') |         document.getElementById(`draw-content-${tid}`).classList.remove('d-none') | ||||||
|  |  | ||||||
|             let dicesDiv = document.getElementById(`dices-${tournament.id}`) |         let dicesDiv = document.getElementById(`dices-${tid}`) | ||||||
|         for (let team of teams) { |         for (let team of teams) { | ||||||
|             // Add empty dice score badge for each team |             // Add empty dice score badge for each team | ||||||
|             let col = document.createElement('div') |             let col = document.createElement('div') | ||||||
| @@ -161,11 +161,11 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|             dicesDiv.append(col) |             dicesDiv.append(col) | ||||||
|  |  | ||||||
|             let diceDiv = document.createElement('div') |             let diceDiv = document.createElement('div') | ||||||
|                 diceDiv.id = `dice-${tournament.id}-${team}` |             diceDiv.id = `dice-${tid}-${team}` | ||||||
|             diceDiv.classList.add('badge', 'rounded-pill', 'text-bg-warning') |             diceDiv.classList.add('badge', 'rounded-pill', 'text-bg-warning') | ||||||
|                 if (document.getElementById(`abort-${tournament.id}`) !== null) { |             if (document.getElementById(`abort-${tid}`) !== null) { | ||||||
|                     // Check if this is a volunteer, who can launch a dice for a specific team |                 // Check if this is a volunteer, who can launch a die for a specific team | ||||||
|                     diceDiv.onclick = (e) => drawDice(tournament.id, team) |                 diceDiv.onclick = (_) => drawDice(tid, team) | ||||||
|             } |             } | ||||||
|             diceDiv.textContent = `${team} 🎲 ??` |             diceDiv.textContent = `${team} 🎲 ??` | ||||||
|             col.append(diceDiv) |             col.append(diceDiv) | ||||||
| @@ -174,28 +174,30 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Abort the current draw, and make all invisible, except the not-started-banner. |      * Abort the current draw, and make all invisible, except the not-started-banner. | ||||||
|  |      * @param tid The tournament id | ||||||
|      */ |      */ | ||||||
|         function drawAbort() { |     function drawAbort(tid) { | ||||||
|             document.getElementById(`banner-not-started-${tournament.id}`).classList.remove('d-none') |         document.getElementById(`banner-not-started-${tid}`).classList.remove('d-none') | ||||||
|             document.getElementById(`draw-content-${tournament.id}`).classList.add('d-none') |         document.getElementById(`draw-content-${tid}`).classList.add('d-none') | ||||||
|             document.getElementById(`dices-${tournament.id}`).innerHTML = "" |         document.getElementById(`dices-${tid}`).innerHTML = "" | ||||||
|             document.getElementById(`recap-${tournament.id}-round-list`).innerHTML = "" |         document.getElementById(`recap-${tid}-round-list`).innerHTML = "" | ||||||
|             document.getElementById(`tables-${tournament.id}`).innerHTML = "" |         document.getElementById(`tables-${tid}`).innerHTML = "" | ||||||
|             updateDiceVisibility(false) |         updateDiceVisibility(tid, false) | ||||||
|             updateBoxVisibility(false) |         updateBoxVisibility(tid, false) | ||||||
|             updateButtonsVisibility(false) |         updateButtonsVisibility(tid, false) | ||||||
|             updateExportVisibility(false) |         updateExportVisibility(tid, false) | ||||||
|             updateContinueVisibility(false) |         updateContinueVisibility(tid, false) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * This function is triggered after a new dice result. We update the score of the team. |      * 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. |      * 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 trigram The trigram of the team that launched its dice | ||||||
|      * @param result The result of the dice. null if it is a reset. |      * @param result The result of the dice. null if it is a reset. | ||||||
|      */ |      */ | ||||||
|         function updateDiceInfo(trigram, result) { |     function updateDiceInfo(tid, trigram, result) { | ||||||
|             let elem = document.getElementById(`dice-${tournament.id}-${trigram}`) |         let elem = document.getElementById(`dice-${tid}-${trigram}`) | ||||||
|         if (result === null) { |         if (result === null) { | ||||||
|             elem.classList.remove('text-bg-success') |             elem.classList.remove('text-bg-success') | ||||||
|             elem.classList.add('text-bg-warning') |             elem.classList.add('text-bg-warning') | ||||||
| @@ -210,10 +212,11 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Display or hide the dice button. |      * Display or hide the dice button. | ||||||
|  |      * @param tid The tournament id | ||||||
|      * @param visible The visibility status |      * @param visible The visibility status | ||||||
|      */ |      */ | ||||||
|         function updateDiceVisibility(visible) { |     function updateDiceVisibility(tid, visible) { | ||||||
|             let div = document.getElementById(`launch-dice-${tournament.id}`) |         let div = document.getElementById(`launch-dice-${tid}`) | ||||||
|         if (visible) |         if (visible) | ||||||
|             div.classList.remove('d-none') |             div.classList.remove('d-none') | ||||||
|         else |         else | ||||||
| @@ -222,10 +225,11 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Display or hide the box button. |      * Display or hide the box button. | ||||||
|  |      * @param tid The tournament id | ||||||
|      * @param visible The visibility status |      * @param visible The visibility status | ||||||
|      */ |      */ | ||||||
|         function updateBoxVisibility(visible) { |     function updateBoxVisibility(tid, visible) { | ||||||
|             let div = document.getElementById(`draw-problem-${tournament.id}`) |         let div = document.getElementById(`draw-problem-${tid}`) | ||||||
|         if (visible) |         if (visible) | ||||||
|             div.classList.remove('d-none') |             div.classList.remove('d-none') | ||||||
|         else |         else | ||||||
| @@ -234,10 +238,11 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Display or hide the accept and reject buttons. |      * Display or hide the accept and reject buttons. | ||||||
|  |      * @param tid The tournament id | ||||||
|      * @param visible The visibility status |      * @param visible The visibility status | ||||||
|      */ |      */ | ||||||
|         function updateButtonsVisibility(visible) { |     function updateButtonsVisibility(tid, visible) { | ||||||
|             let div = document.getElementById(`buttons-${tournament.id}`) |         let div = document.getElementById(`buttons-${tid}`) | ||||||
|         if (visible) |         if (visible) | ||||||
|             div.classList.remove('d-none') |             div.classList.remove('d-none') | ||||||
|         else |         else | ||||||
| @@ -246,10 +251,11 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Display or hide the export button. |      * Display or hide the export button. | ||||||
|  |      * @param tid The tournament id | ||||||
|      * @param visible The visibility status |      * @param visible The visibility status | ||||||
|      */ |      */ | ||||||
|         function updateExportVisibility(visible) { |     function updateExportVisibility(tid, visible) { | ||||||
|             let div = document.getElementById(`export-${tournament.id}`) |         let div = document.getElementById(`export-${tid}`) | ||||||
|         if (visible) |         if (visible) | ||||||
|             div.classList.remove('d-none') |             div.classList.remove('d-none') | ||||||
|         else |         else | ||||||
| @@ -258,32 +264,37 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Display or hide the continuation button. |      * Display or hide the continuation button. | ||||||
|  |      * @param tid The tournament id | ||||||
|      * @param visible The visibility status |      * @param visible The visibility status | ||||||
|      */ |      */ | ||||||
|         function updateContinueVisibility(visible) { |     function updateContinueVisibility(tid, visible) { | ||||||
|             let div = document.getElementById(`continue-${tournament.id}`) |         let div = document.getElementById(`continue-${tid}`) | ||||||
|  |         if (div !== null) { | ||||||
|  |             // Only present during the final | ||||||
|             if (visible) |             if (visible) | ||||||
|                 div.classList.remove('d-none') |                 div.classList.remove('d-none') | ||||||
|             else |             else | ||||||
|                 div.classList.add('d-none') |                 div.classList.add('d-none') | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Set the different pools for the given round, and update the interface. |      * 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 round The round number, as integer (1 or 2) | ||||||
|      * @param poules The list of poules, which are represented with their letters and trigrams, |      * @param poules The list of poules, which are represented with their letters and trigrams, | ||||||
|      *                  [{'letter': 'A', 'teams': ['ABC', 'DEF', 'GHI']}] |      *                  [{'letter': 'A', 'teams': ['ABC', 'DEF', 'GHI']}] | ||||||
|      */ |      */ | ||||||
|         function updatePoules(round, poules) { |     function updatePoules(tid, round, poules) { | ||||||
|             let roundList = document.getElementById(`recap-${tournament.id}-round-list`) |         let roundList = document.getElementById(`recap-${tid}-round-list`) | ||||||
|             let poolListId = `recap-${tournament.id}-round-${round}-pool-list` |         let poolListId = `recap-${tid}-round-${round}-pool-list` | ||||||
|         let poolList = document.getElementById(poolListId) |         let poolList = document.getElementById(poolListId) | ||||||
|         if (poolList === null) { |         if (poolList === null) { | ||||||
|             // Add a div for the round in the recap div |             // Add a div for the round in the recap div | ||||||
|             let div = document.createElement('div') |             let div = document.createElement('div') | ||||||
|                 div.id = `recap-${tournament.id}-round-${round}` |             div.id = `recap-${tid}-round-${round}` | ||||||
|             div.classList.add('col-md-6', 'px-3', 'py-3') |             div.classList.add('col-md-6', 'px-3', 'py-3') | ||||||
|                 div.setAttribute('data-tournament', tournament.id) |             div.setAttribute('data-tournament', tid) | ||||||
|  |  | ||||||
|             let title = document.createElement('strong') |             let title = document.createElement('strong') | ||||||
|             title.textContent = 'Tour ' + round |             title.textContent = 'Tour ' + round | ||||||
| @@ -299,14 +310,14 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|         let c = 1 |         let c = 1 | ||||||
|  |  | ||||||
|         for (let poule of poules) { |         for (let poule of poules) { | ||||||
|                 let teamListId = `recap-${tournament.id}-round-${round}-pool-${poule.letter}-team-list` |             let teamListId = `recap-${tid}-round-${round}-pool-${poule.letter}-team-list` | ||||||
|             let teamList = document.getElementById(teamListId) |             let teamList = document.getElementById(teamListId) | ||||||
|             if (teamList === null) { |             if (teamList === null) { | ||||||
|                 // Add a div for the pool in the recap div |                 // Add a div for the pool in the recap div | ||||||
|                 let li = document.createElement('li') |                 let li = document.createElement('li') | ||||||
|                     li.id = `recap-${tournament.id}-round-${round}-pool-${poule.letter}` |                 li.id = `recap-${tid}-round-${round}-pool-${poule.letter}` | ||||||
|                 li.classList.add('list-group-item', 'px-3', 'py-3') |                 li.classList.add('list-group-item', 'px-3', 'py-3') | ||||||
|                     li.setAttribute('data-tournament', tournament.id) |                 li.setAttribute('data-tournament', tid) | ||||||
|  |  | ||||||
|                 let title = document.createElement('strong') |                 let title = document.createElement('strong') | ||||||
|                 title.textContent = 'Poule ' + poule.letter + round |                 title.textContent = 'Poule ' + poule.letter + round | ||||||
| @@ -323,11 +334,11 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|                 // The pool is initialized |                 // The pool is initialized | ||||||
|                 for (let team of poule.teams) { |                 for (let team of poule.teams) { | ||||||
|                     // Reorder dices |                     // Reorder dices | ||||||
|                         let diceDiv = document.getElementById(`dice-${tournament.id}-${team}`) |                     let diceDiv = document.getElementById(`dice-${tid}-${team}`) | ||||||
|                     diceDiv.parentElement.style.order = c.toString() |                     diceDiv.parentElement.style.order = c.toString() | ||||||
|                     c += 1 |                     c += 1 | ||||||
|  |  | ||||||
|                         let teamLiId = `recap-${tournament.id}-round-${round}-team-${team}` |                     let teamLiId = `recap-${tid}-round-${round}-team-${team}` | ||||||
|                     let teamLi = document.getElementById(teamLiId) |                     let teamLi = document.getElementById(teamLiId) | ||||||
|  |  | ||||||
|                     if (teamLi === null) { |                     if (teamLi === null) { | ||||||
| @@ -335,13 +346,13 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|                         teamLi = document.createElement('li') |                         teamLi = document.createElement('li') | ||||||
|                         teamLi.id = teamLiId |                         teamLi.id = teamLiId | ||||||
|                         teamLi.classList.add('list-group-item') |                         teamLi.classList.add('list-group-item') | ||||||
|                             teamLi.setAttribute('data-tournament', tournament.id) |                         teamLi.setAttribute('data-tournament', tid) | ||||||
|  |  | ||||||
|                         teamList.append(teamLi) |                         teamList.append(teamLi) | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     // Add the accepted problem div (empty for now) |                     // Add the accepted problem div (empty for now) | ||||||
|                         let acceptedDivId = `recap-${tournament.id}-round-${round}-team-${team}-accepted` |                     let acceptedDivId = `recap-${tid}-round-${round}-team-${team}-accepted` | ||||||
|                     let acceptedDiv = document.getElementById(acceptedDivId) |                     let acceptedDiv = document.getElementById(acceptedDivId) | ||||||
|                     if (acceptedDiv === null) { |                     if (acceptedDiv === null) { | ||||||
|                         acceptedDiv = document.createElement('div') |                         acceptedDiv = document.createElement('div') | ||||||
| @@ -352,7 +363,7 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     // Add the rejected problems div (empty for now) |                     // Add the rejected problems div (empty for now) | ||||||
|                         let rejectedDivId = `recap-${tournament.id}-round-${round}-team-${team}-rejected` |                     let rejectedDivId = `recap-${tid}-round-${round}-team-${team}-rejected` | ||||||
|                     let rejectedDiv = document.getElementById(rejectedDivId) |                     let rejectedDiv = document.getElementById(rejectedDivId) | ||||||
|                     if (rejectedDiv === null) { |                     if (rejectedDiv === null) { | ||||||
|                         rejectedDiv = document.createElement('div') |                         rejectedDiv = document.createElement('div') | ||||||
| @@ -365,8 +376,8 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|             } |             } | ||||||
|  |  | ||||||
|             // Draw tables |             // Draw tables | ||||||
|                 let tablesDiv = document.getElementById(`tables-${tournament.id}`) |             let tablesDiv = document.getElementById(`tables-${tid}`) | ||||||
|                 let tablesRoundDiv = document.getElementById(`tables-${tournament.id}-round-${round}`) |             let tablesRoundDiv = document.getElementById(`tables-${tid}-round-${round}`) | ||||||
|             if (tablesRoundDiv === null) { |             if (tablesRoundDiv === null) { | ||||||
|                 // Add the tables div for the current round if necessary |                 // Add the tables div for the current round if necessary | ||||||
|                 let card = document.createElement('div') |                 let card = document.createElement('div') | ||||||
| @@ -379,7 +390,7 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|                 card.append(cardHeader) |                 card.append(cardHeader) | ||||||
|  |  | ||||||
|                 tablesRoundDiv = document.createElement('div') |                 tablesRoundDiv = document.createElement('div') | ||||||
|                     tablesRoundDiv.id = `tables-${tournament.id}-round-${round}` |                 tablesRoundDiv.id = `tables-${tid}-round-${round}` | ||||||
|                 tablesRoundDiv.classList.add('card-body', 'd-flex', 'flex-wrap') |                 tablesRoundDiv.classList.add('card-body', 'd-flex', 'flex-wrap') | ||||||
|                 card.append(tablesRoundDiv) |                 card.append(tablesRoundDiv) | ||||||
|             } |             } | ||||||
| @@ -389,20 +400,21 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|                     continue |                     continue | ||||||
|  |  | ||||||
|                 // Display the table for the pool |                 // Display the table for the pool | ||||||
|                     updatePouleTable(round, poule) |                 updatePouleTable(tid, round, poule) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Update the table for the given round and the given pool, where there will be the chosen problems. |      * 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 round The round number, as integer (1 or 2) | ||||||
|      * @param poule The current pool, which id represented with its letter and trigrams, |      * @param poule The current pool, which id represented with its letter and trigrams, | ||||||
|      *                  {'letter': 'A', 'teams': ['ABC', 'DEF', 'GHI']} |      *                  {'letter': 'A', 'teams': ['ABC', 'DEF', 'GHI']} | ||||||
|      */ |      */ | ||||||
|         function updatePouleTable(round, poule) { |     function updatePouleTable(tid, round, poule) { | ||||||
|             let tablesRoundDiv = document.getElementById(`tables-${tournament.id}-round-${round}`) |         let tablesRoundDiv = document.getElementById(`tables-${tid}-round-${round}`) | ||||||
|             let pouleTable = document.getElementById(`table-${tournament.id}-${round}-${poule.letter}`) |         let pouleTable = document.getElementById(`table-${tid}-${round}-${poule.letter}`) | ||||||
|         if (pouleTable === null) { |         if (pouleTable === null) { | ||||||
|             // Create table |             // Create table | ||||||
|             let card = document.createElement('div') |             let card = document.createElement('div') | ||||||
| @@ -419,7 +431,7 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|             card.append(cardBody) |             card.append(cardBody) | ||||||
|  |  | ||||||
|             pouleTable = document.createElement('table') |             pouleTable = document.createElement('table') | ||||||
|                 pouleTable.id = `table-${tournament.id}-${round}-${poule.letter}` |             pouleTable.id = `table-${tid}-${round}-${poule.letter}` | ||||||
|             pouleTable.classList.add('table', 'table-stripped') |             pouleTable.classList.add('table', 'table-stripped') | ||||||
|             cardBody.append(pouleTable) |             cardBody.append(pouleTable) | ||||||
|  |  | ||||||
| @@ -464,7 +476,7 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|                 let problemTh = document.createElement('th') |                 let problemTh = document.createElement('th') | ||||||
|                 problemTh.classList.add('text-center') |                 problemTh.classList.add('text-center') | ||||||
|                 // Problem is unknown for now |                 // Problem is unknown for now | ||||||
|                     problemTh.innerHTML = `Pb. <span id="table-${tournament.id}-round-${round}-problem-${team}">?</span>` |                 problemTh.innerHTML = `Pb. <span id="table-${tid}-round-${round}-problem-${team}">?</span>` | ||||||
|                 problemTr.append(problemTh) |                 problemTr.append(problemTh) | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -553,45 +565,47 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|          * Highligh the team that is currently choosing its problem. |      * 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 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 pool The current pool letter (A, B, C or D) (null if non-relevant) | ||||||
|      * @param team The current team trigram (null if non-relevant) |      * @param team The current team trigram (null if non-relevant) | ||||||
|      */ |      */ | ||||||
|         function updateActiveRecap(round, pool, team) { |     function updateActiveRecap(tid, round, pool, team) { | ||||||
|         // Remove the previous highlights |         // Remove the previous highlights | ||||||
|             document.querySelectorAll(`div.text-bg-secondary[data-tournament="${tournament.id}"]`) |         document.querySelectorAll(`div.text-bg-secondary[data-tournament="${tid}"]`) | ||||||
|             .forEach(elem => elem.classList.remove('text-bg-secondary')) |             .forEach(elem => elem.classList.remove('text-bg-secondary')) | ||||||
|             document.querySelectorAll(`li.list-group-item-success[data-tournament="${tournament.id}"]`) |         document.querySelectorAll(`li.list-group-item-success[data-tournament="${tid}"]`) | ||||||
|             .forEach(elem => elem.classList.remove('list-group-item-success')) |             .forEach(elem => elem.classList.remove('list-group-item-success')) | ||||||
|             document.querySelectorAll(`li.list-group-item-info[data-tournament="${tournament.id}"]`) |         document.querySelectorAll(`li.list-group-item-info[data-tournament="${tid}"]`) | ||||||
|             .forEach(elem => elem.classList.remove('list-group-item-info')) |             .forEach(elem => elem.classList.remove('list-group-item-info')) | ||||||
|  |  | ||||||
|         // Highlight current round, if existing |         // Highlight current round, if existing | ||||||
|             let roundDiv = document.getElementById(`recap-${tournament.id}-round-${round}`) |         let roundDiv = document.getElementById(`recap-${tid}-round-${round}`) | ||||||
|         if (roundDiv !== null) |         if (roundDiv !== null) | ||||||
|             roundDiv.classList.add('text-bg-secondary') |             roundDiv.classList.add('text-bg-secondary') | ||||||
|  |  | ||||||
|         // Highlight current pool, if existing |         // Highlight current pool, if existing | ||||||
|             let poolLi = document.getElementById(`recap-${tournament.id}-round-${round}-pool-${pool}`) |         let poolLi = document.getElementById(`recap-${tid}-round-${round}-pool-${pool}`) | ||||||
|         if (poolLi !== null) |         if (poolLi !== null) | ||||||
|             poolLi.classList.add('list-group-item-success') |             poolLi.classList.add('list-group-item-success') | ||||||
|  |  | ||||||
|         // Highlight current team, if existing |         // Highlight current team, if existing | ||||||
|             let teamLi = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}`) |         let teamLi = document.getElementById(`recap-${tid}-round-${round}-team-${team}`) | ||||||
|         if (teamLi !== null) |         if (teamLi !== null) | ||||||
|             teamLi.classList.add('list-group-item-info') |             teamLi.classList.add('list-group-item-info') | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Update the recap and the table when a team accepts a problem. |      * 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 round The current round, as integer (1 or 2) | ||||||
|      * @param team The current team trigram |      * @param team The current team trigram | ||||||
|      * @param problem The accepted problem, as integer |      * @param problem The accepted problem, as integer | ||||||
|      */ |      */ | ||||||
|         function setProblemAccepted(round, team, problem) { |     function setProblemAccepted(tid, round, team, problem) { | ||||||
|         // Update recap |         // Update recap | ||||||
|             let recapDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-accepted`) |         let recapDiv = document.getElementById(`recap-${tid}-round-${round}-team-${team}-accepted`) | ||||||
|         if (problem !== null) { |         if (problem !== null) { | ||||||
|             recapDiv.classList.remove('text-bg-warning') |             recapDiv.classList.remove('text-bg-warning') | ||||||
|             recapDiv.classList.add('text-bg-success') |             recapDiv.classList.add('text-bg-success') | ||||||
| @@ -603,27 +617,28 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|         recapDiv.textContent = `${team} 📃 ${problem ? problem : '?'}` |         recapDiv.textContent = `${team} 📃 ${problem ? problem : '?'}` | ||||||
|  |  | ||||||
|         // Update table |         // Update table | ||||||
|             let tableSpan = document.getElementById(`table-${tournament.id}-round-${round}-problem-${team}`) |         let tableSpan = document.getElementById(`table-${tid}-round-${round}-problem-${team}`) | ||||||
|         tableSpan.textContent = problem ? problem : '?' |         tableSpan.textContent = problem ? problem : '?' | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Update the recap when a team rejects a problem. |      * 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 round The current round, as integer (1 or 2) | ||||||
|      * @param team The current team trigram |      * @param team The current team trigram | ||||||
|      * @param rejected The full list of rejected problems |      * @param rejected The full list of rejected problems | ||||||
|      */ |      */ | ||||||
|         function setProblemRejected(round, team, rejected) { |     function setProblemRejected(tid, round, team, rejected) { | ||||||
|         // Update recap |         // Update recap | ||||||
|             let recapDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-rejected`) |         let recapDiv = document.getElementById(`recap-${tid}-round-${round}-team-${team}-rejected`) | ||||||
|         recapDiv.textContent = `🗑️ ${rejected.join(', ')}` |         recapDiv.textContent = `🗑️ ${rejected.join(', ')}` | ||||||
|  |  | ||||||
|             let penaltyDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-penalty`) |         let penaltyDiv = document.getElementById(`recap-${tid}-round-${round}-team-${team}-penalty`) | ||||||
|         if (rejected.length > problems_count - 5) { |         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 more than P - 5 problems were rejected, add a penalty of 0.5 of the coefficient of the oral defender | ||||||
|             if (penaltyDiv === null) { |             if (penaltyDiv === null) { | ||||||
|                 penaltyDiv = document.createElement('div') |                 penaltyDiv = document.createElement('div') | ||||||
|                     penaltyDiv.id = `recap-${tournament.id}-round-${round}-team-${team}-penalty` |                 penaltyDiv.id = `recap-${tid}-round-${round}-team-${team}-penalty` | ||||||
|                 penaltyDiv.classList.add('badge', 'rounded-pill', 'text-bg-info') |                 penaltyDiv.classList.add('badge', 'rounded-pill', 'text-bg-info') | ||||||
|                 recapDiv.parentNode.append(penaltyDiv) |                 recapDiv.parentNode.append(penaltyDiv) | ||||||
|             } |             } | ||||||
| @@ -639,32 +654,34 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|     /** |     /** | ||||||
|      * For a 5-teams pool, we may reorder the pool if two teams select the same problem. |      * 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. |      * 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 round The current round, as integer (1 or 2) | ||||||
|      * @param poule The pool represented by its letter |      * @param poule The pool represented by its letter | ||||||
|      * @param teams The teams list represented by their trigrams, ["ABC", "DEF", "GHI", "JKL", "MNO"] |      * @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] |      * @param problems The accepted problems in the same order than the teams, [1, 1, 2, 2, 3] | ||||||
|      */ |      */ | ||||||
|         function reorderPoule(round, poule, teams, problems) { |     function reorderPoule(tid, round, poule, teams, problems) { | ||||||
|         // Redraw the pool table |         // Redraw the pool table | ||||||
|             let table = document.getElementById(`table-${tournament.id}-${round}-${poule}`) |         let table = document.getElementById(`table-${tid}-${round}-${poule}`) | ||||||
|         table.parentElement.parentElement.remove() |         table.parentElement.parentElement.remove() | ||||||
|  |  | ||||||
|             updatePouleTable(round, {'letter': poule, 'teams': teams}) |         updatePouleTable(tid, round, {'letter': poule, 'teams': teams}) | ||||||
|  |  | ||||||
|         // Put the problems in the table |         // Put the problems in the table | ||||||
|         for (let i = 0; i < teams.length; ++i) { |         for (let i = 0; i < teams.length; ++i) { | ||||||
|             let team = teams[i] |             let team = teams[i] | ||||||
|             let problem = problems[i] |             let problem = problems[i] | ||||||
|  |  | ||||||
|                 setProblemAccepted(round, team, problem) |             setProblemAccepted(tid, round, team, problem) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|         // Listen on websockets and process messages from the server |     /** | ||||||
|         socket.addEventListener('message', e => { |      * Process the received data from the server. | ||||||
|             // Parse received data as JSON |      * @param tid The tournament id | ||||||
|             const data = JSON.parse(e.data) |      * @param data The received message | ||||||
|  |      */ | ||||||
|  |     function processMessage(tid, data) { | ||||||
|         switch (data.type) { |         switch (data.type) { | ||||||
|             case 'alert': |             case 'alert': | ||||||
|                 // Add alert message |                 // Add alert message | ||||||
| @@ -676,61 +693,69 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|                 break |                 break | ||||||
|             case 'set_info': |             case 'set_info': | ||||||
|                 // Update information banner |                 // Update information banner | ||||||
|                     setInfo(data.information) |                 setInfo(tid, data.information) | ||||||
|                 break |                 break | ||||||
|             case 'draw_start': |             case 'draw_start': | ||||||
|                 // Start the draw and update the interface |                 // Start the draw and update the interface | ||||||
|                     drawStart(data.trigrams) |                 drawStart(tid, data.trigrams) | ||||||
|                 break |                 break | ||||||
|             case 'abort': |             case 'abort': | ||||||
|                 // Abort the current draw |                 // Abort the current draw | ||||||
|                     drawAbort() |                 drawAbort(tid) | ||||||
|                 break |                 break | ||||||
|             case 'dice': |             case 'dice': | ||||||
|                 // Update the interface after a dice launch |                 // Update the interface after a dice launch | ||||||
|                     updateDiceInfo(data.team, data.result) |                 updateDiceInfo(tid, data.team, data.result) | ||||||
|                 break |                 break | ||||||
|             case 'dice_visibility': |             case 'dice_visibility': | ||||||
|                 // Update the dice button visibility |                 // Update the dice button visibility | ||||||
|                     updateDiceVisibility(data.visible) |                 updateDiceVisibility(tid, data.visible) | ||||||
|                 break |                 break | ||||||
|             case 'box_visibility': |             case 'box_visibility': | ||||||
|                 // Update the box button visibility |                 // Update the box button visibility | ||||||
|                     updateBoxVisibility(data.visible) |                 updateBoxVisibility(tid, data.visible) | ||||||
|                 break |                 break | ||||||
|             case 'buttons_visibility': |             case 'buttons_visibility': | ||||||
|                 // Update the accept/reject buttons visibility |                 // Update the accept/reject buttons visibility | ||||||
|                     updateButtonsVisibility(data.visible) |                 updateButtonsVisibility(tid, data.visible) | ||||||
|                 break |                 break | ||||||
|             case 'export_visibility': |             case 'export_visibility': | ||||||
|                 // Update the export button visibility |                 // Update the export button visibility | ||||||
|                     updateExportVisibility(data.visible) |                 updateExportVisibility(tid, data.visible) | ||||||
|                 break |                 break | ||||||
|             case 'continue_visibility': |             case 'continue_visibility': | ||||||
|                 // Update the continue button visibility for the final tournament |                 // Update the continue button visibility for the final tournament | ||||||
|                     updateContinueVisibility(data.visible) |                 updateContinueVisibility(tid, data.visible) | ||||||
|                 break |                 break | ||||||
|             case 'set_poules': |             case 'set_poules': | ||||||
|                 // Set teams order and pools and update the interface |                 // Set teams order and pools and update the interface | ||||||
|                     updatePoules(data.round, data.poules) |                 updatePoules(tid, data.round, data.poules) | ||||||
|                 break |                 break | ||||||
|             case 'set_active': |             case 'set_active': | ||||||
|                 // Highlight the team that is selecting a problem |                 // Highlight the team that is selecting a problem | ||||||
|                     updateActiveRecap(data.round, data.poule, data.team) |                 updateActiveRecap(tid, data.round, data.poule, data.team) | ||||||
|                 break |                 break | ||||||
|             case 'set_problem': |             case 'set_problem': | ||||||
|                 // Mark a problem as accepted and update the interface |                 // Mark a problem as accepted and update the interface | ||||||
|                     setProblemAccepted(data.round, data.team, data.problem) |                 setProblemAccepted(tid, data.round, data.team, data.problem) | ||||||
|                 break |                 break | ||||||
|             case 'reject_problem': |             case 'reject_problem': | ||||||
|                 // Mark a problem as rejected and update the interface |                 // Mark a problem as rejected and update the interface | ||||||
|                     setProblemRejected(data.round, data.team, data.rejected) |                 setProblemRejected(tid, data.round, data.team, data.rejected) | ||||||
|                 break |                 break | ||||||
|             case 'reorder_poule': |             case 'reorder_poule': | ||||||
|                 // Reorder a pool and redraw the associated table |                 // Reorder a pool and redraw the associated table | ||||||
|                     reorderPoule(data.round, data.poule, data.teams, data.problems) |                 reorderPoule(tid, data.round, data.poule, data.teams, data.problems) | ||||||
|                 break |                 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 |     // Manage errors | ||||||
| @@ -741,11 +766,13 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|     // When the socket is opened, set the language in order to receive alerts in the good language |     // When the socket is opened, set the language in order to receive alerts in the good language | ||||||
|     socket.addEventListener('open', e => { |     socket.addEventListener('open', e => { | ||||||
|         socket.send(JSON.stringify({ |         socket.send(JSON.stringify({ | ||||||
|  |             'tid': tournaments[0].id, | ||||||
|             'type': 'set_language', |             'type': 'set_language', | ||||||
|             'language': document.getElementsByName('language')[0].value, |             'language': document.getElementsByName('language')[0].value, | ||||||
|         })) |         })) | ||||||
|     }) |     }) | ||||||
|  |  | ||||||
|  |     for (let tournament of tournaments) { | ||||||
|         // Manage the start form |         // Manage the start form | ||||||
|         let format_form = document.getElementById('format-form-' + tournament.id) |         let format_form = document.getElementById('format-form-' + tournament.id) | ||||||
|         if (format_form !== null) { |         if (format_form !== null) { | ||||||
| @@ -753,6 +780,7 @@ document.addEventListener('DOMContentLoaded', () => { | |||||||
|                 e.preventDefault() |                 e.preventDefault() | ||||||
|  |  | ||||||
|                 socket.send(JSON.stringify({ |                 socket.send(JSON.stringify({ | ||||||
|  |                     'tid': tournament.id, | ||||||
|                     'type': 'start_draw', |                     'type': 'start_draw', | ||||||
|                     'fmt': document.getElementById('format-' + tournament.id).value |                     'fmt': document.getElementById('format-' + tournament.id).value | ||||||
|                 })) |                 })) | ||||||
|   | |||||||
							
								
								
									
										270
									
								
								draw/tests.py
									
									
									
									
									
								
							
							
						
						
									
										270
									
								
								draw/tests.py
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| # Copyright (C) 2023 by Animath | # Copyright (C) 2023 by Animath | ||||||
| # SPDX-License-Identifier: GPL-3.0-or-later | # SPDX-License-Identifier: GPL-3.0-or-later | ||||||
|  | import asyncio | ||||||
| from random import shuffle | from random import shuffle | ||||||
|  |  | ||||||
| from asgiref.sync import sync_to_async | 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) |         await sync_to_async(self.async_client.force_login)(self.superuser) | ||||||
|  |  | ||||||
|  |         tid = self.tournament.id | ||||||
|  |  | ||||||
|         resp = await self.async_client.get(reverse('draw:index')) |         resp = await self.async_client.get(reverse('draw:index')) | ||||||
|         self.assertEqual(resp.status_code, 200) |         self.assertEqual(resp.status_code, 200) | ||||||
|  |  | ||||||
|         # Connect to Websocket |         # Connect to Websocket | ||||||
|         headers = [(b'cookie', self.async_client.cookies.output(header='', sep='; ').encode())] |         headers = [(b'cookie', self.async_client.cookies.output(header='', sep='; ').encode())] | ||||||
|         communicator = WebsocketCommunicator(AuthMiddlewareStack(URLRouter(routing.websocket_urlpatterns)), |         communicator = WebsocketCommunicator(AuthMiddlewareStack(URLRouter(routing.websocket_urlpatterns)), | ||||||
|                                              f"/ws/draw/{self.tournament.id}/", |                                              "/ws/draw/", headers) | ||||||
|                                              headers) |  | ||||||
|         connected, subprotocol = await communicator.connect() |         connected, subprotocol = await communicator.connect() | ||||||
|         self.assertTrue(connected) |         self.assertTrue(connected) | ||||||
|  |  | ||||||
|         # Define language |         # 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 |         # Ensure that Draw has not started | ||||||
|         self.assertFalse(await Draw.objects.filter(tournament=self.tournament).aexists()) |         self.assertFalse(await Draw.objects.filter(tournament=self.tournament).aexists()) | ||||||
|  |  | ||||||
|         # Must be an error since 1+1+1 != 12 |         # 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() |         resp = await communicator.receive_json_from() | ||||||
|         self.assertEqual(resp['type'], 'alert') |         self.assertEqual(resp['type'], 'alert') | ||||||
|         self.assertEqual(resp['alert_type'], 'danger') |         self.assertEqual(resp['alert_type'], 'danger') | ||||||
| @@ -74,29 +75,30 @@ class TestDraw(TestCase): | |||||||
|         self.assertFalse(await Draw.objects.filter(tournament=self.tournament).aexists()) |         self.assertFalse(await Draw.objects.filter(tournament=self.tournament).aexists()) | ||||||
|  |  | ||||||
|         # Now start the draw |         # 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 |         # Receive data after the start | ||||||
|         self.assertEqual((await communicator.receive_json_from())['type'], 'alert') |         self.assertEqual((await communicator.receive_json_from())['type'], 'alert') | ||||||
|         self.assertEqual(await communicator.receive_json_from(), |         self.assertEqual(await communicator.receive_json_from(), | ||||||
|                          {'type': 'set_poules', 'round': 1, |                          {'tid': tid, 'type': 'set_poules', 'round': 1, | ||||||
|                           'poules': [{'letter': 'A', 'teams': []}, |                           'poules': [{'letter': 'A', 'teams': []}, | ||||||
|                                      {'letter': 'B', 'teams': []}, |                                      {'letter': 'B', 'teams': []}, | ||||||
|                                      {'letter': 'C', 'teams': []}]}) |                                      {'letter': 'C', 'teams': []}]}) | ||||||
|         self.assertEqual(await communicator.receive_json_from(), |         self.assertEqual(await communicator.receive_json_from(), | ||||||
|                          {'type': 'set_poules', 'round': 2, |                          {'tid': tid, 'type': 'set_poules', 'round': 2, | ||||||
|                           'poules': [{'letter': 'A', 'teams': []}, |                           'poules': [{'letter': 'A', 'teams': []}, | ||||||
|                                      {'letter': 'B', 'teams': []}, |                                      {'letter': 'B', 'teams': []}, | ||||||
|                                      {'letter': 'C', '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'], 'alert') | ||||||
|         self.assertEqual(await communicator.receive_json_from(), |         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', |                           'trigrams': ['AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF', | ||||||
|                                        'GGG', 'HHH', 'III', 'JJJ', 'KKK', 'LLL']}) |                                        '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_info') | ||||||
|         self.assertEqual(await communicator.receive_json_from(), |         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') |         self.assertEqual((await communicator.receive_json_from())['type'], 'notification') | ||||||
|  |  | ||||||
|         # Ensure that now tournament has started |         # Ensure that now tournament has started | ||||||
| @@ -107,7 +109,7 @@ class TestDraw(TestCase): | |||||||
|         self.assertEqual(resp.status_code, 200) |         self.assertEqual(resp.status_code, 200) | ||||||
|  |  | ||||||
|         # Try to relaunch the draw |         # 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() |         resp = await communicator.receive_json_from() | ||||||
|         self.assertEqual(resp['type'], 'alert') |         self.assertEqual(resp['type'], 'alert') | ||||||
|         self.assertEqual(resp['alert_type'], 'danger') |         self.assertEqual(resp['alert_type'], 'danger') | ||||||
| @@ -119,7 +121,7 @@ class TestDraw(TestCase): | |||||||
|  |  | ||||||
|         for i, team in enumerate(self.teams): |         for i, team in enumerate(self.teams): | ||||||
|             # Launch a new dice |             # 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() |             resp = await communicator.receive_json_from() | ||||||
|             self.assertEqual(resp['type'], "dice") |             self.assertEqual(resp['type'], "dice") | ||||||
|             self.assertEqual(resp['team'], team.trigram) |             self.assertEqual(resp['team'], team.trigram) | ||||||
| @@ -130,7 +132,7 @@ class TestDraw(TestCase): | |||||||
|                 self.assertEqual(resp['result'], td.passage_dice) |                 self.assertEqual(resp['result'], td.passage_dice) | ||||||
|  |  | ||||||
|                 # Try to relaunch the 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() |                 resp = await communicator.receive_json_from() | ||||||
|                 self.assertEqual(resp['type'], 'alert') |                 self.assertEqual(resp['type'], 'alert') | ||||||
|                 self.assertEqual(resp['message'], "You've already launched the dice.") |                 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') |             self.assertEqual((await communicator.receive_json_from())['type'], 'alert') | ||||||
|  |  | ||||||
|             for i in range(dup_count): |             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() |                 await communicator.receive_json_from() | ||||||
|  |  | ||||||
|         # Reset dices |         # Reset dices | ||||||
| @@ -161,8 +163,10 @@ class TestDraw(TestCase): | |||||||
|             self.assertIsNone(resp['result']) |             self.assertIsNone(resp['result']) | ||||||
|  |  | ||||||
|         # Hide and re-display the dice |         # 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(), | ||||||
|         self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': True}) |                          {'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 |         # Set pools for the two rounds | ||||||
|         self.assertEqual((await communicator.receive_json_from())['type'], 'set_poules') |         self.assertEqual((await communicator.receive_json_from())['type'], 'set_poules') | ||||||
| @@ -172,7 +176,7 @@ class TestDraw(TestCase): | |||||||
|  |  | ||||||
|         # Manage the first pool |         # Manage the first pool | ||||||
|         self.assertEqual(await communicator.receive_json_from(), |         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')\ |         r: Round = await Round.objects.prefetch_related('current_pool__current_team__participation__team')\ | ||||||
|             .aget(number=1, draw=draw) |             .aget(number=1, draw=draw) | ||||||
|         p = r.current_pool |         p = r.current_pool | ||||||
| @@ -188,7 +192,7 @@ class TestDraw(TestCase): | |||||||
|         i = 0 |         i = 0 | ||||||
|         async for td in p.teamdraw_set.prefetch_related('participation__team').all(): |         async for td in p.teamdraw_set.prefetch_related('participation__team').all(): | ||||||
|             # Launch a new dice |             # 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() |             resp = await communicator.receive_json_from() | ||||||
|             self.assertEqual(resp['type'], "dice") |             self.assertEqual(resp['type'], "dice") | ||||||
|             trigram = td.participation.team.trigram |             trigram = td.participation.team.trigram | ||||||
| @@ -200,7 +204,7 @@ class TestDraw(TestCase): | |||||||
|                 self.assertEqual(resp['result'], td.choice_dice) |                 self.assertEqual(resp['result'], td.choice_dice) | ||||||
|  |  | ||||||
|                 # Try to relaunch the 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() |                 resp = await communicator.receive_json_from() | ||||||
|                 self.assertEqual(resp['type'], 'alert') |                 self.assertEqual(resp['type'], 'alert') | ||||||
|                 self.assertEqual(resp['message'], "You've already launched the dice.") |                 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') |             self.assertEqual((await communicator.receive_json_from())['type'], 'alert') | ||||||
|  |  | ||||||
|             for i in range(dup_count): |             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() |                 await communicator.receive_json_from() | ||||||
|  |  | ||||||
|         self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') |         self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
| @@ -232,27 +236,32 @@ class TestDraw(TestCase): | |||||||
|         td = p.current_team |         td = p.current_team | ||||||
|         trigram = td.participation.team.trigram |         trigram = td.participation.team.trigram | ||||||
|         self.assertEqual(td.choose_index, 0) |         self.assertEqual(td.choose_index, 0) | ||||||
|         self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'A', |         self.assertEqual(await communicator.receive_json_from(), | ||||||
|                                                                   'team': td.participation.team.trigram}) |                          {'tid': tid, 'type': 'set_active', 'round': 1, | ||||||
|  |                           'poule': 'A', 'team': td.participation.team.trigram}) | ||||||
|         # Dice is hidden for everyone first |         # 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 |         # 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 |         # Render page | ||||||
|         resp = await self.async_client.get(reverse('draw:index')) |         resp = await self.async_client.get(reverse('draw:index')) | ||||||
|         self.assertEqual(resp.status_code, 200) |         self.assertEqual(resp.status_code, 200) | ||||||
|  |  | ||||||
|         # Try to launch a dice while it is not the time |         # 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() |         resp = await communicator.receive_json_from() | ||||||
|         self.assertEqual(resp['type'], 'alert') |         self.assertEqual(resp['type'], 'alert') | ||||||
|         self.assertEqual(resp['message'], "This is not the time for this.") |         self.assertEqual(resp['message'], "This is not the time for this.") | ||||||
|  |  | ||||||
|         # Draw a problem |         # Draw a problem | ||||||
|         await communicator.send_json_to({'type': 'draw_problem'}) |         await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'}) | ||||||
|         self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False}) |         self.assertEqual(await communicator.receive_json_from(), | ||||||
|         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') |         self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|  |  | ||||||
|         td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |         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) |         self.assertEqual(resp.status_code, 200) | ||||||
|  |  | ||||||
|         # Try to redraw a problem while it is not the time |         # 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() |         resp = await communicator.receive_json_from() | ||||||
|         self.assertEqual(resp['type'], 'alert') |         self.assertEqual(resp['type'], 'alert') | ||||||
|         self.assertEqual(resp['message'], "This is not the time for this.") |         self.assertEqual(resp['message'], "This is not the time for this.") | ||||||
|  |  | ||||||
|         # Reject the first problem |         # Reject the first problem | ||||||
|         await communicator.send_json_to({'type': 'reject'}) |         await communicator.send_json_to({'tid': tid, 'type': 'reject'}) | ||||||
|         self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': False}) |  | ||||||
|         self.assertEqual(await communicator.receive_json_from(), |         self.assertEqual(await communicator.receive_json_from(), | ||||||
|                          {'type': 'reject_problem', 'round': 1, 'team': trigram, 'rejected': [purposed]}) |                          {'tid': tid, 'type': 'buttons_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': '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') |         self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|         td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |         td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) | ||||||
|         self.assertIsNone(td.purposed) |         self.assertIsNone(td.purposed) | ||||||
| @@ -287,17 +298,19 @@ class TestDraw(TestCase): | |||||||
|             td = p.current_team |             td = p.current_team | ||||||
|             trigram = td.participation.team.trigram |             trigram = td.participation.team.trigram | ||||||
|             self.assertEqual(td.choose_index, i + 1) |             self.assertEqual(td.choose_index, i + 1) | ||||||
|             self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'A', |             self.assertEqual(await communicator.receive_json_from(), | ||||||
|                                                                       'team': trigram}) |                              {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'A', 'team': trigram}) | ||||||
|  |  | ||||||
|             # Render page |             # Render page | ||||||
|             resp = await self.async_client.get(reverse('draw:index')) |             resp = await self.async_client.get(reverse('draw:index')) | ||||||
|             self.assertEqual(resp.status_code, 200) |             self.assertEqual(resp.status_code, 200) | ||||||
|  |  | ||||||
|             # Draw a problem |             # Draw a problem | ||||||
|             await communicator.send_json_to({'type': 'draw_problem'}) |             await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'}) | ||||||
|             self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False}) |             self.assertEqual(await communicator.receive_json_from(), | ||||||
|             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') |             self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|  |  | ||||||
|             td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |             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) |             self.assertEqual(resp.status_code, 200) | ||||||
|  |  | ||||||
|             # Accept the problem |             # 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}) |  | ||||||
|             self.assertEqual(await communicator.receive_json_from(), |             self.assertEqual(await communicator.receive_json_from(), | ||||||
|                              {'type': 'set_problem', 'round': 1, 'team': trigram, 'problem': 1 + (i % 2)}) |                              {'tid': tid, 'type': 'buttons_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': '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') |             self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|             td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |             td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) | ||||||
|             self.assertIsNone(td.purposed) |             self.assertIsNone(td.purposed) | ||||||
| @@ -332,15 +347,17 @@ class TestDraw(TestCase): | |||||||
|         td = p.current_team |         td = p.current_team | ||||||
|         trigram = td.participation.team.trigram |         trigram = td.participation.team.trigram | ||||||
|         self.assertEqual(td.choose_index, 0) |         self.assertEqual(td.choose_index, 0) | ||||||
|         self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'A', |         self.assertEqual(await communicator.receive_json_from(), | ||||||
|                                                                   'team': trigram}) |                          {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'A', 'team': trigram}) | ||||||
|  |  | ||||||
|         # Draw and reject 100 times a problem |         # Draw and reject 100 times a problem | ||||||
|         for _i in range(100): |         for _i in range(100): | ||||||
|             # Draw a problem |             # Draw a problem | ||||||
|             await communicator.send_json_to({'type': 'draw_problem'}) |             await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'}) | ||||||
|             self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False}) |             self.assertEqual(await communicator.receive_json_from(), | ||||||
|             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') |             self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|  |  | ||||||
|             td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |             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)) |             self.assertIn(td.purposed, range(3, len(settings.PROBLEMS) + 1)) | ||||||
|  |  | ||||||
|             # Reject |             # Reject | ||||||
|             await communicator.send_json_to({'type': 'reject'}) |             await communicator.send_json_to({'tid': tid, 'type': 'reject'}) | ||||||
|             self.assertEqual(await communicator.receive_json_from(), {'type': 'buttons_visibility', 'visible': False}) |             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'], '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') |             self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|             td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |             td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) | ||||||
|             self.assertIsNone(td.purposed) |             self.assertIsNone(td.purposed) | ||||||
| @@ -361,8 +380,8 @@ class TestDraw(TestCase): | |||||||
|             # Ensures that this is still the first team |             # Ensures that this is still the first team | ||||||
|             p: Pool = await Pool.objects.prefetch_related('current_team__participation__team').aget(round=r, letter=1) |             p: Pool = await Pool.objects.prefetch_related('current_team__participation__team').aget(round=r, letter=1) | ||||||
|             self.assertEqual(p.current_team, td) |             self.assertEqual(p.current_team, td) | ||||||
|             self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'A', |             self.assertEqual(await communicator.receive_json_from(), | ||||||
|                                                                       'team': trigram}) |                              {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'A', 'team': trigram}) | ||||||
|  |  | ||||||
|         # Render page |         # Render page | ||||||
|         resp = await self.async_client.get(reverse('draw:index')) |         resp = await self.async_client.get(reverse('draw:index')) | ||||||
| @@ -372,9 +391,11 @@ class TestDraw(TestCase): | |||||||
|         self.assertGreaterEqual(td.penalty, 1) |         self.assertGreaterEqual(td.penalty, 1) | ||||||
|  |  | ||||||
|         # Draw a last problem |         # Draw a last problem | ||||||
|         await communicator.send_json_to({'type': 'draw_problem'}) |         await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'}) | ||||||
|         self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False}) |         self.assertEqual(await communicator.receive_json_from(), | ||||||
|         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') |         self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|  |  | ||||||
|         td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |         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)) |         self.assertIn(td.purposed, range(1, len(settings.PROBLEMS) + 1)) | ||||||
|  |  | ||||||
|         # Accept the problem |         # 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}) |  | ||||||
|         self.assertEqual(await communicator.receive_json_from(), |         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) |         td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) | ||||||
|         self.assertIsNone(td.purposed) |         self.assertIsNone(td.purposed) | ||||||
|  |  | ||||||
|         # Reorder the pool since there are 5 teams |         # 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'], '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_info') | ||||||
|         self.assertEqual(await communicator.receive_json_from(), |         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 |         # Start pool 2 | ||||||
|         r: Round = await Round.objects.prefetch_related('current_pool__current_team__participation__team')\ |         r: Round = await Round.objects.prefetch_related('current_pool__current_team__participation__team')\ | ||||||
| @@ -412,7 +435,7 @@ class TestDraw(TestCase): | |||||||
|         i = 0 |         i = 0 | ||||||
|         async for td in p.teamdraw_set.prefetch_related('participation__team').all(): |         async for td in p.teamdraw_set.prefetch_related('participation__team').all(): | ||||||
|             # Launch a new dice |             # 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 communicator.receive_json_from() | ||||||
|             await td.arefresh_from_db() |             await td.arefresh_from_db() | ||||||
|             td.choice_dice = 101 + i  # Avoid duplicates |             td.choice_dice = 101 + i  # Avoid duplicates | ||||||
| @@ -427,20 +450,24 @@ class TestDraw(TestCase): | |||||||
|             td = p.current_team |             td = p.current_team | ||||||
|             trigram = td.participation.team.trigram |             trigram = td.participation.team.trigram | ||||||
|             self.assertEqual(td.choose_index, i) |             self.assertEqual(td.choose_index, i) | ||||||
|             self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'B', |             self.assertEqual(await communicator.receive_json_from(), | ||||||
|                                                                       'team': trigram}) |                              {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'B', 'team': trigram}) | ||||||
|             if i == 0: |             if i == 0: | ||||||
|                 self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': False}) |                 self.assertEqual(await communicator.receive_json_from(), | ||||||
|                 self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': True}) |                                  {'tid': tid, 'type': 'dice_visibility', 'visible': False}) | ||||||
|  |                 self.assertEqual(await communicator.receive_json_from(), | ||||||
|  |                                  {'tid': tid, 'type': 'box_visibility', 'visible': True}) | ||||||
|  |  | ||||||
|             # Render page |             # Render page | ||||||
|             resp = await self.async_client.get(reverse('draw:index')) |             resp = await self.async_client.get(reverse('draw:index')) | ||||||
|             self.assertEqual(resp.status_code, 200) |             self.assertEqual(resp.status_code, 200) | ||||||
|  |  | ||||||
|             # Draw a problem |             # Draw a problem | ||||||
|             await communicator.send_json_to({'type': 'draw_problem'}) |             await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'}) | ||||||
|             self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False}) |             self.assertEqual(await communicator.receive_json_from(), | ||||||
|             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') |             self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|  |  | ||||||
|             td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |             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) |             self.assertEqual(resp.status_code, 200) | ||||||
|  |  | ||||||
|             # Accept the problem |             # 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}) |  | ||||||
|             self.assertEqual(await communicator.receive_json_from(), |             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: |             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: |             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') |             self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|             td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |             td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) | ||||||
|             self.assertIsNone(td.purposed) |             self.assertIsNone(td.purposed) | ||||||
| @@ -483,8 +513,8 @@ class TestDraw(TestCase): | |||||||
|         self.assertEqual(p.size, 3) |         self.assertEqual(p.size, 3) | ||||||
|         self.assertEqual(await p.teamdraw_set.acount(), 3) |         self.assertEqual(await p.teamdraw_set.acount(), 3) | ||||||
|         self.assertEqual(p.current_team, None) |         self.assertEqual(p.current_team, None) | ||||||
|         self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'C', |         self.assertEqual(await communicator.receive_json_from(), | ||||||
|                                                                   'team': None}) |                          {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'C', 'team': None}) | ||||||
|  |  | ||||||
|         # Render page |         # Render page | ||||||
|         resp = await self.async_client.get(reverse('draw:index')) |         resp = await self.async_client.get(reverse('draw:index')) | ||||||
| @@ -493,7 +523,7 @@ class TestDraw(TestCase): | |||||||
|         i = 0 |         i = 0 | ||||||
|         async for td in p.teamdraw_set.prefetch_related('participation__team').all(): |         async for td in p.teamdraw_set.prefetch_related('participation__team').all(): | ||||||
|             # Launch a new dice |             # 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 communicator.receive_json_from() | ||||||
|             await td.arefresh_from_db() |             await td.arefresh_from_db() | ||||||
|             td.choice_dice = 101 + i  # Avoid duplicates |             td.choice_dice = 101 + i  # Avoid duplicates | ||||||
| @@ -508,20 +538,24 @@ class TestDraw(TestCase): | |||||||
|             td = p.current_team |             td = p.current_team | ||||||
|             trigram = td.participation.team.trigram |             trigram = td.participation.team.trigram | ||||||
|             self.assertEqual(td.choose_index, i) |             self.assertEqual(td.choose_index, i) | ||||||
|             self.assertEqual(await communicator.receive_json_from(), {'type': 'set_active', 'round': 1, 'poule': 'C', |             self.assertEqual(await communicator.receive_json_from(), | ||||||
|                                                                       'team': trigram}) |                              {'tid': tid, 'type': 'set_active', 'round': 1, 'poule': 'C', 'team': trigram}) | ||||||
|             if i == 0: |             if i == 0: | ||||||
|                 self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': False}) |                 self.assertEqual(await communicator.receive_json_from(), | ||||||
|                 self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': True}) |                                  {'tid': tid, 'type': 'dice_visibility', 'visible': False}) | ||||||
|  |                 self.assertEqual(await communicator.receive_json_from(), | ||||||
|  |                                  {'tid': tid, 'type': 'box_visibility', 'visible': True}) | ||||||
|  |  | ||||||
|             # Render page |             # Render page | ||||||
|             resp = await self.async_client.get(reverse('draw:index')) |             resp = await self.async_client.get(reverse('draw:index')) | ||||||
|             self.assertEqual(resp.status_code, 200) |             self.assertEqual(resp.status_code, 200) | ||||||
|  |  | ||||||
|             # Draw a problem |             # Draw a problem | ||||||
|             await communicator.send_json_to({'type': 'draw_problem'}) |             await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'}) | ||||||
|             self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False}) |             self.assertEqual(await communicator.receive_json_from(), | ||||||
|             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') |             self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|  |  | ||||||
|             td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |             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) |             self.assertEqual(resp.status_code, 200) | ||||||
|  |  | ||||||
|             # Accept the problem |             # 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}) |  | ||||||
|             self.assertEqual(await communicator.receive_json_from(), |             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) |             td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) | ||||||
|             self.assertIsNone(td.purposed) |             self.assertIsNone(td.purposed) | ||||||
|             self.assertEqual(td.accepted, i + 1) |             self.assertEqual(td.accepted, i + 1) | ||||||
|             if i == 2: |             if i == 2: | ||||||
|                 break |                 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') |             self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|  |  | ||||||
|             # Render page |             # Render page | ||||||
| @@ -572,8 +608,10 @@ class TestDraw(TestCase): | |||||||
|         self.assertEqual(resp['type'], 'set_poules') |         self.assertEqual(resp['type'], 'set_poules') | ||||||
|         self.assertEqual(resp['round'], 2) |         self.assertEqual(resp['round'], 2) | ||||||
|  |  | ||||||
|         self.assertEqual(await communicator.receive_json_from(), {'type': 'dice_visibility', 'visible': True}) |         self.assertEqual(await communicator.receive_json_from(), | ||||||
|         self.assertEqual(await communicator.receive_json_from(), {'type': 'export_visibility', 'visible': True}) |                          {'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') |         self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|  |  | ||||||
|         # Render page |         # Render page | ||||||
| @@ -589,12 +627,12 @@ class TestDraw(TestCase): | |||||||
|             self.assertEqual(p.size, 5 - i) |             self.assertEqual(p.size, 5 - i) | ||||||
|  |  | ||||||
|             self.assertEqual(await communicator.receive_json_from(), |             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 |             j = 0 | ||||||
|             async for td in p.teamdraw_set.prefetch_related('participation__team').all(): |             async for td in p.teamdraw_set.prefetch_related('participation__team').all(): | ||||||
|                 # Launch a new dice |                 # 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 communicator.receive_json_from() | ||||||
|                 await td.arefresh_from_db() |                 await td.arefresh_from_db() | ||||||
|                 td.choice_dice = 101 + j  # Avoid duplicates |                 td.choice_dice = 101 + j  # Avoid duplicates | ||||||
| @@ -612,23 +650,24 @@ class TestDraw(TestCase): | |||||||
|                 trigram = td.participation.team.trigram |                 trigram = td.participation.team.trigram | ||||||
|                 self.assertEqual(td.choose_index, j) |                 self.assertEqual(td.choose_index, j) | ||||||
|                 self.assertEqual(await communicator.receive_json_from(), |                 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}) |                                   'team': trigram}) | ||||||
|                 if j == 0: |                 if j == 0: | ||||||
|                     self.assertEqual(await communicator.receive_json_from(), |                     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(), |                     self.assertEqual(await communicator.receive_json_from(), | ||||||
|                                      {'type': 'box_visibility', 'visible': True}) |                                      {'tid': tid, 'type': 'box_visibility', 'visible': True}) | ||||||
|  |  | ||||||
|                 # Render page |                 # Render page | ||||||
|                 resp = await self.async_client.get(reverse('draw:index')) |                 resp = await self.async_client.get(reverse('draw:index')) | ||||||
|                 self.assertEqual(resp.status_code, 200) |                 self.assertEqual(resp.status_code, 200) | ||||||
|  |  | ||||||
|                 # Draw a problem |                 # Draw a problem | ||||||
|                 await communicator.send_json_to({'type': 'draw_problem'}) |                 await communicator.send_json_to({'tid': tid, 'type': 'draw_problem'}) | ||||||
|                 self.assertEqual(await communicator.receive_json_from(), {'type': 'box_visibility', 'visible': False}) |  | ||||||
|                 self.assertEqual(await communicator.receive_json_from(), |                 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') |                 self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|  |  | ||||||
|                 td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |                 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) |                 self.assertNotEqual(td.purposed, old_td.accepted) | ||||||
|  |  | ||||||
|                 # Accept the problem |                 # 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(), |                 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') |                 self.assertEqual((await communicator.receive_json_from())['type'], 'set_problem') | ||||||
|                 td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) |                 td: TeamDraw = await TeamDraw.objects.prefetch_related('participation__team').aget(pk=td.pk) | ||||||
|                 self.assertIsNone(td.purposed) |                 self.assertIsNone(td.purposed) | ||||||
|                 if j == 4 - i: |                 if j == 4 - i: | ||||||
|                     break |                     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') |                 self.assertEqual((await communicator.receive_json_from())['type'], 'set_info') | ||||||
|  |  | ||||||
|             if i == 0: |             if i == 0: | ||||||
|                 # Reorder the pool since there are 5 teams |                 # 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'], 'reorder_poule') | ||||||
|             if i < 2: |             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: |             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_info') | ||||||
|  |  | ||||||
|         self.assertEqual((await communicator.receive_json_from())['type'], 'set_active') |         self.assertEqual((await communicator.receive_json_from())['type'], 'set_active') | ||||||
|  |  | ||||||
|         # Export the draw |         # Export the draw | ||||||
|         await communicator.send_json_to({'type': 'export'}) |         await communicator.send_json_to({'tid': tid, 'type': 'export'}) | ||||||
|         self.assertEqual(await communicator.receive_json_from(), {'type': 'export_visibility', 'visible': False}) |         self.assertEqual(await communicator.receive_json_from(), | ||||||
|  |                          {'tid': tid, 'type': 'export_visibility', 'visible': False}) | ||||||
|  |  | ||||||
|         # Cancel all steps and reset all |         # Cancel all steps and reset all | ||||||
|         for i in range(1000): |         for i in range(1000): | ||||||
|             await communicator.send_json_to({'type': 'cancel'}) |             await communicator.send_json_to({'tid': tid, 'type': 'cancel'}) | ||||||
|             if not await Draw.objects.filter(tournament=self.tournament).aexists(): |  | ||||||
|  |         # Purge receive queue | ||||||
|  |         while True: | ||||||
|  |             try: | ||||||
|  |                 await communicator.receive_json_from() | ||||||
|  |             except asyncio.TimeoutError: | ||||||
|                 break |                 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() |                 'current_round__current_pool__current_team__participation__team').aget()).get_state() | ||||||
|             raise AssertionError("Draw wasn't aborted after 1000 steps, current state: " + current_state) |             raise AssertionError("Draw wasn't aborted after 1000 steps, current state: " + current_state) | ||||||
|  |  | ||||||
|         # Abort while the tournament is already aborted |         # 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): |     def test_admin_pages(self): | ||||||
|         """ |         """ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user