import re from bootstrap_datepicker_plus import DateTimePickerInput from django import forms from django.core.exceptions import ValidationError from django.db.models import Q from django.utils.translation import gettext_lazy as _ from .models import Participation, Phase, Team, Video class TeamForm(forms.ModelForm): """ Form to create a team, with the name and the trigram, and if the team accepts that Animath diffuse the videos. """ def clean_trigram(self): trigram = self.cleaned_data["trigram"].upper() if not re.match("[A-Z]{3}", trigram): raise ValidationError(_("The trigram must be composed of three uppercase letters.")) return trigram class Meta: model = Team fields = ('name', 'trigram', 'grant_animath_access_videos',) class JoinTeamForm(forms.ModelForm): """ Form to join a team by the access code. """ def clean_access_code(self): access_code = self.cleaned_data["access_code"] if not Team.objects.filter(access_code=access_code).exists(): raise ValidationError(_("No team was found with this access code.")) return access_code def clean(self): cleaned_data = super().clean() if "access_code" in cleaned_data: team = Team.objects.get(access_code=cleaned_data["access_code"]) self.instance = team return cleaned_data class Meta: model = Team fields = ('access_code',) class ParticipationForm(forms.ModelForm): """ Form to update the problem of a team participation. """ class Meta: model = Participation fields = ('problem',) class RequestValidationForm(forms.Form): """ Form to ask about validation. """ _form_type = forms.CharField( initial="RequestValidationForm", widget=forms.HiddenInput(), ) engagement = forms.BooleanField( label=_("I engage myself to participate to the whole \"Correspondances\"."), required=True, ) class ValidateParticipationForm(forms.Form): """ Form to let administrators to accept or refuse a team. """ _form_type = forms.CharField( initial="ValidateParticipationForm", widget=forms.HiddenInput(), ) message = forms.CharField( label=_("Message to address to the team:"), widget=forms.Textarea(), ) class UploadVideoForm(forms.ModelForm): """ Form to upload a video, for a solution or a synthesis. """ class Meta: model = Video fields = ('link',) def clean(self): if Phase.current_phase().phase_number != 1 and self.instance.link: self.add_error("link", _("You can't upload your video after the deadline.")) return super().clean() class ReceiveParticipationForm(forms.ModelForm): """ Update the received participation of a participation. """ def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["received_participation"].queryset = Participation.objects.filter( ~Q(pk=self.instance.pk) & Q(problem=self.instance.problem, valid=True) ) class Meta: model = Participation fields = ('received_participation',) class SendParticipationForm(forms.ModelForm): """ Update the sent participation of a participation. """ sent_participation = forms.ModelChoiceField( queryset=Participation.objects, label=lambda: _("Send to team"), ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["sent_participation"].initial = self.instance.sent_participation self.fields["sent_participation"].queryset = Participation.objects.filter( ~Q(pk=self.instance.pk) & Q(problem=self.instance.problem, valid=True) ) def clean(self, commit=True): cleaned_data = super().clean() participation = cleaned_data["sent_participation"] participation.received_participation = self.instance self.instance = participation return cleaned_data class Meta: model = Participation fields = ('sent_participation',) class PhaseForm(forms.ModelForm): """ Form to update the calendar of a phase. """ class Meta: model = Phase fields = ('start', 'end',) widgets = { 'start': DateTimePickerInput(format='%d/%m/%Y %H:%M'), 'end': DateTimePickerInput(format='%d/%m/%Y %H:%M'), } def clean(self): # Ensure that dates are in a right order cleaned_data = super().clean() if cleaned_data["end"] <= cleaned_data["start"]: self.add_error("end", _("Start date must be before the end date.")) if Phase.objects.filter(phase_number__lt=self.instance.phase_number, end__gt=cleaned_data["start"]).exists(): self.add_error("start", _("This phase must start after the previous phases.")) if Phase.objects.filter(phase_number__gt=self.instance.phase_number, start__lt=cleaned_data["end"]).exists(): self.add_error("end", _("This phase must end after the next phases.")) return cleaned_data