import os import re from django import forms from django.db.models import Q from django.template.defaultfilters import filesizeformat from django.utils import timezone from django.utils.translation import gettext_lazy as _ from member.models import TFJMUser, Solution, Synthesis from tfjm.inputs import DatePickerInput, DateTimePickerInput, AmountInput from tournament.models import Tournament, Team, Pool class TournamentForm(forms.ModelForm): """ Create and update tournaments. """ # Only organizers can organize tournaments. Well, that's pretty normal... organizers = forms.ModelMultipleChoiceField( TFJMUser.objects.filter(Q(role="0admin") | Q(role="1volunteer")).order_by('role'), label=_("Organizers"), ) def clean(self): cleaned_data = super().clean() if not self.instance.pk: if Tournament.objects.filter(name=cleaned_data["data"], year=os.getenv("TFJM_YEAR")): self.add_error("name", _("This tournament already exists.")) if cleaned_data["final"] and Tournament.objects.filter(final=True, year=os.getenv("TFJM_YEAR")): self.add_error("name", _("The final tournament was already defined.")) return cleaned_data class Meta: model = Tournament exclude = ('year',) widgets = { "price": AmountInput(), "date_start": DatePickerInput(), "date_end": DatePickerInput(), "date_inscription": DateTimePickerInput(), "date_solutions": DateTimePickerInput(), "date_syntheses": DateTimePickerInput(), "date_solutions_2": DateTimePickerInput(), "date_syntheses_2": DateTimePickerInput(), } class OrganizerForm(forms.ModelForm): """ Register an organizer in the website. """ class Meta: model = TFJMUser fields = ('last_name', 'first_name', 'email', 'is_superuser',) def clean(self): cleaned_data = super().clean() if TFJMUser.objects.filter(email=cleaned_data["email"], year=os.getenv("TFJM_YEAR")).exists(): self.add_error("email", _("This organizer already exist.")) return cleaned_data def save(self, commit=True): user = self.instance user.role = '0admin' if user.is_superuser else '1volunteer' user.save() super().save(commit) class TeamForm(forms.ModelForm): """ Add and update a team. """ tournament = forms.ModelChoiceField( Tournament.objects.filter(date_inscription__gte=timezone.now(), final=False), ) class Meta: model = Team fields = ('name', 'trigram', 'tournament',) def clean(self): cleaned_data = super().clean() cleaned_data["trigram"] = cleaned_data["trigram"].upper() if not re.match("[A-Z]{3}", cleaned_data["trigram"]): self.add_error("trigram", _("The trigram must be composed of three upcase letters.")) if not self.instance.pk: if Team.objects.filter(trigram=cleaned_data["trigram"], year=os.getenv("TFJM_YEAR")).exists(): self.add_error("trigram", _("This trigram is already used.")) if Team.objects.filter(name=cleaned_data["name"], year=os.getenv("TFJM_YEAR")).exists(): self.add_error("name", _("This name is already used.")) if cleaned_data["tournament"].date_inscription < timezone.now: self.add_error("tournament", _("This tournament is already closed.")) return cleaned_data class JoinTeam(forms.Form): """ Form to join a team with an access code. """ access_code = forms.CharField( label=_("Access code"), max_length=6, ) def clean(self): cleaned_data = super().clean() if not re.match("[a-z0-9]{6}", cleaned_data["access_code"]): self.add_error('access_code', _("The access code must be composed of 6 alphanumeric characters.")) team = Team.objects.filter(access_code=cleaned_data["access_code"]) if not team.exists(): self.add_error('access_code', _("This access code is invalid.")) team = team.get() if not team.invalid: self.add_error('access_code', _("The team is already validated.")) cleaned_data["team"] = team return cleaned_data class SolutionForm(forms.ModelForm): """ Form to upload a solution. """ problem = forms.ChoiceField( label=_("Problem"), choices=[(str(i), _("Problem #%(problem)d") % {"problem": i}) for i in range(1, 9)], ) def clean_file(self): content = self.cleaned_data['file'] content_type = content.content_type if content_type in ["application/pdf"]: if content.size > 5 * 2 ** 20: raise forms.ValidationError( _('Please keep filesize under %(max_size)s. Current filesize %(current_size)s') % { "max_size": filesizeformat(2 * 2 ** 20), "current_size": filesizeformat(content.size) }) else: raise forms.ValidationError(_('The file should be a PDF file.')) return content class Meta: model = Solution fields = ('file', 'problem',) class SynthesisForm(forms.ModelForm): """ Form to upload a synthesis. """ def clean_file(self): content = self.cleaned_data['file'] content_type = content.content_type if content_type in ["application/pdf"]: if content.size > 5 * 2 ** 20: raise forms.ValidationError( _('Please keep filesize under %(max_size)s. Current filesize %(current_size)s') % { "max_size": filesizeformat(2 * 2 ** 20), "current_size": filesizeformat(content.size) }) else: raise forms.ValidationError(_('The file should be a PDF file.')) return content class Meta: model = Synthesis fields = ('file', 'source', 'round',) class PoolForm(forms.ModelForm): """ Form to add a pool. Should not be used: prefer to pass by API and auto-add pools with the results of the draw. """ team1 = forms.ModelChoiceField( Team.objects.filter(validation_status="2valid").all(), empty_label=_("Choose a team..."), label=_("Team 1"), ) problem1 = forms.IntegerField( min_value=1, max_value=8, initial=1, label=_("Problem defended by team 1"), ) team2 = forms.ModelChoiceField( Team.objects.filter(validation_status="2valid").all(), empty_label=_("Choose a team..."), label=_("Team 2"), ) problem2 = forms.IntegerField( min_value=1, max_value=8, initial=2, label=_("Problem defended by team 2"), ) team3 = forms.ModelChoiceField( Team.objects.filter(validation_status="2valid").all(), empty_label=_("Choose a team..."), label=_("Team 3"), ) problem3 = forms.IntegerField( min_value=1, max_value=8, initial=3, label=_("Problem defended by team 3"), ) def clean(self): cleaned_data = super().clean() team1, pb1 = cleaned_data["team1"], cleaned_data["problem1"] team2, pb2 = cleaned_data["team2"], cleaned_data["problem2"] team3, pb3 = cleaned_data["team3"], cleaned_data["problem3"] sol1 = Solution.objects.get(team=team1, problem=pb1, final=team1.selected_for_final) sol2 = Solution.objects.get(team=team2, problem=pb2, final=team2.selected_for_final) sol3 = Solution.objects.get(team=team3, problem=pb3, final=team3.selected_for_final) cleaned_data["teams"] = [team1, team2, team3] cleaned_data["solutions"] = [sol1, sol2, sol3] return cleaned_data def save(self, commit=True): pool = super().save(commit) pool.refresh_from_db() pool.teams.set(self.cleaned_data["teams"]) pool.solutions.set(self.cleaned_data["solutions"]) pool.save() return pool class Meta: model = Pool fields = ('round', 'juries',)