Add & join teams

This commit is contained in:
Yohann D'ANELLO 2020-05-05 00:56:34 +02:00
parent b55aa6f4f3
commit 3889256fb1
8 changed files with 82 additions and 24 deletions

View File

@ -141,7 +141,7 @@ class TFJMUser(AbstractUser):
@property @property
def participates(self): def participates(self):
return self.role == "3participant" or self.role == "2encadrant" return self.role == "3participant" or self.role == "2coach"
@property @property
def organizes(self): def organizes(self):

View File

@ -1,9 +1,20 @@
import django_tables2 as tables import django_tables2 as tables
from django_tables2 import A
from member.models import TFJMUser from member.models import TFJMUser
class UserTable(tables.Table): class UserTable(tables.Table):
last_name = tables.LinkColumn(
"member:information",
args=[A("pk")],
)
first_name = tables.LinkColumn(
"member:information",
args=[A("pk")],
)
class Meta: class Meta:
model = TFJMUser model = TFJMUser
fields = ("last_name", "first_name", "role", "date_joined", ) fields = ("last_name", "first_name", "role", "date_joined", )

View File

@ -1,7 +1,6 @@
from django.urls import path 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 ProfileListView, OrphanedProfileListView, OrganizersListView, ResetAdminView
app_name = "member" app_name = "member"
@ -10,10 +9,9 @@ urlpatterns = [
path('signup/', CreateUserView.as_view(), name="signup"), path('signup/', CreateUserView.as_view(), name="signup"),
path("my-account/", MyAccountView.as_view(), name="my_account"), path("my-account/", MyAccountView.as_view(), name="my_account"),
path("information/<int:pk>/", UserDetailView.as_view(), name="information"), path("information/<int:pk>/", UserDetailView.as_view(), name="information"),
path("add-team/", RedirectView.as_view(pattern_name="index"), name="add_team"), path("add-team/", AddTeamView.as_view(), name="add_team"),
path("join-team/", RedirectView.as_view(pattern_name="index"), name="join_team"), path("join-team/", JoinTeamView.as_view(), name="join_team"),
path("my-team/", MyTeamView.as_view(), name="my_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("profiles/", ProfileListView.as_view(), name="all_profiles"),
path("orphaned-profiles/", OrphanedProfileListView.as_view(), name="orphaned_profiles"), path("orphaned-profiles/", OrphanedProfileListView.as_view(), name="orphaned_profiles"),
path("organizers/", OrganizersListView.as_view(), name="organizers"), path("organizers/", OrganizersListView.as_view(), name="organizers"),

View File

@ -1,14 +1,18 @@
import random
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import AnonymousUser from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db.models import Q from django.db.models import Q
from django.http import FileResponse from django.http import FileResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views import View 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 django_tables2 import SingleTableView
from tournament.forms import TeamForm, JoinTeam
from tournament.models import Team from tournament.models import Team
from tournament.views import AdminMixin, TeamMixin from tournament.views import AdminMixin, TeamMixin
from .forms import SignUpForm, TFJMUserForm from .forms import SignUpForm, TFJMUserForm
@ -65,28 +69,49 @@ class UserDetailView(LoginRequiredMixin, DetailView):
return context return context
class MyTeamView(TeamMixin, DetailView): class AddTeamView(LoginRequiredMixin, CreateView):
model = Team model = Team
form_class = TeamForm
def get_object(self, queryset=None): def form_valid(self, form):
return self.request.user.team 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): team.save()
if isinstance(request.user, AnonymousUser): team.refresh_from_db()
raise PermissionDenied
team = self.get_object() self.request.user.team = team
self.request.user.save()
if not request.user.participates or team is None: return super().form_valid(form)
raise PermissionDenied
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_success_url(self):
context = super().get_context_data(**kwargs) 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): class DocumentView(LoginRequiredMixin, View):

View File

