mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2025-02-26 21:06:27 +00:00
Compare commits
No commits in common. "8778f58fe4ce9391b468a92e1b6c0febcbb6b571" and "746aae464a9a94caa3507aa881b70832fad1e2d2" have entirely different histories.
8778f58fe4
...
746aae464a
@ -2,16 +2,13 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import json
|
|
||||||
from random import randint, shuffle
|
from random import randint, shuffle
|
||||||
|
|
||||||
from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
from channels.generic.websocket import AsyncJsonWebsocketConsumer
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.models import ContentType
|
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from draw.models import Draw, Pool, Round, TeamDraw
|
from draw.models import Draw, Pool, Round, TeamDraw
|
||||||
from logs.models import Changelog
|
|
||||||
from participation.models import Participation, Tournament
|
from participation.models import Participation, Tournament
|
||||||
from registration.models import Registration
|
from registration.models import Registration
|
||||||
|
|
||||||
@ -118,9 +115,6 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||||||
case 'abort':
|
case 'abort':
|
||||||
# Abort the current draw
|
# Abort the current draw
|
||||||
await self.abort(**content)
|
await self.abort(**content)
|
||||||
case 'cancel':
|
|
||||||
# Cancel the last step
|
|
||||||
await self.cancel_last_step(**content)
|
|
||||||
case 'dice':
|
case 'dice':
|
||||||
# Launch a dice
|
# Launch a dice
|
||||||
await self.process_dice(**content)
|
await self.process_dice(**content)
|
||||||
@ -351,14 +345,11 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||||||
if values.count(v) > 1:
|
if values.count(v) > 1:
|
||||||
# v is a duplicate value
|
# v is a duplicate value
|
||||||
# Get all teams that have the same result
|
# Get all teams that have the same result
|
||||||
dups = [td for td in tds if (td.passage_dice if state == 'DICE_SELECT_POULES' else td.choice_dice) == v]
|
dups = [td for td in tds if td.passage_dice == v]
|
||||||
|
|
||||||
for dup in dups:
|
for dup in dups:
|
||||||
# Reset the dice
|
# Reset the dice
|
||||||
if state == 'DICE_SELECT_POULES':
|
dup.passage_dice = None
|
||||||
dup.passage_dice = None
|
|
||||||
else:
|
|
||||||
dup.choice_dice = None
|
|
||||||
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}",
|
||||||
@ -656,7 +647,7 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||||||
:param pool: The pool to end.
|
:param pool: The pool to end.
|
||||||
"""
|
"""
|
||||||
msg = self.tournament.draw.last_message
|
msg = self.tournament.draw.last_message
|
||||||
r = self.tournament.draw.current_round
|
r = pool.round
|
||||||
|
|
||||||
if pool.size == 5:
|
if pool.size == 5:
|
||||||
# Maybe reorder teams if the same problem is presented twice
|
# Maybe reorder teams if the same problem is presented twice
|
||||||
@ -934,350 +925,6 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||||||
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', 'draw': self.tournament.draw})
|
{'type': 'draw.set_active', 'draw': self.tournament.draw})
|
||||||
|
|
||||||
@ensure_orga
|
|
||||||
async def cancel_last_step(self, **kwargs):
|
|
||||||
"""
|
|
||||||
Cancel the last step of the draw.
|
|
||||||
"""
|
|
||||||
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 = ""
|
|
||||||
await self.tournament.draw.asave()
|
|
||||||
|
|
||||||
r = self.tournament.draw.current_round
|
|
||||||
|
|
||||||
if state == 'DRAW_ENDED' or state == 'WAITING_FINAL':
|
|
||||||
td = self.tournament.draw.current_round.current_pool.current_team
|
|
||||||
td.purposed = td.accepted
|
|
||||||
td.accepted = None
|
|
||||||
await td.asave()
|
|
||||||
|
|
||||||
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
|
|
||||||
{'type': 'draw.continue_visibility', 'visible': False})
|
|
||||||
|
|
||||||
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
|
|
||||||
{'type': 'draw.buttons_visibility', 'visible': True})
|
|
||||||
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 state == 'WAITING_CHOOSE_PROBLEM':
|
|
||||||
td = self.tournament.draw.current_round.current_pool.current_team
|
|
||||||
td.purposed = None
|
|
||||||
await td.asave()
|
|
||||||
|
|
||||||
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
|
|
||||||
{'type': 'draw.buttons_visibility', 'visible': False})
|
|
||||||
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
|
|
||||||
{'type': 'draw.buttons_visibility', 'visible': False})
|
|
||||||
await self.channel_layer.group_send(f"team-{td.participation.team.trigram}",
|
|
||||||
{'type': 'draw.box_visibility', 'visible': True})
|
|
||||||
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=content_type,
|
|
||||||
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)
|
|
||||||
|
|
||||||
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=content_type,
|
|
||||||
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})
|
|
||||||
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):
|
async def draw_alert(self, content):
|
||||||
"""
|
"""
|
||||||
Send alert to the current user.
|
Send alert to the current user.
|
||||||
|
@ -20,15 +20,6 @@ function abortDraw(tid) {
|
|||||||
sockets[tid].send(JSON.stringify({'type': 'abort'}))
|
sockets[tid].send(JSON.stringify({'type': 'abort'}))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Request to cancel the last step.
|
|
||||||
* Only volunteers are allowed to do this.
|
|
||||||
* @param tid The tournament id
|
|
||||||
*/
|
|
||||||
function cancelLastStep(tid) {
|
|
||||||
sockets[tid].send(JSON.stringify({'type': 'cancel'}))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request to launch a dice between 1 and 100, for the two first steps.
|
* Request to launch a dice between 1 and 100, for the two first steps.
|
||||||
* The parameter `trigram` can be specified (by volunteers) to launch a dice for a specific team.
|
* The parameter `trigram` can be specified (by volunteers) to launch a dice for a specific team.
|
||||||
@ -592,19 +583,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
function setProblemAccepted(round, team, problem) {
|
function setProblemAccepted(round, team, problem) {
|
||||||
// Update recap
|
// Update recap
|
||||||
let recapDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-accepted`)
|
let recapDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-accepted`)
|
||||||
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')
|
recapDiv.textContent = `${team} 📃 ${problem}`
|
||||||
}
|
|
||||||
else {
|
|
||||||
recapDiv.classList.add('text-bg-warning')
|
|
||||||
recapDiv.classList.remove('text-bg-success')
|
|
||||||
}
|
|
||||||
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-${tournament.id}-round-${round}-problem-${team}`)
|
||||||
tableSpan.textContent = problem ? problem : '?'
|
tableSpan.textContent = problem
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -618,9 +603,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
let recapDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-rejected`)
|
let recapDiv = document.getElementById(`recap-${tournament.id}-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`)
|
|
||||||
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
|
||||||
|
let penaltyDiv = document.getElementById(`recap-${tournament.id}-round-${round}-team-${team}-penalty`)
|
||||||
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-${tournament.id}-round-${round}-team-${team}-penalty`
|
||||||
@ -629,11 +614,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
penaltyDiv.textContent = `❌ ${0.5 * (rejected.length - (problems_count - 5))}`
|
penaltyDiv.textContent = `❌ ${0.5 * (rejected.length - (problems_count - 5))}`
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// Eventually remove this div
|
|
||||||
if (penaltyDiv !== null)
|
|
||||||
penaltyDiv.remove()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,13 +54,6 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
Recap
|
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>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div id="recap-{{ tournament.id }}-round-list" class="row">
|
<div id="recap-{{ tournament.id }}-round-list" class="row">
|
||||||
@ -327,17 +320,17 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</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 %}
|
|
||||||
</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 %}
|
||||||
|
|
||||||
<div id="abort{{ tournament.id }}Modal" class="modal fade" tabindex="-1" role="dialog">
|
<div id="abort{{ tournament.id }}Modal" class="modal fade" tabindex="-1" role="dialog">
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
|
@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: TFJM\n"
|
"Project-Id-Version: TFJM\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2023-04-05 18:54+0200\n"
|
"POT-Creation-Date: 2023-04-05 18:37+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
|
"Last-Translator: Emmy D'Anello <emmy.danello@animath.fr>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -46,64 +46,64 @@ msgstr "Tirage au sort"
|
|||||||
msgid "You are not an organizer."
|
msgid "You are not an organizer."
|
||||||
msgstr "Vous n'êtes pas un⋅e organisateur⋅rice."
|
msgstr "Vous n'êtes pas un⋅e organisateur⋅rice."
|
||||||
|
|
||||||
#: draw/consumers.py:148
|
#: draw/consumers.py:145
|
||||||
msgid "The draw is already started."
|
msgid "The draw is already started."
|
||||||
msgstr "Le tirage a déjà commencé."
|
msgstr "Le tirage a déjà commencé."
|
||||||
|
|
||||||
#: draw/consumers.py:154
|
#: draw/consumers.py:151
|
||||||
msgid "Invalid format"
|
msgid "Invalid format"
|
||||||
msgstr "Format invalide"
|
msgstr "Format invalide"
|
||||||
|
|
||||||
#: draw/consumers.py:159
|
#: draw/consumers.py:156
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "The sum must be equal to the number of teams: expected {len}, got {sum}"
|
msgid "The sum must be equal to the number of teams: expected {len}, got {sum}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"La somme doit être égale au nombre d'équipes : attendu {len}, obtenu {sum}"
|
"La somme doit être égale au nombre d'équipes : attendu {len}, obtenu {sum}"
|
||||||
|
|
||||||
#: draw/consumers.py:164
|
#: draw/consumers.py:161
|
||||||
msgid "There can be at most one pool with 5 teams."
|
msgid "There can be at most one pool with 5 teams."
|
||||||
msgstr "Il ne peut y avoir au plus qu'une seule poule de 5 équipes."
|
msgstr "Il ne peut y avoir au plus qu'une seule poule de 5 équipes."
|
||||||
|
|
||||||
#: draw/consumers.py:192
|
#: draw/consumers.py:189
|
||||||
msgid "Draw started!"
|
msgid "Draw started!"
|
||||||
msgstr "Le tirage a commencé !"
|
msgstr "Le tirage a commencé !"
|
||||||
|
|
||||||
#: draw/consumers.py:212
|
#: draw/consumers.py:209
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "The draw for the tournament {tournament} will start."
|
msgid "The draw for the tournament {tournament} will start."
|
||||||
msgstr "Le tirage au sort du tournoi {tournament} va commencer."
|
msgstr "Le tirage au sort du tournoi {tournament} va commencer."
|
||||||
|
|
||||||
#: draw/consumers.py:223 draw/consumers.py:248 draw/consumers.py:579
|
#: draw/consumers.py:220 draw/consumers.py:245 draw/consumers.py:576
|
||||||
#: draw/consumers.py:768 draw/consumers.py:850 draw/consumers.py:867
|
#: draw/consumers.py:765 draw/consumers.py:847 draw/consumers.py:864
|
||||||
#: draw/consumers.py:937 draw/templates/draw/tournament_content.html:5
|
#: draw/templates/draw/tournament_content.html:5
|
||||||
msgid "The draw has not started yet."
|
msgid "The draw has not started yet."
|
||||||
msgstr "Le tirage au sort n'a pas encore commencé."
|
msgstr "Le tirage au sort n'a pas encore commencé."
|
||||||
|
|
||||||
#: draw/consumers.py:235
|
#: draw/consumers.py:232
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "The draw for the tournament {tournament} is aborted."
|
msgid "The draw for the tournament {tournament} is aborted."
|
||||||
msgstr "Le tirage au sort du tournoi {tournament} est annulé."
|
msgstr "Le tirage au sort du tournoi {tournament} est annulé."
|
||||||
|
|
||||||
#: draw/consumers.py:275 draw/consumers.py:296 draw/consumers.py:525
|
#: draw/consumers.py:272 draw/consumers.py:293 draw/consumers.py:522
|
||||||
#: draw/consumers.py:584 draw/consumers.py:773
|
#: draw/consumers.py:581 draw/consumers.py:770
|
||||||
msgid "This is not the time for this."
|
msgid "This is not the time for this."
|
||||||
msgstr "Ce n'est pas le moment pour cela."
|
msgstr "Ce n'est pas le moment pour cela."
|
||||||
|
|
||||||
#: draw/consumers.py:288 draw/consumers.py:291
|
#: draw/consumers.py:285 draw/consumers.py:288
|
||||||
msgid "You've already launched the dice."
|
msgid "You've already launched the dice."
|
||||||
msgstr "Vous avez déjà lancé le dé."
|
msgstr "Vous avez déjà lancé le dé."
|
||||||
|
|
||||||
#: draw/consumers.py:294
|
#: draw/consumers.py:291
|
||||||
msgid "It is not your turn."
|
msgid "It is not your turn."
|
||||||
msgstr "Ce n'est pas votre tour."
|
msgstr "Ce n'est pas votre tour."
|
||||||
|
|
||||||
#: draw/consumers.py:372
|
#: draw/consumers.py:369
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Dices from teams {teams} are identical. Please relaunch your dices."
|
msgid "Dices from teams {teams} are identical. Please relaunch your dices."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Les dés des équipes {teams} sont identiques. Merci de relancer vos dés."
|
"Les dés des équipes {teams} sont identiques. Merci de relancer vos dés."
|
||||||
|
|
||||||
#: draw/consumers.py:870
|
#: draw/consumers.py:867
|
||||||
msgid "This is only available for the final tournament."
|
msgid "This is only available for the final tournament."
|
||||||
msgstr "Cela n'est possible que pour la finale."
|
msgstr "Cela n'est possible que pour la finale."
|
||||||
|
|
||||||
@ -312,46 +312,42 @@ msgstr "Exporter"
|
|||||||
msgid "Continue draw"
|
msgid "Continue draw"
|
||||||
msgstr "Continuer le tirage"
|
msgstr "Continuer le tirage"
|
||||||
|
|
||||||
#: draw/templates/draw/tournament_content.html:183
|
#: draw/templates/draw/tournament_content.html:209 participation/admin.py:100
|
||||||
msgid "Cancel last step"
|
|
||||||
msgstr "Annuler la dernière étape"
|
|
||||||
|
|
||||||
#: draw/templates/draw/tournament_content.html:215 participation/admin.py:100
|
|
||||||
#: participation/models.py:125 participation/models.py:310
|
#: participation/models.py:125 participation/models.py:310
|
||||||
#: registration/models.py:127
|
#: registration/models.py:127
|
||||||
msgid "team"
|
msgid "team"
|
||||||
msgstr "équipe"
|
msgstr "équipe"
|
||||||
|
|
||||||
#: draw/templates/draw/tournament_content.html:225
|
#: draw/templates/draw/tournament_content.html:219
|
||||||
#: draw/templates/draw/tournament_content.html:226
|
#: draw/templates/draw/tournament_content.html:220
|
||||||
#: draw/templates/draw/tournament_content.html:227
|
#: draw/templates/draw/tournament_content.html:221
|
||||||
#: draw/templates/draw/tournament_content.html:228
|
#: draw/templates/draw/tournament_content.html:222
|
||||||
#: draw/templates/draw/tournament_content.html:229
|
#: draw/templates/draw/tournament_content.html:223
|
||||||
msgid "Room"
|
msgid "Room"
|
||||||
msgstr "Salle"
|
msgstr "Salle"
|
||||||
|
|
||||||
#: draw/templates/draw/tournament_content.html:335
|
#: draw/templates/draw/tournament_content.html:329
|
||||||
#: draw/templates/draw/tournament_content.html:353
|
#: draw/templates/draw/tournament_content.html:347
|
||||||
msgid "Abort"
|
msgid "Abort"
|
||||||
msgstr "Annuler"
|
msgstr "Annuler"
|
||||||
|
|
||||||
#: draw/templates/draw/tournament_content.html:344
|
#: draw/templates/draw/tournament_content.html:338
|
||||||
msgid "Are you sure?"
|
msgid "Are you sure?"
|
||||||
msgstr "Êtes-vous sûr⋅e ?"
|
msgstr "Êtes-vous sûr⋅e ?"
|
||||||
|
|
||||||
#: draw/templates/draw/tournament_content.html:348
|
#: draw/templates/draw/tournament_content.html:342
|
||||||
msgid "This will reset the draw from the beginning."
|
msgid "This will reset the draw from the beginning."
|
||||||
msgstr "Cela va réinitialiser le tirage au sort depuis le début."
|
msgstr "Cela va réinitialiser le tirage au sort depuis le début."
|
||||||
|
|
||||||
#: draw/templates/draw/tournament_content.html:349
|
#: draw/templates/draw/tournament_content.html:343
|
||||||
msgid "This operation is irreversible."
|
msgid "This operation is irreversible."
|
||||||
msgstr "Cette opération est irréversible."
|
msgstr "Cette opération est irréversible."
|
||||||
|
|
||||||
#: draw/templates/draw/tournament_content.html:350
|
#: draw/templates/draw/tournament_content.html:344
|
||||||
msgid "Are you sure you want to abort this draw?"
|
msgid "Are you sure you want to abort this draw?"
|
||||||
msgstr "Êtes-vous sûr·e de vouloir annuler le tirage au sort ?"
|
msgstr "Êtes-vous sûr·e de vouloir annuler le tirage au sort ?"
|
||||||
|
|
||||||
#: draw/templates/draw/tournament_content.html:354
|
#: draw/templates/draw/tournament_content.html:348
|
||||||
#: tfjm/templates/base_modal.html:17
|
#: tfjm/templates/base_modal.html:17
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Fermer"
|
msgstr "Fermer"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user