mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-10-31 07:29:52 +01: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')), | ||||
| ] | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user