import io import os import zipfile from django.contrib.auth.mixins import LoginRequiredMixin from django.core.files import File from django.db.models import Q from django.http import Http404 from django.shortcuts import HttpResponse, get_object_or_404, redirect, render from django.urls import reverse_lazy from django.utils.safestring import mark_safe from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ from django.views.generic import (CreateView, DeleteView, ListView, TemplateView, UpdateView) from gestion.mixins import ChefMuRequiredMixin from gestion.models import Photo from partitions.forms import UploadFileForm, UploadMorceauForm from partitions.models import Category, Partition, PartitionSet, SetList from .forms import ChefEditMorceauForm def download_musecores(request): p = Partition.objects.filter( Q(part__contains=".mscz") & Q( Q(morceau__category__name="Partitions actives") | Q(morceau__category__name="Partitions optionnelles") ) ) zip_subdir = "Ernestophone_musescores" zip_filename = "%s.zip" % zip_subdir # Open StringIO to grab in-memory ZIP contents s = io.BytesIO() # The zip compressor zf = zipfile.ZipFile(s, "w") for part in p: fpath = part.part.path typ = ".mscz" # Calculate path for file in zip fdir, fname = os.path.split(fpath) zip_path = os.path.join( zip_subdir, "%s_%s_%s.%s" % ( slugify(part.morceau.nom), slugify(part.morceau.auteur), slugify(part.nom), typ, ), ) # Add file, at correct path zf.write(fpath, zip_path) # Must close zip for all contents to be written zf.close() # Grab ZIP file from in-memory, make response with correct MIME-type resp = HttpResponse(s.getvalue()) # ..and correct content-disposition resp["Content-Disposition"] = "attachment; filename=%s" % zip_filename return resp from datetime import date, timedelta class Repertoire(TemplateView): template_name = "partitions/repertoire.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["setlists"] = ( SetList.objects.filter( is_current="y", date__gt=(date.today() - timedelta(days=7)) ) .order_by("date") .prefetch_related("morceaux") ) context["categories"] = Category.objects.prefetch_related( "partitionset_set" ).order_by("order") context["photo"] = Photo.objects.filter(cat="part").order_by("?").first() return context class Morceau(LoginRequiredMixin, TemplateView): template_name = "partitions/part.html" form_class = ChefEditMorceauForm def get_context_data(self, **kwargs): context = super(Morceau, self).get_context_data(**kwargs) p = get_object_or_404( PartitionSet, nom=self.kwargs["nom"], auteur=self.kwargs["auteur"] ) part = p.partition_set.all().order_by("nom") form = self.form_class(instance=p) infos = mark_safe(p.infos) infos_en = mark_safe(p.infos_en) context["p"] = p context["infos"] = infos context["infos_en"] = infos_en context["form"] = form context["part"] = part context["nom"] = self.kwargs["nom"] context["auteur"] = self.kwargs["auteur"] return context def post(self, request, *args, **kwargs): p = get_object_or_404( PartitionSet, nom=self.kwargs["nom"], auteur=self.kwargs["auteur"] ) if request.user.profile.is_chef: form = self.form_class(request.POST, instance=p) if form.is_valid(): form.save() context = self.get_context_data() return render(request, self.template_name, context) class Upload(ChefMuRequiredMixin, TemplateView): form_class = UploadFileForm template_name = "partitions/upload.html" def get_context_data(self, **kwargs): context = super(Upload, self).get_context_data(**kwargs) form = self.form_class() context["nom"] = self.kwargs["nom"] context["auteur"] = self.kwargs["auteur"] context["form"] = form return context def post(self, request, *args, **kwargs): form = UploadFileForm(request.POST, request.FILES) error = False sauvegarde = False if form.is_valid(): partition = Partition() partition.part = form.cleaned_data["file"] partition.nom = form.cleaned_data["title"] if "/" in partition.nom: error = _("Le caractère / n'est pas autorisé dans le nom") context = self.get_context_data() context["error"] = error return render(request, self.template_name, context) mor = get_object_or_404( PartitionSet, nom=self.kwargs["nom"], auteur=self.kwargs["auteur"] ) partition.morceau = mor try: mor.partition_set.get(nom=partition.nom) error = _("Un morceau du même nom existe déjà") except Partition.DoesNotExist: partition.save() sauvegarde = True context = self.get_context_data() context["form"] = form context["error"] = error context["sauvegarde"] = sauvegarde return render(request, self.template_name, context) def see(request, nom, auteur, partition_id): partition = get_object_or_404(Partition, id=partition_id) _, extension = os.path.splitext(partition.part.path) download_unlogged = partition.morceau.download_unlogged if download_unlogged == "o" or request.user.is_authenticated: if ".pdf" == extension: with open(partition.part.path, "rb") as f: myfile = File(f) response = HttpResponse(content=myfile.read()) response["Content-Type"] = "application/pdf" response["Content-Disposition"] = "inline; filename=%s_%s_%s.pdf" % ( slugify(nom), slugify(auteur), slugify(partition.nom), ) return response elif ".mp3" == extension: with open(partition.part.path, "rb") as f: myfile = File(f) response = HttpResponse() response.write(myfile.read()) response["Content-Type"] = "audio/mp3" response["Content-Length"] = myfile.size return response else: p = get_object_or_404(PartitionSet, nom=nom, auteur=auteur) part = p.partition_set.all() return render( request, "partitions/part.html", {"p": p, "part": part, "nom": nom, "auteur": auteur}, ) else: return redirect("login") class DeletePart(ChefMuRequiredMixin, TemplateView): model = PartitionSet def get(self, request, *args, **kwargs): p = get_object_or_404( self.model, nom=self.kwargs["nom"], auteur=self.kwargs["auteur"] ) try: part = p.partition_set.get(id=self.kwargs["id"]) except Partition.DoesNotExist: raise Http404 part.delete() return redirect( "partitions:listepart", nom=self.kwargs["nom"], auteur=self.kwargs["auteur"] ) class CreateMorc(ChefMuRequiredMixin, TemplateView): form_class = UploadMorceauForm template_name = "partitions/new.html" def get_context_data(self, **kwargs): context = super(CreateMorc, self).get_context_data(**kwargs) context["form"] = self.form_class() return context def post(self, request, *args, **kwargs): form = self.form_class(request.POST) sauvegarde = False error = False if form.is_valid(): partitionset = PartitionSet() partitionset.nom = form.cleaned_data["titre"] partitionset.auteur = form.cleaned_data["auteur"] if "/" in partitionset.auteur or "/" in partitionset.nom: error = _("Le caractère / n'est pas autorisé") context = self.get_context_data() context["error"] = error return render(request, self.template_name, context) try: PartitionSet.objects.get( nom=partitionset.nom, auteur=partitionset.auteur ) error = _("Un morceau du même nom existe déjà") except PartitionSet.DoesNotExist: # XXX. Hideous cat = Category.objects.first() try: cat = Category.objects.get(name="Partitions à venir") except Category.DoesNotExist: pass partitionset.category = cat partitionset.save() sauvegarde = True return redirect("partitions:liste") context = self.get_context_data() context["sauvegarde"] = sauvegarde context["error"] = error context["form"] = form return render(request, self.template_name, context) class ConfDelete(ChefMuRequiredMixin, TemplateView): template_name = "partitions/conf_delete.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["nom"] = self.kwargs.get("nom") context["auteur"] = self.kwargs.get("auteur") context["id"] = self.kwargs.get("id") return context class DeleteMorc(ChefMuRequiredMixin, TemplateView): model = PartitionSet def get(self, request, *args, **kwargs): p = get_object_or_404( self.model, nom=self.kwargs["nom"], auteur=self.kwargs["auteur"] ) part = p.partition_set.all() for pa in part: pa.delete() p.delete() return redirect("partitions:liste") class ConfDeleteMorc(ChefMuRequiredMixin, TemplateView): template_name = "partitions/conf_delete_morc.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["nom"] = self.kwargs.get("nom") context["auteur"] = self.kwargs.get("auteur") return context def download(request, nom, auteur, partition_id): partition = get_object_or_404(Partition, id=partition_id) download_unlogged = partition.morceau.download_unlogged if download_unlogged == "o" or request.user.is_authenticated: with open(partition.part.path, "rb") as f: myfile = File(f) response = HttpResponse(content=myfile.read()) typ = os.path.splitext(myfile.name)[1][1:] response["Content-Type"] = "application/%s" % (typ,) response["Content-Disposition"] = "attachment; filename=%s_%s_%s.%s" % ( slugify(nom), slugify(auteur), slugify(partition.nom), typ, ) return response else: return redirect("login") class SetListListView(ChefMuRequiredMixin, ListView): model = SetList def get_queryset(self): return SetList.objects.all().order_by("-date") class SetListCreate(ChefMuRequiredMixin, CreateView): model = SetList fields = ["date", "morceaux", "is_current"] success_url = reverse_lazy("partitions:list_setlist") class SetListUpdate(ChefMuRequiredMixin, UpdateView): model = SetList fields = ["date", "morceaux", "is_current"] success_url = reverse_lazy("partitions:list_setlist") class SetListDelete(ChefMuRequiredMixin, DeleteView): model = SetList success_url = reverse_lazy("partitions:list_setlist")