265 lines
9.2 KiB
Python
265 lines
9.2 KiB
Python
import random
|
|
import zipfile
|
|
from io import BytesIO
|
|
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
from django.core.exceptions import PermissionDenied
|
|
from django.db.models import Q
|
|
from django.http import HttpResponse
|
|
from django.shortcuts import redirect
|
|
from django.urls import reverse_lazy
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django.views.generic import DetailView, CreateView, UpdateView
|
|
from django.views.generic.edit import FormMixin, BaseFormView
|
|
from django_tables2.views import SingleTableView
|
|
|
|
from member.models import TFJMUser, Solution
|
|
from .forms import TournamentForm, OrganizerForm, TeamForm, SolutionForm
|
|
from .models import Tournament, Team
|
|
from .tables import TournamentTable, TeamTable, SolutionTable
|
|
|
|
|
|
class AdminMixin(LoginRequiredMixin):
|
|
def dispatch(self, request, *args, **kwargs):
|
|
if not request.user.admin:
|
|
raise PermissionDenied
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
|
|
class TeamMixin(LoginRequiredMixin):
|
|
def dispatch(self, request, *args, **kwargs):
|
|
if not request.user.team:
|
|
raise PermissionDenied
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
|
|
class TournamentListView(SingleTableView):
|
|
model = Tournament
|
|
table_class = TournamentTable
|
|
extra_context = dict(title=_("Tournaments list"),)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
team_users = TFJMUser.objects.filter(Q(team__isnull=False) | Q(role="admin") | Q(role="organizer"))\
|
|
.order_by('-role')
|
|
valid_team_users = team_users.filter(
|
|
Q(team__validation_status="2valid") | Q(role="admin") | Q(role="organizer"))
|
|
|
|
context["team_users_emails"] = [user.email for user in team_users]
|
|
context["valid_team_users_emails"] = [user.email for user in valid_team_users]
|
|
|
|
return context
|
|
|
|
|
|
class TournamentCreateView(AdminMixin, CreateView):
|
|
model = Tournament
|
|
form_class = TournamentForm
|
|
extra_context = dict(title=_("Add tournament"),)
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy('tournament:detail', args=(self.object.pk,))
|
|
|
|
|
|
class TournamentDetailView(DetailView):
|
|
model = Tournament
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
context["title"] = _("Tournament of {name}").format(name=self.object.name)
|
|
|
|
team_users = TFJMUser.objects.filter(
|
|
Q(team__tournament=self.object)
|
|
| Q(organized_tournaments=self.object)).order_by('role')
|
|
valid_team_users = team_users.filter(
|
|
Q(team__validation_status="2valid")
|
|
| Q(role="admin")
|
|
| Q(organized_tournaments=self.object))
|
|
|
|
context["team_users_emails"] = [user.email for user in team_users]
|
|
context["valid_team_users_emails"] = [user.email for user in valid_team_users]
|
|
|
|
context["teams"] = TeamTable(self.object.teams.all())
|
|
|
|
return context
|
|
|
|
|
|
class TournamentUpdateView(AdminMixin, UpdateView):
|
|
model = Tournament
|
|
form_class = TournamentForm
|
|
extra_context = dict(title=_("Update tournament"),)
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy('tournament:detail', args=(self.object.pk,))
|
|
|
|
|
|
class TeamDetailView(LoginRequiredMixin, DetailView):
|
|
model = Team
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
if not request.user.admin and self.request.user not in self.get_object().tournament.organizers.all()\
|
|
and self.get_object() != request.user.team:
|
|
raise PermissionDenied
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
team = self.get_object()
|
|
if "zip" in request.POST:
|
|
solutions = team.solutions.all()
|
|
|
|
out = BytesIO()
|
|
zf = zipfile.ZipFile(out, "w")
|
|
|
|
for solution in solutions:
|
|
zf.write(solution.file.path, str(solution) + ".pdf")
|
|
|
|
zf.close()
|
|
|
|
resp = HttpResponse(out.getvalue(), content_type="application/x-zip-compressed")
|
|
resp['Content-Disposition'] = 'attachment; filename={}'\
|
|
.format(_("Solutions for team {team}.zip")
|
|
.format(team=str(team)).replace(" ", "%20"))
|
|
return resp
|
|
elif "delete" in request.POST:
|
|
team.delete()
|
|
return redirect('tournament:detail', pk=team.tournament.pk)
|
|
|
|
return self.get(request, *args, **kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
context["title"] = _("Information about team")
|
|
|
|
return context
|
|
|
|
|
|
class TeamUpdateView(LoginRequiredMixin, UpdateView):
|
|
model = Team
|
|
form_class = TeamForm
|
|
extra_context = dict(title=_("Update team"),)
|
|
|
|
def dispatch(self, request, *args, **kwargs):
|
|
if not request.user.admin and self.request.user not in self.get_object().tournament.organizers.all() \
|
|
and self.get_object() != self.request.user.team:
|
|
raise PermissionDenied
|
|
return super().dispatch(request, *args, **kwargs)
|
|
|
|
|
|
class AddOrganizerView(AdminMixin, CreateView):
|
|
model = TFJMUser
|
|
form_class = OrganizerForm
|
|
extra_context = dict(title=_("Add organizer"),)
|
|
template_name = "tournament/add_organizer.html"
|
|
|
|
|
|
class SolutionsView(TeamMixin, BaseFormView, SingleTableView):
|
|
model = Solution
|
|
table_class = SolutionTable
|
|
form_class = SolutionForm
|
|
template_name = "tournament/solutions_list.html"
|
|
extra_context = dict(title=_("Solutions"))
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
if "zip" in request.POST:
|
|
solutions = request.user.team.solutions
|
|
|
|
out = BytesIO()
|
|
zf = zipfile.ZipFile(out, "w")
|
|
|
|
for solution in solutions:
|
|
zf.write(solution.file.path, str(solution) + ".pdf")
|
|
|
|
zf.close()
|
|
|
|
resp = HttpResponse(out.getvalue(), content_type="application/x-zip-compressed")
|
|
resp['Content-Disposition'] = 'attachment; filename={}'\
|
|
.format(_("Solutions for team {team}.zip")
|
|
.format(team=str(request.user.team)).replace(" ", "%20"))
|
|
return resp
|
|
|
|
return super().post(request, *args, **kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
context["tournaments"] = \
|
|
Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
|
|
|
|
return context
|
|
|
|
def get_queryset(self):
|
|
qs = super().get_queryset()
|
|
if not self.request.user.admin:
|
|
qs = qs.filter(team=self.request.user.team)
|
|
return qs.order_by('team__tournament__date_start', 'team__tournament__name', 'team__trigram', 'problem',)
|
|
|
|
def form_valid(self, form):
|
|
solution = form.instance
|
|
solution.team = self.request.user.team
|
|
solution.final = solution.team.selected_for_final
|
|
prev_sol = Solution.objects.filter(problem=solution.problem, team=solution.team, final=solution.final)
|
|
for sol in prev_sol.all():
|
|
sol.delete()
|
|
alphabet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789"
|
|
id = ""
|
|
for _ in range(64):
|
|
id += random.choice(alphabet)
|
|
solution.file.name = id
|
|
solution.save()
|
|
|
|
return super().form_valid(form)
|
|
|
|
def form_invalid(self, form):
|
|
print(form.errors)
|
|
|
|
return super().form_invalid(form)
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy("tournament:solutions")
|
|
|
|
|
|
class SolutionsOrgaListView(AdminMixin, SingleTableView):
|
|
model = Solution
|
|
table_class = SolutionTable
|
|
template_name = "tournament/solutions_orga_list.html"
|
|
extra_context = dict(title=_("All solutions"))
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
if "tournament_zip" in request.POST:
|
|
tournament = Tournament.objects.get(pk=request.POST["tournament_zip"][0])
|
|
solutions = tournament.solutions
|
|
if not request.user.admin and request.user not in tournament.organizers.all():
|
|
raise PermissionDenied
|
|
|
|
out = BytesIO()
|
|
zf = zipfile.ZipFile(out, "w")
|
|
|
|
for solution in solutions:
|
|
zf.write(solution.file.path, str(solution) + ".pdf")
|
|
|
|
zf.close()
|
|
|
|
resp = HttpResponse(out.getvalue(), content_type="application/x-zip-compressed")
|
|
resp['Content-Disposition'] = 'attachment; filename={}'\
|
|
.format(_("Solutions for tournament {tournament}.zip")
|
|
.format(tournament=str(tournament)).replace(" ", "%20"))
|
|
return resp
|
|
|
|
return self.get(request, *args, **kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super().get_context_data(**kwargs)
|
|
|
|
context["tournaments"] = \
|
|
Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
|
|
|
|
return context
|
|
|
|
def get_queryset(self):
|
|
qs = super().get_queryset()
|
|
if not self.request.user.admin:
|
|
qs = qs.filter(team__tournament__organizers=self.request.user)
|
|
return qs.order_by('team__tournament__date_start', 'team__tournament__name', 'team__trigram', 'problem',)
|