Upload syntheses

This commit is contained in:
Yohann D'ANELLO 2021-01-14 17:26:08 +01:00
parent 6f26b24359
commit c8780a6d9d
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
8 changed files with 110 additions and 20 deletions

View File

@ -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',)

View 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'),
),
]

View 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")

View File

@ -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>
{% 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" %}
{% 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 () {
$('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")
});
{% 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 %}

View File

@ -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 %}

View File

@ -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")
]

View File

@ -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,))

View File

@ -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)