build logo form (header & footer)

This commit is contained in:
Jean-Marie Place 2021-11-16 18:48:56 +01:00
parent d8091b4efb
commit 483c22678a
6 changed files with 175 additions and 72 deletions

View File

@ -160,7 +160,7 @@ class Logo:
"Not inited: call the select or create function before access" "Not inited: call the select or create function before access"
) )
self.density = "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): def _set_format(self, fmt):
self.suffix = fmt self.suffix = fmt
@ -199,21 +199,21 @@ class Logo:
unit = 1 unit = 1
if self.density is None: # no dpi found try jfif infos if self.density is None: # no dpi found try jfif infos
self.density = img.info.get("jfif_density", None) 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: if self.density is not None:
x_density, y_density = self.density x_density, y_density = self.density
if unit != 0: if unit != 0:
unit2cm = [0, 1 / 2.54, 1][unit] unit2mm = [0, 1 / 0.254, 0.1][unit]
x_cm = round(x_size * unit2cm / x_density, 2) x_mm = round(x_size * unit2mm / x_density, 2)
y_cm = round(y_size * unit2cm / y_density, 2) y_mm = round(y_size * unit2mm / y_density, 2)
self.cm = (x_cm, y_cm) self.mm = (x_mm, y_mm)
else: else:
self.cm = None self.mm = None
else: else:
self.cm = None self.mm = None
self.size = (x_size, y_size) 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): def select(self):
""" """
@ -250,6 +250,12 @@ class Logo:
global_if_not_found=False, global_if_not_found=False,
) )
def get_usage(self):
if self.mm is None:
return f'<logo name="{self.logoname}" width="?? mm" height="?? mm">'
else:
return f'<logo name="{self.logoname}" width="{self.mm[0]}mm" height="{self.mm[1]}mm">'
def guess_image_type(stream) -> str: def guess_image_type(stream) -> str:
"guess image type from header in stream" "guess image type from header in stream"

View File

