mirror of
https://gitlab.com/animath/si/plateforme.git
synced 2024-12-24 17:42:23 +00:00
Upload syntheses
This commit is contained in:
parent
6f26b24359
commit
c8780a6d9d
@ -9,7 +9,7 @@ from django.core.exceptions import ValidationError
|
||||
from django.utils import formats
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .models import Participation, Passage, Pool, Team, Tournament, Solution
|
||||
from .models import Participation, Passage, Pool, Team, Tournament, Solution, Synthesis
|
||||
|
||||
|
||||
class TeamForm(forms.ModelForm):
|
||||
@ -162,3 +162,14 @@ class PassageForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Passage
|
||||
fields = ('solution_number', 'place', 'defender', 'opponent', 'reporter',)
|
||||
|
||||
|
||||
class SynthesisForm(forms.ModelForm):
|
||||
def save(self, commit=True):
|
||||
"""
|
||||
Don't save a synthesis with this way. Use a view instead
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = Synthesis
|
||||
fields = ('type', 'file',)
|
||||
|
@ -24,6 +24,6 @@ class Migration(migrations.Migration):
|
||||
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'),
|
||||
field=models.FileField(blank=True, default='', unique=True, upload_to=participation.models.get_synthesis_filename, verbose_name='file'),
|
||||
),
|
||||
]
|
||||
|
@ -404,8 +404,8 @@ def get_solution_filename(instance, filename):
|
||||
+ ("final" if instance.final_solution else "")
|
||||
|
||||
|
||||
def get_random_synthesis_filename(instance, filename):
|
||||
return "syntheses/" + get_random_string(64)
|
||||
def get_synthesis_filename(instance, filename):
|
||||
return f"syntheses/{instance.participation.team.trigram}_{instance.type}_{instance.passage.pk}"
|
||||
|
||||
|
||||
class Solution(models.Model):
|
||||
@ -469,12 +469,15 @@ class Synthesis(models.Model):
|
||||
|
||||
file = models.FileField(
|
||||
verbose_name=_("file"),
|
||||
upload_to=get_random_synthesis_filename,
|
||||
upload_to=get_synthesis_filename,
|
||||
unique=True,
|
||||
blank=True,
|
||||
default="",
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return _("Synthesis for the {type} of the {passage}").format(type=self.get_type_display(), passage=self.passage)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("synthesis")
|
||||
verbose_name_plural = _("syntheses")
|
||||
|
@ -27,29 +27,57 @@
|
||||
|
||||
<dt class="col-sm-3">{% trans "Place:" %}</dt>
|
||||
<dd class="col-sm-9">{{ passage.place }}</dd>
|
||||
|
||||
<dt class="col-sm-3">{% trans "Syntheses:" %}</dt>
|
||||
<dd class="col-sm-9">
|
||||
{% for synthesis in passage.syntheses.all %}
|
||||
<a href="{{ synthesis.file.url }}" data-turbolinks="false">{{ synthesis }}{% if not forloop.last %}, {% endif %}</a>
|
||||
{% empty %}
|
||||
{% trans "No synthesis was uploaded yet." %}
|
||||
{% endfor %}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
{% if user.registration.is_admin %}
|
||||
<div class="card-footer text-center">
|
||||
<button class="btn btn-primary" data-toggle="modal" data-target="#updatePassageModal">{% trans "Update" %}</button>
|
||||
</div>
|
||||
{% elif user.registration.participates %}
|
||||
<div class="card-footer text-center">
|
||||
<button class="btn btn-primary" data-toggle="modal" data-target="#uploadSynthesisModal">{% trans "Upload synthesis" %}</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if user.registration.is_admin %}
|
||||
{% trans "Update passage" as modal_title %}
|
||||
{% trans "Update" as modal_button %}
|
||||
{% url "participation:passage_update" pk=passage.pk as modal_action %}
|
||||
{% include "base_modal.html" with modal_id="updatePassage" %}
|
||||
{% elif user.registration.participates %}
|
||||
{% trans "Upload synthesis" as modal_title %}
|
||||
{% trans "Upload" as modal_button %}
|
||||
{% url "participation:upload_synthesis" pk=passage.pk as modal_action %}
|
||||
{% include "base_modal.html" with modal_id="uploadSynthesis" modal_enctype="multipart/form-data" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block extrajavascript %}
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
{% if user.registration.is_admin %}
|
||||
$('button[data-target="#updatePassageModal"]').click(function() {
|
||||
let modalBody = $("#updatePassageModal div.modal-body");
|
||||
if (!modalBody.html().trim())
|
||||
modalBody.load("{% url "participation:passage_update" pk=passage.pk %} #form-content")
|
||||
});
|
||||
{% elif user.registration.participates %}
|
||||
$('button[data-target="#uploadSynthesisModal"]').click(function() {
|
||||
let modalBody = $("#uploadSynthesisModal div.modal-body");
|
||||
if (!modalBody.html().trim())
|
||||
modalBody.load("{% url "participation:upload_synthesis" pk=passage.pk %} #form-content")
|
||||
});
|
||||
{% endif %}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@ -0,0 +1,13 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% load crispy_forms_filters i18n %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div id="form-content">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
</div>
|
||||
<button class="btn btn-primary" type="submit">{% trans "Upload" %}</button>
|
||||
</form>
|
||||
{% endblock content %}
|
@ -9,7 +9,7 @@ from .views import CreateTeamView, JoinTeamView, \
|
||||
PassageCreateView, PassageDetailView, PassageUpdateView, PoolCreateView, PoolDetailView, \
|
||||
PoolUpdateView, PoolUpdateTeamsView, TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamListView, \
|
||||
TeamUpdateView, TournamentCreateView, TournamentDetailView, TournamentListView, TournamentUpdateView, \
|
||||
SolutionUploadView
|
||||
SolutionUploadView, SynthesisUploadView
|
||||
|
||||
|
||||
app_name = "participation"
|
||||
@ -37,5 +37,6 @@ urlpatterns = [
|
||||
path("pools/passages/add/<int:pk>/", PassageCreateView.as_view(), name="passage_create"),
|
||||
path("pools/passages/<int:pk>/", PassageDetailView.as_view(), name="passage_detail"),
|
||||
path("pools/passages/<int:pk>/update/", PassageUpdateView.as_view(), name="passage_update"),
|
||||
path("pools/passages/<int:pk>/solution/", SynthesisUploadView.as_view(), name="upload_synthesis"),
|
||||
path("chat/", TemplateView.as_view(template_name="participation/chat.html"), name="chat")
|
||||
]
|
||||
|
@ -24,8 +24,8 @@ from tfjm.matrix import Matrix
|
||||
from tfjm.views import AdminMixin
|
||||
|
||||
from .forms import JoinTeamForm, ParticipationForm, PassageForm, PoolForm, PoolTeamsForm, RequestValidationForm, \
|
||||
SolutionForm, TeamForm, TournamentForm, ValidateParticipationForm
|
||||
from .models import Participation, Passage, Pool, Team, Tournament, Solution
|
||||
TeamForm, TournamentForm, ValidateParticipationForm, SolutionForm, SynthesisForm
|
||||
from .models import Participation, Passage, Pool, Team, Tournament, Solution, Synthesis
|
||||
from .tables import TeamTable, TournamentTable, ParticipationTable, PoolTable
|
||||
|
||||
|
||||
@ -460,6 +460,7 @@ class SolutionUploadView(LoginRequiredMixin, FormView):
|
||||
for sol in Solution.objects.filter(participation=self.participation,
|
||||
problem=form_sol.problem,
|
||||
final_solution=self.participation.final).all():
|
||||
sol.file.delete()
|
||||
sol.delete()
|
||||
form_sol.participation = self.participation
|
||||
form_sol.final = self.participation.final
|
||||
@ -475,7 +476,7 @@ class PoolCreateView(AdminMixin, CreateView):
|
||||
form_class = PoolForm
|
||||
|
||||
|
||||
class PoolDetailView(AdminMixin, DetailView):
|
||||
class PoolDetailView(LoginRequiredMixin, DetailView):
|
||||
model = Pool
|
||||
|
||||
|
||||
@ -509,7 +510,7 @@ class PassageCreateView(AdminMixin, CreateView):
|
||||
return form
|
||||
|
||||
|
||||
class PassageDetailView(AdminMixin, DetailView):
|
||||
class PassageDetailView(LoginRequiredMixin, DetailView):
|
||||
model = Passage
|
||||
|
||||
|
||||
@ -517,3 +518,36 @@ class PassageUpdateView(AdminMixin, UpdateView):
|
||||
model = Passage
|
||||
form_class = PassageForm
|
||||
|
||||
|
||||
class SynthesisUploadView(LoginRequiredMixin, FormView):
|
||||
template_name = "participation/upload_synthesis.html"
|
||||
form_class = SynthesisForm
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
qs = Passage.objects.filter(pk=self.kwargs["pk"])
|
||||
if not qs.exists():
|
||||
raise Http404
|
||||
self.participation = self.request.user.registration.team.participation
|
||||
self.passage = qs.get()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
"""
|
||||
When a solution is submitted, it replaces a previous solution if existing,
|
||||
otherwise it creates a new solution.
|
||||
It is discriminating whenever the team is selected for the final tournament or not.
|
||||
"""
|
||||
form_syn = form.instance
|
||||
# Drop previous solution if existing
|
||||
for syn in Synthesis.objects.filter(participation=self.participation,
|
||||
passage=self.passage,
|
||||
type=form_syn.type).all():
|
||||
syn.file.delete()
|
||||
syn.delete()
|
||||
form_syn.participation = self.participation
|
||||
form_syn.passage = self.passage
|
||||
form_syn.save()
|
||||
return super().form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("participation:passage_detail", args=(self.passage.pk,))
|
||||
|
@ -372,7 +372,7 @@ class SynthesisView(LoginRequiredMixin, View):
|
||||
"""
|
||||
def get(self, request, *args, **kwargs):
|
||||
filename = kwargs["filename"]
|
||||
path = f"media/syhntheses/{filename}"
|
||||
path = f"media/syntheses/{filename}"
|
||||
if not os.path.exists(path):
|
||||
raise Http404
|
||||
solution = Synthesis.objects.get(file__endswith=filename)
|
||||
|
Loading…
Reference in New Issue
Block a user