diff --git a/stages/pdf.py b/stages/pdf.py index 79213e8..1da60ec 100644 --- a/stages/pdf.py +++ b/stages/pdf.py @@ -1,5 +1,3 @@ -import os -import tempfile from datetime import date from django.conf import settings @@ -50,10 +48,9 @@ class HorLine(Flowable): class EpcBaseDocTemplate(SimpleDocTemplate): points = '.' * 93 - def __init__(self, filename, title=''): - path = os.path.join(tempfile.gettempdir(), filename) + def __init__(self, filelike, title=''): super().__init__( - path, + filelike, pagesize=A4, lefMargin=2.5 * cm, bottomMargin=1 * cm, topMargin=1 * cm, rightMargin=2.5 * cm ) @@ -117,10 +114,9 @@ class ChargeSheetPDF(EpcBaseDocTemplate): """ Génération des feuilles de charges en pdf. """ - def __init__(self, teacher): + def __init__(self, out, teacher): self.teacher = teacher - filename = slugify('{0}_{1}'.format(teacher.last_name, teacher.first_name)) + '.pdf' - super().__init__(filename) + super().__init__(out) self.addPageTemplates([ PageTemplate(id='FirstPage', frames=[self.page_frame], onPage=self.header) ]) @@ -185,8 +181,8 @@ class UpdateDataFormPDF(EpcBaseDocTemplate): """ Génération des formulaires PDF de mise à jour des données. """ - def __init__(self, filename, return_date): - super().__init__(filename) + def __init__(self, out, return_date): + super().__init__(out) self.text = ( "Afin de mettre à jour nos bases de données, nous vous serions reconnaissant " "de contrôler les données ci-dessous qui vous concernent selon votre filière " @@ -415,12 +411,9 @@ class CompensationForm: class ExpertEdeLetterPdf(CompensationForm, EpcBaseDocTemplate): - def __init__(self, student): + def __init__(self, out, student): self.student = student - filename = slugify( - '{0}_{1}'.format(self.student.last_name, self.student.first_name) - ) + '_Expert.pdf' - super().__init__(filename) + super().__init__(out) self.addPageTemplates([ PageTemplate(id='FirstPage', frames=[self.page_frame], onPage=self.header), PageTemplate(id='ISOPage', frames=[self.page_frame], onPage=self.header_iso), @@ -501,12 +494,9 @@ class ExpertEdeLetterPdf(CompensationForm, EpcBaseDocTemplate): class MentorCompensationPdfForm(CompensationForm, EpcBaseDocTemplate): - def __init__(self, student): + def __init__(self, out, student): self.student = student - filename = slugify( - '{0}_{1}'.format(self.student.last_name, self.student.first_name) - ) + '_Indemn_mentor.pdf' - super().__init__(filename) + super().__init__(out) self.addPageTemplates([ PageTemplate(id='FirstPage', frames=[self.page_frame], onPage=self.header_iso) ]) @@ -533,10 +523,9 @@ class KlassListPDF(EpcBaseDocTemplate): """ Génération des rôles de classes en pdf. """ - def __init__(self, klass): + def __init__(self, out, klass): self.klass = klass - filename = slugify('{0}'.format(klass.name)) + '.pdf' - super().__init__(filename) + super().__init__(out) self.addPageTemplates([ PageTemplate(id='FirstPage', frames=[self.page_frame], onPage=self.header), diff --git a/stages/tests.py b/stages/tests.py index a58f4e2..22cf92f 100644 --- a/stages/tests.py +++ b/stages/tests.py @@ -345,7 +345,7 @@ tél. 032 886 33 00 'attachment; filename="dupond_albin_Expert.pdf"' ) self.assertEqual(response['Content-Type'], 'application/pdf') - self.assertGreater(len(response.content), 200) + self.assertGreater(int(response['Content-Length']), 1000) # Expert without corporation st.expert = CorpContact.objects.create(first_name='James', last_name='Bond') st.save() @@ -361,7 +361,7 @@ tél. 032 886 33 00 'attachment; filename="dupond_albin_Indemn_mentor.pdf"' ) self.assertEqual(response['Content-Type'], 'application/pdf') - self.assertGreater(len(response.content), 200) + self.assertGreater(int(response['Content-Length']), 1000) def test_EDEpe_klass(self): lev3 = Level.objects.create(name='3') diff --git a/stages/views/__init__.py b/stages/views/__init__.py index d1b32f7..91e9690 100644 --- a/stages/views/__init__.py +++ b/stages/views/__init__.py @@ -1,3 +1,4 @@ +import io import json import os @@ -8,7 +9,7 @@ from django.contrib import messages from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.mail import EmailMessage from django.db.models import Count -from django.http import HttpResponse, HttpResponseNotAllowed, HttpResponseRedirect +from django.http import FileResponse, HttpResponse, HttpResponseNotAllowed, HttpResponseRedirect from django.shortcuts import get_object_or_404, redirect from django.template import loader from django.urls import reverse, reverse_lazy @@ -536,9 +537,10 @@ class PrintUpdateForm(ZippedFilesBaseView): def generate_files(self): for klass in Klass.objects.filter(level__gte=2 ).exclude(section__name='MP_ASSC').exclude(section__name='MP_ASE'): - pdf = UpdateDataFormPDF('{0}.pdf'.format(klass.name), self.return_date) + buff = io.BytesIO() + pdf = UpdateDataFormPDF(buff, self.return_date) pdf.produce(klass) - yield pdf.filename + yield ('{0}.pdf'.format(klass.name), buff.getvalue()) def print_expert_ede_compensation_form(request, pk): @@ -554,13 +556,14 @@ def print_expert_ede_compensation_form(request, pk): + missing )) return redirect(reverse("admin:stages_student_change", args=(student.pk,))) - pdf = ExpertEdeLetterPdf(student) + buff = io.BytesIO() + pdf = ExpertEdeLetterPdf(buff, student) pdf.produce() - - with open(pdf.filename, mode='rb') as fh: - response = HttpResponse(fh.read(), content_type='application/pdf') - response['Content-Disposition'] = 'attachment; filename="{0}"'.format(os.path.basename(pdf.filename)) - return response + filename = slugify( + '{0}_{1}'.format(student.last_name, student.first_name) + ) + '_Expert.pdf' + buff.seek(0) + return FileResponse(buff, as_attachment=True, filename=filename) def print_mentor_ede_compensation_form(request, pk): @@ -571,13 +574,16 @@ def print_mentor_ede_compensation_form(request, pk): if not student.mentor: messages.error(request, "Aucun mentor n'est attribué à cet étudiant") return redirect(reverse("admin:stages_student_change", args=(student.pk,))) - pdf = MentorCompensationPdfForm(student) + buff = io.BytesIO() + pdf = MentorCompensationPdfForm(buff, student) pdf.produce() + filename = slugify( + '{0}_{1}'.format(student.last_name, student.first_name) + ) + '_Indemn_mentor.pdf' + buff.seek(0) + return FileResponse(buff, as_attachment=True, filename=filename) + - with open(pdf.filename, mode='rb') as fh: - response = HttpResponse(fh.read(), content_type='application/pdf') - response['Content-Disposition'] = 'attachment; filename="{0}"'.format(os.path.basename(pdf.filename)) - return response class PrintKlassList(ZippedFilesBaseView): @@ -585,9 +591,11 @@ class PrintKlassList(ZippedFilesBaseView): def generate_files(self): for klass in Klass.active.order_by('section', 'name'): - pdf = KlassListPDF(klass) + buff = io.BytesIO() + pdf = KlassListPDF(buff, klass) pdf.produce(klass) - yield pdf.filename + filename = slugify('{0}.pdf'.format(klass.name)) + yield (filename, buff.getvalue()) class PrintChargeSheet(ZippedFilesBaseView): @@ -601,6 +609,8 @@ class PrintChargeSheet(ZippedFilesBaseView): queryset = Teacher.objects.filter(pk__in=self.request.GET.get('ids').split(',')) for teacher in queryset: activities = teacher.calc_activity() - pdf = ChargeSheetPDF(teacher) + buff = io.BytesIO() + pdf = ChargeSheetPDF(buff, teacher) pdf.produce(activities) - yield pdf.filename + filename = slugify('{0}_{1}.pdf'.format(teacher.last_name, teacher.first_name)) + yield (filename, buff.getvalue()) diff --git a/stages/views/base.py b/stages/views/base.py index 6bc7938..7977b83 100644 --- a/stages/views/base.py +++ b/stages/views/base.py @@ -56,13 +56,14 @@ class ZippedFilesBaseView(View): filename = 'to_be_defined.zip' def generate_files(self): + """Generator yielding (file_name, file_data) tuples.""" raise NotImplementedError() def get(self, request, *args, **kwargs): tmp_file = tempfile.NamedTemporaryFile() with zipfile.ZipFile(tmp_file, mode='w', compression=zipfile.ZIP_DEFLATED) as filezip: - for file_name in self.generate_files(): - filezip.write(file_name, arcname=os.path.basename(file_name)) + for file_name, file_data in self.generate_files(): + filezip.writestr(file_name, file_data) with open(filezip.filename, mode='rb') as fh: response = HttpResponse(fh.read(), content_type='application/zip')