forked from ScoDoc/DocScoDoc
integration master
This commit is contained in:
parent
01c264c3c7
commit
a23ae38014
@ -60,7 +60,6 @@ from app.scodoc import sco_pdf
|
|||||||
from app.scodoc import sco_xml
|
from app.scodoc import sco_xml
|
||||||
from app.scodoc.sco_pdf import SU
|
from app.scodoc.sco_pdf import SU
|
||||||
from app import log
|
from app import log
|
||||||
from app.scodoc.sco_utils import flaskPDFResponse
|
|
||||||
|
|
||||||
|
|
||||||
def mark_paras(L, tags):
|
def mark_paras(L, tags):
|
||||||
@ -611,7 +610,6 @@ class GenTable(object):
|
|||||||
format="html",
|
format="html",
|
||||||
page_title="",
|
page_title="",
|
||||||
filename=None,
|
filename=None,
|
||||||
REQUEST=None,
|
|
||||||
javascripts=[],
|
javascripts=[],
|
||||||
with_html_headers=True,
|
with_html_headers=True,
|
||||||
publish=True,
|
publish=True,
|
||||||
@ -644,40 +642,55 @@ class GenTable(object):
|
|||||||
H.append(html_sco_header.sco_footer())
|
H.append(html_sco_header.sco_footer())
|
||||||
return "\n".join(H)
|
return "\n".join(H)
|
||||||
elif format == "pdf":
|
elif format == "pdf":
|
||||||
objects = self.pdf()
|
pdf_objs = self.pdf()
|
||||||
doc = sco_pdf.pdf_basic_page(
|
pdf_doc = sco_pdf.pdf_basic_page(
|
||||||
objects, title=title, preferences=self.preferences
|
pdf_objs, title=title, preferences=self.preferences
|
||||||
)
|
)
|
||||||
if publish:
|
if publish:
|
||||||
return scu.PDF_FORMAT.send_file(doc, filename, add_suffix=True, attached=True)
|
return scu.send_file(
|
||||||
# return scu.flaskPDFResponse(doc, filename + ".pdf")
|
pdf_doc,
|
||||||
# return scu.sendPDFFile(REQUEST, doc, filename + ".pdf")
|
filename,
|
||||||
|
suffix=".pdf",
|
||||||
|
mime=scu.PDF_MIMETYPE,
|
||||||
|
attached=True,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return doc
|
return pdf_doc
|
||||||
elif format == "xls" or format == "xlsx":
|
elif format == "xls" or format == "xlsx": # dans les 2 cas retourne du xlsx
|
||||||
xls = self.excel()
|
xls = self.excel()
|
||||||
if publish:
|
if publish:
|
||||||
return scu.XLSX_FORMAT.send_file(xls, filename, add_suffix=True, attached=True)
|
return scu.send_file(
|
||||||
# return sco_excel.send_from_flask(xls, filename + scu.XLSX_SUFFIX)
|
xls,
|
||||||
# return sco_excel.send_excel_file(REQUEST, xls, filename + scu.XLSX_SUFFIX)
|
filename,
|
||||||
|
suffix=scu.XLSX_SUFFIX,
|
||||||
|
mime=scu.XLSX_MIMETYPE,
|
||||||
|
attached=True,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return xls
|
return xls
|
||||||
elif format == "text":
|
elif format == "text":
|
||||||
return self.text()
|
return self.text()
|
||||||
elif format == "csv":
|
elif format == "csv":
|
||||||
return scu.CSV_FORMAT.send_file(self.text(), filename, add_suffix=True, attached=True)
|
return scu.send_file(
|
||||||
# return scu.sendCSVFile(REQUEST, self.text(), filename + ".csv")
|
self.text(),
|
||||||
|
filename,
|
||||||
|
suffix=".csv",
|
||||||
|
mime=scu.CSV_MIMETYPE,
|
||||||
|
attached=True,
|
||||||
|
)
|
||||||
elif format == "xml":
|
elif format == "xml":
|
||||||
xml = self.xml()
|
xml = self.xml()
|
||||||
if publish:
|
if publish:
|
||||||
# REQUEST.RESPONSE.setHeader("content-type", scu.XML_MIMETYPE)
|
return scu.send_file(
|
||||||
# return xml
|
xml, filename, suffix=".xml", mime=scu.XML_MIMETYPE, attached=True
|
||||||
return scu.XML_FORMAT.send_file(self.xml)
|
)
|
||||||
|
return xml
|
||||||
elif format == "json":
|
elif format == "json":
|
||||||
js = self.json()
|
js = self.json()
|
||||||
if publish:
|
if publish:
|
||||||
return scu.JSON_FORMAT.send_file(self.xml)
|
return scu.send_file(
|
||||||
# REQUEST.RESPONSE.setHeader("content-type", scu.JSON_MIMETYPE)
|
js, filename, suffix=".json", mime=scu.JSON_MIMETYPE, attached=True
|
||||||
|
)
|
||||||
return js
|
return js
|
||||||
else:
|
else:
|
||||||
log("make_page: format=%s" % format)
|
log("make_page: format=%s" % format)
|
||||||
@ -738,5 +751,5 @@ if __name__ == "__main__":
|
|||||||
document.build(objects)
|
document.build(objects)
|
||||||
data = doc.getvalue()
|
data = doc.getvalue()
|
||||||
open("/tmp/gen_table.pdf", "wb").write(data)
|
open("/tmp/gen_table.pdf", "wb").write(data)
|
||||||
p = T.make_page(format="pdf", REQUEST=None)
|
p = T.make_page(format="pdf")
|
||||||
open("toto.pdf", "wb").write(p)
|
open("toto.pdf", "wb").write(p)
|
||||||
|
@ -31,7 +31,7 @@ import datetime
|
|||||||
import operator
|
import operator
|
||||||
import pprint
|
import pprint
|
||||||
import time
|
import time
|
||||||
import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error
|
import urllib
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
@ -921,7 +921,7 @@ def formsemestre_evaluations_delai_correction(
|
|||||||
+ "",
|
+ "",
|
||||||
filename=scu.make_filename("evaluations_delais_" + sem["titreannee"]),
|
filename=scu.make_filename("evaluations_delais_" + sem["titreannee"]),
|
||||||
)
|
)
|
||||||
return tab.make_page(format=format, REQUEST=REQUEST)
|
return tab.make_page(format=format)
|
||||||
|
|
||||||
|
|
||||||
def module_evaluation_insert_before(ModEvals, next_eval):
|
def module_evaluation_insert_before(ModEvals, next_eval):
|
||||||
@ -1046,7 +1046,7 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
|
|||||||
resp = u["prenomnom"]
|
resp = u["prenomnom"]
|
||||||
nomcomplet = u["nomcomplet"]
|
nomcomplet = u["nomcomplet"]
|
||||||
can_edit = sco_permissions_check.can_edit_notes(
|
can_edit = sco_permissions_check.can_edit_notes(
|
||||||
, moduleimpl_id, allow_ens=False
|
current_user, moduleimpl_id, allow_ens=False
|
||||||
)
|
)
|
||||||
|
|
||||||
link = (
|
link = (
|
||||||
@ -1089,7 +1089,7 @@ def evaluation_describe(evaluation_id="", edit_in_place=True):
|
|||||||
% (
|
% (
|
||||||
scu.ScoURL(),
|
scu.ScoURL(),
|
||||||
group_id,
|
group_id,
|
||||||
six.moves.urllib.parse.quote(E["jour"], safe=""),
|
urllib.parse.quote(E["jour"], safe=""),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
H.append(
|
H.append(
|
||||||
|
@ -49,11 +49,12 @@ import unicodedata
|
|||||||
import urllib
|
import urllib
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
|
||||||
from flask import g, current_app, make_response
|
from flask import g, current_app
|
||||||
|
|
||||||
from PIL import Image as PILImage
|
from PIL import Image as PILImage
|
||||||
|
|
||||||
from flask import g, url_for, request
|
from flask import g, url_for, request, make_response
|
||||||
|
from werkzeug.wrappers import response
|
||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from app import log
|
from app import log
|
||||||
@ -64,6 +65,7 @@ from app.scodoc import sco_exceptions
|
|||||||
from app.scodoc import sco_xml
|
from app.scodoc import sco_xml
|
||||||
import sco_version
|
import sco_version
|
||||||
|
|
||||||
|
|
||||||
# ----- CALCUL ET PRESENTATION DES NOTES
|
# ----- CALCUL ET PRESENTATION DES NOTES
|
||||||
NOTES_PRECISION = 1e-4 # evite eventuelles erreurs d'arrondis
|
NOTES_PRECISION = 1e-4 # evite eventuelles erreurs d'arrondis
|
||||||
NOTES_MIN = 0.0 # valeur minimale admise pour une note (sauf malus, dans [-20, 20])
|
NOTES_MIN = 0.0 # valeur minimale admise pour une note (sauf malus, dans [-20, 20])
|
||||||
@ -72,6 +74,7 @@ NOTES_NEUTRALISE = -1000.0 # notes non prises en comptes dans moyennes
|
|||||||
NOTES_SUPPRESS = -1001.0 # note a supprimer
|
NOTES_SUPPRESS = -1001.0 # note a supprimer
|
||||||
NOTES_ATTENTE = -1002.0 # note "en attente" (se calcule comme une note neutralisee)
|
NOTES_ATTENTE = -1002.0 # note "en attente" (se calcule comme une note neutralisee)
|
||||||
|
|
||||||
|
|
||||||
# Types de modules
|
# Types de modules
|
||||||
MODULE_STANDARD = 0
|
MODULE_STANDARD = 0
|
||||||
MODULE_MALUS = 1
|
MODULE_MALUS = 1
|
||||||
@ -232,9 +235,11 @@ if not os.path.exists(SCO_TMP_DIR):
|
|||||||
SCODOC_LOGOS_DIR = os.path.join(SCODOC_CFG_DIR, "logos")
|
SCODOC_LOGOS_DIR = os.path.join(SCODOC_CFG_DIR, "logos")
|
||||||
LOGOS_IMAGES_ALLOWED_TYPES = ("jpg", "jpeg", "png") # remind that PIL does not read pdf
|
LOGOS_IMAGES_ALLOWED_TYPES = ("jpg", "jpeg", "png") # remind that PIL does not read pdf
|
||||||
|
|
||||||
|
|
||||||
# ----- Les outils distribués
|
# ----- Les outils distribués
|
||||||
SCO_TOOLS_DIR = os.path.join(Config.SCODOC_DIR, "tools")
|
SCO_TOOLS_DIR = os.path.join(Config.SCODOC_DIR, "tools")
|
||||||
|
|
||||||
|
|
||||||
# ----- Lecture du fichier de configuration
|
# ----- Lecture du fichier de configuration
|
||||||
from app.scodoc import sco_config
|
from app.scodoc import sco_config
|
||||||
from app.scodoc import sco_config_load
|
from app.scodoc import sco_config_load
|
||||||
@ -268,6 +273,7 @@ else:
|
|||||||
|
|
||||||
SCO_ENCODING = "utf-8" # used by Excel, XML, PDF, ...
|
SCO_ENCODING = "utf-8" # used by Excel, XML, PDF, ...
|
||||||
|
|
||||||
|
|
||||||
SCO_DEFAULT_SQL_USER = "scodoc" # should match Zope process UID
|
SCO_DEFAULT_SQL_USER = "scodoc" # should match Zope process UID
|
||||||
SCO_DEFAULT_SQL_PORT = "5432"
|
SCO_DEFAULT_SQL_PORT = "5432"
|
||||||
SCO_DEFAULT_SQL_USERS_CNX = "dbname=SCOUSERS port=%s" % SCO_DEFAULT_SQL_PORT
|
SCO_DEFAULT_SQL_USERS_CNX = "dbname=SCOUSERS port=%s" % SCO_DEFAULT_SQL_PORT
|
||||||
@ -295,15 +301,33 @@ SCO_DUMP_UP_URL = "https://scodoc.iutv.univ-paris13.fr/scodoc-installmgr/upload-
|
|||||||
CSV_FIELDSEP = ";"
|
CSV_FIELDSEP = ";"
|
||||||
CSV_LINESEP = "\n"
|
CSV_LINESEP = "\n"
|
||||||
CSV_MIMETYPE = "text/comma-separated-values"
|
CSV_MIMETYPE = "text/comma-separated-values"
|
||||||
|
CSV_SUFFIX = ".csv"
|
||||||
|
JSON_MIMETYPE = "application/json"
|
||||||
|
JSON_SUFFIX = ".json"
|
||||||
|
PDF_MIMETYPE = "application/pdf"
|
||||||
|
PDF_SUFFIX = ".pdf"
|
||||||
XLS_MIMETYPE = "application/vnd.ms-excel"
|
XLS_MIMETYPE = "application/vnd.ms-excel"
|
||||||
XLSX_MIMETYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
XLSX_MIMETYPE = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||||
XLSX_SUFFIX = ".xlsx"
|
XLSX_SUFFIX = ".xlsx"
|
||||||
PDF_MIMETYPE = "application/pdf"
|
|
||||||
PDF_SUFFIX = ".pdf"
|
|
||||||
XML_MIMETYPE = "text/xml"
|
XML_MIMETYPE = "text/xml"
|
||||||
XML_SUFFIX = ".xml"
|
XML_SUFFIX = ".xml"
|
||||||
JSON_MIMETYPE = "application/json"
|
|
||||||
JSON_SUFFIX = ".json"
|
|
||||||
|
def get_mime_suffix(format_code: str) -> tuple[str, str]:
|
||||||
|
"""Returns (MIME, SUFFIX) from format_code == "xls", "xml", ...
|
||||||
|
SUFFIX includes the dot: ".xlsx", ".xml", ...
|
||||||
|
"xls" and "xlsx" format codes give XLSX
|
||||||
|
"""
|
||||||
|
d = {
|
||||||
|
"csv": (CSV_MIMETYPE, CSV_SUFFIX),
|
||||||
|
"xls": (XLSX_MIMETYPE, XLSX_SUFFIX),
|
||||||
|
"xlsx": (XLSX_MIMETYPE, XLSX_SUFFIX),
|
||||||
|
"pdf": (PDF_MIMETYPE, PDF_SUFFIX),
|
||||||
|
"xml": (XML_MIMETYPE, XML_SUFFIX),
|
||||||
|
"json": (JSON_MIMETYPE, JSON_SUFFIX),
|
||||||
|
}
|
||||||
|
return d[format_code]
|
||||||
|
|
||||||
|
|
||||||
# Admissions des étudiants
|
# Admissions des étudiants
|
||||||
# Différents types de voies d'admission:
|
# Différents types de voies d'admission:
|
||||||
@ -313,31 +337,6 @@ TYPES_ADMISSION = (TYPE_ADMISSION_DEFAULT, "APB", "APB-PC", "CEF", "Direct")
|
|||||||
|
|
||||||
BULLETINS_VERSIONS = ("short", "selectedevals", "long")
|
BULLETINS_VERSIONS = ("short", "selectedevals", "long")
|
||||||
|
|
||||||
|
|
||||||
# File format management
|
|
||||||
class FileFormat:
|
|
||||||
def __init__(self, suffix, mime):
|
|
||||||
self._mime = mime
|
|
||||||
self._suffix = suffix
|
|
||||||
|
|
||||||
def send_file(self, data, filename, add_suffix=False, attached=False):
|
|
||||||
filename = make_filename(filename)
|
|
||||||
if add_suffix:
|
|
||||||
filename += self._suffix
|
|
||||||
response = make_response(data)
|
|
||||||
response.headers['Content-Type'] = self._mime
|
|
||||||
if attached:
|
|
||||||
response.headers['Content-Disposition'] = 'attachment; filename="%s"' % filename
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
CSV_FORMAT = FileFormat(CSV_SUFFIX, CSV_MIMETYPE)
|
|
||||||
XLSX_FORMAT = FileFormat(XLSX_SUFFIX, XLSX_MIMETYPE)
|
|
||||||
XLS_FORMAT = FileFormat(XLS_SUFFIX, XLS_MIMETYPE)
|
|
||||||
PDF_FORMAT = FileFormat(PDF_SUFFIX, PDF_MIMETYPE)
|
|
||||||
XML_FORMAT = FileFormat(XML_SUFFIX, XML_MIMETYPE)
|
|
||||||
JSON_FORMAT = FileFormat(JSON_SUFFIX, JSON_MIMETYPE)
|
|
||||||
|
|
||||||
# Support for ScoDoc7 compatibility
|
# Support for ScoDoc7 compatibility
|
||||||
|
|
||||||
|
|
||||||
@ -513,7 +512,7 @@ def is_valid_filename(filename):
|
|||||||
return VALID_EXP.match(filename)
|
return VALID_EXP.match(filename)
|
||||||
|
|
||||||
|
|
||||||
def sendCSVFile(REQUEST, data, filename):
|
def sendCSVFile(REQUEST, data, filename): # DEPRECATED ne plus utiliser
|
||||||
"""publication fichier.
|
"""publication fichier.
|
||||||
(on ne doit rien avoir émis avant, car ici sont générés les entetes)
|
(on ne doit rien avoir émis avant, car ici sont générés les entetes)
|
||||||
"""
|
"""
|
||||||
@ -527,14 +526,6 @@ def sendCSVFile(REQUEST, data, filename):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def flaskPDFResponse(data, filename, mime=PDF_MIMETYPE):
|
|
||||||
filename = make_filename(filename)
|
|
||||||
response = make_response(data)
|
|
||||||
response.headers['Content-Type'] = mime
|
|
||||||
response.headers['Content-Disposition'] = 'attachment; filename="%s"' % filename
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
def sendPDFFile(REQUEST, data, filename):
|
def sendPDFFile(REQUEST, data, filename):
|
||||||
filename = (
|
filename = (
|
||||||
unescape_html(suppress_accents(filename)).replace("&", "").replace(" ", "_")
|
unescape_html(suppress_accents(filename)).replace("&", "").replace(" ", "_")
|
||||||
@ -559,19 +550,16 @@ class ScoDocJSONEncoder(json.JSONEncoder):
|
|||||||
|
|
||||||
def sendJSON(REQUEST, data):
|
def sendJSON(REQUEST, data):
|
||||||
js = json.dumps(data, indent=1, cls=ScoDocJSONEncoder)
|
js = json.dumps(data, indent=1, cls=ScoDocJSONEncoder)
|
||||||
if REQUEST:
|
return send_file(js, filename="sco_data.json", mime=JSON_MIMETYPE, attached=False)
|
||||||
REQUEST.RESPONSE.setHeader("content-type", JSON_MIMETYPE)
|
|
||||||
return js
|
|
||||||
|
|
||||||
|
|
||||||
def sendXML(REQUEST, data, tagname=None, force_outer_xml_tag=True):
|
def sendXML(REQUEST, data, tagname=None, force_outer_xml_tag=True):
|
||||||
if type(data) != list:
|
if type(data) != list:
|
||||||
data = [data] # always list-of-dicts
|
data = [data] # always list-of-dicts
|
||||||
if force_outer_xml_tag:
|
if force_outer_xml_tag:
|
||||||
root_tagname = tagname + "_list"
|
data = [{tagname: data}]
|
||||||
data = [{root_tagname: data}]
|
tagname += "_list"
|
||||||
doc = sco_xml.simple_dictlist2xml(data, tagname=tagname)
|
doc = sco_xml.simple_dictlist2xml(data, tagname=tagname)
|
||||||
|
|
||||||
if REQUEST:
|
if REQUEST:
|
||||||
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
REQUEST.RESPONSE.setHeader("content-type", XML_MIMETYPE)
|
||||||
return doc
|
return doc
|
||||||
@ -590,6 +578,18 @@ def sendResult(REQUEST, data, name=None, format=None, force_outer_xml_tag=True):
|
|||||||
raise ValueError("invalid format: %s" % format)
|
raise ValueError("invalid format: %s" % format)
|
||||||
|
|
||||||
|
|
||||||
|
def send_file(data, filename, suffix="", mime=None, attached=True):
|
||||||
|
"Build Flask Response for file download of given type"
|
||||||
|
if suffix:
|
||||||
|
filename += suffix
|
||||||
|
filename = make_filename(filename)
|
||||||
|
response = make_response(data)
|
||||||
|
response.headers["Content-Type"] = mime
|
||||||
|
if attached:
|
||||||
|
response.headers["Content-Disposition"] = 'attachment; filename="%s"' % filename
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
def get_scodoc_version():
|
def get_scodoc_version():
|
||||||
"return a string identifying ScoDoc version"
|
"return a string identifying ScoDoc version"
|
||||||
return sco_version.SCOVERSION
|
return sco_version.SCOVERSION
|
||||||
|
Loading…
Reference in New Issue
Block a user