mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2025-02-13 22:21:18 +00:00
Compare commits
4 Commits
2ca0444053
...
170326d503
Author | SHA1 | Date | |
---|---|---|---|
|
170326d503 | ||
|
d75ba1f890 | ||
|
e51674e76c | ||
|
ead59e28b8 |
29
apps/participation/migrations/0007_auto_20210112_1801.py
Normal file
29
apps/participation/migrations/0007_auto_20210112_1801.py
Normal 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'),
|
||||
),
|
||||
]
|
@ -4,12 +4,14 @@
|
||||
import os
|
||||
|
||||
from address.models import AddressField
|
||||
from django.conf import settings
|
||||
from django.core.validators import RegexValidator
|
||||
from django.db import models
|
||||
from django.db.models import Index
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils import timezone
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.text import format_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from registration.models import VolunteerRegistration
|
||||
from tfjm.lists import get_sympa_client
|
||||
@ -312,6 +314,15 @@ class Pool(models.Model):
|
||||
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):
|
||||
participation = models.ForeignKey(
|
||||
Participation,
|
||||
@ -322,6 +333,9 @@ class Solution(models.Model):
|
||||
|
||||
problem = models.PositiveSmallIntegerField(
|
||||
verbose_name=_("problem"),
|
||||
choices=[
|
||||
(i, format_lazy(_("Problem #{problem}"), problem=i)) for i in range(1, settings.PROBLEM_COUNT + 1)
|
||||
],
|
||||
)
|
||||
|
||||
final_solution = models.BooleanField(
|
||||
@ -331,14 +345,15 @@ class Solution(models.Model):
|
||||
|
||||
file = models.FileField(
|
||||
verbose_name=_("file"),
|
||||
upload_to="solutions/",
|
||||
upload_to=get_solution_filename,
|
||||
unique=True,
|
||||
blank=True,
|
||||
default="",
|
||||
)
|
||||
|
||||
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:
|
||||
verbose_name = _("solution")
|
||||
@ -369,7 +384,7 @@ class Synthesis(models.Model):
|
||||
|
||||
file = models.FileField(
|
||||
verbose_name=_("file"),
|
||||
upload_to="syntheses/",
|
||||
upload_to=get_random_synthesis_filename,
|
||||
unique=True,
|
||||
blank=True,
|
||||
default="",
|
||||
|
@ -19,9 +19,7 @@
|
||||
<dt class="col-sm-2">{% trans "Solutions:" %}</dt>
|
||||
<dd class="col-sm-10">
|
||||
{% for solution in participation.solutions.all %}
|
||||
<a href="{% url "solution" filename=solution.file %}">
|
||||
{% blocktrans trimmed with problem=solution.problem %}problem {{ problem }}{% endblocktrans %}{% if not forloop.last %}, {% endif %}
|
||||
</a>
|
||||
<a href="{{ solution.file.url }}" data-turbolinks="false">{{ solution }}{% if not forloop.last %}, {% endif %}</a>
|
||||
{% empty %}
|
||||
{% trans "No solution was uploaded yet." %}
|
||||
{% endfor %}
|
||||
@ -36,7 +34,7 @@
|
||||
{% trans "Upload solution" as modal_title %}
|
||||
{% trans "Upload" as modal_button %}
|
||||
{% 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 %}
|
||||
|
||||
{% block extrajavascript %}
|
||||
|
@ -3,7 +3,7 @@
|
||||
{% load crispy_forms_filters i18n %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div id="form-content">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
|
@ -456,11 +456,10 @@ class SolutionUploadView(LoginRequiredMixin, FormView):
|
||||
"""
|
||||
form_sol = form.instance
|
||||
# Drop previous solution if existing
|
||||
Solution.objects.filter(
|
||||
participation=self.participation,
|
||||
problem=form_sol.problem,
|
||||
final_solution=self.participation.final,
|
||||
).delete()
|
||||
for sol in Solution.objects.filter(participation=self.participation,
|
||||
problem=form_sol.problem,
|
||||
final_solution=self.participation.final).all():
|
||||
sol.delete()
|
||||
form_sol.participation = self.participation
|
||||
form_sol.final = self.participation.final
|
||||
form_sol.save()
|
||||
|
@ -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_tables2 import SingleTableView
|
||||
from magic import Magic
|
||||
|
||||
from participation.models import Solution, Synthesis
|
||||
from tfjm.tokens import email_validation_token
|
||||
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)
|
||||
|
||||
|
||||
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):
|
||||
"""
|
||||
An administrator can log in through this page as someone else, and act as this other person.
|
||||
|
@ -236,3 +236,6 @@ GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
||||
|
||||
# Use local Jquery
|
||||
JQUERY_URL = False
|
||||
|
||||
# Custom parameters
|
||||
PROBLEM_COUNT = 8
|
||||
|
@ -21,7 +21,8 @@ from django.contrib import admin
|
||||
from django.urls import include, path
|
||||
from django.views.defaults import bad_request, page_not_found, permission_denied, server_error
|
||||
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
|
||||
|
||||
@ -45,6 +46,11 @@ urlpatterns = [
|
||||
path('media/authorization/parental/<str:filename>/', ParentalAuthorizationView.as_view(),
|
||||
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')),
|
||||
]
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user