The draw is now fully reversible
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
parent
751e35ac62
commit
8778f58fe4
|
@ -1,7 +1,8 @@
|
|||
# Copyright (C) 2023 by Animath
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
import json
|
||||
|
||||
from collections import OrderedDict
|
||||
import json
|
||||
from random import randint, shuffle
|
||||
|
||||
from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
||||
|
@ -350,11 +351,14 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
if values.count(v) > 1:
|
||||
# v is a duplicate value
|
||||
# Get all teams that have the same result
|
||||
dups = [td for td in tds if td.passage_dice == v]
|
||||
dups = [td for td in tds if (td.passage_dice if state == 'DICE_SELECT_POULES' else td.choice_dice) == v]
|
||||
|
||||
for dup in dups:
|
||||
# Reset the dice
|
||||
dup.passage_dice = None
|
||||
if state == 'DICE_SELECT_POULES':
|
||||
dup.passage_dice = None
|
||||
else:
|
||||
dup.choice_dice = None
|
||||
await dup.asave()
|
||||
await self.channel_layer.group_send(
|
||||
f"tournament-{self.tournament.id}",
|
||||
|
@ -938,6 +942,9 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
if not await Draw.objects.filter(tournament=self.tournament).aexists():
|
||||
return await self.alert(_("The draw has not started yet."), 'danger')
|
||||
|
||||
content_type = await ContentType.objects.aget(app_label=TeamDraw._meta.app_label,
|
||||
model=TeamDraw._meta.model_name)
|
||||
|
||||
state = self.tournament.draw.get_state()
|
||||
|
||||
self.tournament.draw.last_message = ""
|
||||
|
@ -952,7 +959,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
await td.asave()
|
||||
|
||||
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
|
||||
{'type': 'draw.continue_visibility', 'visible': False})
|
||||
{'type': 'draw.continue_visibility', 'visible': False})
|
||||
|
||||
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
|
||||
{'type': 'draw.buttons_visibility', 'visible': True})
|
||||
|
@ -989,8 +996,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
if accepted_tds or has_rejected_one_tds:
|
||||
# One team of the already accepted or its problem, we fetch the last one
|
||||
changelogs = Changelog.objects.filter(
|
||||
model=await ContentType.objects.aget(app_label=TeamDraw._meta.app_label,
|
||||
model=TeamDraw._meta.model_name),
|
||||
model=content_type,
|
||||
action='edit',
|
||||
instance_pk__in=set(accepted_tds.keys()).union(set(has_rejected_one_tds.keys()))
|
||||
).order_by('-timestamp')
|
||||
|
@ -999,7 +1005,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
previous = json.loads(changelog.previous)
|
||||
data = json.loads(changelog.data)
|
||||
pk = int(changelog.instance_pk)
|
||||
print(previous, data, pk)
|
||||
|
||||
if 'accepted' in data and data['accepted'] and pk in accepted_tds:
|
||||
# Undo the last acceptance
|
||||
last_td = accepted_tds[pk]
|
||||
|
@ -1043,7 +1049,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
# Return to the dice choice
|
||||
pool_tds = {td.id: td async for td in p.team_draws.prefetch_related('participation__team')}
|
||||
changelogs = Changelog.objects.filter(
|
||||
model=ContentType.objects.get_for_model(TeamDraw),
|
||||
model=content_type,
|
||||
action='edit',
|
||||
instance_pk__in=set(pool_tds.keys())
|
||||
).order_by('-timestamp')
|
||||
|
@ -1076,13 +1082,202 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
|
||||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
{'type': 'draw.box_visibility', 'visible': False})
|
||||
elif state == 'DICE_ORDER_POULE':
|
||||
p = r.current_pool
|
||||
already_launched_tds = {td.id: td async for td in p.team_draws.filter(choice_dice__isnull=False)
|
||||
.prefetch_related('participation__team')}
|
||||
|
||||
if already_launched_tds:
|
||||
# Reset the last dice
|
||||
changelogs = Changelog.objects.filter(
|
||||
model=content_type,
|
||||
action='edit',
|
||||
instance_pk__in=set(already_launched_tds.keys())
|
||||
).order_by('-timestamp')
|
||||
|
||||
# Find the last dice that was launched
|
||||
async for changelog in changelogs:
|
||||
data = json.loads(changelog.data)
|
||||
if 'choice_dice' in data and data['choice_dice']:
|
||||
last_td = already_launched_tds[int(changelog.instance_pk)]
|
||||
# Reset the dice
|
||||
last_td.choice_dice = None
|
||||
await last_td.asave()
|
||||
|
||||
# Reset the dice on the interface
|
||||
await self.channel_layer.group_send(
|
||||
f"tournament-{self.tournament.id}", {'type': 'draw.dice',
|
||||
'team': last_td.participation.team.trigram,
|
||||
'result': None})
|
||||
break
|
||||
else:
|
||||
# Go to the previous pool if possible
|
||||
if p.letter > 1:
|
||||
# Go to the previous pool
|
||||
previous_pool = await r.pool_set.prefetch_related('current_team__participation__team')\
|
||||
.aget(letter=p.letter - 1)
|
||||
r.current_pool = previous_pool
|
||||
await r.asave()
|
||||
|
||||
td = previous_pool.current_team
|
||||
td.purposed = td.accepted
|
||||
td.accepted = None
|
||||
await td.asave()
|
||||
|
||||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
{'type': 'draw.dice_visibility', 'visible': False})
|
||||
|
||||
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
|
||||
{'type': 'draw.buttons_visibility', 'visible': True})
|
||||
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
|
||||
{'type': 'draw.buttons_visibility', 'visible': True})
|
||||
|
||||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
{'type': 'draw.set_problem',
|
||||
'round': r.number,
|
||||
'team': td.participation.team.trigram,
|
||||
'problem': td.accepted})
|
||||
elif r.number == 2:
|
||||
if not self.tournament.final:
|
||||
# Go to the previous round
|
||||
r1 = await self.tournament.draw.round_set\
|
||||
.prefetch_related('current_pool__current_team__participation__team').aget(number=1)
|
||||
self.tournament.draw.current_round = r1
|
||||
await self.tournament.draw.asave()
|
||||
|
||||
async for td in r1.team_draws.prefetch_related('participation__team').all():
|
||||
await self.channel_layer.group_send(
|
||||
f"tournament-{self.tournament.id}", {'type': 'draw.dice',
|
||||
'team': td.participation.team.trigram,
|
||||
'result': td.choice_dice})
|
||||
|
||||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
{'type': 'draw.send_poules', 'round': r1})
|
||||
|
||||
previous_pool = r1.current_pool
|
||||
|
||||
td = previous_pool.current_team
|
||||
td.purposed = td.accepted
|
||||
td.accepted = None
|
||||
await td.asave()
|
||||
|
||||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
{'type': 'draw.dice_visibility', 'visible': False})
|
||||
|
||||
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
|
||||
{'type': 'draw.buttons_visibility', 'visible': True})
|
||||
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
|
||||
{'type': 'draw.buttons_visibility', 'visible': True})
|
||||
|
||||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
{'type': 'draw.set_problem',
|
||||
'round': r1.number,
|
||||
'team': td.participation.team.trigram,
|
||||
'problem': td.accepted})
|
||||
else:
|
||||
# Don't continue the final tournament
|
||||
r1 = await self.tournament.draw.round_set \
|
||||
.prefetch_related('current_pool__current__team__participation__team').aget(number=1)
|
||||
self.tournament.draw.current_round = r1
|
||||
await self.tournament.draw.asave()
|
||||
|
||||
async for td in r.teamdraw_set.all():
|
||||
td.pool = None
|
||||
td.choose_index = None
|
||||
td.choice_dice = None
|
||||
await td.asave()
|
||||
|
||||
async for td in r1.team_draws.prefetch_related('participation__team').all():
|
||||
await self.channel_layer.group_send(
|
||||
f"tournament-{self.tournament.id}", {'type': 'draw.dice',
|
||||
'team': td.participation.team.trigram,
|
||||
'result': td.choice_dice})
|
||||
|
||||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
{'type': 'draw.dice_visibility', 'visible': False})
|
||||
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
|
||||
{'type': 'draw.continue_visibility', 'visible': True})
|
||||
else:
|
||||
# Go to the dice order
|
||||
async for r0 in self.tournament.draw.round_set.all():
|
||||
async for td in r0.teamdraw_set.all():
|
||||
td.pool = None
|
||||
td.passage_index = None
|
||||
td.choose_index = None
|
||||
td.choice_dice = None
|
||||
await td.asave()
|
||||
|
||||
r.current_pool = None
|
||||
await r.asave()
|
||||
|
||||
round_tds = {td.id: td async for td in r.team_draws.prefetch_related('participation__team')}
|
||||
|
||||
# Reset the last dice
|
||||
changelogs = Changelog.objects.filter(
|
||||
model=content_type,
|
||||
action='edit',
|
||||
instance_pk__in=set(round_tds.keys())
|
||||
).order_by('-timestamp')
|
||||
|
||||
# Find the last dice that was launched
|
||||
async for changelog in changelogs:
|
||||
data = json.loads(changelog.data)
|
||||
if 'passage_dice' in data and data['passage_dice']:
|
||||
last_td = round_tds[int(changelog.instance_pk)]
|
||||
# Reset the dice
|
||||
last_td.passage_dice = None
|
||||
await last_td.asave()
|
||||
|
||||
# Reset the dice on the interface
|
||||
await self.channel_layer.group_send(
|
||||
f"tournament-{self.tournament.id}", {'type': 'draw.dice',
|
||||
'team': last_td.participation.team.trigram,
|
||||
'result': None})
|
||||
break
|
||||
|
||||
async for td in r.team_draws.prefetch_related('participation__team').all():
|
||||
await self.channel_layer.group_send(
|
||||
f"tournament-{self.tournament.id}", {'type': 'draw.dice',
|
||||
'team': td.participation.team.trigram,
|
||||
'result': td.passage_dice})
|
||||
|
||||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
{'type': 'draw.dice_visibility', 'visible': True})
|
||||
elif state == 'DICE_SELECT_POULES':
|
||||
already_launched_tds = {td.id: td async for td in r.team_draws.filter(passage_dice__isnull=False)
|
||||
.prefetch_related('participation__team')}
|
||||
|
||||
if already_launched_tds:
|
||||
# Reset the last dice
|
||||
changelogs = Changelog.objects.filter(
|
||||
model=content_type,
|
||||
action='edit',
|
||||
instance_pk__in=set(already_launched_tds.keys())
|
||||
).order_by('-timestamp')
|
||||
|
||||
# Find the last dice that was launched
|
||||
async for changelog in changelogs:
|
||||
data = json.loads(changelog.data)
|
||||
if 'passage_dice' in data and data['passage_dice']:
|
||||
last_td = already_launched_tds[int(changelog.instance_pk)]
|
||||
# Reset the dice
|
||||
last_td.passage_dice = None
|
||||
await last_td.asave()
|
||||
|
||||
# Reset the dice on the interface
|
||||
await self.channel_layer.group_send(
|
||||
f"tournament-{self.tournament.id}", {'type': 'draw.dice',
|
||||
'team': last_td.participation.team.trigram,
|
||||
'result': None})
|
||||
break
|
||||
else:
|
||||
await self.abort()
|
||||
|
||||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
{'type': 'draw.set_info', 'draw': self.tournament.draw})
|
||||
await self.channel_layer.group_send(f"tournament-{self.tournament.id}",
|
||||
{'type': 'draw.set_active', 'draw': self.tournament.draw})
|
||||
|
||||
|
||||
async def draw_alert(self, content):
|
||||
"""
|
||||
Send alert to the current user.
|
||||
|
|
|
@ -54,6 +54,13 @@
|
|||
<div class="card">
|
||||
<div class="card-header">
|
||||
Recap
|
||||
{% if user.registration.is_volunteer %}
|
||||
<button id="cancel-last-step-{{ tournament.id }}"
|
||||
class="badge rounded-pill text-bg-warning"
|
||||
onclick="cancelLastStep({{ tournament.id }})">
|
||||
🔙 {% trans "Cancel last step" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="recap-{{ tournament.id }}-round-list" class="row">
|
||||
|
@ -177,12 +184,6 @@
|
|||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div id="cancel-last-step-{{ tournament.id }}"
|
||||
class="card-footer text-center">
|
||||
<button class="badge rounded-pill text-bg-warning" onclick="cancelLastStep({{ tournament.id }})">
|
||||
🔙 {% trans "Cancel last step" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -326,16 +327,16 @@
|
|||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if user.registration.is_volunteer %}
|
||||
{# Volunteers can click on this button to abort the draw #}
|
||||
<div class="text-center mt-3">
|
||||
<button id="abort-{{ tournament.id }}" class="badge rounded-pill text-bg-danger" data-bs-toggle="modal" data-bs-target="#abort{{ tournament.id }}Modal">
|
||||
{% trans "Abort" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if user.registration.is_volunteer %}
|
||||
{# Volunteers can click on this button to abort the draw #}
|
||||
<div class="text-center mt-3">
|
||||
<button id="abort-{{ tournament.id }}" class="badge rounded-pill text-bg-danger" data-bs-toggle="modal" data-bs-target="#abort{{ tournament.id }}Modal">
|
||||
{% trans "Abort" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div id="abort{{ tournament.id }}Modal" class="modal fade" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
|
|
Loading…
Reference in New Issue