From 751e35ac62b0da80dc038d8265319da8daea8721 Mon Sep 17 00:00:00 2001 From: Emmy D'Anello Date: Wed, 5 Apr 2023 23:28:12 +0200 Subject: [PATCH] Cancel draw problem Signed-off-by: Emmy D'Anello --- draw/consumers.py | 103 +++++++++++++++++++++++++++++++++++++++++++- draw/static/draw.js | 7 ++- 2 files changed, 108 insertions(+), 2 deletions(-) diff --git a/draw/consumers.py b/draw/consumers.py index a67f98d..d7c644f 100644 --- a/draw/consumers.py +++ b/draw/consumers.py @@ -1,14 +1,16 @@ # Copyright (C) 2023 by Animath # SPDX-License-Identifier: GPL-3.0-or-later - +import json from collections import OrderedDict from random import randint, shuffle from channels.generic.websocket import AsyncJsonWebsocketConsumer from django.conf import settings +from django.contrib.contenttypes.models import ContentType from django.utils import translation from django.utils.translation import gettext_lazy as _ from draw.models import Draw, Pool, Round, TeamDraw +from logs.models import Changelog from participation.models import Participation, Tournament from registration.models import Registration @@ -975,6 +977,105 @@ class DrawConsumer(AsyncJsonWebsocketConsumer): {'type': 'draw.box_visibility', 'visible': True}) await self.channel_layer.group_send(f"volunteer-{self.tournament.id}", {'type': 'draw.box_visibility', 'visible': True}) + elif state == 'WAITING_DRAW_PROBLEM': + p = r.current_pool + accepted_tds = {td.id: td async for td in p.team_draws.filter(accepted__isnull=False) + .prefetch_related('participation__team')} + has_rejected_one_tds = {td.id: td async for td in p.team_draws.exclude(rejected=[]) + .prefetch_related('participation__team')} + + last_td = None + + 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), + action='edit', + instance_pk__in=set(accepted_tds.keys()).union(set(has_rejected_one_tds.keys())) + ).order_by('-timestamp') + + async for changelog in changelogs: + 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] + last_td.purposed = last_td.accepted + last_td.accepted = None + await last_td.asave() + + await self.channel_layer.group_send(f"tournament-{self.tournament.id}", + {'type': 'draw.set_problem', + 'round': r.number, + 'team': last_td.participation.team.trigram, + 'problem': last_td.accepted}) + break + if 'rejected' in data and len(data['rejected']) > len(previous['rejected']) \ + and pk in has_rejected_one_tds: + # Undo the last reject + last_td = has_rejected_one_tds[pk] + rejected_problem = set(data['rejected']).difference(previous['rejected']).pop() + if rejected_problem not in last_td.rejected: + # This is an old diff + continue + last_td.rejected.remove(rejected_problem) + last_td.purposed = rejected_problem + await last_td.asave() + + await self.channel_layer.group_send(f"tournament-{self.tournament.id}", + {'type': 'draw.reject_problem', + 'round': r.number, + 'team': last_td.participation.team.trigram, + 'rejected': last_td.rejected}) + break + + r.current_pool.current_team = last_td + await r.current_pool.asave() + + await self.channel_layer.group_send(f"team-{last_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}) + else: + # 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), + action='edit', + instance_pk__in=set(pool_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 = pool_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 + + p.current_team = None + await p.asave() + + # Make dice box visible + for td in pool_tds.values(): + await self.channel_layer.group_send(f"team-{td.participation.team.trigram}", + {'type': 'draw.dice_visibility', 'visible': True}) + await self.channel_layer.group_send(f"volunteer-{self.tournament.id}", + {'type': 'draw.dice_visibility', 'visible': True}) + + await self.channel_layer.group_send(f"tournament-{self.tournament.id}", + {'type': 'draw.box_visibility', 'visible': False}) await self.channel_layer.group_send(f"tournament-{self.tournament.id}", {'type': 'draw.set_info', 'draw': self.tournament.draw}) diff --git a/draw/static/draw.js b/draw/static/draw.js index 200107b..efdf508 100644 --- a/draw/static/draw.js +++ b/draw/static/draw.js @@ -618,9 +618,9 @@ document.addEventListener('DOMContentLoaded', () => { let recapDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-rejected`) recapDiv.textContent = `🗑️ ${rejected.join(', ')}` + let penaltyDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-penalty`) if (rejected.length > problems_count - 5) { // If more than P - 5 problems were rejected, add a penalty of 0.5 of the coefficient of the oral defender - let penaltyDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-penalty`) if (penaltyDiv === null) { penaltyDiv = document.createElement('div') penaltyDiv.id = `recap-${tournament.id}-round-${round}-team-${team}-penalty` @@ -629,6 +629,11 @@ document.addEventListener('DOMContentLoaded', () => { } penaltyDiv.textContent = `❌ ${0.5 * (rejected.length - (problems_count - 5))}` } + else { + // Eventually remove this div + if (penaltyDiv !== null) + penaltyDiv.remove() + } } /**