From 3576847fb8672b4745c46a433c27755623fc88e5 Mon Sep 17 00:00:00 2001 From: Place Jean-Marie Date: Sat, 6 Nov 2021 16:04:20 +0100 Subject: [PATCH] avant tests --- app/pe/pe_tools.py | 2 +- app/scodoc/sco_bulletins_pdf.py | 1 - app/scodoc/sco_logos.py | 61 ++++++++---------- app/scodoc/sco_pdf.py | 6 +- app/scodoc/sco_pvpdf.py | 63 +++++++++---------- app/templates/configuration.html | 4 +- app/views/scodoc.py | 104 ++++++++++++++++++++++++------- 7 files changed, 138 insertions(+), 103 deletions(-) diff --git a/app/pe/pe_tools.py b/app/pe/pe_tools.py index 3ab92452..99adbedd 100644 --- a/app/pe/pe_tools.py +++ b/app/pe/pe_tools.py @@ -202,7 +202,7 @@ def add_pe_stuff_to_zip(zipfile, ziproot): add_local_file_to_zip(zipfile, ziproot, pathname, "avis/" + filename) # Logos: (add to logos/ directory in zip) - logos_names = ["logo_header.jpg", "logo_footer.jpg"] + logos_names = ["header", "footer"] for name in logos_names: logo = find_logo(logoname=name, dept_id=g.scodoc_dept_id) if logo is not None: diff --git a/app/scodoc/sco_bulletins_pdf.py b/app/scodoc/sco_bulletins_pdf.py index 885b5a53..e2660545 100644 --- a/app/scodoc/sco_bulletins_pdf.py +++ b/app/scodoc/sco_bulletins_pdf.py @@ -142,7 +142,6 @@ def process_field(field, cdict, style, suppress_empty_pars=False, format="pdf"): return text # --- PDF format: # handle logos: - breakpoint() # la protection contre des noms malveillants est assuré par l'utilisation de secure_filename dans la classe Logo text = re.sub( r"<(\s*)logo(.*?)src\s*=\s*(.*?)>", r"<\1logo\2\3>", text diff --git a/app/scodoc/sco_logos.py b/app/scodoc/sco_logos.py index 73edabb6..6ad2ec9b 100644 --- a/app/scodoc/sco_logos.py +++ b/app/scodoc/sco_logos.py @@ -48,44 +48,27 @@ from PIL import Image as PILImage GLOBAL = "_SERVER" # category for server level logos -def find_logo( - logoname, dept_id=None, global_if_not_found=True, prefix=scu.LOGO_FILE_PREFIX -): +def find_logo(logoname, dept_id=None, strict=False, prefix=scu.LOGO_FILE_PREFIX): """ "Recherche un logo 'name' existant. Deux strategies: - si global_if_not_found: - On recherche en local au dept d'abord puis si pas trouvé recherche globale - sinon + si strict: reherche uniquement dans le département puis si non trouvé au niveau global + sinon + On recherche en local au dept d'abord puis si pas trouvé recherche globale quelquesoit la stratégie, retourne None si pas trouvé :param logoname: le nom recherche :param dept_id: l'id du département dans lequel se fait la recherche (None si global) - :param global_if_not_found: stratégie de recherche + :param strict: stratégie de recherche (strict = False => dept ou global) :param prefix: le prefix utilisé (parmi scu.LOGO_FILE_PREFIX / scu.BACKGROUND_FILE_PREFIX) :return: un objet Logo désignant le fichier image trouvé (ou None) """ - try: - logo = Logo(logoname, dept_id, prefix).read() - except ScoValueError: - logo = None - if logo is None and global_if_not_found: - try: - logo = Logo(logoname=logoname, dept_id=None), prefix.read() - except ScoValueError: - logo = None + logo = Logo(logoname, dept_id, prefix).select() + if logo is None and not strict: + logo = Logo(logoname=logoname, dept_id=None, prefix=prefix).select() return logo -def get_logo_filename(name, dept_id=None): - breakpoint() - return find_logo(name, dept_id).read().filepath - - -def get_logo_url(name, dept_id): - return find_logo(name, dept_id).read().get_url() - - def write_logo(stream, name, dept_id=None): Logo(logoname=name, dept_id=dept_id).create(stream) @@ -117,7 +100,7 @@ def _list_dept_logos(dept_id=None, prefix=scu.LOGO_FILE_PREFIX): result = filename_parser.match(entry.name) if result: logoname = result.group(1) - logos[logoname] = Logo(logoname=logoname, dept_id=dept_id).read() + logos[logoname] = Logo(logoname=logoname, dept_id=dept_id).select() return logos if len(logos.keys()) > 0 else None @@ -156,7 +139,7 @@ class Logo: self.filepath = None self.filename = None - def set_format(self, fmt): + def _set_format(self, fmt): self.suffix = fmt self.filepath = self.basepath + "." + fmt self.filename = self.logoname + "." + fmt @@ -171,7 +154,7 @@ class Logo: img_type = guess_image_type(stream) if img_type not in scu.LOGOS_IMAGES_ALLOWED_TYPES: abort(400, "type d'image invalide") - self.set_format(img_type) + self._set_format(img_type) self._ensure_directory_exists() filename = self.basepath + "." + self.suffix with open(filename, "wb") as f: @@ -184,7 +167,7 @@ class Logo: except IOError: pass - def read(self): + def select(self): """ Récupération des données pour un logo existant (sinon -> Exception) il doit exister un et un seul fichier image parmi les types autorisés @@ -194,19 +177,27 @@ class Logo: for suffix in scu.LOGOS_IMAGES_ALLOWED_TYPES: path = Path(self.basepath + "." + suffix) if path.exists(): - self.set_format(suffix) + self._set_format(suffix) with open(self.filepath, "rb") as f: img = PILImage.open(f) self.dimensions = img.size return self - # if no file found, raise exception - raise ScoValueError( - "Logo %s not found for dept %s" % (self.logoname, self.scodoc_dept_id) - ) + return None def get_url(self): return url_for( - "scodoc.logo_custom", scodoc_dept=self.scodoc_dept_id, name=self.logoname + "scodoc.get_logo", + scodoc_dept=self.scodoc_dept_id, + name=self.logoname, + global_if_not_found=False, + ) + + def get_url_small(self): + return url_for( + "scodoc.get_logo_small", + scodoc_dept=self.scodoc_dept_id, + name=self.logoname, + global_if_not_found=False, ) diff --git a/app/scodoc/sco_pdf.py b/app/scodoc/sco_pdf.py index 9b0a0b09..54ed29b2 100755 --- a/app/scodoc/sco_pdf.py +++ b/app/scodoc/sco_pdf.py @@ -61,11 +61,7 @@ from flask import g import app.scodoc.sco_utils as scu from app.scodoc.sco_logos import find_logo -from app.scodoc.sco_utils import ( - CONFIG, - SCODOC_LOGOS_DIR, - LOGOS_IMAGES_ALLOWED_TYPES, -) +from app.scodoc.sco_utils import CONFIG from app import log from app.scodoc.sco_exceptions import ScoGenError, ScoValueError import sco_version diff --git a/app/scodoc/sco_pvpdf.py b/app/scodoc/sco_pvpdf.py index ce9cc583..b8664c51 100644 --- a/app/scodoc/sco_pvpdf.py +++ b/app/scodoc/sco_pvpdf.py @@ -202,43 +202,36 @@ class CourrierIndividuelTemplate(PageTemplate): self.logo_footer = None self.logo_header = None # Search logos in dept specific dir, then in global scu.CONFIG dir - for image_dir in ( - scu.SCODOC_LOGOS_DIR + "/logos_" + g.scodoc_dept, - scu.SCODOC_LOGOS_DIR, # global logos - ): - for suffix in scu.LOGOS_IMAGES_ALLOWED_TYPES: - if template_name == "PVJuryTemplate": - background = find_logo( - logoname="pvjury_background", - dept_id=g.scodoc_dept_id, - prefix="", - global_if_not_found=True, - ) - else: - background = find_logo( - logoname="letter_background", - dept_id=g.scodoc_dept_id, - prefix="", - global_if_not_found=True, - ) - if not self.background_image_filename and background is not None: - self.background_image_filename = background.filepath + if template_name == "PVJuryTemplate": + background = find_logo( + logoname="pvjury_background", + dept_id=g.scodoc_dept_id, + prefix="", + ) + else: + background = find_logo( + logoname="letter_background", + dept_id=g.scodoc_dept_id, + prefix="", + ) + if not self.background_image_filename and background is not None: + self.background_image_filename = background.filepath - footer = find_logo(logoname="footer", dept_id=g.scodoc_dept_id) - if footer is not None: - self.logo_footer = Image( - footer.filepath, - height=LOGO_FOOTER_HEIGHT, - width=LOGO_FOOTER_WIDTH, - ) + footer = find_logo(logoname="footer", dept_id=g.scodoc_dept_id) + if footer is not None: + self.logo_footer = Image( + footer.filepath, + height=LOGO_FOOTER_HEIGHT, + width=LOGO_FOOTER_WIDTH, + ) - header = find_logo(logoname="header", dept_id=g.scodoc_dept_id) - if header is not None: - self.logo_header = Image( - header.filepath, - height=LOGO_HEADER_HEIGHT, - width=LOGO_HEADER_WIDTH, - ) + header = find_logo(logoname="header", dept_id=g.scodoc_dept_id) + if header is not None: + self.logo_header = Image( + header.filepath, + height=LOGO_HEADER_HEIGHT, + width=LOGO_HEADER_WIDTH, + ) def beforeDrawPage(self, canvas, doc): """Draws a logo and an contribution message on each page.""" diff --git a/app/templates/configuration.html b/app/templates/configuration.html index 6dcf1c51..c4099c75 100644 --- a/app/templates/configuration.html +++ b/app/templates/configuration.html @@ -36,12 +36,12 @@ diff --git a/app/views/scodoc.py b/app/views/scodoc.py index 1722aca2..4de2baa4 100644 --- a/app/views/scodoc.py +++ b/app/views/scodoc.py @@ -30,6 +30,8 @@ Module main: page d'accueil, avec liste des départements Emmanuel Viennet, 2021 """ +import io + from app.auth.models import User import os @@ -38,7 +40,7 @@ from flask import abort, flash, url_for, redirect, render_template, send_file from flask import request from flask.app import Flask import flask_login -from flask_login.utils import login_required +from flask_login.utils import login_required, current_user from flask_wtf import FlaskForm from flask_wtf.file import FileField, FileAllowed from werkzeug.exceptions import BadRequest, NotFound @@ -61,10 +63,14 @@ from app.decorators import ( scodoc, permission_required_compat_scodoc7, ) +from app.scodoc.imageresize import ImageScale from app.scodoc.sco_exceptions import AccessDenied +from app.scodoc.sco_logos import Logo from app.scodoc.sco_permissions import Permission from app.views import scodoc_bp as bp +from PIL import Image as PILImage + @bp.route("/") @bp.route("/ScoDoc") @@ -240,13 +246,9 @@ def configuration(): if form.validate_on_submit(): ScoDocSiteConfig.set_bonus_sport_func(form.bonus_sport_func_name.data) if form.logo_header.data: - sco_logos.store_image( - form.logo_header.data, os.path.join(scu.SCODOC_LOGOS_DIR, "logo_header") - ) + sco_logos.write_logo(stream=form.logo_header.data, name="header") if form.logo_footer.data: - sco_logos.store_image( - form.logo_footer.data, os.path.join(scu.SCODOC_LOGOS_DIR, "logo_footer") - ) + sco_logos.write_logo(stream=form.logo_footer.data, name="footer") app.clear_scodoc_cache() flash(f"Configuration enregistrée") return redirect(url_for("scodoc.index")) @@ -259,29 +261,83 @@ def configuration(): ) -def _return_logo(logo_type="header", scodoc_dept=""): +SMALL_SIZE = (300, 300) + + +def _return_logo( + name="header", dept_id="", small=False, global_if_not_found: bool = True +): # stockée dans /opt/scodoc-data/config/logos donc servie manuellement ici - filename = sco_logos.get_logo_filename(logo_type, scodoc_dept) - if filename: - extension = os.path.splitext(filename)[1] - return send_file(filename, mimetype=f"image/{extension}") + # génération d'une url + # url = url_for( + # "scodoc.get_logo_small", + # name=name, + # dept_id=dept_id, + # global_if_not_found=global_if_not_found, + # ) + logo = sco_logos.find_logo(name, dept_id, global_if_not_found) + if logo is not None: + suffix = logo.suffix + if small: + with PILImage.open(logo.filepath) as im: + im.thumbnail(SMALL_SIZE) + stream = io.BytesIO() + # on garde le même format (on pourrait plus simplement générer systématiquement du JPEG) + fmt = { # adapt suffix to be compliant with PIL save format + "PNG": "PNG", + "JPG": "JPEG", + "JPEG": "JPEG", + }[suffix.upper()] + im.save(stream, fmt) + stream.seek(0) + return send_file(stream, mimetype=f"image/{fmt}") + else: + return send_file(logo.filepath, mimetype=f"image/{suffix}") else: - return "" + abort(404) -@bp.route("/ScoDoc/logo_header") -@bp.route("/ScoDoc//logo_header") -def logo_header(scodoc_dept=""): - "Image logo header" - # "/opt/scodoc-data/config/logos/logo_header") - return _return_logo(logo_type="header", scodoc_dept=scodoc_dept) +# small version (copy/paste from get_logo +@bp.route("/ScoDoc/logos//small", defaults={"dept_id": None}) +@bp.route("/ScoDoc//logos//small") +@admin_required +def get_logo_small(name: str, dept_id: int): + global_if_not_found = request.args.get("global_if_not_found", "True") + return _return_logo( + name, + dept_id=dept_id, + small=True, + global_if_not_found=global_if_not_found.upper() not in ["0", "FALSE"], + ) -@bp.route("/ScoDoc/logo_footer") -@bp.route("/ScoDoc//logo_footer") -def logo_footer(scodoc_dept=""): - "Image logo footer" - return _return_logo(logo_type="footer", scodoc_dept=scodoc_dept) +@bp.route( + "/ScoDoc/logos/", defaults={"dept_id": None} +) # if dept not specified, take global logo +@bp.route("/ScoDoc//logos/") +@admin_required +def get_logo(name: str, dept_id: int): + global_if_not_found = request.args.get("global_if_not_found", "True") + return _return_logo( + name, + dept_id=dept_id, + small=False, + global_if_not_found=global_if_not_found.upper() not in ["0", "FALSE"], + ) + + +# @bp.route("/ScoDoc/logo_header") +# @bp.route("/ScoDoc//logo_header") +# def logo_header(scodoc_dept=""): +# "Image logo header" +# return _return_logo(name="header", scodoc_dept=scodoc_dept) + + +# @bp.route("/ScoDoc/logo_footer") +# @bp.route("/ScoDoc//logo_footer") +# def logo_footer(scodoc_dept=""): +# "Image logo footer" +# return _return_logo(name="footer", scodoc_dept=scodoc_dept) # essais