Add & join teams
This commit is contained in:
parent
b55aa6f4f3
commit
3889256fb1
|
@ -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):
|
||||||
|
|
|
@ -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", )
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
Loading…
Reference in New Issue