Send solutions

This commit is contained in:
Yohann D'ANELLO 2020-05-04 23:37:21 +02:00
parent 9499e10524
commit 26eacad2fd
9 changed files with 118 additions and 21 deletions

View File

@ -10,7 +10,6 @@ class SignUpForm(UserCreationForm):
super().__init__(*args, **kwargs)
self.fields["first_name"].required = True
self.fields["last_name"].required = True
print(self.fields["role"].choices)
self.fields["role"].choices = [
('', _("Choose a role...")),
('participant', _("Participant")),

View File

@ -178,6 +178,10 @@ class Document(PolymorphicModel):
verbose_name = _("document")
verbose_name_plural = _("documents")
def delete(self, *args, **kwargs):
self.file.delete(True)
return super().delete(*args, **kwargs)
class Authorization(Document):
user = models.ForeignKey(
@ -234,14 +238,15 @@ class Solution(Document):
verbose_name=_("problem"),
)
def save(self, **kwargs):
self.type = "solution"
super().save(**kwargs)
final = models.BooleanField(
default=False,
verbose_name=_("final solution"),
)
class Meta:
verbose_name = _("solution")
verbose_name_plural = _("solutions")
unique_together = ('team', 'problem',)
unique_together = ('team', 'problem', 'final',)
def __str__(self):
return _("Solution of team {trigram} for problem {problem}")\
@ -274,13 +279,15 @@ class Synthesis(Document):
verbose_name=_("round"),
)
def save(self, **kwargs):
self.type = "synthesis"
super().save(**kwargs)
final = models.BooleanField(
default=False,
verbose_name=_("final synthesis"),
)
class Meta:
verbose_name = _("synthesis")
verbose_name_plural = _("syntheses")
unique_together = ('team', 'dest', 'round', 'final',)
def __str__(self):
return _("Synthesis of team {trigram} that is {dest} for problem {problem}")\

View File

@ -12,7 +12,7 @@ from django_tables2 import SingleTableView
from tournament.models import Team
from tournament.views import AdminMixin, TeamMixin
from .forms import SignUpForm, TFJMUserForm
from .models import TFJMUser, Document
from .models import TFJMUser, Document, Solution, MotivationLetter, Synthesis
from .tables import UserTable
@ -93,7 +93,12 @@ class DocumentView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
doc = Document.objects.get(file=self.kwargs["file"])
if not request.user.admin:
grant = request.user.admin
if isinstance(doc, Solution) or isinstance(doc, Synthesis) or isinstance(doc, MotivationLetter):
grant = grant or doc.team == request.user.team or request.user in doc.team.tournament.organizers.all()
if not grant:
raise PermissionDenied
return FileResponse(doc.file, content_type="application/pdf")

View File

@ -1,7 +1,7 @@
from django import forms
from django.utils.translation import gettext_lazy as _
from member.models import TFJMUser
from member.models import TFJMUser, Solution, Synthesis
from tfjm.inputs import DatePickerInput, DateTimePickerInput, AmountInput
from tournament.models import Tournament, Team
@ -42,3 +42,20 @@ class JoinTeam(forms.Form):
label=_("Access code"),
max_length=6,
)
class SolutionForm(forms.ModelForm):
problem = forms.ChoiceField(
label=_("Problem"),
choices=[(str(i), _("Problem #{problem:d}").format(problem=i)) for i in range(1, 9)],
)
class Meta:
model = Solution
fields = ('file', 'problem',)
class SynthesisForm(forms.ModelForm):
class Meta:
model = Synthesis
fields = ('file', 'dest',)

View File

@ -2,6 +2,7 @@ import django_tables2 as tables
from django.utils.translation import gettext as _
from django_tables2 import A
from member.models import Solution
from .models import Tournament, Team
@ -41,6 +42,39 @@ class TeamTable(tables.Table):
class SolutionTable(tables.Table):
team = tables.LinkColumn(
"tournament:team_detail",
args=[A("team.pk")],
)
tournament = tables.LinkColumn(
"tournament:detail",
args=[A("team.tournament.pk")],
accessor=A("team.tournament"),
)
file = tables.LinkColumn(
"document",
args=[A("file")],
attrs={
"a": {
"data-turbolinks": "false",
}
}
)
def render_file(self):
return _("Download")
class Meta:
model = Solution
fields = ("team", "tournament", "problem", "uploaded_at", "file", )
attrs = {
'class': 'table table-condensed table-striped table-hover'
}
class SynthesisTable(tables.Table):
file = tables.LinkColumn(
"document",
args=[A("file")],
@ -56,7 +90,7 @@ class SolutionTable(tables.Table):
class Meta:
model = Team
fields = ("team", "team.tournament", "problem", "uploaded_at", "file", )
fields = ("team", "team.tournament", "round", "dest", "uploaded_at", "file", )
attrs = {
'class': 'table table-condensed table-striped table-hover'
}

View File

@ -1,3 +1,4 @@
import random
import zipfile
from io import BytesIO
@ -9,10 +10,11 @@ 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
from .forms import TournamentForm, OrganizerForm, TeamForm, SolutionForm
from .models import Tournament, Team
from .tables import TournamentTable, TeamTable, SolutionTable
@ -96,7 +98,8 @@ 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:
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)
@ -151,9 +154,10 @@ class AddOrganizerView(AdminMixin, CreateView):
template_name = "tournament/add_organizer.html"
class SolutionsView(TeamMixin, SingleTableView):
class SolutionsView(TeamMixin, BaseFormView, SingleTableView):
model = Solution
table_class = SolutionTable
form_class = SolutionForm
template_name = "tournament/solutions_list.html"
extra_context = dict(title=_("Solutions"))
@ -175,7 +179,7 @@ class SolutionsView(TeamMixin, SingleTableView):
.format(team=str(request.user.team)).replace(" ", "%20"))
return resp
return self.get(request, *args, **kwargs)
return super().post(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
@ -188,9 +192,33 @@ class SolutionsView(TeamMixin, SingleTableView):
def get_queryset(self):
qs = super().get_queryset()
if not self.request.user.admin:
qs = qs.filter(team__tournament__organizers=self.request.user)
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
@ -202,7 +230,7 @@ class SolutionsOrgaListView(AdminMixin, SingleTableView):
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:
if not request.user.admin and request.user not in tournament.organizers.all():
raise PermissionDenied
out = BytesIO()

View File

@ -1,7 +1,15 @@
{% extends "base.html" %}
{% load i18n django_tables2 %}
{% load i18n crispy_forms_filters django_tables2 %}
{% block content %}
{% if form %}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-block btn-success">{% trans "Submit" %}</button>
</form>
<hr>
{% endif %}
{% render_table table %}
{% endblock %}

View File

@ -16,7 +16,7 @@
<dd class="col-xl-6">{{ team.trigram }}</dd>
<dt class="col-xl-6 text-right">{% trans 'tournament'|capfirst %}</dt>
<dd class="col-xl-6">{{ team.tournament }}</dd>
<dd class="col-xl-6"><a href="{% url "tournament:detail" pk=team.tournament.pk %}">{{ team.tournament }}</a></dd>
<dt class="col-xl-6 text-right">{% trans 'coachs'|capfirst %}</dt>
<dd class="col-xl-6">{% autoescape off %}{{ team.linked_encadrants|join:", " }}{% endautoescape %}</dd>

View File

@ -55,7 +55,6 @@ class SessionMiddleware(object):
request.user = TFJMUser.objects.get(pk=request.session["_fake_user_id"])
user = request.user
print(user)
if 'HTTP_X_FORWARDED_FOR' in request.META:
ip = request.META.get('HTTP_X_FORWARDED_FOR')
else: