mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-10-31 16:20:00 +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 | import os | ||||||
|  |  | ||||||
| from address.models import AddressField | from address.models import AddressField | ||||||
|  | from django.conf import settings | ||||||
| from django.core.validators import RegexValidator | from django.core.validators import RegexValidator | ||||||
| from django.db import models | from django.db import models | ||||||
| from django.db.models import Index | from django.db.models import Index | ||||||
| from django.urls import reverse_lazy | from django.urls import reverse_lazy | ||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| from django.utils.crypto import get_random_string | from django.utils.crypto import get_random_string | ||||||
|  | from django.utils.text import format_lazy | ||||||
| from django.utils.translation import gettext_lazy as _ | from django.utils.translation import gettext_lazy as _ | ||||||
| from registration.models import VolunteerRegistration | from registration.models import VolunteerRegistration | ||||||
| from tfjm.lists import get_sympa_client | from tfjm.lists import get_sympa_client | ||||||
| @@ -312,6 +314,15 @@ class Pool(models.Model): | |||||||
|         verbose_name_plural = _("pools") |         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): | class Solution(models.Model): | ||||||
|     participation = models.ForeignKey( |     participation = models.ForeignKey( | ||||||
|         Participation, |         Participation, | ||||||
| @@ -322,6 +333,9 @@ class Solution(models.Model): | |||||||
|  |  | ||||||
|     problem = models.PositiveSmallIntegerField( |     problem = models.PositiveSmallIntegerField( | ||||||
|         verbose_name=_("problem"), |         verbose_name=_("problem"), | ||||||
|  |         choices=[ | ||||||
|  |             (i, format_lazy(_("Problem #{problem}"), problem=i)) for i in range(1, settings.PROBLEM_COUNT + 1) | ||||||
|  |         ], | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     final_solution = models.BooleanField( |     final_solution = models.BooleanField( | ||||||
| @@ -331,14 +345,15 @@ class Solution(models.Model): | |||||||
|  |  | ||||||
|     file = models.FileField( |     file = models.FileField( | ||||||
|         verbose_name=_("file"), |         verbose_name=_("file"), | ||||||
|         upload_to="solutions/", |         upload_to=get_solution_filename, | ||||||
|         unique=True, |         unique=True, | ||||||
|         blank=True, |         blank=True, | ||||||
|         default="", |         default="", | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     def __str__(self): |     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: |     class Meta: | ||||||
|         verbose_name = _("solution") |         verbose_name = _("solution") | ||||||
| @@ -369,7 +384,7 @@ class Synthesis(models.Model): | |||||||
|  |  | ||||||
|     file = models.FileField( |     file = models.FileField( | ||||||
|         verbose_name=_("file"), |         verbose_name=_("file"), | ||||||
|         upload_to="syntheses/", |         upload_to=get_random_synthesis_filename, | ||||||
|         unique=True, |         unique=True, | ||||||
|         blank=True, |         blank=True, | ||||||
|         default="", |         default="", | ||||||
|   | |||||||
| @@ -19,9 +19,7 @@ | |||||||
|                 <dt class="col-sm-2">{% trans "Solutions:" %}</dt> |                 <dt class="col-sm-2">{% trans "Solutions:" %}</dt> | ||||||
|                 <dd class="col-sm-10"> |                 <dd class="col-sm-10"> | ||||||
|                     {% for solution in participation.solutions.all %} |                     {% for solution in participation.solutions.all %} | ||||||
|                         <a href="{% url "solution" filename=solution.file %}"> |                         <a href="{{ solution.file.url }}" data-turbolinks="false">{{ solution }}{% if not forloop.last %}, {% endif %}</a> | ||||||
|                             {% blocktrans trimmed with problem=solution.problem %}problem {{ problem }}{% endblocktrans %}{% if not forloop.last %}, {% endif %} |  | ||||||
|                         </a> |  | ||||||
|                     {% empty %} |                     {% empty %} | ||||||
|                         {% trans "No solution was uploaded yet." %} |                         {% trans "No solution was uploaded yet." %} | ||||||
|                     {% endfor %} |                     {% endfor %} | ||||||
| @@ -36,7 +34,7 @@ | |||||||
|     {% trans "Upload solution" as modal_title %} |     {% trans "Upload solution" as modal_title %} | ||||||
|     {% trans "Upload" as modal_button %} |     {% trans "Upload" as modal_button %} | ||||||
|     {% url "participation:upload_solution" pk=participation.pk as modal_action %} |     {% 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 %} | {% endblock %} | ||||||
|  |  | ||||||
| {% block extrajavascript %} | {% block extrajavascript %} | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ | |||||||
| {% load crispy_forms_filters i18n %} | {% load crispy_forms_filters i18n %} | ||||||
|  |  | ||||||
| {% block content %} | {% block content %} | ||||||
|     <form method="post"> |     <form method="post" enctype="multipart/form-data"> | ||||||
|         <div id="form-content"> |         <div id="form-content"> | ||||||
|             {% csrf_token %} |             {% csrf_token %} | ||||||
|             {{ form|crispy }} |             {{ form|crispy }} | ||||||
|   | |||||||
| @@ -456,11 +456,10 @@ class SolutionUploadView(LoginRequiredMixin, FormView): | |||||||
|         """ |         """ | ||||||
|         form_sol = form.instance |         form_sol = form.instance | ||||||
|         # Drop previous solution if existing |         # Drop previous solution if existing | ||||||
|         Solution.objects.filter( |         for sol in Solution.objects.filter(participation=self.participation, | ||||||
|             participation=self.participation, |                                            problem=form_sol.problem, | ||||||
|             problem=form_sol.problem, |                                            final_solution=self.participation.final).all(): | ||||||
|             final_solution=self.participation.final, |             sol.delete() | ||||||
|         ).delete() |  | ||||||
|         form_sol.participation = self.participation |         form_sol.participation = self.participation | ||||||
|         form_sol.final = self.participation.final |         form_sol.final = self.participation.final | ||||||
|         form_sol.save() |         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.views.generic import CreateView, DetailView, RedirectView, TemplateView, UpdateView, View | ||||||
| from django_tables2 import SingleTableView | from django_tables2 import SingleTableView | ||||||
| from magic import Magic | from magic import Magic | ||||||
|  |  | ||||||
|  | from participation.models import Solution, Synthesis | ||||||
| from tfjm.tokens import email_validation_token | from tfjm.tokens import email_validation_token | ||||||
| from tfjm.views import AdminMixin, UserMixin | 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) |         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): | class UserImpersonateView(LoginRequiredMixin, RedirectView): | ||||||
|     """ |     """ | ||||||
|     An administrator can log in through this page as someone else, and act as this other person. |     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 | # Use local Jquery | ||||||
| JQUERY_URL = False | 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.urls import include, path | ||||||
| from django.views.defaults import bad_request, page_not_found, permission_denied, server_error | from django.views.defaults import bad_request, page_not_found, permission_denied, server_error | ||||||
| from django.views.generic import TemplateView | 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 | from .views import AdminSearchView | ||||||
|  |  | ||||||
| @@ -45,6 +46,11 @@ urlpatterns = [ | |||||||
|     path('media/authorization/parental/<str:filename>/', ParentalAuthorizationView.as_view(), |     path('media/authorization/parental/<str:filename>/', ParentalAuthorizationView.as_view(), | ||||||
|          name='parental_authorization'), |          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')), |     path('', include('eastereggs.urls')), | ||||||
| ] | ] | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user