mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2024-12-25 19:02:33 +00:00
Send solutions
This commit is contained in:
parent
9499e10524
commit
26eacad2fd
@ -10,7 +10,6 @@ class SignUpForm(UserCreationForm):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.fields["first_name"].required = True
|
self.fields["first_name"].required = True
|
||||||
self.fields["last_name"].required = True
|
self.fields["last_name"].required = True
|
||||||
print(self.fields["role"].choices)
|
|
||||||
self.fields["role"].choices = [
|
self.fields["role"].choices = [
|
||||||
('', _("Choose a role...")),
|
('', _("Choose a role...")),
|
||||||
('participant', _("Participant")),
|
('participant', _("Participant")),
|
||||||
|
@ -178,6 +178,10 @@ class Document(PolymorphicModel):
|
|||||||
verbose_name = _("document")
|
verbose_name = _("document")
|
||||||
verbose_name_plural = _("documents")
|
verbose_name_plural = _("documents")
|
||||||
|
|
||||||
|
def delete(self, *args, **kwargs):
|
||||||
|
self.file.delete(True)
|
||||||
|
return super().delete(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Authorization(Document):
|
class Authorization(Document):
|
||||||
user = models.ForeignKey(
|
user = models.ForeignKey(
|
||||||
@ -234,14 +238,15 @@ class Solution(Document):
|
|||||||
verbose_name=_("problem"),
|
verbose_name=_("problem"),
|
||||||
)
|
)
|
||||||
|
|
||||||
def save(self, **kwargs):
|
final = models.BooleanField(
|
||||||
self.type = "solution"
|
default=False,
|
||||||
super().save(**kwargs)
|
verbose_name=_("final solution"),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("solution")
|
verbose_name = _("solution")
|
||||||
verbose_name_plural = _("solutions")
|
verbose_name_plural = _("solutions")
|
||||||
unique_together = ('team', 'problem',)
|
unique_together = ('team', 'problem', 'final',)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return _("Solution of team {trigram} for problem {problem}")\
|
return _("Solution of team {trigram} for problem {problem}")\
|
||||||
@ -274,13 +279,15 @@ class Synthesis(Document):
|
|||||||
verbose_name=_("round"),
|
verbose_name=_("round"),
|
||||||
)
|
)
|
||||||
|
|
||||||
def save(self, **kwargs):
|
final = models.BooleanField(
|
||||||
self.type = "synthesis"
|
default=False,
|
||||||
super().save(**kwargs)
|
verbose_name=_("final synthesis"),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("synthesis")
|
verbose_name = _("synthesis")
|
||||||
verbose_name_plural = _("syntheses")
|
verbose_name_plural = _("syntheses")
|
||||||
|
unique_together = ('team', 'dest', 'round', 'final',)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return _("Synthesis of team {trigram} that is {dest} for problem {problem}")\
|
return _("Synthesis of team {trigram} that is {dest} for problem {problem}")\
|
||||||
|
@ -12,7 +12,7 @@ from django_tables2 import SingleTableView
|
|||||||
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
|
||||||
from .models import TFJMUser, Document
|
from .models import TFJMUser, Document, Solution, MotivationLetter, Synthesis
|
||||||
from .tables import UserTable
|
from .tables import UserTable
|
||||||
|
|
||||||
|
|
||||||
@ -93,7 +93,12 @@ class DocumentView(LoginRequiredMixin, View):
|
|||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
doc = Document.objects.get(file=self.kwargs["file"])
|
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
|
raise PermissionDenied
|
||||||
|
|
||||||
return FileResponse(doc.file, content_type="application/pdf")
|
return FileResponse(doc.file, content_type="application/pdf")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import gettext_lazy as _
|
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 tfjm.inputs import DatePickerInput, DateTimePickerInput, AmountInput
|
||||||
from tournament.models import Tournament, Team
|
from tournament.models import Tournament, Team
|
||||||
|
|
||||||
@ -42,3 +42,20 @@ class JoinTeam(forms.Form):
|
|||||||
label=_("Access code"),
|
label=_("Access code"),
|
||||||
max_length=6,
|
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',)
|
||||||
|
@ -2,6 +2,7 @@ import django_tables2 as tables
|
|||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django_tables2 import A
|
from django_tables2 import A
|
||||||
|
|
||||||
|
from member.models import Solution
|
||||||
from .models import Tournament, Team
|
from .models import Tournament, Team
|
||||||
|
|
||||||
|
|
||||||
@ -41,6 +42,39 @@ class TeamTable(tables.Table):
|
|||||||
|
|
||||||
|
|
||||||
class SolutionTable(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(
|
file = tables.LinkColumn(
|
||||||
"document",
|
"document",
|
||||||
args=[A("file")],
|
args=[A("file")],
|
||||||
@ -56,7 +90,7 @@ class SolutionTable(tables.Table):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Team
|
model = Team
|
||||||
fields = ("team", "team.tournament", "problem", "uploaded_at", "file", )
|
fields = ("team", "team.tournament", "round", "dest", "uploaded_at", "file", )
|
||||||
attrs = {
|
attrs = {
|
||||||
'class': 'table table-condensed table-striped table-hover'
|
'class': 'table table-condensed table-striped table-hover'
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import random
|
||||||
import zipfile
|
import zipfile
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
@ -9,10 +10,11 @@ from django.shortcuts import redirect
|
|||||||
from django.urls import reverse_lazy
|
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.generic import DetailView, CreateView, UpdateView
|
from django.views.generic import DetailView, CreateView, UpdateView
|
||||||
|
from django.views.generic.edit import FormMixin, BaseFormView
|
||||||
from django_tables2.views import SingleTableView
|
from django_tables2.views import SingleTableView
|
||||||
|
|
||||||
from member.models import TFJMUser, Solution
|
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 .models import Tournament, Team
|
||||||
from .tables import TournamentTable, TeamTable, SolutionTable
|
from .tables import TournamentTable, TeamTable, SolutionTable
|
||||||
|
|
||||||
@ -96,7 +98,8 @@ class TeamDetailView(LoginRequiredMixin, DetailView):
|
|||||||
model = Team
|
model = Team
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
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
|
raise PermissionDenied
|
||||||
return super().dispatch(request, *args, **kwargs)
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
@ -151,9 +154,10 @@ class AddOrganizerView(AdminMixin, CreateView):
|
|||||||
template_name = "tournament/add_organizer.html"
|
template_name = "tournament/add_organizer.html"
|
||||||
|
|
||||||
|
|
||||||
class SolutionsView(TeamMixin, SingleTableView):
|
class SolutionsView(TeamMixin, BaseFormView, SingleTableView):
|
||||||
model = Solution
|
model = Solution
|
||||||
table_class = SolutionTable
|
table_class = SolutionTable
|
||||||
|
form_class = SolutionForm
|
||||||
template_name = "tournament/solutions_list.html"
|
template_name = "tournament/solutions_list.html"
|
||||||
extra_context = dict(title=_("Solutions"))
|
extra_context = dict(title=_("Solutions"))
|
||||||
|
|
||||||
@ -175,7 +179,7 @@ class SolutionsView(TeamMixin, SingleTableView):
|
|||||||
.format(team=str(request.user.team)).replace(" ", "%20"))
|
.format(team=str(request.user.team)).replace(" ", "%20"))
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
return self.get(request, *args, **kwargs)
|
return super().post(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
@ -188,9 +192,33 @@ class SolutionsView(TeamMixin, SingleTableView):
|
|||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs = super().get_queryset()
|
qs = super().get_queryset()
|
||||||
if not self.request.user.admin:
|
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',)
|
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):
|
class SolutionsOrgaListView(AdminMixin, SingleTableView):
|
||||||
model = Solution
|
model = Solution
|
||||||
@ -202,7 +230,7 @@ class SolutionsOrgaListView(AdminMixin, SingleTableView):
|
|||||||
if "tournament_zip" in request.POST:
|
if "tournament_zip" in request.POST:
|
||||||
tournament = Tournament.objects.get(pk=request.POST["tournament_zip"][0])
|
tournament = Tournament.objects.get(pk=request.POST["tournament_zip"][0])
|
||||||
solutions = tournament.solutions
|
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
|
raise PermissionDenied
|
||||||
|
|
||||||
out = BytesIO()
|
out = BytesIO()
|
||||||
|
@ -1,7 +1,15 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% load i18n django_tables2 %}
|
{% load i18n crispy_forms_filters django_tables2 %}
|
||||||
|
|
||||||
{% block content %}
|
{% 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 %}
|
{% render_table table %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
<dd class="col-xl-6">{{ team.trigram }}</dd>
|
<dd class="col-xl-6">{{ team.trigram }}</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">{{ 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>
|
<dt class="col-xl-6 text-right">{% trans 'coachs'|capfirst %}</dt>
|
||||||
<dd class="col-xl-6">{% autoescape off %}{{ team.linked_encadrants|join:", " }}{% endautoescape %}</dd>
|
<dd class="col-xl-6">{% autoescape off %}{{ team.linked_encadrants|join:", " }}{% endautoescape %}</dd>
|
||||||
|
@ -55,7 +55,6 @@ class SessionMiddleware(object):
|
|||||||
request.user = TFJMUser.objects.get(pk=request.session["_fake_user_id"])
|
request.user = TFJMUser.objects.get(pk=request.session["_fake_user_id"])
|
||||||
|
|
||||||
user = request.user
|
user = request.user
|
||||||
print(user)
|
|
||||||
if 'HTTP_X_FORWARDED_FOR' in request.META:
|
if 'HTTP_X_FORWARDED_FOR' in request.META:
|
||||||
ip = request.META.get('HTTP_X_FORWARDED_FOR')
|
ip = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||||
else:
|
else:
|
||||||
|
Loading…
Reference in New Issue
Block a user