Add export button
Signed-off-by: Emmy D'Anello <emmy.danello@animath.fr>
This commit is contained in:
parent
e95d511017
commit
b838f1b3f0
|
@ -1,5 +1,6 @@
|
|||
# Copyright (C) 2023 by Animath
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from collections import OrderedDict
|
||||
from random import randint
|
||||
|
||||
|
@ -85,6 +86,8 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
await self.accept_problem(**content)
|
||||
case 'reject':
|
||||
await self.reject_problem(**content)
|
||||
case 'export':
|
||||
await self.export(**content)
|
||||
|
||||
@ensure_orga
|
||||
async def start_draw(self, fmt, **kwargs):
|
||||
|
@ -503,6 +506,9 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
|
||||
{'type': 'draw.dice_visibility', 'visible': True})
|
||||
|
||||
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
|
||||
{'type': 'draw.export_visibility', 'visible': True})
|
||||
|
||||
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}",
|
||||
|
@ -572,6 +578,15 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
{'type': 'draw.set_active', 'draw': self.tournament.draw})
|
||||
|
||||
|
||||
async def export(self, **kwargs):
|
||||
async for r in self.tournament.draw.round_set.all():
|
||||
async for pool in r.pool_set.all():
|
||||
if await sync_to_async(lambda: pool.exportable)():
|
||||
await sync_to_async(pool.export)()
|
||||
|
||||
await self.channel_layer.group_send(f"volunteer-{self.tournament.id}",
|
||||
{'type': 'draw.export_visibility', 'visible': False})
|
||||
|
||||
async def draw_alert(self, content):
|
||||
return await self.alert(**content)
|
||||
|
||||
|
@ -593,6 +608,9 @@ class DrawConsumer(AsyncJsonWebsocketConsumer):
|
|||
async def draw_buttons_visibility(self, content):
|
||||
await self.send_json({'type': 'buttons_visibility', 'visible': content['visible']})
|
||||
|
||||
async def draw_export_visibility(self, content):
|
||||
await self.send_json({'type': 'export_visibility', 'visible': content['visible']})
|
||||
|
||||
async def draw_send_poules(self, content):
|
||||
await self.send_json({'type': 'set_poules', 'round': content['round'].number,
|
||||
'poules': [{'letter': pool.get_letter_display(), 'teams': await pool.atrigrams()}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# Generated by Django 4.1.7 on 2023-03-25 07:22
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("participation", "0003_alter_team_trigram"),
|
||||
("draw", "0005_draw_last_message"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="pool",
|
||||
name="associated_pool",
|
||||
field=models.OneToOneField(
|
||||
default=None,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="draw_pool",
|
||||
to="participation.pool",
|
||||
verbose_name="associated pool",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -1,12 +1,13 @@
|
|||
# Copyright (C) 2023 by Animath
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from asgiref.sync import sync_to_async
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils.text import format_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from participation.models import Participation, Tournament
|
||||
from participation.models import Passage, Participation, Pool as PPool, Tournament
|
||||
|
||||
|
||||
class Draw(models.Model):
|
||||
|
@ -31,6 +32,10 @@ class Draw(models.Model):
|
|||
verbose_name=_("last message"),
|
||||
)
|
||||
|
||||
@property
|
||||
def exportable(self):
|
||||
return any(pool.exportable for r in self.round_set.all() for pool in r.pool_set.all())
|
||||
|
||||
def get_state(self):
|
||||
if self.current_round.current_pool is None:
|
||||
return 'DICE_SELECT_POULES'
|
||||
|
@ -173,6 +178,15 @@ class Pool(models.Model):
|
|||
verbose_name=_('current team'),
|
||||
)
|
||||
|
||||
associated_pool = models.OneToOneField(
|
||||
'participation.Pool',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
default=None,
|
||||
related_name='draw_pool',
|
||||
verbose_name=_("associated pool"),
|
||||
)
|
||||
|
||||
@property
|
||||
def team_draws(self):
|
||||
return self.teamdraw_set.order_by('passage_index').all()
|
||||
|
@ -194,6 +208,53 @@ class Pool(models.Model):
|
|||
td = await self.teamdraw_set.aget(choose_index=current_index)
|
||||
return td
|
||||
|
||||
@property
|
||||
def exportable(self):
|
||||
return self.associated_pool is None and all(td.accepted is not None for td in self.teamdraw_set.all())
|
||||
|
||||
def export(self):
|
||||
from django.db import transaction
|
||||
with transaction.atomic():
|
||||
self.associated_pool = PPool.objects.create(
|
||||
tournament=self.round.draw.tournament,
|
||||
round=self.round.number,
|
||||
)
|
||||
self.associated_pool.juries.set(self.round.draw.tournament.organizers.all())
|
||||
tds = list(self.team_draws)
|
||||
self.associated_pool.participations.set([td.participation for td in tds])
|
||||
|
||||
if len(tds) == 3:
|
||||
table = [
|
||||
[0, 1, 2],
|
||||
[1, 2, 0],
|
||||
[2, 0, 1],
|
||||
]
|
||||
elif len(tds) == 4:
|
||||
table = [
|
||||
[0, 1, 2],
|
||||
[1, 2, 3],
|
||||
[2, 3, 0],
|
||||
[3, 0, 1],
|
||||
]
|
||||
elif len(tds) == 5:
|
||||
table = [
|
||||
[0, 2, 3],
|
||||
[1, 3, 4],
|
||||
[2, 0, 1],
|
||||
[3, 4, 0],
|
||||
[4, 1, 2],
|
||||
]
|
||||
|
||||
for line in table:
|
||||
Passage.objects.create(
|
||||
pool=self.associated_pool,
|
||||
solution_number=tds[line[0]].accepted,
|
||||
defender=tds[line[0]].participation,
|
||||
opponent=tds[line[1]].participation,
|
||||
reporter=tds[line[2]].participation,
|
||||
defender_penalties=tds[line[0]].penalty_int,
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.get_letter_display()}{self.round.number}"
|
||||
|
||||
|
@ -267,9 +328,13 @@ class TeamDraw(models.Model):
|
|||
verbose_name=_('rejected problems'),
|
||||
)
|
||||
|
||||
@property
|
||||
def penalty_int(self):
|
||||
return max(0, len(self.rejected) - (settings.PROBLEM_COUNT - 5))
|
||||
|
||||
@property
|
||||
def penalty(self):
|
||||
return max(0, 0.5 * (len(self.rejected) - (settings.PROBLEM_COUNT - 5)))
|
||||
return 0.5 * self.penalty_int
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('team draw')
|
||||
|
|
|
@ -28,6 +28,10 @@ function rejectProblem(tid) {
|
|||
sockets[tid].send(JSON.stringify({'type': 'reject'}))
|
||||
}
|
||||
|
||||
function exportDraw(tid) {
|
||||
sockets[tid].send(JSON.stringify({'type': 'export'}))
|
||||
}
|
||||
|
||||
function showNotification(title, body, timeout = 5000) {
|
||||
let notif = new Notification(title, {'body': body, 'icon': "/static/tfjm.svg"})
|
||||
if (timeout)
|
||||
|
@ -139,6 +143,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
div.classList.add('d-none')
|
||||
}
|
||||
|
||||
function updateExportVisibility(visible) {
|
||||
let div = document.getElementById(`export-${tournament.id}`)
|
||||
if (visible)
|
||||
div.classList.remove('d-none')
|
||||
else
|
||||
div.classList.add('d-none')
|
||||
}
|
||||
|
||||
function updatePoules(round, poules) {
|
||||
let roundList = document.getElementById(`recap-${tournament.id}-round-list`)
|
||||
let poolListId = `recap-${tournament.id}-round-${round}-pool-list`
|
||||
|
@ -493,6 +505,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
case 'buttons_visibility':
|
||||
updateButtonsVisibility(data.visible)
|
||||
break
|
||||
case 'export_visibility':
|
||||
updateExportVisibility(data.visible)
|
||||
break
|
||||
case 'set_poules':
|
||||
updatePoules(data.round, data.poules)
|
||||
break
|
||||
|
|
|
@ -148,6 +148,14 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if user.registration.is_volunteer %}
|
||||
<div id="export-{{ tournament.id }}"
|
||||
class="card-footer text-center{% if not tournament.draw.exportable %} d-none{% endif %}">
|
||||
<button class="btn btn-info text-center" onclick="exportDraw({{ tournament.id }})">
|
||||
📁 {% trans "Export" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue