1
0
mirror of https://gitlab.com/animath/si/plateforme.git synced 2025-02-18 23:41:19 +00:00

Compare commits

...

4 Commits

Author SHA1 Message Date
Yohann D'ANELLO
170326d503
Use a selector to choose a problem number 2021-01-12 18:02:00 +01:00
Yohann D'ANELLO
d75ba1f890
Disable turbolinks to load the solution file 2021-01-12 17:58:06 +01:00
Yohann D'ANELLO
e51674e76c
Display solutions and syntheses 2021-01-12 17:56:40 +01:00
Yohann D'ANELLO
ead59e28b8
Upload to the good place 2021-01-12 17:51:55 +01:00
8 changed files with 112 additions and 14 deletions

View File

@ -0,0 +1,29 @@
# Generated by Django 3.0.11 on 2021-01-12 17:01
from django.db import migrations, models
import participation.models
class Migration(migrations.Migration):
dependencies = [
('participation', '0006_participation_final'),
]
operations = [
migrations.AlterField(
model_name='solution',
name='file',
field=models.FileField(blank=True, default='', unique=True, upload_to=participation.models.get_solution_filename, verbose_name='file'),
),
migrations.AlterField(
model_name='solution',
name='problem',
field=models.PositiveSmallIntegerField(choices=[(1, 'Problem #1'), (2, 'Problem #2'), (3, 'Problem #3'), (4, 'Problem #4'), (5, 'Problem #5'), (6, 'Problem #6'), (7, 'Problem #7'), (8, 'Problem #8')], verbose_name='problem'),
),
migrations.AlterField(
model_name='synthesis',
name='file',
field=models.FileField(blank=True, default='', unique=True, upload_to=participation.models.get_random_synthesis_filename, verbose_name='file'),
),
]

View File

@ -4,12 +4,14 @@
import os import os
from address.models import AddressField from address.models import AddressField
from django.conf import settings
from django.core.validators import RegexValidator from django.core.validators import RegexValidator
from django.db import models from django.db import models
from django.db.models import Index from django.db.models import Index
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.utils import timezone from django.utils import timezone
from django.utils.crypto import get_random_string from django.utils.crypto import get_random_string
from django.utils.text import format_lazy
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from registration.models import VolunteerRegistration from registration.models import VolunteerRegistration
from tfjm.lists import get_sympa_client from tfjm.lists import get_sympa_client
@ -312,6 +314,15 @@ class Pool(models.Model):
verbose_name_plural = _("pools") verbose_name_plural = _("pools")
def get_solution_filename(instance, filename):
return f"solutions/{instance.participation.team.trigram}_{instance.problem}" \
+ ("final" if instance.final_solution else "")
def get_random_synthesis_filename(instance, filename):
return "syntheses/" + get_random_string(64)
class Solution(models.Model): class Solution(models.Model):
participation = models.ForeignKey( participation = models.ForeignKey(
Participation, Participation,
@ -322,6 +333,9 @@ class Solution(models.Model):
problem = models.PositiveSmallIntegerField( problem = models.PositiveSmallIntegerField(
verbose_name=_("problem"), verbose_name=_("problem"),
choices=[
(i, format_lazy(_("Problem #{problem}"), problem=i)) for i in range(1, settings.PROBLEM_COUNT + 1)
],
) )
final_solution = models.BooleanField( final_solution = models.BooleanField(
@ -331,14 +345,15 @@ class Solution(models.Model):
file = models.FileField( file = models.FileField(
verbose_name=_("file"), verbose_name=_("file"),
upload_to="solutions/", upload_to=get_solution_filename,
unique=True, unique=True,
blank=True, blank=True,
default="", default="",
) )
def __str__(self): def __str__(self):
return repr(self) return _("Solution of team {team} for problem {problem}")\
.format(team=self.participation.team.name, problem=self.problem)
class Meta: class Meta:
verbose_name = _("solution") verbose_name = _("solution")
@ -369,7 +384,7 @@ class Synthesis(models.Model):
file = models.FileField( file = models.FileField(
verbose_name=_("file"), verbose_name=_("file"),
upload_to="syntheses/", upload_to=get_random_synthesis_filename,
unique=True, unique=True,
blank=True, blank=True,
default="", default="",

View File

@ -19,9 +19,7 @@
<dt class="col-sm-2">{% trans "Solutions:" %}</dt> <dt class="col-sm-2">{% trans "Solutions:" %}</dt>
<dd class="col-sm-10"> <dd class="col-sm-10">
{% for solution in participation.solutions.all %} {% for solution in participation.solutions.all %}
<a href="{% url "solution" filename=solution.file %}"> <a href="{{ solution.file.url }}" data-turbolinks="false">{{ solution }}{% if not forloop.last %}, {% endif %}</a>
{% blocktrans trimmed with problem=solution.problem %}problem {{ problem }}{% endblocktrans %}{% if not forloop.last %}, {% endif %}
</a>
{% empty %} {% empty %}
{% trans "No solution was uploaded yet." %} {% trans "No solution was uploaded yet." %}
{% endfor %} {% endfor %}
@ -36,7 +34,7 @@
{% trans "Upload solution" as modal_title %} {% trans "Upload solution" as modal_title %}
{% trans "Upload" as modal_button %} {% trans "Upload" as modal_button %}
{% url "participation:upload_solution" pk=participation.pk as modal_action %} {% url "participation:upload_solution" pk=participation.pk as modal_action %}
{% include "base_modal.html" with modal_id="uploadSolution" %} {% include "base_modal.html" with modal_id="uploadSolution" modal_enctype="multipart/form-data" %}
{% endblock %} {% endblock %}
{% block extrajavascript %} {% block extrajavascript %}

View File

@ -3,7 +3,7 @@
{% load crispy_forms_filters i18n %} {% load crispy_forms_filters i18n %}
{% block content %} {% block content %}
<form method="post"> <form method="post" enctype="multipart/form-data">
<div id="form-content"> <div id="form-content">
{% csrf_token %} {% csrf_token %}
{{ form|crispy }} {{ form|crispy }}

View File

@ -456,11 +456,10 @@ class SolutionUploadView(LoginRequiredMixin, FormView):
""" """
form_sol = form.instance form_sol = form.instance
# Drop previous solution if existing # Drop previous solution if existing
Solution.objects.filter( for sol in Solution.objects.filter(participation=self.participation,
participation=self.participation, problem=form_sol.problem,
problem=form_sol.problem, final_solution=self.participation.final).all():
final_solution=self.participation.final, sol.delete()
).delete()
form_sol.participation = self.participation form_sol.participation = self.participation
form_sol.final = self.participation.final form_sol.final = self.participation.final
form_sol.save() form_sol.save()

View File

@ -16,6 +16,8 @@ from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView, DetailView, RedirectView, TemplateView, UpdateView, View from django.views.generic import CreateView, DetailView, RedirectView, TemplateView, UpdateView, View
from django_tables2 import SingleTableView from django_tables2 import SingleTableView
from magic import Magic from magic import Magic
from participation.models import Solution, Synthesis
from tfjm.tokens import email_validation_token from tfjm.tokens import email_validation_token
from tfjm.views import AdminMixin, UserMixin from tfjm.views import AdminMixin, UserMixin
@ -341,6 +343,52 @@ class ParentalAuthorizationView(LoginRequiredMixin, View):
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name) return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
class SolutionView(LoginRequiredMixin, View):
"""
Display the sent solution.
"""
def get(self, request, *args, **kwargs):
filename = kwargs["filename"]
path = f"media/solutions/{filename}"
if not os.path.exists(path):
raise Http404
solution = Solution.objects.get(file__endswith=filename)
# user = request.user
# if False:
# FIXME Check ACL
# raise PermissionDenied
# Guess mime type of the file
mime = Magic(mime=True)
mime_type = mime.from_file(path)
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
# Replace file name
true_file_name = str(solution) + f".{ext}"
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
class SynthesisView(LoginRequiredMixin, View):
"""
Display the sent synthesis.
"""
def get(self, request, *args, **kwargs):
filename = kwargs["filename"]
path = f"media/syhntheses/{filename}"
if not os.path.exists(path):
raise Http404
solution = Synthesis.objects.get(file__endswith=filename)
# user = request.user
# if False:
# FIXME Check ACL
# raise PermissionDenied
# Guess mime type of the file
mime = Magic(mime=True)
mime_type = mime.from_file(path)
ext = mime_type.split("/")[1].replace("jpeg", "jpg")
# Replace file name
true_file_name = str(solution) + f".{ext}"
return FileResponse(open(path, "rb"), content_type=mime_type, filename=true_file_name)
class UserImpersonateView(LoginRequiredMixin, RedirectView): class UserImpersonateView(LoginRequiredMixin, RedirectView):
""" """
An administrator can log in through this page as someone else, and act as this other person. An administrator can log in through this page as someone else, and act as this other person.

View File

@ -236,3 +236,6 @@ GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
# Use local Jquery # Use local Jquery
JQUERY_URL = False JQUERY_URL = False
# Custom parameters
PROBLEM_COUNT = 8

View File

@ -21,7 +21,8 @@ from django.contrib import admin
from django.urls import include, path from django.urls import include, path
from django.views.defaults import bad_request, page_not_found, permission_denied, server_error from django.views.defaults import bad_request, page_not_found, permission_denied, server_error
from django.views.generic import TemplateView from django.views.generic import TemplateView
from registration.views import HealthSheetView, ParentalAuthorizationView, PhotoAuthorizationView from registration.views import HealthSheetView, ParentalAuthorizationView, PhotoAuthorizationView, \
SolutionView, SynthesisView
from .views import AdminSearchView from .views import AdminSearchView
@ -45,6 +46,11 @@ urlpatterns = [
path('media/authorization/parental/<str:filename>/', ParentalAuthorizationView.as_view(), path('media/authorization/parental/<str:filename>/', ParentalAuthorizationView.as_view(),
name='parental_authorization'), name='parental_authorization'),
path('media/solutions/<str:filename>/', SolutionView.as_view(),
name='solution'),
path('media/syntheses/<str:filename>/', SynthesisView.as_view(),
name='synthesis'),
path('', include('eastereggs.urls')), path('', include('eastereggs.urls')),
] ]