Prepare the data structure for the participations
This commit is contained in:
parent
d9a85948b3
commit
18b4fa81d3
|
@ -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', ), )
|
||||||
|
|
Loading…
Reference in New Issue