Merge pull request 'logo_config' (#367) from jmplace/ScoDoc-Lille:logo_config into dev93

Reviewed-on: #367
This commit is contained in:
Emmanuel Viennet 2022-04-19 18:01:05 +02:00
commit bc6c220f70
5 changed files with 153 additions and 58 deletions

View File

@ -41,11 +41,8 @@ from wtforms.fields.simple import StringField, HiddenField
from app.models import Departement
from app.scodoc import sco_logos, html_sco_header
from app.scodoc import sco_utils as scu
from app.scodoc.sco_config_actions import (
LogoDelete,
LogoUpdate,
LogoInsert,
)
from app.scodoc.sco_config_actions import LogoInsert
from app.scodoc.sco_logos import find_logo
@ -120,6 +117,8 @@ def logo_name_validator(message=None):
class AddLogoForm(FlaskForm):
"""Formulaire permettant l'ajout d'un logo (dans un département)"""
from app.scodoc.sco_config_actions import LogoInsert
dept_key = HiddenField()
name = StringField(
label="Nom",
@ -160,13 +159,13 @@ class AddLogoForm(FlaskForm):
return LogoInsert.build_action(self.data)
return None
def errors(self):
def opened(self):
if self.do_insert.data:
if self.name.errors:
return True
return "open"
if self.upload.errors:
return True
return False
return "open"
return ""
class LogoForm(FlaskForm):
@ -184,7 +183,18 @@ class LogoForm(FlaskForm):
)
],
)
do_delete = SubmitField("Supprimer l'image")
do_delete = SubmitField("Supprimer")
do_rename = SubmitField("Renommer")
new_name = StringField(
label="Nom",
validators=[
logo_name_validator("Nom de logo invalide (alphanumérique, _)"),
validators.Length(
max=20, message="Un nom ne doit pas dépasser 20 caractères"
),
validators.DataRequired("Nom de logo requis (alphanumériques ou '-')"),
],
)
def __init__(self, *args, **kwargs):
kwargs["meta"] = {"csrf": False}
@ -213,16 +223,24 @@ class LogoForm(FlaskForm):
self.titre = "Logo pied de page"
def select_action(self):
from app.scodoc.sco_config_actions import LogoRename
from app.scodoc.sco_config_actions import LogoUpdate
from app.scodoc.sco_config_actions import LogoDelete
if self.do_delete.data and self.can_delete:
return LogoDelete.build_action(self.data)
if self.upload.data and self.validate():
return LogoUpdate.build_action(self.data)
if self.do_rename.data and self.validate():
return LogoRename.build_action(self.data)
return None
def errors(self):
def opened(self):
if self.upload.data and self.upload.errors:
return True
return False
return "open"
if self.new_name.data and self.new_name.errors:
return "open"
return ""
class DeptForm(FlaskForm):
@ -257,13 +275,22 @@ class DeptForm(FlaskForm):
return self
return self.index.get(logoname, None)
def errors(self):
if self.add_logo.errors():
return True
def opened(self):
if self.add_logo.opened():
return "open"
for logo_form in self.logos:
if logo_form.errors():
return True
return False
if logo_form.opened():
return "open"
return ""
def count(self):
compte = len(self.logos.entries)
if compte == 0:
return "vide"
elif compte == 1:
return "1 élément"
else:
return f"{compte} éléments"
def _make_dept_id_name():

View File

