forked from ScoDoc/DocScoDoc
build logo form (header & footer)
This commit is contained in:
parent
d8091b4efb
commit
483c22678a
@ -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"
|
||||||
|
@ -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 %}
|
@ -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():
|
||||||
|
@ -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 |
@ -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):
|
||||||
|
Loading…
Reference in New Issue
Block a user