mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-10-31 19:04:33 +01:00 
			
		
		
		
	Compare commits
	
		
			2 Commits
		
	
	
		
			b4e7ec6550
			...
			2ca0444053
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 2ca0444053 | ||
|  | 09e5a72470 | 
| @@ -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, Team, Tournament | ||||
| from .models import Participation, Team, Tournament, Solution | ||||
|  | ||||
|  | ||||
| class TeamForm(forms.ModelForm): | ||||
| @@ -112,3 +112,14 @@ class TournamentForm(forms.ModelForm): | ||||
|     class Meta: | ||||
|         model = Tournament | ||||
|         fields = '__all__' | ||||
|  | ||||
|  | ||||
| class SolutionForm(forms.ModelForm): | ||||
|     def save(self, commit=True): | ||||
|         """ | ||||
|         Don't save a solution with this way. Use a view instead | ||||
|         """ | ||||
|  | ||||
|     class Meta: | ||||
|         model = Solution | ||||
|         fields = ('problem', 'file',) | ||||
|   | ||||
							
								
								
									
										18
									
								
								apps/participation/migrations/0006_participation_final.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								apps/participation/migrations/0006_participation_final.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| # Generated by Django 3.0.11 on 2021-01-12 16:07 | ||||
|  | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ('participation', '0005_auto_20210101_1149'), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.AddField( | ||||
|             model_name='participation', | ||||
|             name='final', | ||||
|             field=models.BooleanField(default=False, help_text='The team is selected for the final tournament.', verbose_name='selected for final'), | ||||
|         ), | ||||
|     ] | ||||
| @@ -259,6 +259,12 @@ class Participation(models.Model): | ||||
|         help_text=_("The participation got the validation of the organizers."), | ||||
|     ) | ||||
|  | ||||
|     final = models.BooleanField( | ||||
|         default=False, | ||||
|         verbose_name=_("selected for final"), | ||||
|         help_text=_("The team is selected for the final tournament."), | ||||
|     ) | ||||
|  | ||||
|     def get_absolute_url(self): | ||||
|         return reverse_lazy("participation:participation_detail", args=(self.pk,)) | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,42 @@ | ||||
|             <dl class="row"> | ||||
|                 <dt class="col-sm-2">{% trans "Team:" %}</dt> | ||||
|                 <dd class="col-sm-10"><a href="{% url "participation:team_detail" pk=participation.team.pk %}">{{ participation.team }}</a></dd> | ||||
|  | ||||
|                 <dt class="col-sm-2">{% trans "Tournament:" %}</dt> | ||||
|                 <dd class="col-sm-10"><a href="{% url "participation:tournament_detail" pk=participation.tournament.pk %}">{{ participation.tournament }}</a></dd> | ||||
|  | ||||
|                 <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> | ||||
|                     {% empty %} | ||||
|                         {% trans "No solution was uploaded yet." %} | ||||
|                     {% endfor %} | ||||
|                 </dd> | ||||
|             </dl> | ||||
|         </div> | ||||
|         <div class="card-footer text-center"> | ||||
|             <button class="btn btn-primary" data-toggle="modal" data-target="#uploadSolutionModal">{% trans "Upload solution" %}</button> | ||||
|         </div> | ||||
|     </div> | ||||
|  | ||||
|     {% 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" %} | ||||
| {% endblock %} | ||||
|  | ||||
| {% block extrajavascript %} | ||||
|     <script> | ||||
|         $(document).ready(function () { | ||||
|             $('button[data-target="#uploadSolutionModal"]').click(function() { | ||||
|                 console.log(42) | ||||
|                 let modalBody = $("#uploadSolutionModal div.modal-body"); | ||||
|                 if (!modalBody.html().trim()) | ||||
|                     modalBody.load("{% url "participation:upload_solution" pk=participation.pk %} #form-content") | ||||
|             }); | ||||
|         }); | ||||
|     </script> | ||||
| {% endblock %} | ||||
|   | ||||
| @@ -0,0 +1,13 @@ | ||||
| {% extends "base.html" %} | ||||
|  | ||||
| {% load crispy_forms_filters i18n %} | ||||
|  | ||||
| {% block content %} | ||||
|     <form method="post"> | ||||
|         <div id="form-content"> | ||||
|             {% csrf_token %} | ||||
|             {{ form|crispy }} | ||||
|         </div> | ||||
|         <button class="btn btn-primary" type="submit">{% trans "Upload" %}</button> | ||||
|     </form> | ||||
| {% endblock content %} | ||||
| @@ -7,7 +7,7 @@ from django.views.generic import TemplateView | ||||
| from .views import CreateTeamView, JoinTeamView, \ | ||||
|     MyParticipationDetailView, MyTeamDetailView, ParticipationDetailView, TeamAuthorizationsView, \ | ||||
|     TeamDetailView, TeamLeaveView, TeamListView, TeamUpdateView, TournamentCreateView, TournamentDetailView, \ | ||||
|     TournamentListView, TournamentUpdateView | ||||
|     TournamentListView, TournamentUpdateView, SolutionUploadView | ||||
|  | ||||
|  | ||||
| app_name = "participation" | ||||
| @@ -23,6 +23,7 @@ urlpatterns = [ | ||||
|     path("team/leave/", TeamLeaveView.as_view(), name="team_leave"), | ||||
|     path("detail/", MyParticipationDetailView.as_view(), name="my_participation_detail"), | ||||
|     path("detail/<int:pk>/", ParticipationDetailView.as_view(), name="participation_detail"), | ||||
|     path("detail/<int:pk>/solution/", SolutionUploadView.as_view(), name="upload_solution"), | ||||
|     path("tournament/", TournamentListView.as_view(), name="tournament_list"), | ||||
|     path("tournament/create/", TournamentCreateView.as_view(), name="tournament_create"), | ||||
|     path("tournament/<int:pk>/", TournamentDetailView.as_view(), name="tournament_detail"), | ||||
|   | ||||
| @@ -9,7 +9,7 @@ from django.contrib.sites.models import Site | ||||
| from django.core.exceptions import PermissionDenied | ||||
| from django.core.mail import send_mail | ||||
| from django.db import transaction | ||||
| from django.http import HttpResponse | ||||
| from django.http import HttpResponse, Http404 | ||||
| from django.shortcuts import redirect | ||||
| from django.template.loader import render_to_string | ||||
| from django.urls import reverse_lazy | ||||
| @@ -23,9 +23,9 @@ from tfjm.lists import get_sympa_client | ||||
| from tfjm.matrix import Matrix | ||||
| from tfjm.views import AdminMixin | ||||
|  | ||||
| from .forms import JoinTeamForm, ParticipationForm, RequestValidationForm, TeamForm, ValidateParticipationForm, \ | ||||
|     TournamentForm | ||||
| from .models import Participation, Team, Tournament | ||||
| from .forms import JoinTeamForm, ParticipationForm, RequestValidationForm, SolutionForm, TeamForm, TournamentForm, \ | ||||
|     ValidateParticipationForm | ||||
| from .models import Participation, Team, Tournament, Solution | ||||
| from .tables import TeamTable, TournamentTable, ParticipationTable | ||||
|  | ||||
|  | ||||
| @@ -435,3 +435,36 @@ class TournamentDetailView(DetailView): | ||||
|         context = super().get_context_data(**kwargs) | ||||
|         context["teams"] = ParticipationTable(self.object.participations.all()) | ||||
|         return context | ||||
|  | ||||
|  | ||||
| class SolutionUploadView(LoginRequiredMixin, FormView): | ||||
|     template_name = "participation/upload_solution.html" | ||||
|     form_class = SolutionForm | ||||
|  | ||||
|     def dispatch(self, request, *args, **kwargs): | ||||
|         qs = Participation.objects.filter(pk=self.kwargs["pk"]) | ||||
|         if not qs.exists(): | ||||
|             raise Http404 | ||||
|         self.participation = 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_sol = form.instance | ||||
|         # Drop previous solution if existing | ||||
|         Solution.objects.filter( | ||||
|             participation=self.participation, | ||||
|             problem=form_sol.problem, | ||||
|             final_solution=self.participation.final, | ||||
|         ).delete() | ||||
|         form_sol.participation = self.participation | ||||
|         form_sol.final = self.participation.final | ||||
|         form_sol.save() | ||||
|         return super().form_valid(form) | ||||
|  | ||||
|     def get_success_url(self): | ||||
|         return reverse_lazy("participation:participation_detail", args=(self.participation.pk,)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user