From 483c22678aa76257e20e0f4e6871e1c647d7b152 Mon Sep 17 00:00:00 2001 From: Place Jean-Marie Date: Tue, 16 Nov 2021 18:48:56 +0100 Subject: [PATCH] build logo form (header & footer) --- app/scodoc/sco_logos.py | 24 ++++--- app/templates/configuration.html | 60 +++++++++++----- app/views/scodoc.py | 96 ++++++++++++++----------- app/views/scolar.py | 63 +++++++++++++++- tests/ressources/test_logos/logo_D.png | Bin 15701 -> 15640 bytes tests/unit/test_logos.py | 4 +- 6 files changed, 175 insertions(+), 72 deletions(-) diff --git a/app/scodoc/sco_logos.py b/app/scodoc/sco_logos.py index d2814fe6..5808945f 100644 --- a/app/scodoc/sco_logos.py +++ b/app/scodoc/sco_logos.py @@ -160,7 +160,7 @@ class Logo: "Not inited: call the select or create function before access" ) self.density = "Not inited: call the select or create function before access" - self.cm = "Not inited: call the select or create function before access" + self.mm = "Not inited: call the select or create function before access" def _set_format(self, fmt): self.suffix = fmt @@ -199,21 +199,21 @@ class Logo: unit = 1 if self.density is None: # no dpi found try jfif infos self.density = img.info.get("jfif_density", None) - unit = img.info.get("jfif_unit", 0) # 0 = no unit ; 1 = inch ; 2 = cm + unit = img.info.get("jfif_unit", 0) # 0 = no unit ; 1 = inch ; 2 = mm if self.density is not None: x_density, y_density = self.density if unit != 0: - unit2cm = [0, 1 / 2.54, 1][unit] - x_cm = round(x_size * unit2cm / x_density, 2) - y_cm = round(y_size * unit2cm / y_density, 2) - self.cm = (x_cm, y_cm) + unit2mm = [0, 1 / 0.254, 0.1][unit] + x_mm = round(x_size * unit2mm / x_density, 2) + y_mm = round(y_size * unit2mm / y_density, 2) + self.mm = (x_mm, y_mm) else: - self.cm = None + self.mm = None else: - self.cm = None + self.mm = None self.size = (x_size, y_size) - self.aspect_ratio = float(x_size) / y_size + self.aspect_ratio = round(float(x_size) / y_size, 2) def select(self): """ @@ -250,6 +250,12 @@ class Logo: global_if_not_found=False, ) + def get_usage(self): + if self.mm is None: + return f'' + else: + return f'' + def guess_image_type(stream) -> str: "guess image type from header in stream" diff --git a/app/templates/configuration.html b/app/templates/configuration.html index 88f1fd81..077c094d 100644 --- a/app/templates/configuration.html +++ b/app/templates/configuration.html @@ -16,38 +16,66 @@ {% endmacro %} +{% macro render_logo(logo_form, titre=None) %} + {% if titre %} + + +

{{ titre }}

+ + + {% endif %} + + +

{{ logo_form.form.description }} Image actuelle:

+
pas de logo chargé
+ + + Nom: {{ logo_form.form.logo.logoname }}
+ {{ logo_form.form.description }}
+ Format: {{ logo_form.logo.suffix }}
+ Taille en px: {{ logo_form.logo.size }}
+ {% if logo_form.logo.mm %} + Taile en mm: {{ logo_form.logo.mm }}
+ {% endif %} + Aspect ratio: {{ logo_form.logo.aspect_ratio }}
+ Usage: {{ logo_form.logo.get_usage() }} + {{ logo_form.action()|safe }} + {{ render_field(logo_form.upload) }} + {% if logo_form.can_delete %} + {{ render_field(logo_form.do_delete) }} + {% endif %} + + +{% endmacro %} + + {% block app_content %} {% if scodoc_dept %}

Logos du département {{ scodoc_dept }}

{% else %} -

Configuration générale {{ scodoc_dept }}

+

Configuration générale

{% endif %}
{{ form.hidden_tag() }} - {% if not scodoc_dept %}
Les paramètres donnés ici s'appliquent à tout ScoDoc (tous les départements):
- - {{ render_field(form.bonus_sport_func_name)}} + {{ render_field(form.bonus_sport_func_name)}} + {% endif %} - +
{{ form.submit() }}
{% endblock %} \ No newline at end of file diff --git a/app/views/scodoc.py b/app/views/scodoc.py index 0def371c..70433025 100644 --- a/app/views/scodoc.py +++ b/app/views/scodoc.py @@ -32,6 +32,8 @@ Emmanuel Viennet, 2021 """ import io +import wtforms.validators + from app.auth.models import User import os @@ -44,9 +46,9 @@ 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 -from wtforms import SelectField, SubmitField +from wtforms import SelectField, SubmitField, FormField, validators, Form from wtforms.fields import IntegerField -from wtforms.fields.simple import BooleanField, StringField, TextAreaField +from wtforms.fields.simple import BooleanField, StringField, TextAreaField, HiddenField from wtforms.validators import ValidationError, DataRequired, Email, EqualTo import app @@ -64,6 +66,7 @@ from app.decorators import ( permission_required_compat_scodoc7, ) from app.scodoc.sco_exceptions import AccessDenied +from app.scodoc.sco_logos import find_logo from app.scodoc.sco_permissions import Permission from app.views import scodoc_bp as bp @@ -178,6 +181,34 @@ def about(scodoc_dept=None): # ---- CONFIGURATION +class LogoForm(FlaskForm): + action = HiddenField("action") + upload = FileField( + label="Modifier l'image:", + validators=[ + FileAllowed( + scu.LOGOS_IMAGES_ALLOWED_TYPES, + f"n'accepte que les fichiers image {','.join([e for e in scu.LOGOS_IMAGES_ALLOWED_TYPES])}", + ) + ], + ) + do_delete = SubmitField("Supprimer") + + def set_infos(self, logo, description=None, can_delete=None): + self.logo = logo + self.description = description + self.can_delete = can_delete + + def breakpoint(self, form): + breakpoint() + + def __init__(self, *args, **kwargs): + super(LogoForm, self).__init__(*args, **kwargs) + self.logo = None + self.description = None + self.can_delete = None + + class ScoDocConfigurationForm(FlaskForm): "Panneau de configuration général" @@ -188,31 +219,24 @@ class ScoDocConfigurationForm(FlaskForm): for x in ScoDocSiteConfig.get_bonus_sport_func_names() ], ) - - logo_header = FileField( - label="Modifier l'image:", - description="logo placé en haut des documents PDF", - validators=[ - FileAllowed( - scu.LOGOS_IMAGES_ALLOWED_TYPES, - f"n'accepte que les fichiers image {','.join([e for e in scu.LOGOS_IMAGES_ALLOWED_TYPES])}", - ) - ], - ) - - logo_footer = FileField( - label="Modifier l'image:", - description="logo placé en pied des documents PDF", - validators=[ - FileAllowed( - scu.LOGOS_IMAGES_ALLOWED_TYPES, - f"n'accepte que les fichiers image {','.join([e for e in scu.LOGOS_IMAGES_ALLOWED_TYPES])}", - ) - ], - ) - + header = FormField(LogoForm) + footer = FormField(LogoForm) submit = SubmitField("Enregistrer") + def __init__(self, *args, **kwargs): + super(ScoDocConfigurationForm, self).__init__(*args, **kwargs) + breakpoint() + self.header.form.set_infos( + logo=find_logo("header", dept_id=None).select(), + description="image placée en haut de certains documents documents PDF.", + can_delete=False, + ) + self.footer.form.set_infos( + logo=find_logo("footer", dept_id=None).select(), + description="image placée en pied de page de certains documents documents PDF.", + can_delete=False, + ) + # Notes pour variables config: (valeurs par défaut des paramètres de département) # Chaines simples @@ -241,10 +265,10 @@ 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.write_logo(stream=form.logo_header.data, name="header") - if form.logo_footer.data: - sco_logos.write_logo(stream=form.logo_footer.data, name="footer") + if form.header.data: + sco_logos.write_logo(stream=form.header.data, name="header") + if form.footer.data: + sco_logos.write_logo(stream=form.footer.data, name="footer") app.clear_scodoc_cache() flash(f"Configuration enregistrée") return redirect(url_for("scodoc.index")) @@ -313,20 +337,6 @@ def get_logo(name: str, dept_id: int): ) -# @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 # @bp.route("/testlog") # def testlog(): diff --git a/app/views/scolar.py b/app/views/scolar.py index d284b04e..c708495a 100644 --- a/app/views/scolar.py +++ b/app/views/scolar.py @@ -39,7 +39,7 @@ from flask import current_app, g, request from flask_login import current_user from flask_wtf import FlaskForm from flask_wtf.file import FileField, FileAllowed -from wtforms import SubmitField, FormField +from wtforms import SubmitField from app.decorators import ( scodoc, @@ -49,7 +49,6 @@ from app.decorators import ( admin_required, login_required, ) -from app.scodoc.sco_logos import find_logo from app.views import scolar_bp as bp @@ -166,6 +165,66 @@ def doc_preferences(): return response +class DeptLogosConfigurationForm(FlaskForm): + "Panneau de configuration logos dept" + + logo_header = FileField( + label="Modifier l'image:", + description="logo placé en haut des documents PDF", + validators=[ + FileAllowed( + scu.LOGOS_IMAGES_ALLOWED_TYPES, + f"n'accepte que les fichiers image {','.join([e for e in scu.LOGOS_IMAGES_ALLOWED_TYPES])}", + ) + ], + ) + + logo_footer = FileField( + label="Modifier l'image:", + description="logo placé en pied des documents PDF", + validators=[ + FileAllowed( + scu.LOGOS_IMAGES_ALLOWED_TYPES, + f"n'accepte que les fichiers image {','.join([e for e in scu.LOGOS_IMAGES_ALLOWED_TYPES])}", + ) + ], + ) + + submit = SubmitField("Enregistrer") + + +@bp.route("/config_logos", methods=["GET", "POST"]) +@permission_required(Permission.ScoChangePreferences) +def config_logos(scodoc_dept): + "Panneau de configuration général" + form = DeptLogosConfigurationForm() + if form.validate_on_submit(): + if form.logo_header.data: + sco_logos.store_image( + form.logo_header.data, + os.path.join( + scu.SCODOC_LOGOS_DIR, "logos_" + scodoc_dept, "logo_header" + ), + ) + if form.logo_footer.data: + sco_logos.store_image( + form.logo_footer.data, + os.path.join( + scu.SCODOC_LOGOS_DIR, "logos_" + scodoc_dept, "logo_footer" + ), + ) + app.clear_scodoc_cache() + flash(f"Logos enregistrés") + return flask.redirect(url_for("scolar.index_html", scodoc_dept=scodoc_dept)) + + return render_template( + "configuration.html", + title="Configuration Logos du département", + form=form, + scodoc_dept=scodoc_dept, + ) + + # -------------------------------------------------------------------- # # ETUDIANTS diff --git a/tests/ressources/test_logos/logo_D.png b/tests/ressources/test_logos/logo_D.png index 7ac56e1681c3657043bf9dcbcaed5d8295fa745b..8239e535ca8f59df405f5064192135893a3b8669 100644 GIT binary patch delta 377 zcmV-<0fzq7dYF0&iBL{Q3K|Lk005B;?*_CZ7;kQhlLG<6lg9yH8hX>c9jJkjF+~H) z8i?v_KUbS${eC|-sw{1@Ljno`lTHJ!v;6~?0kf3_Jpq%`2Ga$yg%-#Zv#kgA0h6Q& z;S*K~kl4#%Pf{Z-XHnH)B9T4L_LG_l9kaL!HvzNo3&aDnwGS);lj0GivxgE_0<+%~ zzygz?7sZoi7-o~r7&(&%8N9Q^8QcN|KYvyOT$869bCVk#>$3+Qv;nic9}ohQ%^@U{ z@*z@_MIxS)8Ld5~$66MOc*hJS?ZP zAtqA+lXWMTlMN_LlUgY2vqmZ20h1*wP_uR`Dg(2jE?fhX{xP$&vNDGP6oJN;8dj)n z!^&#weFkKG0|HWLAps5d;5?Saqv<;Vlj=NcMsl1` delta 436 zcmbPHb+wA8Gr-TCmrII^fq{W{BG-Ek-Yv=!`FUNu6aOD(g4in zwr1jD1oB;(*D>;L{>(fb$l2V*Y6}uO&UTrdcT=m_2@&4S^Vz?Fgr;&n6y*)$oN(iG zqJNOGZhGL=1f_|#=f3ey?&OjM>RiTU4l>{__Yr0wwUA$j38?9;;1VFGP$(S8*?dCe z07$Gu{3ww0l}H1Unfzmw6`5;x*DhVLh-c|*<>4$1Ch~uq39Y{V>_W_c6 z8XzMjHSd8WzH0>lIquq8ASV~<#Q>?vXAL(4ISoebOk%u^$EHbzt;jumD(iJEXZjlR zwstui-p$gc28^P--Tuc{mj4SEJ7{+!{Vwad7grx>@@|eZ69$=EXl?@}*P6cslG7{} Z0!eert3XqEtQG>L7q7JjDOzij4FEB>iR%CW diff --git a/tests/unit/test_logos.py b/tests/unit/test_logos.py index 8cf2e275..1ed62a49 100644 --- a/tests/unit/test_logos.py +++ b/tests/unit/test_logos.py @@ -124,7 +124,7 @@ def test_get_jpg_data(create_dept, create_logos): assert logo.suffix == "jpg" assert logo.filename == "A.jpg" assert logo.size == (1200, 600) - assert logo.cm == approx((4.0, 3.0), 0.01) + assert logo.mm == approx((40, 30), 0.1) def test_get_png_without_data(create_dept, create_logos): @@ -136,7 +136,7 @@ def test_get_png_without_data(create_dept, create_logos): assert logo.filename == "D.png" assert logo.size == (121, 121) assert logo.density is None - assert logo.cm is None + assert logo.mm is None def test_create_globale_jpg_logo(create_dept, create_logos):