mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-11-04 07:42:11 +01:00 
			
		
		
		
	Solutions
This commit is contained in:
		@@ -63,6 +63,11 @@ class Tournament(models.Model):
 | 
			
		||||
        verbose_name=_("year"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def solutions(self):
 | 
			
		||||
        from member.models import Solution
 | 
			
		||||
        return Solution.objects.filter(team__tournament=self)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_final(cls):
 | 
			
		||||
        return cls.objects.get(year=os.getenv("TFJM_YEAR"), final=True)
 | 
			
		||||
 
 | 
			
		||||
@@ -38,3 +38,25 @@ class TeamTable(tables.Table):
 | 
			
		||||
        attrs = {
 | 
			
		||||
            'class': 'table table-condensed table-striped table-hover'
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SolutionTable(tables.Table):
 | 
			
		||||
    file = tables.LinkColumn(
 | 
			
		||||
        "document",
 | 
			
		||||
        args=[A("file")],
 | 
			
		||||
        attrs={
 | 
			
		||||
            "a": {
 | 
			
		||||
                "data-turbolinks": "false",
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def render_file(self):
 | 
			
		||||
        return _("Download")
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Team
 | 
			
		||||
        fields = ("team", "team.tournament", "problem", "uploaded_at", "file", )
 | 
			
		||||
        attrs = {
 | 
			
		||||
            'class': 'table table-condensed table-striped table-hover'
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
from django.urls import path
 | 
			
		||||
from django.views.generic import RedirectView
 | 
			
		||||
 | 
			
		||||
from .views import TournamentListView, TournamentDetailView, TeamDetailView
 | 
			
		||||
from .views import TournamentListView, TournamentDetailView, TeamDetailView, SolutionsView, SolutionsOrgaListView
 | 
			
		||||
 | 
			
		||||
app_name = "tournament"
 | 
			
		||||
 | 
			
		||||
@@ -11,8 +11,8 @@ urlpatterns = [
 | 
			
		||||
    path('<int:pk>/', TournamentDetailView.as_view(), name="detail"),
 | 
			
		||||
    path('team/<int:pk>/', TeamDetailView.as_view(), name="team_detail"),
 | 
			
		||||
    path("add-organizer/", RedirectView.as_view(pattern_name="index"), name="add_organizer"),
 | 
			
		||||
    path("solutions/", RedirectView.as_view(pattern_name="index"), name="solutions"),
 | 
			
		||||
    path("all-solutions/", RedirectView.as_view(pattern_name="index"), name="all_solutions"),
 | 
			
		||||
    path("solutions/", SolutionsView.as_view(), name="solutions"),
 | 
			
		||||
    path("all-solutions/", SolutionsOrgaListView.as_view(), name="all_solutions"),
 | 
			
		||||
    path("syntheses/", RedirectView.as_view(pattern_name="index"), name="syntheses"),
 | 
			
		||||
    path("all_syntheses/", RedirectView.as_view(pattern_name="index"), name="all_syntheses"),
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,31 @@
 | 
			
		||||
import zipfile
 | 
			
		||||
from io import BytesIO
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth.mixins import LoginRequiredMixin
 | 
			
		||||
from django.core.exceptions import PermissionDenied
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
from django.http import HttpResponse
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from django.views.generic import DetailView
 | 
			
		||||
from django_tables2.views import SingleTableView
 | 
			
		||||
 | 
			
		||||
from member.models import TFJMUser
 | 
			
		||||
from member.models import TFJMUser, Solution
 | 
			
		||||
from .models import Tournament, Team
 | 
			
		||||
from .tables import TournamentTable, TeamTable
 | 
			
		||||
from .tables import TournamentTable, TeamTable, SolutionTable
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AdminMixin(object):
 | 
			
		||||
    def dispatch(self, request, *args, **kwargs):
 | 
			
		||||
        if not request.user.admin:
 | 
			
		||||
            raise PermissionDenied
 | 
			
		||||
        return super().dispatch(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TeamMixin(object):
 | 
			
		||||
    def dispatch(self, request, *args, **kwargs):
 | 
			
		||||
        if not request.user.team:
 | 
			
		||||
            raise PermissionDenied
 | 
			
		||||
        return super().dispatch(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TournamentListView(SingleTableView):
 | 
			
		||||
@@ -61,3 +80,88 @@ class TeamDetailView(LoginRequiredMixin, DetailView):
 | 
			
		||||
        context["title"] = _("Information about team")
 | 
			
		||||
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SolutionsView(LoginRequiredMixin, TeamMixin, SingleTableView):
 | 
			
		||||
    model = Solution
 | 
			
		||||
    table_class = SolutionTable
 | 
			
		||||
    template_name = "tournament/solutions_list.html"
 | 
			
		||||
    extra_context = dict(title=_("Solutions"))
 | 
			
		||||
 | 
			
		||||
    def post(self, request, *args, **kwargs):
 | 
			
		||||
        if "zip" in request.POST:
 | 
			
		||||
            solutions = request.user.team.solutions
 | 
			
		||||
 | 
			
		||||
            out = BytesIO()
 | 
			
		||||
            zf = zipfile.ZipFile(out, "w")
 | 
			
		||||
 | 
			
		||||
            for solution in solutions:
 | 
			
		||||
                zf.write(solution.file.path, str(solution) + ".pdf")
 | 
			
		||||
 | 
			
		||||
            zf.close()
 | 
			
		||||
 | 
			
		||||
            resp = HttpResponse(out.getvalue(), content_type="application/x-zip-compressed")
 | 
			
		||||
            resp['Content-Disposition'] = 'attachment; filename={}'\
 | 
			
		||||
                .format(_("Solutions for team {team}.zip")
 | 
			
		||||
                        .format(team=str(request.user.team)).replace(" ", "%20"))
 | 
			
		||||
            return resp
 | 
			
		||||
 | 
			
		||||
        return self.get(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
        context["tournaments"] = \
 | 
			
		||||
            Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
 | 
			
		||||
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        qs = super().get_queryset()
 | 
			
		||||
        if not self.request.user.admin:
 | 
			
		||||
            qs = qs.filter(team__tournament__organizers=self.request.user)
 | 
			
		||||
        return qs.order_by('team__tournament__date_start', 'team__tournament__name', 'team__trigram', 'problem',)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SolutionsOrgaListView(LoginRequiredMixin, AdminMixin, SingleTableView):
 | 
			
		||||
    model = Solution
 | 
			
		||||
    table_class = SolutionTable
 | 
			
		||||
    template_name = "tournament/solutions_orga_list.html"
 | 
			
		||||
    extra_context = dict(title=_("All solutions"))
 | 
			
		||||
 | 
			
		||||
    def post(self, request, *args, **kwargs):
 | 
			
		||||
        if "tournament_zip" in request.POST:
 | 
			
		||||
            tournament = Tournament.objects.get(pk=request.POST["tournament_zip"][0])
 | 
			
		||||
            solutions = tournament.solutions
 | 
			
		||||
            if not request.user.admin and request.user not in tournament.organizers:
 | 
			
		||||
                raise PermissionDenied
 | 
			
		||||
 | 
			
		||||
            out = BytesIO()
 | 
			
		||||
            zf = zipfile.ZipFile(out, "w")
 | 
			
		||||
 | 
			
		||||
            for solution in solutions:
 | 
			
		||||
                zf.write(solution.file.path, str(solution) + ".pdf")
 | 
			
		||||
 | 
			
		||||
            zf.close()
 | 
			
		||||
 | 
			
		||||
            resp = HttpResponse(out.getvalue(), content_type="application/x-zip-compressed")
 | 
			
		||||
            resp['Content-Disposition'] = 'attachment; filename={}'\
 | 
			
		||||
                .format(_("Solutions for tournament {tournament}.zip")
 | 
			
		||||
                        .format(tournament=str(tournament)).replace(" ", "%20"))
 | 
			
		||||
            return resp
 | 
			
		||||
 | 
			
		||||
        return self.get(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        context = super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
        context["tournaments"] = \
 | 
			
		||||
            Tournament.objects if self.request.user.admin else self.request.user.organized_tournaments
 | 
			
		||||
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        qs = super().get_queryset()
 | 
			
		||||
        if not self.request.user.admin:
 | 
			
		||||
            qs = qs.filter(team__tournament__organizers=self.request.user)
 | 
			
		||||
        return qs.order_by('team__tournament__date_start', 'team__tournament__name', 'team__trigram', 'problem',)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user