Prepare the data structure for the participations

This commit is contained in:
Yohann D'ANELLO 2020-12-28 13:47:05 +01:00
parent d9a85948b3
commit 18b4fa81d3
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
1 changed files with 145 additions and 121 deletions

View File

@ -4,6 +4,7 @@
import os import os
import re import re
from registration.models import VolunteerRegistration
from tfjm.lists import get_sympa_client from tfjm.lists import get_sympa_client
from tfjm.matrix import Matrix, RoomPreset, RoomVisibility from tfjm.matrix import Matrix, RoomPreset, RoomVisibility
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
@ -43,12 +44,6 @@ class Team(models.Model):
help_text=_("The access code let other people to join the team."), help_text=_("The access code let other people to join the team."),
) )
grant_animath_access_videos = models.BooleanField(
verbose_name=_("Grant Animath to publish my video"),
help_text=_("Give the authorisation to publish the video on the main website to promote the action."),
default=False,
)
@property @property
def email(self): def email(self):
""" """
@ -117,6 +112,95 @@ class Team(models.Model):
] ]
class Tournament(models.Model):
name = models.CharField(
max_length=255,
verbose_name=_("name"),
unique=True,
)
date_start = models.DateField(
verbose_name=_("start"),
default=timezone.now,
)
date_end = models.DateField(
verbose_name=_("start"),
default=timezone.now,
)
inscription_limit = models.DateTimeField(
verbose_name=_("limit date for registrations"),
default=timezone.now,
)
solution_limit = models.DateTimeField(
verbose_name=_("limit date to upload solutions"),
default=timezone.now,
)
syntheses_first_phase_limit = models.DateTimeField(
verbose_name=_("limit date to upload the syntheses for the first phase"),
default=timezone.now,
)
syntheses_second_phase_limit = models.DateTimeField(
verbose_name=_("limit date to upload the syntheses for the second phase"),
default=timezone.now,
)
description = models.TextField(
verbose_name=_("description"),
blank=True,
)
organizers = models.ManyToManyField(
VolunteerRegistration,
verbose_name=_("organizers"),
related_name="organized_tournaments",
)
final = models.BooleanField(
verbose_name=_("final"),
default=False,
)
@staticmethod
def final_tournament():
qs = Tournament.objects.filter(final=True)
if qs.exists():
return qs.get()
class Meta:
verbose_name = _("tournament")
verbose_name_plural = _("tournaments")
indexes = [
Index(fields=("name", "date_start", "date_end", )),
]
class Pool(models.Model):
tournament = models.ForeignKey(
Tournament,
on_delete=models.CASCADE,
verbose_name=_("tournament"),
)
round = models.PositiveSmallIntegerField(
verbose_name=_("round"),
)
juries = models.ManyToManyField(
VolunteerRegistration,
verbose_name=_("juries"),
related_name="jury_in",
)
class Meta:
verbose_name = _("pool")
verbose_name_plural = _("pools")
class Participation(models.Model): class Participation(models.Model):
""" """
The Participation model contains all data that are related to the participation: The Participation model contains all data that are related to the participation:
@ -128,11 +212,13 @@ class Participation(models.Model):
verbose_name=_("team"), verbose_name=_("team"),
) )
problem = models.IntegerField( tournament = models.ForeignKey(
choices=[(i, format_lazy(_("Problem #{problem:d}"), problem=i)) for i in range(1, 4)], Tournament,
on_delete=models.SET_NULL,
null=True, null=True,
blank=True,
default=None, default=None,
verbose_name=_("problem number"), verbose_name=_("tournament"),
) )
valid = models.BooleanField( valid = models.BooleanField(
@ -180,128 +266,66 @@ class Participation(models.Model):
verbose_name_plural = _("participations") verbose_name_plural = _("participations")
class Video(models.Model): class Solution(models.Model):
"""
The Video model only contains a link and a validity status.
"""
link = models.URLField(
verbose_name=_("link"),
help_text=_("The full video link."),
)
valid = models.BooleanField(
null=True,
default=None,
verbose_name=_("valid"),
help_text=_("The video got the validation of the administrators."),
)
@property
def participation(self):
"""
Retrives the participation that is associated to this video,
whatever it is a solution or a synthesis.
"""
try:
# If this is a solution
return self.participation_solution
except ObjectDoesNotExist:
# If this is a synthesis
return self.participation_synthesis
@property
def platform(self):
"""
According to the link, retrieve the platform that is used to upload the video.
"""
if "youtube.com" in self.link or "youtu.be" in self.link:
return "youtube"
return "unknown"
@property
def youtube_code(self):
"""
If the video is uploaded on Youtube, search in the URL the video code.
"""
return re.compile("(https?://|)(www\\.|)(youtube\\.com/watch\\?v=|youtu\\.be/)([a-zA-Z0-9-_]*)?.*?")\
.match(self.link).group(4)
def as_iframe(self):
"""
Generate the HTML code to embed the video in an iframe, according to the type of the host platform.
"""
if self.platform == "youtube":
return render_to_string("participation/youtube_iframe.html", context=dict(youtube_code=self.youtube_code))
return None
def __str__(self):
return _("Video of team {name} ({trigram})")\
.format(name=self.participation.team.name, trigram=self.participation.team.trigram)
class Meta:
verbose_name = _("video")
verbose_name_plural = _("videos")
class Question(models.Model):
"""
Question to ask to the team that sent a solution.
"""
participation = models.ForeignKey( participation = models.ForeignKey(
Participation, Participation,
on_delete=models.CASCADE, on_delete=models.CASCADE,
verbose_name=_("participation"), verbose_name=_("participation"),
related_name="questions", related_name="solutions",
) )
question = models.TextField( problem = models.PositiveSmallIntegerField(
verbose_name=_("question"), verbose_name=_("problem"),
) )
def __str__(self): final_solution = models.BooleanField(
return self.question verbose_name=_("solution for the final tournament"),
default=False,
)
file = models.FileField(
class Phase(models.Model): verbose_name=_("file"),
""" upload_to="solutions/",
The Phase model corresponds to the dates of the phase.
"""
phase_number = models.AutoField(
primary_key=True,
unique=True, unique=True,
verbose_name=_("phase number"), blank=True,
default="",
) )
description = models.CharField(
max_length=255,
verbose_name=_("phase description"),
)
start = models.DateTimeField(
verbose_name=_("start date of the given phase"),
default=timezone.now,
)
end = models.DateTimeField(
verbose_name=_("end date of the given phase"),
default=timezone.now,
)
@classmethod
def current_phase(cls):
"""
Retrieve the current phase of this day
"""
qs = Phase.objects.filter(start__lte=timezone.now(), end__gte=timezone.now())
if qs.exists():
return qs.get()
qs = Phase.objects.filter(start__lte=timezone.now()).order_by("phase_number").all()
return qs.last() if qs.exists() else None
def __str__(self):
return _("Phase {phase_number:d} starts on {start:%Y-%m-%d %H:%M} and ends on {end:%Y-%m-%d %H:%M}")\
.format(phase_number=self.phase_number, start=self.start, end=self.end)
class Meta: class Meta:
verbose_name = _("phase") verbose_name = _("solution")
verbose_name_plural = _("phases") verbose_name_plural = _("solutions")
unique_by = (('participation', 'problem', 'final_solution', ), )
class Synthesis(models.Model):
participation = models.ForeignKey(
Participation,
on_delete=models.CASCADE,
verbose_name=_("participation"),
)
pool = models.ForeignKey(
Pool,
on_delete=models.CASCADE,
verbose_name=_("pool"),
)
type = models.PositiveSmallIntegerField(
choices=[
(1, _("opponent"), ),
(2, _("reporter"), ),
]
)
file = models.FileField(
verbose_name=_("file"),
upload_to="syntheses/",
unique=True,
blank=True,
default="",
)
class Meta:
verbose_name = _("synthesis")
verbose_name_plural = _("syntheses")
unique_by = (('participation', 'pool', 'type', ), )