avant tests

This commit is contained in:
Jean-Marie Place 2021-11-06 16:04:20 +01:00
parent 0d0ba5ae60
commit 3576847fb8
7 changed files with 138 additions and 103 deletions

View File

@ -202,7 +202,7 @@ def add_pe_stuff_to_zip(zipfile, ziproot):
add_local_file_to_zip(zipfile, ziproot, pathname, "avis/" + filename) add_local_file_to_zip(zipfile, ziproot, pathname, "avis/" + filename)
# Logos: (add to logos/ directory in zip) # Logos: (add to logos/ directory in zip)
logos_names = ["logo_header.jpg", "logo_footer.jpg"] logos_names = ["header", "footer"]
for name in logos_names: for name in logos_names:
logo = find_logo(logoname=name, dept_id=g.scodoc_dept_id) logo = find_logo(logoname=name, dept_id=g.scodoc_dept_id)
if logo is not None: if logo is not None:

View File

@ -142,7 +142,6 @@ def process_field(field, cdict, style, suppress_empty_pars=False, format="pdf"):
return text return text
# --- PDF format: # --- PDF format:
# handle logos: # handle logos:
breakpoint()
# la protection contre des noms malveillants est assuré par l'utilisation de secure_filename dans la classe Logo # la protection contre des noms malveillants est assuré par l'utilisation de secure_filename dans la classe Logo
text = re.sub( text = re.sub(
r"<(\s*)logo(.*?)src\s*=\s*(.*?)>", r"<\1logo\2\3>", text r"<(\s*)logo(.*?)src\s*=\s*(.*?)>", r"<\1logo\2\3>", text

View File

@ -48,44 +48,27 @@ from PIL import Image as PILImage
GLOBAL = "_SERVER" # category for server level logos GLOBAL = "_SERVER" # category for server level logos
def find_logo( def find_logo(logoname, dept_id=None, strict=False, prefix=scu.LOGO_FILE_PREFIX):
logoname, dept_id=None, global_if_not_found=True, prefix=scu.LOGO_FILE_PREFIX
):
""" """
"Recherche un logo 'name' existant. "Recherche un logo 'name' existant.
Deux strategies: Deux strategies:
si global_if_not_found: si strict:
On recherche en local au dept d'abord puis si pas trouvé recherche globale
sinon
reherche uniquement dans le département puis si non trouvé au niveau global 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é quelquesoit la stratégie, retourne None si pas trouvé
:param logoname: le nom recherche :param logoname: le nom recherche
:param dept_id: l'id du département dans lequel se fait la recherche (None si global) :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) :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) :return: un objet Logo désignant le fichier image trouvé (ou None)
""" """
try: logo = Logo(logoname, dept_id, prefix).select()
logo = Logo(logoname, dept_id, prefix).read() if logo is None and not strict:
except ScoValueError: logo = Logo(logoname=logoname, dept_id=None, prefix=prefix).select()
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
return logo 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): def write_logo(stream, name, dept_id=None):
Logo(logoname=name, dept_id=dept_id).create(stream) 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) result = filename_parser.match(entry.name)
if result: if result:
logoname = result.group(1) 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 return logos if len(logos.keys()) > 0 else None
@ -156,7 +139,7 @@ class Logo:
self.filepath = None self.filepath = None
self.filename = None self.filename = None
def set_format(self, fmt): def _set_format(self, fmt):
self.suffix = fmt self.suffix = fmt
self.filepath = self.basepath + "." + fmt self.filepath = self.basepath + "." + fmt
self.filename = self.logoname + "." + fmt self.filename = self.logoname + "." + fmt
@ -171,7 +154,7 @@ class Logo:
img_type = guess_image_type(stream) img_type = guess_image_type(stream)
if img_type not in scu.LOGOS_IMAGES_ALLOWED_TYPES: if img_type not in scu.LOGOS_IMAGES_ALLOWED_TYPES:
abort(400, "type d'image invalide") abort(400, "type d'image invalide")
self.set_format(img_type) self._set_format(img_type)
self._ensure_directory_exists() self._ensure_directory_exists()
filename = self.basepath + "." + self.suffix filename = self.basepath + "." + self.suffix
with open(filename, "wb") as f: with open(filename, "wb") as f:
@ -184,7 +167,7 @@ class Logo:
except IOError: except IOError:
pass pass
def read(self): def select(self):
""" """
Récupération des données pour un logo existant (sinon -> Exception) 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 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: for suffix in scu.LOGOS_IMAGES_ALLOWED_TYPES:
path = Path(self.basepath + "." + suffix) path = Path(self.basepath + "." + suffix)
if path.exists(): if path.exists():
self.set_format(suffix) self._set_format(suffix)
with open(self.filepath, "rb") as f: with open(self.filepath, "rb") as f:
img = PILImage.open(f) img = PILImage.open(f)
self.dimensions = img.size self.dimensions = img.size
return self return self
# if no file found, raise exception return None
raise ScoValueError(
"Logo %s not found for dept %s" % (self.logoname, self.scodoc_dept_id)
)
def get_url(self): def get_url(self):
return url_for( 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,
) )

