diff --git a/apps/participation/forms.py b/apps/participation/forms.py index 66d7965..45839d9 100644 --- a/apps/participation/forms.py +++ b/apps/participation/forms.py @@ -44,6 +44,30 @@ class ParticipationForm(forms.ModelForm): fields = ('problem',) +class RequestValidationForm(forms.Form): + _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_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): class Meta: model = Video diff --git a/apps/participation/templates/participation/team_detail.html b/apps/participation/templates/participation/team_detail.html index 89471ab..6451db7 100644 --- a/apps/participation/templates/participation/team_detail.html +++ b/apps/participation/templates/participation/team_detail.html @@ -78,6 +78,7 @@
{% csrf_token %} + {{ request_validation_form|crispy }}
@@ -98,8 +99,17 @@ {% trans "Your validation is pending." %} {% else %} - Team asked for validation. - {# TODO Add validation form: validate or invalidate, with a message #} +
+ {% trans "The team requested to be validated. You may now control the authorizations and confirm that they can participate." %} +
+
+ {% csrf_token %} + {{ validation_form|crispy }} +
+ + +
+
{% endif %} {% endif %} diff --git a/apps/participation/views.py b/apps/participation/views.py index b708eff..381367a 100644 --- a/apps/participation/views.py +++ b/apps/participation/views.py @@ -6,15 +6,16 @@ from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied from django.db import transaction from django.http import HttpResponse -from django.shortcuts import redirect from django.template.loader import render_to_string from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView, DetailView, FormView, RedirectView, UpdateView +from django.views.generic.edit import FormMixin, ProcessFormView from magic import Magic from registration.models import AdminRegistration -from .forms import JoinTeamForm, ParticipationForm, TeamForm, UploadVideoForm +from .forms import JoinTeamForm, ParticipationForm, RequestValidationForm, TeamForm, UploadVideoForm,\ + ValidateParticipationForm from .models import Participation, Team, Video @@ -90,32 +91,22 @@ class MyTeamDetailView(LoginRequiredMixin, RedirectView): raise PermissionDenied(_("You don't participate, so you don't have any team.")) -class TeamDetailView(LoginRequiredMixin, DetailView): +class TeamDetailView(LoginRequiredMixin, FormMixin, ProcessFormView, DetailView): model = Team def get(self, request, *args, **kwargs): user = request.user + self.object = self.get_object() if user.registration.is_admin or user.registration.participates and user.registration.team.pk == kwargs["pk"]: return super().get(request, *args, **kwargs) raise PermissionDenied - def post(self, request, *args, **kwargs): - if request.user.registration.participates: - if "request-validation" in request.POST: - request.user.registration.team.participation.valid = False - request.user.registration.team.participation.save() - - for admin in AdminRegistration.objects.all(): - mail_context = dict(user=admin.user, team=request.user.registration.team) - mail_plain = render_to_string("participation/mails/request_validation.txt", mail_context) - mail_html = render_to_string("participation/mails/request_validation.html", mail_context) - admin.user.email_user("[Corres2math] Validation d'équipe", mail_plain, html_message=mail_html) - return redirect(request.path) - def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - team = self.object + team = self.get_object() + context["request_validation_form"] = RequestValidationForm(self.request.POST or None) + context["validation_form"] = ValidateParticipationForm(self.request.POST or None) context["can_validate"] = team.students.count() >= 3 and \ all(r.email_confirmed for r in team.students.all()) and \ all(r.photo_authorization for r in team.students.all()) and \ @@ -123,6 +114,56 @@ class TeamDetailView(LoginRequiredMixin, DetailView): return context + def get_form_class(self): + if not self.request.POST: + return RequestValidationForm + elif self.request.POST["_form_type"] == "RequestValidationForm": + return RequestValidationForm + elif self.request.POST["_form_type"] == "ValidateParticipationForm": + return ValidateParticipationForm + return None + + def form_valid(self, form): + self.object = self.get_object() + if isinstance(form, RequestValidationForm): + if not self.request.user.registration.participates: + form.add_error(None, _("You don't participate, so you can't request the validation of the team.")) + return self.form_invalid(form) + if self.object.participation.valid is not None: + form.add_error(None, _("The validation of the team is already done or pending.")) + return self.form_invalid(form) + + self.object.participation.valid = False + self.object.participation.save() + + for admin in AdminRegistration.objects.all(): + mail_context = dict(user=admin.user, team=self.object) + mail_plain = render_to_string("participation/mails/request_validation.txt", mail_context) + mail_html = render_to_string("participation/mails/request_validation.html", mail_context) + admin.user.email_user("[Corres2math] Validation d'équipe", mail_plain, html_message=mail_html) + elif isinstance(form, ValidateParticipationForm): + if not self.request.user.registration.is_admin: + form.add_error(None, _("You are not an administrator.")) + return self.form_invalid(form) + elif self.object.participation.valid is not False: + form.add_error(None, _("This team has no pending validation.")) + return self.form_invalid(form) + + if "validate" in self.request.POST: + self.object.participation.valid = True + self.object.participation.save() + elif "invalidate" in self.request.POST: + self.object.participation.valid = None + self.object.participation.save() + else: + form.add_error(None, _("You must specify if you validate the registration or not.")) + return self.form_invalid(form) + + return super().form_invalid(form) + + def get_success_url(self): + return self.request.path + class TeamUpdateView(LoginRequiredMixin, UpdateView): model = Team diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index ea110aa..9305d78 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Corres2math\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-10-11 16:48+0200\n" +"POT-Creation-Date: 2020-10-11 18:43+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Yohann D'ANELLO \n" "Language-Team: LANGUAGE \n" @@ -107,6 +107,14 @@ msgstr "Le trigramme doit être composé de trois lettres majuscules." msgid "No team was found with this access code." msgstr "Aucune équipe n'a été trouvée avec ce code d'accès." +#: apps/participation/forms.py:54 +msgid "I engage myself to participate to the whole \"Correspondances\"." +msgstr "Je m'engage à participer à l'intégralité des Correspondances." + +#: apps/participation/forms.py:66 +msgid "Message to address to the team:" +msgstr "Message à adresser à l'équipe :" + #: apps/participation/models.py:16 msgid "name" msgstr "nom" @@ -135,80 +143,80 @@ msgstr "" "Donner l'autorisation de publier la vidéo sur le site principal pour " "promouvoir les Correspondances." -#: apps/participation/models.py:59 +#: apps/participation/models.py:60 #, python-brace-format msgid "Team {name} ({trigram})" msgstr "Équipe {name} ({trigram})" -#: apps/participation/models.py:62 apps/participation/models.py:73 +#: apps/participation/models.py:63 apps/participation/models.py:74 #: apps/registration/models.py:85 apps/registration/models.py:130 msgid "team" msgstr "équipe" -#: apps/participation/models.py:63 +#: apps/participation/models.py:64 msgid "teams" msgstr "équipes" -#: apps/participation/models.py:77 +#: apps/participation/models.py:78 #, python-brace-format msgid "Problem #{problem:d}" msgstr "Problème n°{problem:d}" -#: apps/participation/models.py:80 +#: apps/participation/models.py:81 msgid "problem number" msgstr "numéro de problème" -#: apps/participation/models.py:86 apps/participation/models.py:134 +#: apps/participation/models.py:87 apps/participation/models.py:135 msgid "valid" msgstr "valide" -#: apps/participation/models.py:87 apps/participation/models.py:135 +#: apps/participation/models.py:88 apps/participation/models.py:136 msgid "The video got the validation of the administrators." msgstr "La vidéo a été validée par les administrateurs." -#: apps/participation/models.py:96 +#: apps/participation/models.py:97 msgid "solution video" msgstr "vidéo de solution" -#: apps/participation/models.py:105 +#: apps/participation/models.py:106 msgid "received participation" msgstr "participation reçue" -#: apps/participation/models.py:114 +#: apps/participation/models.py:115 msgid "synthesis video" msgstr "vidéo de synthèse" -#: apps/participation/models.py:118 +#: apps/participation/models.py:119 #, python-brace-format msgid "Participation of the team {name} ({trigram})" msgstr "Participation de l'équipe {name} ({trigram})" -#: apps/participation/models.py:121 +#: apps/participation/models.py:122 msgid "participation" msgstr "participation" -#: apps/participation/models.py:122 +#: apps/participation/models.py:123 msgid "participations" msgstr "participations" -#: apps/participation/models.py:127 +#: apps/participation/models.py:128 msgid "link" msgstr "lien" -#: apps/participation/models.py:128 +#: apps/participation/models.py:129 msgid "The full video link." msgstr "Le lien complet de la vidéo." -#: apps/participation/models.py:157 +#: apps/participation/models.py:158 #, python-brace-format msgid "Video of team {name} ({trigram})" msgstr "Vidéo de l'équipe {name} ({trigram})" -#: apps/participation/models.py:161 +#: apps/participation/models.py:162 msgid "video" msgstr "vidéo" -#: apps/participation/models.py:162 +#: apps/participation/models.py:163 msgid "videos" msgstr "vidéos" @@ -302,7 +310,7 @@ msgid "Not uploaded yet" msgstr "Pas encore envoyée" #: apps/participation/templates/participation/team_detail.html:61 -#: apps/participation/templates/participation/team_detail.html:104 +#: apps/participation/templates/participation/team_detail.html:117 #: apps/participation/templates/participation/update_team.html:12 #: apps/registration/templates/registration/update_user.html:12 #: apps/registration/templates/registration/user_detail.html:64 @@ -322,11 +330,11 @@ msgstr "" "Votre équipe contient au moins 3 personnes et toutes les autorisations de " "droit à l'image ont été données : l'équipe peut être validée." -#: apps/participation/templates/participation/team_detail.html:79 +#: apps/participation/templates/participation/team_detail.html:82 msgid "Submit my team to validation" msgstr "Soumettre mon équipe à validation" -#: apps/participation/templates/participation/team_detail.html:84 +#: apps/participation/templates/participation/team_detail.html:88 msgid "" "Your team must be composed of 3 members and each member must upload its " "photo authorization and confirm its email address." @@ -334,55 +342,93 @@ msgstr "" "Votre équipe doit être composée de 3 membres et chaque membre doit envoyer " "son autorisation de droit à l'image et confirmé son adresse e-mail." -#: apps/participation/templates/participation/team_detail.html:89 +#: apps/participation/templates/participation/team_detail.html:93 msgid "This team didn't ask for validation yet." msgstr "L'équipe n'a pas encore demandé à être validée." -#: apps/participation/templates/participation/team_detail.html:95 +#: apps/participation/templates/participation/team_detail.html:99 msgid "Your validation is pending." msgstr "Votre validation est en attente." #: apps/participation/templates/participation/team_detail.html:103 +msgid "" +"The team requested to be validated. You may now control the authorizations " +"and confirm that they can participate." +msgstr "" +"L'équipe a demandé à être validée. Vous pouvez désormais contrôler les " +"différentes autorisations et confirmer qu'elle peut participer." + +#: apps/participation/templates/participation/team_detail.html:109 +msgid "Validate" +msgstr "Valider" + +#: apps/participation/templates/participation/team_detail.html:110 +msgid "Invalidate" +msgstr "Invalider" + +#: apps/participation/templates/participation/team_detail.html:116 msgid "Update team" msgstr "Modifier l'équipe" -#: apps/participation/views.py:21 templates/base.html:70 +#: apps/participation/views.py:25 templates/base.html:70 #: templates/base.html:206 msgid "Create team" msgstr "Créer une équipe" -#: apps/participation/views.py:28 apps/participation/views.py:58 +#: apps/participation/views.py:32 apps/participation/views.py:62 msgid "You don't participate, so you can't create a team." msgstr "Vous ne participez pas, vous ne pouvez pas créer d'équipe." -#: apps/participation/views.py:30 apps/participation/views.py:60 +#: apps/participation/views.py:34 apps/participation/views.py:64 msgid "You are already in a team." msgstr "Vous êtes déjà dans une équipe." -#: apps/participation/views.py:51 templates/base.html:75 +#: apps/participation/views.py:55 templates/base.html:75 #: templates/base.html:202 msgid "Join team" msgstr "Rejoindre une équipe" -#: apps/participation/views.py:86 apps/participation/views.py:175 +#: apps/participation/views.py:90 apps/participation/views.py:232 msgid "You are not in a team." msgstr "Vous n'êtes pas dans une équipe." -#: apps/participation/views.py:87 apps/participation/views.py:176 +#: apps/participation/views.py:91 apps/participation/views.py:233 msgid "You don't participate, so you don't have any team." msgstr "Vous ne participez pas, vous n'avez donc pas d'équipe." -#: apps/participation/views.py:159 apps/registration/views.py:213 +#: apps/participation/views.py:130 +msgid "You don't participate, so you can't request the validation of the team." +msgstr "" +"Vous ne participez pas, vous ne pouvez pas demander la validation de " +"l'équipe." + +#: apps/participation/views.py:133 +msgid "The validation of the team is already done or pending." +msgstr "La validation de l'équipe est déjà faite ou en cours." + +#: apps/participation/views.py:146 +msgid "You are not an administrator." +msgstr "Vous n'êtes pas administrateur." + +#: apps/participation/views.py:149 +msgid "This team has no pending validation." +msgstr "L'équipe n'a pas de validation en attente." + +#: apps/participation/views.py:159 +msgid "You must specify if you validate the registration or not." +msgstr "Vous devez spécifier si vous validez l'inscription ou non." + +#: apps/participation/views.py:216 apps/registration/views.py:213 #, python-brace-format msgid "Photo authorization of {student}.{ext}" msgstr "Autorisation de droit à l'image de {student}.{ext}" -#: apps/participation/views.py:163 +#: apps/participation/views.py:220 #, python-brace-format msgid "Photo authorizations of team {trigram}.zip" msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip" -#: apps/participation/views.py:185 +#: apps/participation/views.py:242 msgid "The team is not validated yet." msgstr "L'équipe n'est pas encore validée."