@ -16,38 +16,66 @@
</div> </div>
{% endmacro %} {% endmacro %}
{% macro render_logo(logo_form, titre=None) %}
{% if titre %}
<tr>
<td colspan="2">
<h3>{{ titre }}</h3>
</td>
</tr>
{% endif %}
<tr>
<td style="padding-right: 20px">
<p class="help">{{ logo_form.form.description }} Image actuelle:</p>
<div class="img-container"><img src="{{ logo_form.logo.get_url_small() }}"
alt="pas de logo chargé" /></div>
</td>
<td>
Nom: {{ logo_form.form.logo.logoname }}<br/>
{{ logo_form.form.description }}<br/>
Format: {{ logo_form.logo.suffix }}<br/>
Taille en px: {{ logo_form.logo.size }}<br/>
{% if logo_form.logo.mm %}
Taile en mm: {{ logo_form.logo.mm }}<br/>
{% endif %}
Aspect ratio: {{ logo_form.logo.aspect_ratio }}<br/>
Usage: {{ logo_form.logo.get_usage() }}
<span class="wtf-field">{{ logo_form.action()|safe }}</span>
<span class="wtf-field">{{ render_field(logo_form.upload) }}</span>
{% if logo_form.can_delete %}
{{ render_field(logo_form.do_delete) }}
{% endif %}
</td>
</tr>
{% endmacro %}
{% block app_content %} {% block app_content %}
{% if scodoc_dept %} {% if scodoc_dept %}
<h1>Logos du département {{ scodoc_dept }}</h1> <h1>Logos du département {{ scodoc_dept }}</h1>
{% else %} {% else %}
<h1>Configuration générale {{ scodoc_dept }}</h1> <h1>Configuration générale</h1>
{% endif %} {% endif %}
<form class="sco-form" action="" method="post" enctype="multipart/form-data" novalidate> <form class="sco-form" action="" method="post" enctype="multipart/form-data" novalidate>
{{ form.hidden_tag() }} {{ form.hidden_tag() }}
{% if not scodoc_dept %} {% if not scodoc_dept %}
<div class="sco_help">Les paramètres donnés ici s'appliquent à tout ScoDoc (tous les départements):</div> <div class="sco_help">Les paramètres donnés ici s'appliquent à tout ScoDoc (tous les départements):</div>
{{ render_field(form.bonus_sport_func_name)}}
{{ render_field(form.bonus_sport_func_name)}} <div class="configuration_logo">
<table>
{{ form.footer.form.breakpoint(form) }}
{{ render_logo(form.header, 'Logo en-tête') }}
{{ render_logo(form.footer, 'Logo pied de page') }}
</table>
</div>
{% endif %} {% endif %}
<div class="configuration_logo">
<h3>Logo en-tête</h3>
<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.get_logo_small', name="header") }}"
alt="pas de logo chargé" /></div>
{{ render_field(form.logo_header) }}
<h3>Logo pied de page</h3>
<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.get_logo_small', name="footer") }}"
alt="pas de logo chargé" /></div>
{{ render_field(form.logo_footer) }}
</div>
<!-- <div class="sco_help">Les paramètres ci-dessous peuvent être changés dans chaque département <!-- <div class="sco_help">Les paramètres ci-dessous peuvent être changés dans chaque département
(paramétrage).<br />On indique ici les valeurs initiales par défaut: (paramétrage).<br />On indique ici les valeurs initiales par défaut:
</div> --> </div> -->
<div class="sco-submit">{{ form.submit() }}</div> <div class="sco-submit">{{ form.submit() }}</div>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -32,6 +32,8 @@ Emmanuel Viennet, 2021
""" """
import io import io
import wtforms.validators
from app.auth.models import User from app.auth.models import User
import os import os
@ -44,9 +46,9 @@ 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
from wtforms import SelectField, SubmitField from wtforms import SelectField, SubmitField, FormField, validators, Form
from wtforms.fields import IntegerField 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 from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
import app import app
@ -64,6 +66,7 @@ from app.decorators import (
permission_required_compat_scodoc7, permission_required_compat_scodoc7,
) )
from app.scodoc.sco_exceptions import AccessDenied from app.scodoc.sco_exceptions import AccessDenied
from app.scodoc.sco_logos import find_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
@ -178,6 +181,34 @@ def about(scodoc_dept=None):
# ---- CONFIGURATION # ---- 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): class ScoDocConfigurationForm(FlaskForm):
"Panneau de configuration général" "Panneau de configuration général"
@ -188,31 +219,24 @@ class ScoDocConfigurationForm(FlaskForm):
for x in ScoDocSiteConfig.get_bonus_sport_func_names() for x in ScoDocSiteConfig.get_bonus_sport_func_names()
], ],
) )
header = FormField(LogoForm)
logo_header = FileField( footer = FormField(LogoForm)
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 <tt>{','.join([e for e in scu.LOGOS_IMAGES_ALLOWED_TYPES])}</tt>",
)
],
)
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 <tt>{','.join([e for e in scu.LOGOS_IMAGES_ALLOWED_TYPES])}</tt>",
)
],
)
submit = SubmitField("Enregistrer") 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) # Notes pour variables config: (valeurs par défaut des paramètres de département)
# Chaines simples # Chaines simples
@ -241,10 +265,10 @@ 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.header.data:
sco_logos.write_logo(stream=form.logo_header.data, name="header") sco_logos.write_logo(stream=form.header.data, name="header")
if form.logo_footer.data: if form.footer.data:
sco_logos.write_logo(stream=form.logo_footer.data, name="footer") sco_logos.write_logo(stream=form.footer.data, name="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"))
@ -313,20 +337,6 @@ def get_logo(name: str, dept_id: int):
) )
# @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
# @bp.route("/testlog") # @bp.route("/testlog")
# def testlog(): # def testlog():

View File

@ -39,7 +39,7 @@ from flask import current_app, g, request
from flask_login import current_user from flask_login import 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 wtforms import SubmitField, FormField from wtforms import SubmitField
from app.decorators import ( from app.decorators import (
scodoc, scodoc,
@ -49,7 +49,6 @@ from app.decorators import (
admin_required, admin_required,
login_required, login_required,
) )
from app.scodoc.sco_logos import find_logo
from app.views import scolar_bp as bp from app.views import scolar_bp as bp
@ -166,6 +165,66 @@ def doc_preferences():
return response 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 <tt>{','.join([e for e in scu.LOGOS_IMAGES_ALLOWED_TYPES])}</tt>",
)
],
)
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 <tt>{','.join([e for e in scu.LOGOS_IMAGES_ALLOWED_TYPES])}</tt>",
)
],
)
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 # ETUDIANTS

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -124,7 +124,7 @@ def test_get_jpg_data(create_dept, create_logos):
assert logo.suffix == "jpg" assert logo.suffix == "jpg"
assert logo.filename == "A.jpg" assert logo.filename == "A.jpg"
assert logo.size == (1200, 600) 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): 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.filename == "D.png"
assert logo.size == (121, 121) assert logo.size == (121, 121)
assert logo.density is None 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): def test_create_globale_jpg_logo(create_dept, create_logos):