mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-11-04 10:22:11 +01:00 
			
		
		
		
	Prepare the data structure for the participations
This commit is contained in:
		@@ -4,6 +4,7 @@
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
from registration.models import VolunteerRegistration
 | 
			
		||||
from tfjm.lists import get_sympa_client
 | 
			
		||||
from tfjm.matrix import Matrix, RoomPreset, RoomVisibility
 | 
			
		||||
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."),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
    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):
 | 
			
		||||
    """
 | 
			
		||||
    The Participation model contains all data that are related to the participation:
 | 
			
		||||
@@ -128,11 +212,13 @@ class Participation(models.Model):
 | 
			
		||||
        verbose_name=_("team"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    problem = models.IntegerField(
 | 
			
		||||
        choices=[(i, format_lazy(_("Problem #{problem:d}"), problem=i)) for i in range(1, 4)],
 | 
			
		||||
    tournament = models.ForeignKey(
 | 
			
		||||
        Tournament,
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
        default=None,
 | 
			
		||||
        verbose_name=_("problem number"),
 | 
			
		||||
        verbose_name=_("tournament"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    valid = models.BooleanField(
 | 
			
		||||
@@ -180,128 +266,66 @@ class Participation(models.Model):
 | 
			
		||||
        verbose_name_plural = _("participations")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Video(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.
 | 
			
		||||
    """
 | 
			
		||||
class Solution(models.Model):
 | 
			
		||||
    participation = models.ForeignKey(
 | 
			
		||||
        Participation,
 | 
			
		||||
        on_delete=models.CASCADE,
 | 
			
		||||
        verbose_name=_("participation"),
 | 
			
		||||
        related_name="questions",
 | 
			
		||||
        related_name="solutions",
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    question = models.TextField(
 | 
			
		||||
        verbose_name=_("question"),
 | 
			
		||||
    problem = models.PositiveSmallIntegerField(
 | 
			
		||||
        verbose_name=_("problem"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return self.question
 | 
			
		||||
    final_solution = models.BooleanField(
 | 
			
		||||
        verbose_name=_("solution for the final tournament"),
 | 
			
		||||
        default=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Phase(models.Model):
 | 
			
		||||
    """
 | 
			
		||||
    The Phase model corresponds to the dates of the phase.
 | 
			
		||||
    """
 | 
			
		||||
    phase_number = models.AutoField(
 | 
			
		||||
        primary_key=True,
 | 
			
		||||
    file = models.FileField(
 | 
			
		||||
        verbose_name=_("file"),
 | 
			
		||||
        upload_to="solutions/",
 | 
			
		||||
        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:
 | 
			
		||||
        verbose_name = _("phase")
 | 
			
		||||
        verbose_name_plural = _("phases")
 | 
			
		||||
        verbose_name = _("solution")
 | 
			
		||||
        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', ), )
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user