export PDF avec Flask

This commit is contained in:
Emmanuel Viennet 2021-08-31 20:18:50 +02:00
parent a52de101b6
commit de47a5e873
6 changed files with 41 additions and 46 deletions

View File

@ -42,12 +42,9 @@ Created on Fri Sep 9 09:15:05 2016
# a l'edition d'un jury de poursuites d'etudes # a l'edition d'un jury de poursuites d'etudes
# ---------------------------------------------------------- # ----------------------------------------------------------
import io
import os import os
from zipfile import ZipFile
from io import StringIO
from zipfile import ZipFile, BadZipfile
import pprint
from app.scodoc.gen_tables import GenTable, SeqGenTable from app.scodoc.gen_tables import GenTable, SeqGenTable
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
@ -169,7 +166,7 @@ class JuryPE(object):
# Un zip où ranger les fichiers générés: # Un zip où ranger les fichiers générés:
self.NOM_EXPORT_ZIP = "Jury_PE_%s" % self.diplome self.NOM_EXPORT_ZIP = "Jury_PE_%s" % self.diplome
self.zipdata = StringIO() self.zipdata = io.BytesIO()
self.zipfile = ZipFile(self.zipdata, "w") self.zipfile = ZipFile(self.zipdata, "w")
# #
@ -206,11 +203,14 @@ class JuryPE(object):
# ------------------------------------------------------------------------------------------------------------------ # ------------------------------------------------------------------------------------------------------------------
def get_zipped_data(self): def get_zipped_data(self):
"""returns zipped data with all generated (CSV) files""" """returns file-like data with a zip of all generated (CSV) files.
Reset file cursor at the beginning !
"""
if self.zipfile: if self.zipfile:
self.zipfile.close() self.zipfile.close()
self.zipfile = None self.zipfile = None
return self.zipdata.getvalue() self.zipdata.seek(0)
return self.zipdata
# **************************************************************************************************************** # # **************************************************************************************************************** #
# Lancement des différentes actions permettant le calcul du jury PE # Lancement des différentes actions permettant le calcul du jury PE

View File

@ -35,6 +35,8 @@
""" """
from flask import send_file, request
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc import sco_formsemestre from app.scodoc import sco_formsemestre
from app.scodoc import html_sco_header from app.scodoc import html_sco_header
@ -46,7 +48,7 @@ from app.scodoc import pe_jurype
from app.scodoc import pe_avislatex from app.scodoc import pe_avislatex
def _pe_view_sem_recap_form(formsemestre_id, REQUEST=None): def _pe_view_sem_recap_form(formsemestre_id):
H = [ H = [
html_sco_header.sco_header(page_title="Avis de poursuite d'études"), html_sco_header.sco_header(page_title="Avis de poursuite d'études"),
"""<h2 class="formsemestre">Génération des avis de poursuites d'études</h2> """<h2 class="formsemestre">Génération des avis de poursuites d'études</h2>
@ -74,20 +76,15 @@ def _pe_view_sem_recap_form(formsemestre_id, REQUEST=None):
return "\n".join(H) + html_sco_header.sco_footer() return "\n".join(H) + html_sco_header.sco_footer()
# called from the web, POST or GET
def pe_view_sem_recap( def pe_view_sem_recap(
formsemestre_id, formsemestre_id,
avis_tmpl_file=None, avis_tmpl_file=None,
footer_tmpl_file=None, footer_tmpl_file=None,
mode_debug=False,
REQUEST=None,
): ):
"""Génération des avis de poursuite d'étude """Génération des avis de poursuite d'étude"""
if request.method == "GET":
mode_debug = Pour "squeezer" le calcul du jury pe (long) return _pe_view_sem_recap_form(formsemestre_id)
et debugger uniquement la partie avis latex
"""
if REQUEST and REQUEST.REQUEST_METHOD == "GET":
return _pe_view_sem_recap_form(formsemestre_id, REQUEST=REQUEST)
prefs = sco_preferences.SemPreferences(formsemestre_id=formsemestre_id) prefs = sco_preferences.SemPreferences(formsemestre_id=formsemestre_id)
semBase = sco_formsemestre.get_formsemestre(formsemestre_id) semBase = sco_formsemestre.get_formsemestre(formsemestre_id)
@ -169,14 +166,10 @@ def pe_view_sem_recap(
# Ajoute image, LaTeX class file(s) and modeles # Ajoute image, LaTeX class file(s) and modeles
pe_tools.add_pe_stuff_to_zip(jury.zipfile, jury.NOM_EXPORT_ZIP) pe_tools.add_pe_stuff_to_zip(jury.zipfile, jury.NOM_EXPORT_ZIP)
data = jury.get_zipped_data() data = jury.get_zipped_data()
size = len(data)
content_type = "application/zip" return send_file(
if REQUEST != None: data,
REQUEST.RESPONSE.setHeader( mimetype="application/zip",
"content-disposition", download_name=jury.NOM_EXPORT_ZIP + ".zip",
'attachement; filename="%s.zip"' % jury.NOM_EXPORT_ZIP, as_attachment=True,
) )
REQUEST.RESPONSE.setHeader("content-type", content_type)
REQUEST.RESPONSE.setHeader("content-length", size)
return data

View File

@ -1187,7 +1187,6 @@ def export_csv_to_apogee(
export_res_modules=True, export_res_modules=True,
export_res_sdj=True, export_res_sdj=True,
export_res_rat=True, export_res_rat=True,
REQUEST=None,
): ):
"""Genere un fichier CSV Apogée """Genere un fichier CSV Apogée
à partir d'un fichier CSV Apogée vide (ou partiellement rempli) à partir d'un fichier CSV Apogée vide (ou partiellement rempli)
@ -1306,7 +1305,7 @@ def export_csv_to_apogee(
return send_file( return send_file(
data, data,
mimetype="application/zip", mimetype="application/zip",
download_name=basename + "-scodoc.zip", download_name=scu.sanitize_filename(basename + "-scodoc.zip"),
as_attachment=True, as_attachment=True,
) )
else: else:

View File

@ -776,7 +776,6 @@ def apo_csv_export_results(
block_export_res_ues=False, block_export_res_ues=False,
block_export_res_modules=False, block_export_res_modules=False,
block_export_res_sdj=False, block_export_res_sdj=False,
REQUEST=None,
): ):
"""Remplit les fichiers CSV archivés """Remplit les fichiers CSV archivés
et donne un ZIP avec tous les résultats. et donne un ZIP avec tous les résultats.
@ -818,7 +817,6 @@ def apo_csv_export_results(
export_res_sdj=export_res_sdj, export_res_sdj=export_res_sdj,
export_res_rat=export_res_rat, export_res_rat=export_res_rat,
dest_zip=dest_zip, dest_zip=dest_zip,
REQUEST=REQUEST,
) )
dest_zip.close() dest_zip.close()
@ -829,11 +827,11 @@ def apo_csv_export_results(
+ "-%s-" % periode + "-%s-" % periode
+ "-".join(etapes_apo) + "-".join(etapes_apo)
) )
basename = scu.sanitize_filename(scu.unescape_html(basename)) basename = scu.unescape_html(basename)
return send_file( return send_file(
data, data,
mimetype="application/zip", mimetype="application/zip",
download_name=basename + ".zip", download_name=scu.sanitize_filename(basename + ".zip"),
as_attachment=True, as_attachment=True,
) )

View File

@ -44,7 +44,7 @@ from reportlab.lib import colors
from PIL import Image as PILImage from PIL import Image as PILImage
import flask import flask
from flask import url_for, g from flask import url_for, g, send_file
from app import log from app import log
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
@ -90,7 +90,7 @@ def trombino(
return dialog return dialog
if format == "zip": if format == "zip":
return _trombino_zip(groups_infos, REQUEST) return _trombino_zip(groups_infos)
elif format == "pdf": elif format == "pdf":
return _trombino_pdf(groups_infos, REQUEST) return _trombino_pdf(groups_infos, REQUEST)
elif format == "pdflist": elif format == "pdflist":
@ -215,7 +215,7 @@ def check_local_photos_availability(groups_infos, REQUEST, format=""):
return True, "" return True, ""
def _trombino_zip(groups_infos, REQUEST): def _trombino_zip(groups_infos):
"Send photos as zip archive" "Send photos as zip archive"
data = io.BytesIO() data = io.BytesIO()
Z = ZipFile(data, "w") Z = ZipFile(data, "w")
@ -235,13 +235,13 @@ def _trombino_zip(groups_infos, REQUEST):
Z.close() Z.close()
size = data.tell() size = data.tell()
log("trombino_zip: %d bytes" % size) log("trombino_zip: %d bytes" % size)
content_type = "application/zip" data.seek(0)
REQUEST.RESPONSE.setHeader( return send_file(
"content-disposition", 'attachement; filename="trombi.zip"' data,
mimetype="application/zip",
download_name="trombi.zip",
as_attachment=True,
) )
REQUEST.RESPONSE.setHeader("content-type", content_type)
REQUEST.RESPONSE.setHeader("content-length", size)
return data.getvalue()
# Copy photos from portal to ScoDoc # Copy photos from portal to ScoDoc
@ -384,9 +384,13 @@ def _trombino_pdf(groups_infos, REQUEST):
) )
) )
document.build(objects) document.build(objects)
data = report.getvalue() report.seek(0)
return send_file(
return scu.sendPDFFile(REQUEST, data, filename) report,
mimetype=scu.PDF_MIMETYPE,
download_name=scu.sanitize_filename(filename),
as_attachment=True,
)
# --------------------- Sur une idée de l'IUT d'Orléans: # --------------------- Sur une idée de l'IUT d'Orléans:

View File

@ -478,6 +478,7 @@ def sanitize_filename(filename):
"""Keep only valid chars """Keep only valid chars
used for archives filenames used for archives filenames
""" """
filename = suppress_accents(filename.replace(" ", "_"))
sane = "".join([c for c in filename if c in VALID_CARS_SET]) sane = "".join([c for c in filename if c in VALID_CARS_SET])
if len(sane) < 2: if len(sane) < 2:
sane = time.strftime("%Y-%m-%d-%H%M%S") + "-" + sane sane = time.strftime("%Y-%m-%d-%H%M%S") + "-" + sane