@ -28,11 +28,10 @@
"""
"""
from app.models import ScoDocSiteConfig
from app.scodoc.sco_logos import write_logo, find_logo, delete_logo
import app
from flask import current_app
from app.scodoc.sco_logos import find_logo
class Action:
"""Base class for all classes describing an action from from config form."""
@ -42,9 +41,9 @@ class Action:
self.parameters = parameters
@staticmethod
def build_action(parameters, stream=None):
def build_action(parameters):
"""Check (from parameters) if some action has to be done and
then return list of action (or else return empty list)."""
then return list of action (or else return None)."""
raise NotImplementedError
def display(self):
@ -59,6 +58,45 @@ class Action:
GLOBAL = "_"
class LogoRename(Action):
"""Action: rename a logo
dept_id: dept_id or '-'
logo_id: logo_id (old name)
new_name: new_name
"""
def __init__(self, parameters):
super().__init__(
f"Renommage du logo {parameters['logo_id']} en {parameters['new_name']}",
parameters,
)
@staticmethod
def build_action(parameters):
dept_id = parameters["dept_key"]
if dept_id == GLOBAL:
dept_id = None
parameters["dept_id"] = dept_id
if parameters["new_name"]:
logo = find_logo(
logoname=parameters["new_name"],
dept_id=parameters["dept_key"],
strict=True,
)
if logo is None:
return LogoRename(parameters)
def execute(self):
from app.scodoc.sco_logos import rename_logo
current_app.logger.info(self.message)
rename_logo(
old_name=self.parameters["logo_id"],
new_name=self.parameters["new_name"],
dept_id=self.parameters["dept_id"],
)
class LogoUpdate(Action):
"""Action: change a logo
dept_id: dept_id or '_',
@ -83,6 +121,8 @@ class LogoUpdate(Action):
return None
def execute(self):
from app.scodoc.sco_logos import write_logo
current_app.logger.info(self.message)
write_logo(
stream=self.parameters["upload"],
@ -113,6 +153,8 @@ class LogoDelete(Action):
return None
def execute(self):
from app.scodoc.sco_logos import delete_logo
current_app.logger.info(self.message)
delete_logo(name=self.parameters["logo_id"], dept_id=self.parameters["dept_id"])
@ -143,6 +185,8 @@ class LogoInsert(Action):
return None
def execute(self):
from app.scodoc.sco_logos import write_logo
dept_id = self.parameters["dept_key"]
if dept_id == GLOBAL:
dept_id = None

View File

@ -89,6 +89,11 @@ def write_logo(stream, name, dept_id=None):
Logo(logoname=name, dept_id=dept_id).create(stream)
def rename_logo(old_name, new_name, dept_id):
logo = find_logo(old_name, dept_id, True)
logo.rename(new_name)
def list_logos():
"""Crée l'inventaire de tous les logos existants.
L'inventaire se présente comme un dictionnaire de dictionnaire de Logo:
@ -285,6 +290,20 @@ class Logo:
dt = path.stat().st_mtime
return path.stat().st_mtime
def rename(self, new_name):
"""Change le nom (pas le département)
Les éléments non utiles ne sont pas recalculés (car rechargés lors des accès ultérieurs)
"""
old_path = Path(self.filepath)
self.logoname = secure_filename(new_name)
if not self.logoname:
self.logoname = "*** *** nom de logo invalide *** à changer ! *** ***"
else:
new_path = os.path.sep.join(
[self.dirpath, self.prefix + self.logoname + "." + self.suffix]
)
old_path.rename(new_path)
def guess_image_type(stream) -> str:
"guess image type from header in stream"

View File

@ -1055,6 +1055,14 @@ span.wtf-field ul.errors li {
display: list-item !important;
}
.configuration_logo entete_dept {
display: inline-block;
}
.configuration_logo .effectifs {
float: right;
}
.configuration_logo h1 {
display: inline-block;
}

View File

@ -20,28 +20,20 @@
{% endmacro %}
{% macro render_add_logo(add_logo_form) %}
{% if add_logo_form.errors() %}
<details open>
{% else %}
<details>
{% endif %}
<summary>
<h3>Ajouter un logo</h3>
</summary>
<div>
{{ render_field(add_logo_form.name) }}
{{ render_field(add_logo_form.upload) }}
{{ render_field(add_logo_form.do_insert, False, onSubmit="submit_form") }}
</div>
</details>
<details {{ add_logo_form.opened() }}>
<summary>
<h3>Ajouter un logo</h3>
</summary>
<div>
{{ render_field(add_logo_form.name) }}
{{ render_field(add_logo_form.upload) }}
{{ render_field(add_logo_form.do_insert, False, onSubmit="submit_form") }}
</div>
</details>
{% endmacro %}
{% macro render_logo(dept_form, logo_form) %}
{% if logo_form.errors() %}
<details open>
{% else %}
<details>
{% endif %}
<details {{ logo_form.opened() }}>
{{ logo_form.hidden_tag() }}
<summary>
{% if logo_form.titre %}
@ -73,6 +65,11 @@
<span class="wtf-field">{{ render_field(logo_form.upload, False, onchange="submit_form()") }}</span>
</div>
{% if logo_form.can_delete %}
<div class="action_label">Renommer</div>
<div class="action_button">
{{ render_field(logo_form.new_name, False) }}
{{ render_field(logo_form.do_rename, False, onSubmit="submit_form()") }}
</div>
<div class="action_label">Supprimer l'image</div>
<div class="action_button">
{{ render_field(logo_form.do_delete, False, onSubmit="submit_form()") }}
@ -107,22 +104,22 @@
{% for dept_entry in form.depts.entries %}
{% set dept_form = dept_entry.form %}
{{ dept_entry.form.hidden_tag() }}
{% if dept_form.errors() %}
<details open>
{% else %}
<details>
{% endif %}
<details {{ dept_form.opened() }}>
<summary>
{% if dept_entry.form.is_local() %}
<h2>Département {{ dept_form.dept_name.data }}</h2>
<div class="sco_help">Les paramètres donnés sont spécifiques à ce département.<br />
Les logos du département se substituent aux logos de même nom définis globalement:</div>
{% else %}
<h2>Logos généraux</h2>
<div class="sco_help">Les images de cette section sont utilisé pour tous les départements,
mais peuvent être redéfinies localement au niveau de chaque département
(il suffit de définir un logo local de même nom)</div>
{% endif %}
<span class="entete_dept">
{% if dept_entry.form.is_local() %}
<h2>Département {{ dept_form.dept_name.data }}</h2>
<h3 class="effectifs">{{ dept_form.count() }}</h3>
<div class="sco_help">Les paramètres donnés sont spécifiques à ce département.<br />
Les logos du département se substituent aux logos de même nom définis globalement:</div>
{% else %}
<h2>Logos généraux</h2>
<h3 class="effectifs">{{ dept_form.count() }}</h3>
<div class="sco_help">Les images de cette section sont utilisé pour tous les départements,
mais peuvent être redéfinies localement au niveau de chaque département
(il suffit de définir un logo local de même nom)</div>
{% endif %}
</span>
</summary>
<div>
{{ render_logos(dept_form) }}