View File

@ -61,11 +61,7 @@ from flask import g
import app.scodoc.sco_utils as scu import app.scodoc.sco_utils as scu
from app.scodoc.sco_logos import find_logo from app.scodoc.sco_logos import find_logo
from app.scodoc.sco_utils import ( from app.scodoc.sco_utils import CONFIG
CONFIG,
SCODOC_LOGOS_DIR,
LOGOS_IMAGES_ALLOWED_TYPES,
)
from app import log from app import log
from app.scodoc.sco_exceptions import ScoGenError, ScoValueError from app.scodoc.sco_exceptions import ScoGenError, ScoValueError
import sco_version import sco_version

View File

@ -202,43 +202,36 @@ class CourrierIndividuelTemplate(PageTemplate):
self.logo_footer = None self.logo_footer = None
self.logo_header = None self.logo_header = None
# Search logos in dept specific dir, then in global scu.CONFIG dir # Search logos in dept specific dir, then in global scu.CONFIG dir
for image_dir in ( if template_name == "PVJuryTemplate":
scu.SCODOC_LOGOS_DIR + "/logos_" + g.scodoc_dept, background = find_logo(
scu.SCODOC_LOGOS_DIR, # global logos logoname="pvjury_background",
): dept_id=g.scodoc_dept_id,
for suffix in scu.LOGOS_IMAGES_ALLOWED_TYPES: prefix="",
if template_name == "PVJuryTemplate": )
background = find_logo( else:
logoname="pvjury_background", background = find_logo(
dept_id=g.scodoc_dept_id, logoname="letter_background",
prefix="", dept_id=g.scodoc_dept_id,
global_if_not_found=True, prefix="",
) )
else: if not self.background_image_filename and background is not None:
background = find_logo( self.background_image_filename = background.filepath
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
footer = find_logo(logoname="footer", dept_id=g.scodoc_dept_id) footer = find_logo(logoname="footer", dept_id=g.scodoc_dept_id)
if footer is not None: if footer is not None:
self.logo_footer = Image( self.logo_footer = Image(
footer.filepath, footer.filepath,
height=LOGO_FOOTER_HEIGHT, height=LOGO_FOOTER_HEIGHT,
width=LOGO_FOOTER_WIDTH, width=LOGO_FOOTER_WIDTH,
) )
header = find_logo(logoname="header", dept_id=g.scodoc_dept_id) header = find_logo(logoname="header", dept_id=g.scodoc_dept_id)
if header is not None: if header is not None:
self.logo_header = Image( self.logo_header = Image(
header.filepath, header.filepath,
height=LOGO_HEADER_HEIGHT, height=LOGO_HEADER_HEIGHT,
width=LOGO_HEADER_WIDTH, width=LOGO_HEADER_WIDTH,
) )
def beforeDrawPage(self, canvas, doc): def beforeDrawPage(self, canvas, doc):
"""Draws a logo and an contribution message on each page.""" """Draws a logo and an contribution message on each page."""

View File

@ -36,12 +36,12 @@
<div class="configuration_logo"> <div class="configuration_logo">
<h3>Logo en-tête</h3> <h3>Logo en-tête</h3>
<p class="help">image placée en haut de certains documents documents PDF. Image actuelle:</p> <p class="help">image placée en haut de certains documents documents PDF. Image actuelle:</p>
<div class="img-container"><img src="{{ url_for('scodoc.logo_header', scodoc_dept=scodoc_dept) }}" <div class="img-container"><img src="{{ url_for('scodoc.get_logo_global', name="header") }}"
alt="pas de logo chargé" /></div> alt="pas de logo chargé" /></div>
{{ render_field(form.logo_header) }} {{ render_field(form.logo_header) }}
<h3>Logo pied de page</h3> <h3>Logo pied de page</h3>
<p class="help">image placée en pied de page de certains documents documents PDF. Image actuelle:</p> <p class="help">image placée en pied de page de certains documents documents PDF. Image actuelle:</p>
<div class="img-container"><img src="{{ url_for('scodoc.logo_footer', scodoc_dept=g.scodoc_dept) }}" <div class="img-container"><img src="{{ url_for('scodoc.get_logo_global', name="footer") }}"
alt="pas de logo chargé" /></div> alt="pas de logo chargé" /></div>
{{ render_field(form.logo_footer) }} {{ render_field(form.logo_footer) }}
</div> </div>

View File

@ -30,6 +30,8 @@ Module main: page d'accueil, avec liste des départements
Emmanuel Viennet, 2021 Emmanuel Viennet, 2021
""" """
import io
from app.auth.models import User from app.auth.models import User
import os import os
@ -38,7 +40,7 @@ from flask import abort, flash, url_for, redirect, render_template, send_file
from flask import request from flask import request
from flask.app import Flask from flask.app import Flask
import flask_login 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 import FlaskForm
from flask_wtf.file import FileField, FileAllowed from flask_wtf.file import FileField, FileAllowed
from werkzeug.exceptions import BadRequest, NotFound from werkzeug.exceptions import BadRequest, NotFound
@ -61,10 +63,14 @@ from app.decorators import (
scodoc, scodoc,
permission_required_compat_scodoc7, permission_required_compat_scodoc7,
) )
from app.scodoc.imageresize import ImageScale
from app.scodoc.sco_exceptions import AccessDenied from app.scodoc.sco_exceptions import AccessDenied
from app.scodoc.sco_logos import Logo
from app.scodoc.sco_permissions import Permission from app.scodoc.sco_permissions import Permission
from app.views import scodoc_bp as bp from app.views import scodoc_bp as bp
from PIL import Image as PILImage
@bp.route("/") @bp.route("/")
@bp.route("/ScoDoc") @bp.route("/ScoDoc")
@ -240,13 +246,9 @@ def configuration():
if form.validate_on_submit(): if form.validate_on_submit():
ScoDocSiteConfig.set_bonus_sport_func(form.bonus_sport_func_name.data) ScoDocSiteConfig.set_bonus_sport_func(form.bonus_sport_func_name.data)
if form.logo_header.data: if form.logo_header.data:
sco_logos.store_image( sco_logos.write_logo(stream=form.logo_header.data, name="header")
form.logo_header.data, os.path.join(scu.SCODOC_LOGOS_DIR, "logo_header")
)
if form.logo_footer.data: if form.logo_footer.data:
sco_logos.store_image( sco_logos.write_logo(stream=form.logo_footer.data, name="footer")
form.logo_footer.data, os.path.join(scu.SCODOC_LOGOS_DIR, "logo_footer")
)
app.clear_scodoc_cache() app.clear_scodoc_cache()
flash(f"Configuration enregistrée") flash(f"Configuration enregistrée")
return redirect(url_for("scodoc.index")) 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 # stockée dans /opt/scodoc-data/config/logos donc servie manuellement ici
filename = sco_logos.get_logo_filename(logo_type, scodoc_dept) # génération d'une url
if filename: # url = url_for(
extension = os.path.splitext(filename)[1] # "scodoc.get_logo_small",
return send_file(filename, mimetype=f"image/{extension}") # 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: else:
return "" abort(404)
@bp.route("/ScoDoc/logo_header") # small version (copy/paste from get_logo
@bp.route("/ScoDoc/<scodoc_dept>/logo_header") @bp.route("/ScoDoc/logos/<name>/small", defaults={"dept_id": None})
def logo_header(scodoc_dept=""): @bp.route("/ScoDoc/<int:dept_id>/logos/<name>/small")
"Image logo header" @admin_required
# "/opt/scodoc-data/config/logos/logo_header") def get_logo_small(name: str, dept_id: int):
return _return_logo(logo_type="header", scodoc_dept=scodoc_dept) 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(
@bp.route("/ScoDoc/<scodoc_dept>/logo_footer") "/ScoDoc/logos/<name>", defaults={"dept_id": None}
def logo_footer(scodoc_dept=""): ) # if dept not specified, take global logo
"Image logo footer" @bp.route("/ScoDoc/<int:dept_id>/logos/<name>")
return _return_logo(logo_type="footer", scodoc_dept=scodoc_dept) @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/<scodoc_dept>/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/<scodoc_dept>/logo_footer")
# def logo_footer(scodoc_dept=""):
# "Image logo footer"
# return _return_logo(name="footer", scodoc_dept=scodoc_dept)
# essais # essais