@ -43,6 +43,16 @@ class JoinTeam(forms.Form):
max_length=6, 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): class SolutionForm(forms.ModelForm):
problem = forms.ChoiceField( problem = forms.ChoiceField(

View File

@ -14,7 +14,7 @@ from django.views.generic.edit import BaseFormView
from django_tables2.views import SingleTableView from django_tables2.views import SingleTableView
from member.models import TFJMUser, Solution, Synthesis 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 .models import Tournament, Team
from .tables import TournamentTable, TeamTable, SolutionTable, SynthesisTable from .tables import TournamentTable, TeamTable, SolutionTable, SynthesisTable
@ -128,6 +128,12 @@ class TeamDetailView(LoginRequiredMixin, DetailView):
.format(_("Solutions for team {team}.zip") .format(_("Solutions for team {team}.zip")
.format(team=str(team)).replace(" ", "%20")) .format(team=str(team)).replace(" ", "%20"))
return resp 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: elif "delete" in request.POST:
team.delete() team.delete()
return redirect('tournament:detail', pk=team.tournament.pk) return redirect('tournament:detail', pk=team.tournament.pk)

View File

@ -89,7 +89,7 @@
<a class="nav-link" href="{% url "member:my_account" %}"><i class="fas fa-user"></i> {% trans "My account" %}</a> <a class="nav-link" href="{% url "member:my_account" %}"><i class="fas fa-user"></i> {% trans "My account" %}</a>
</li> </li>
{% if user.participates %} {% if user.participates %}
{% if user.team is None %} {% if not user.team %}
<li class="nav-item active"> <li class="nav-item active">
<a class="nav-link" href="{% url "member:add_team" %}"><i class="fas fa-folder-plus"></i> {% trans "Add a team" %}</a> <a class="nav-link" href="{% url "member:add_team" %}"><i class="fas fa-folder-plus"></i> {% trans "Add a team" %}</a>
</li> </li>

View File

@ -15,6 +15,9 @@
<dt class="col-xl-6 text-right">{% trans 'trigram'|capfirst %}</dt> <dt class="col-xl-6 text-right">{% trans 'trigram'|capfirst %}</dt>
<dd class="col-xl-6">{{ team.trigram }}</dd> <dd class="col-xl-6">{{ team.trigram }}</dd>
<dt class="col-xl-6 text-right">{% trans 'access code'|capfirst %}</dt>
<dd class="col-xl-6">{{ team.access_code }}</dd>
<dt class="col-xl-6 text-right">{% trans 'tournament'|capfirst %}</dt> <dt class="col-xl-6 text-right">{% trans 'tournament'|capfirst %}</dt>
<dd class="col-xl-6"><a href="{% url "tournament:detail" pk=team.tournament.pk %}">{{ team.tournament }}</a></dd> <dd class="col-xl-6"><a href="{% url "tournament:detail" pk=team.tournament.pk %}">{{ team.tournament }}</a></dd>
@ -23,12 +26,17 @@
<dt class="col-xl-6 text-right">{% trans 'participants'|capfirst %}</dt> <dt class="col-xl-6 text-right">{% trans 'participants'|capfirst %}</dt>
<dd class="col-xl-6">{% autoescape off %}{{ team.linked_participants|join:", " }}{% endautoescape %}</dd> <dd class="col-xl-6">{% autoescape off %}{{ team.linked_participants|join:", " }}{% endautoescape %}</dd>
<dt class="col-xl-6 text-right">{% trans 'validation status'|capfirst %}</dt>
<dd class="col-xl-6">{{ team.get_validation_status_display }}</dd>
</dl> </dl>
</div> </div>
{% if user.admin or user in team.tournament.organizers.all or team == user.team %} {% if user.admin or user in team.tournament.organizers.all or team == user.team %}
<div class="card-footer text-center"> <div class="card-footer text-center">
{% if team.invalid or user.organizes %}
<a href="{% url "tournament:team_update" pk=team.pk %}"><button class="btn btn-secondary">{% trans "Edit team" %}</button></a> <a href="{% url "tournament:team_update" pk=team.pk %}"><button class="btn btn-secondary">{% trans "Edit team" %}</button></a>
{% endif %}
{% if team.invalid %} {% if team.invalid %}
<form method="post"> <form method="post">
{% csrf_token %} {% csrf_token %}