diff --git a/apps/member/models.py b/apps/member/models.py index c6b6e65..29a387e 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -141,7 +141,7 @@ class TFJMUser(AbstractUser): @property def participates(self): - return self.role == "3participant" or self.role == "2encadrant" + return self.role == "3participant" or self.role == "2coach" @property def organizes(self): diff --git a/apps/member/tables.py b/apps/member/tables.py index e7890ba..6caad0d 100644 --- a/apps/member/tables.py +++ b/apps/member/tables.py @@ -1,9 +1,20 @@ import django_tables2 as tables +from django_tables2 import A from member.models import TFJMUser class UserTable(tables.Table): + last_name = tables.LinkColumn( + "member:information", + args=[A("pk")], + ) + + first_name = tables.LinkColumn( + "member:information", + args=[A("pk")], + ) + class Meta: model = TFJMUser fields = ("last_name", "first_name", "role", "date_joined", ) diff --git a/apps/member/urls.py b/apps/member/urls.py index 5f5a89c..073f057 100644 --- a/apps/member/urls.py +++ b/apps/member/urls.py @@ -1,7 +1,6 @@ from django.urls import path -from django.views.generic import RedirectView -from .views import CreateUserView, MyAccountView, UserDetailView, MyTeamView,\ +from .views import CreateUserView, MyAccountView, UserDetailView, AddTeamView, JoinTeamView, MyTeamView,\ ProfileListView, OrphanedProfileListView, OrganizersListView, ResetAdminView app_name = "member" @@ -10,10 +9,9 @@ urlpatterns = [ path('signup/', CreateUserView.as_view(), name="signup"), path("my-account/", MyAccountView.as_view(), name="my_account"), path("information//", UserDetailView.as_view(), name="information"), - path("add-team/", RedirectView.as_view(pattern_name="index"), name="add_team"), - path("join-team/", RedirectView.as_view(pattern_name="index"), name="join_team"), + path("add-team/", AddTeamView.as_view(), name="add_team"), + path("join-team/", JoinTeamView.as_view(), name="join_team"), path("my-team/", MyTeamView.as_view(), name="my_team"), - path("my-team/update/", RedirectView.as_view(pattern_name="index"), name="update_my_team"), path("profiles/", ProfileListView.as_view(), name="all_profiles"), path("orphaned-profiles/", OrphanedProfileListView.as_view(), name="orphaned_profiles"), path("organizers/", OrganizersListView.as_view(), name="organizers"), diff --git a/apps/member/views.py b/apps/member/views.py index f08563a..4459d6d 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -1,14 +1,18 @@ +import random + from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import AnonymousUser from django.core.exceptions import PermissionDenied from django.db.models import Q from django.http import FileResponse from django.shortcuts import redirect +from django.urls import reverse_lazy from django.utils.translation import gettext_lazy as _ from django.views import View -from django.views.generic import CreateView, UpdateView, DetailView +from django.views.generic import CreateView, UpdateView, DetailView, FormView from django_tables2 import SingleTableView +from tournament.forms import TeamForm, JoinTeam from tournament.models import Team from tournament.views import AdminMixin, TeamMixin from .forms import SignUpForm, TFJMUserForm @@ -65,28 +69,49 @@ class UserDetailView(LoginRequiredMixin, DetailView): return context -class MyTeamView(TeamMixin, DetailView): +class AddTeamView(LoginRequiredMixin, CreateView): model = Team + form_class = TeamForm - def get_object(self, queryset=None): - return self.request.user.team + def form_valid(self, form): + team = form.instance + alphabet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789" + code = "" + for _ in range(6): + code += random.choice(alphabet) + team.access_code = code + team.validation_status = "0invalid" - def dispatch(self, request, *args, **kwargs): - if isinstance(request.user, AnonymousUser): - raise PermissionDenied + team.save() + team.refresh_from_db() - team = self.get_object() + self.request.user.team = team + self.request.user.save() - if not request.user.participates or team is None: - raise PermissionDenied - return super().dispatch(request, *args, **kwargs) + return super().form_valid(form) - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) + def get_success_url(self): + return reverse_lazy("member:my_team") - context["title"] = str(self.object) - return context +class JoinTeamView(LoginRequiredMixin, FormView): + model = Team + form_class = JoinTeam + template_name = "tournament/team_form.html" + + def form_valid(self, form): + team = form.cleaned_data["team"] + self.request.user.team = team + self.request.user.save() + return super().form_valid(form) + + def get_success_url(self): + return reverse_lazy("member:my_team") + + +class MyTeamView(TeamMixin, View): + def get(self, request, *args, **kwargs): + return redirect("tournament:team_detail", pk=request.user.team.pk) class DocumentView(LoginRequiredMixin, View): diff --git a/apps/tournament/forms.py b/apps/tournament/forms.py index cb16020..f5feba7 100644 --- a/apps/tournament/forms.py +++ b/apps/tournament/forms.py @@ -43,6 +43,16 @@ class JoinTeam(forms.Form): max_length=6, ) + def clean(self): + cleaned_data = super().clean() + + team = Team.objects.filter(access_code=cleaned_data["access_code"]) + if not team.exists(): + self.add_error('access_code', _("This access code is invalid.")) + cleaned_data["team"] = team.get() + + return cleaned_data + class SolutionForm(forms.ModelForm): problem = forms.ChoiceField( diff --git a/apps/tournament/views.py b/apps/tournament/views.py index 2d4f32e..d4499d4 100644 --- a/apps/tournament/views.py +++ b/apps/tournament/views.py @@ -14,7 +14,7 @@ from django.views.generic.edit import BaseFormView from django_tables2.views import SingleTableView from member.models import TFJMUser, Solution, Synthesis -from .forms import TournamentForm, OrganizerForm, TeamForm, SolutionForm, SynthesisForm +from .forms import TournamentForm, OrganizerForm, SolutionForm, SynthesisForm, TeamForm from .models import Tournament, Team from .tables import TournamentTable, TeamTable, SolutionTable, SynthesisTable @@ -128,6 +128,12 @@ class TeamDetailView(LoginRequiredMixin, DetailView): .format(_("Solutions for team {team}.zip") .format(team=str(team)).replace(" ", "%20")) return resp + elif "leave" in request.POST: + request.user.team = None + request.user.save() + if not team.users.exists(): + team.delete() + return redirect('tournament:detail', pk=team.tournament.pk) elif "delete" in request.POST: team.delete() return redirect('tournament:detail', pk=team.tournament.pk) diff --git a/templates/base.html b/templates/base.html index 9683977..64713ff 100644 --- a/templates/base.html +++ b/templates/base.html @@ -89,7 +89,7 @@ {% trans "My account" %} {% if user.participates %} - {% if user.team is None %} + {% if not user.team %} diff --git a/templates/tournament/team_detail.html b/templates/tournament/team_detail.html index dcb2dab..cd08882 100644 --- a/templates/tournament/team_detail.html +++ b/templates/tournament/team_detail.html @@ -15,6 +15,9 @@
{% trans 'trigram'|capfirst %}
{{ team.trigram }}
+
{% trans 'access code'|capfirst %}
+
{{ team.access_code }}
+
{% trans 'tournament'|capfirst %}
{{ team.tournament }}
@@ -23,12 +26,17 @@
{% trans 'participants'|capfirst %}
{% autoescape off %}{{ team.linked_participants|join:", " }}{% endautoescape %}
+ +
{% trans 'validation status'|capfirst %}
+
{{ team.get_validation_status_display }}
{% if user.admin or user in team.tournament.organizers.all or team == user.team %}