mirror of
				https://gitlab.com/animath/si/plateforme.git
				synced 2025-11-04 07:42:11 +01:00 
			
		
		
		
	Send syntheses
This commit is contained in:
		@@ -58,4 +58,4 @@ class SolutionForm(forms.ModelForm):
 | 
			
		||||
class SynthesisForm(forms.ModelForm):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Synthesis
 | 
			
		||||
        fields = ('file', 'dest',)
 | 
			
		||||
        fields = ('file', 'source', 'round',)
 | 
			
		||||
 
 | 
			
		||||
@@ -64,10 +64,22 @@ class Tournament(models.Model):
 | 
			
		||||
        verbose_name=_("year"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def linked_organizers(self):
 | 
			
		||||
        return ['<a href="{url}">'.format(url=reverse_lazy("member:information", args=(user.pk,))) + str(user) + '</a>'
 | 
			
		||||
                for user in self.organizers.all()]
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def solutions(self):
 | 
			
		||||
        from member.models import Solution
 | 
			
		||||
        return Solution.objects.filter(team__tournament=self)
 | 
			
		||||
        return Solution.objects.filter(final=self.final) if self.final \
 | 
			
		||||
            else Solution.objects.filter(team__tournament=self)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def syntheses(self):
 | 
			
		||||
        from member.models import Synthesis
 | 
			
		||||
        return Synthesis.objects.filter(final=self.final) if self.final \
 | 
			
		||||
            else Synthesis.objects.filter(team__tournament=self)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_final(cls):
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ import django_tables2 as tables
 | 
			
		||||
from django.utils.translation import gettext as _
 | 
			
		||||
from django_tables2 import A
 | 
			
		||||
 | 
			
		||||
from member.models import Solution
 | 
			
		||||
from member.models import Solution, Synthesis
 | 
			
		||||
from .models import Tournament, Team
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -49,8 +49,8 @@ class SolutionTable(tables.Table):
 | 
			
		||||
 | 
			
		||||
    tournament = tables.LinkColumn(
 | 
			
		||||
        "tournament:detail",
 | 
			
		||||
        args=[A("team.tournament.pk")],
 | 
			
		||||
        accessor=A("team.tournament"),
 | 
			
		||||
        args=[A("tournament.pk")],
 | 
			
		||||
        accessor=A("tournament"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    file = tables.LinkColumn(
 | 
			
		||||
@@ -75,6 +75,17 @@ class SolutionTable(tables.Table):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SynthesisTable(tables.Table):
 | 
			
		||||
    team = tables.LinkColumn(
 | 
			
		||||
        "tournament:team_detail",
 | 
			
		||||
        args=[A("team.pk")],
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    tournament = tables.LinkColumn(
 | 
			
		||||
        "tournament:detail",
 | 
			
		||||
        args=[A("tournament.pk")],
 | 
			
		||||
        accessor=A("tournament"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    file = tables.LinkColumn(
 | 
			
		||||
        "document",
 | 
			
		||||
        args=[A("file")],
 | 
			
		||||
@@ -89,8 +100,8 @@ class SynthesisTable(tables.Table):
 | 
			
		||||
        return _("Download")
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = Team
 | 
			
		||||
        fields = ("team", "team.tournament", "round", "dest", "uploaded_at", "file", )
 | 
			
		||||
        model = Synthesis
 | 
			
		||||
        fields = ("team", "tournament", "round", "source", "uploaded_at", "file", )
 | 
			
		||||
        attrs = {
 | 
			
		||||
            'class': 'table table-condensed table-striped table-hover'
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
from django.urls import path
 | 
			
		||||
from django.views.generic import RedirectView
 | 
			
		||||
 | 
			
		||||
from .views import TournamentListView, TournamentCreateView, TournamentDetailView, TournamentUpdateView,\
 | 
			
		||||
    TeamDetailView, TeamUpdateView, AddOrganizerView, SolutionsView, SolutionsOrgaListView
 | 
			
		||||
from .views import TournamentListView, TournamentCreateView, TournamentDetailView, TournamentUpdateView, \
 | 
			
		||||
    TeamDetailView, TeamUpdateView, AddOrganizerView, SolutionsView, SolutionsOrgaListView, SynthesesView,\
 | 
			
		||||
    SynthesesOrgaListView
 | 
			
		||||
 | 
			
		||||
app_name = "tournament"
 | 
			
		||||
 | 
			
		||||
@@ -16,6 +16,6 @@ urlpatterns = [
 | 
			
		||||
    path("add-organizer/", AddOrganizerView.as_view(), name="add_organizer"),
 | 
			
		||||
    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"),
 | 
			
		||||
    path("syntheses/", SynthesesView.as_view(), name="syntheses"),
 | 
			
		||||
    path("all_syntheses/", SynthesesOrgaListView.as_view(), name="all_syntheses"),
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
@@ -10,13 +10,13 @@ from django.shortcuts import redirect
 | 
			
		||||
from django.urls import reverse_lazy
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from django.views.generic import DetailView, CreateView, UpdateView
 | 
			
		||||
from django.views.generic.edit import FormMixin, BaseFormView
 | 
			
		||||
from django.views.generic.edit import BaseFormView
 | 
			
		||||
from django_tables2.views import SingleTableView
 | 
			
		||||
 | 
			
		||||
from member.models import TFJMUser, Solution
 | 
			
		||||
from .forms import TournamentForm, OrganizerForm, TeamForm, SolutionForm
 | 
			
		||||
from member.models import TFJMUser, Solution, Synthesis
 | 
			
		||||
from .forms import TournamentForm, OrganizerForm, TeamForm, SolutionForm, SynthesisForm
 | 
			
		||||
from .models import Tournament, Team
 | 
			
		||||
from .tables import TournamentTable, TeamTable, SolutionTable
 | 
			
		||||
from .tables import TournamentTable, TeamTable, SolutionTable, SynthesisTable
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AdminMixin(LoginRequiredMixin):
 | 
			
		||||
@@ -26,6 +26,13 @@ class AdminMixin(LoginRequiredMixin):
 | 
			
		||||
        return super().dispatch(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class OrgaMixin(LoginRequiredMixin):
 | 
			
		||||
    def dispatch(self, request, *args, **kwargs):
 | 
			
		||||
        if not request.user.organizes:
 | 
			
		||||
            raise PermissionDenied
 | 
			
		||||
        return super().dispatch(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TeamMixin(LoginRequiredMixin):
 | 
			
		||||
    def dispatch(self, request, *args, **kwargs):
 | 
			
		||||
        if not request.user.team:
 | 
			
		||||
@@ -181,14 +188,6 @@ class SolutionsView(TeamMixin, BaseFormView, SingleTableView):
 | 
			
		||||
 | 
			
		||||
        return super().post(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:
 | 
			
		||||
@@ -211,16 +210,11 @@ class SolutionsView(TeamMixin, BaseFormView, SingleTableView):
 | 
			
		||||
 | 
			
		||||
        return super().form_valid(form)
 | 
			
		||||
 | 
			
		||||
    def form_invalid(self, form):
 | 
			
		||||
        print(form.errors)
 | 
			
		||||
 | 
			
		||||
        return super().form_invalid(form)
 | 
			
		||||
 | 
			
		||||
    def get_success_url(self):
 | 
			
		||||
        return reverse_lazy("tournament:solutions")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SolutionsOrgaListView(AdminMixin, SingleTableView):
 | 
			
		||||
class SolutionsOrgaListView(OrgaMixin, SingleTableView):
 | 
			
		||||
    model = Solution
 | 
			
		||||
    table_class = SolutionTable
 | 
			
		||||
    template_name = "tournament/solutions_orga_list.html"
 | 
			
		||||
@@ -262,3 +256,104 @@ class SolutionsOrgaListView(AdminMixin, SingleTableView):
 | 
			
		||||
        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 SynthesesView(TeamMixin, BaseFormView, SingleTableView):
 | 
			
		||||
    model = Synthesis
 | 
			
		||||
    table_class = SynthesisTable
 | 
			
		||||
    form_class = SynthesisForm
 | 
			
		||||
    template_name = "tournament/syntheses_list.html"
 | 
			
		||||
    extra_context = dict(title=_("Syntheses"))
 | 
			
		||||
 | 
			
		||||
    def post(self, request, *args, **kwargs):
 | 
			
		||||
        if "zip" in request.POST:
 | 
			
		||||
            syntheses = request.user.team.syntheses
 | 
			
		||||
 | 
			
		||||
            out = BytesIO()
 | 
			
		||||
            zf = zipfile.ZipFile(out, "w")
 | 
			
		||||
 | 
			
		||||
            for synthesis in syntheses:
 | 
			
		||||
                zf.write(synthesis.file.path, str(synthesis) + ".pdf")
 | 
			
		||||
 | 
			
		||||
            zf.close()
 | 
			
		||||
 | 
			
		||||
            resp = HttpResponse(out.getvalue(), content_type="application/x-zip-compressed")
 | 
			
		||||
            resp['Content-Disposition'] = 'attachment; filename={}'\
 | 
			
		||||
                .format(_("Syntheses for team {team}.zip")
 | 
			
		||||
                        .format(team=str(request.user.team)).replace(" ", "%20"))
 | 
			
		||||
            return resp
 | 
			
		||||
 | 
			
		||||
        return super().post(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        qs = super().get_queryset()
 | 
			
		||||
        if not self.request.user.admin:
 | 
			
		||||
            qs = qs.filter(team=self.request.user.team)
 | 
			
		||||
        return qs.order_by('team__tournament__date_start', 'team__tournament__name', 'team__trigram', 'round',
 | 
			
		||||
                           'source',)
 | 
			
		||||
 | 
			
		||||
    def form_valid(self, form):
 | 
			
		||||
        synthesis = form.instance
 | 
			
		||||
        synthesis.team = self.request.user.team
 | 
			
		||||
        synthesis.final = synthesis.team.selected_for_final
 | 
			
		||||
        prev_syn = Synthesis.objects.filter(team=synthesis.team, round=synthesis.round, source=synthesis.source,
 | 
			
		||||
                                            final=synthesis.final)
 | 
			
		||||
        for syn in prev_syn.all():
 | 
			
		||||
            syn.delete()
 | 
			
		||||
        alphabet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789"
 | 
			
		||||
        id = ""
 | 
			
		||||
        for _ in range(64):
 | 
			
		||||
            id += random.choice(alphabet)
 | 
			
		||||
        synthesis.file.name = id
 | 
			
		||||
        synthesis.save()
 | 
			
		||||
 | 
			
		||||
        return super().form_valid(form)
 | 
			
		||||
 | 
			
		||||
    def get_success_url(self):
 | 
			
		||||
        return reverse_lazy("tournament:syntheses")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SynthesesOrgaListView(OrgaMixin, SingleTableView):
 | 
			
		||||
    model = Synthesis
 | 
			
		||||
    table_class = SynthesisTable
 | 
			
		||||
    template_name = "tournament/syntheses_orga_list.html"
 | 
			
		||||
    extra_context = dict(title=_("All syntheses"))
 | 
			
		||||
 | 
			
		||||
    def post(self, request, *args, **kwargs):
 | 
			
		||||
        if "tournament_zip" in request.POST:
 | 
			
		||||
            tournament = Tournament.objects.get(pk=request.POST["tournament_zip"][0])
 | 
			
		||||
            syntheses = tournament.syntheses
 | 
			
		||||
            if not request.user.admin and request.user not in tournament.organizers.all():
 | 
			
		||||
                raise PermissionDenied
 | 
			
		||||
 | 
			
		||||
            out = BytesIO()
 | 
			
		||||
            zf = zipfile.ZipFile(out, "w")
 | 
			
		||||
 | 
			
		||||
            for synthesis in syntheses:
 | 
			
		||||
                zf.write(synthesis.file.path, str(synthesis) + ".pdf")
 | 
			
		||||
 | 
			
		||||
            zf.close()
 | 
			
		||||
 | 
			
		||||
            resp = HttpResponse(out.getvalue(), content_type="application/x-zip-compressed")
 | 
			
		||||
            resp['Content-Disposition'] = 'attachment; filename={}'\
 | 
			
		||||
                .format(_("Syntheses 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', 'round',
 | 
			
		||||
                           'source',)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user