From 2920c6f1316b03c1cbd4168c8aa50b8b56ea30d6 Mon Sep 17 00:00:00 2001 From: Place Jean-Marie Date: Fri, 19 Nov 2021 11:51:05 +0100 Subject: [PATCH] temp. le 19/11 12h --- app/__init__.py | 2 + app/scodoc/sco_config_actions.py | 181 ++++++++ app/scodoc/sco_config_form.py | 402 ++++++++++++++++++ app/scodoc/sco_logos.py | 28 +- app/scodoc/sco_pdf.py | 5 +- app/scodoc/sco_preferences.py | 8 +- app/static/css/scodoc.css | 17 + app/static/js/configuration.js | 6 + app/templates/config_dept.html | 81 ++++ app/templates/configuration.html | 148 ++++--- app/views/scodoc.py | 90 +--- app/views/scolar.py | 122 ++++-- tests/ressources/test_logos/logo_A.jpg | Bin 39157 -> 3755 bytes tests/ressources/test_logos/logo_A1.jpg | Bin 0 -> 3954 bytes tests/ressources/test_logos/logo_C.jpg | Bin 2417 -> 3071 bytes tests/ressources/test_logos/logo_D.png | Bin 15640 -> 21297 bytes tests/ressources/test_logos/logo_E.jpg | Bin 2935 -> 2938 bytes tests/ressources/test_logos/logo_F.jpeg | Bin 2882 -> 3002 bytes .../ressources/test_logos/logos_1/logo_A.jpg | Bin 2730 -> 3218 bytes .../ressources/test_logos/logos_1/logo_B.jpg | Bin 2832 -> 3061 bytes .../ressources/test_logos/logos_2/logo_A.jpg | Bin 2703 -> 3241 bytes .../ressources/test_logos/logos_2/logo_A1.jpg | Bin 0 -> 3501 bytes tests/unit/test_logos.py | 97 ++++- 23 files changed, 989 insertions(+), 198 deletions(-) create mode 100644 app/scodoc/sco_config_actions.py create mode 100644 app/scodoc/sco_config_form.py create mode 100644 app/static/js/configuration.js create mode 100644 app/templates/config_dept.html create mode 100644 tests/ressources/test_logos/logo_A1.jpg create mode 100644 tests/ressources/test_logos/logos_2/logo_A1.jpg diff --git a/app/__init__.py b/app/__init__.py index 0943a91f..969c9766 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -33,6 +33,7 @@ from app.scodoc.sco_exceptions import ( ) from config import DevConfig import sco_version +from flask_debugtoolbar import DebugToolbarExtension db = SQLAlchemy() migrate = Migrate(compare_type=True) @@ -187,6 +188,7 @@ def create_app(config_class=DevConfig): moment.init_app(app) cache.init_app(app) sco_cache.CACHE = cache + toolbar = DebugToolbarExtension(app) app.register_error_handler(ScoGenError, handle_sco_value_error) app.register_error_handler(ScoValueError, handle_sco_value_error) diff --git a/app/scodoc/sco_config_actions.py b/app/scodoc/sco_config_actions.py new file mode 100644 index 00000000..bf633a26 --- /dev/null +++ b/app/scodoc/sco_config_actions.py @@ -0,0 +1,181 @@ +# -*- mode: python -*- +# -*- coding: utf-8 -*- + +############################################################################## +# +# ScoDoc +# +# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Emmanuel Viennet emmanuel.viennet@viennet.net +# +############################################################################## + +""" +Module main: page d'accueil, avec liste des départements + +Emmanuel Viennet, 2021 +""" +from app.models import ScoDocSiteConfig +from app.scodoc.sco_logos import write_logo, find_logo, delete_logo +import app +from flask import current_app + + +class Action: + """Base class for all classes describing an action from from config form.""" + + def __init__(self, message, parameters): + self.message = message + self.parameters = parameters + + @staticmethod + def build_action(parameters, stream=None): + """Check (from parameters) if some action has to be done and + then return list of action (or else return empty list).""" + raise NotImplementedError + + def display(self): + """return a str describing the action to be done""" + return self.message.format_map(self.parameters) + + def execute(self): + """Executes the action""" + raise NotImplementedError + + +GLOBAL = "_" + + +class LogoUpdate(Action): + """Action: change a logo + dept_id: dept_id or '_', + logo_id: logo_id, + upload: image file replacement + """ + + def __init__(self, parameters): + super().__init__( + f"Modification du logo {parameters['logo_id']} pour le département {parameters['dept_id']}", + 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["upload"] is not None: + return LogoUpdate(parameters) + return None + + def execute(self): + current_app.logger.info(self.message) + write_logo( + stream=self.parameters["upload"], + dept_id=self.parameters["dept_id"], + name=self.parameters["logo_id"], + ) + + +class LogoDelete(Action): + """Action: Delete an existing logo + dept_id: dept_id or '_', + logo_id: logo_id + """ + + def __init__(self, parameters): + super().__init__( + f"Suppression du logo {parameters['logo_id']} pour le département {parameters['dept_id']}.", + parameters, + ) + + @staticmethod + def build_action(parameters): + parameters["dept_id"] = parameters["dept_key"] + if parameters["dept_key"] == GLOBAL: + parameters["dept_id"] = None + if parameters["do_delete"]: + return LogoDelete(parameters) + return None + + def execute(self): + current_app.logger.info(self.message) + delete_logo(name=self.parameters["logo_id"], dept_id=self.parameters["dept_id"]) + + +class LogoInsert(Action): + """Action: add a new logo + dept_key: dept_id or '_', + logo_id: logo_id, + upload: image file replacement + """ + + def __init__(self, parameters): + super().__init__( + f"Ajout du logo {parameters['name']} pour le département {parameters['dept_key']} ({parameters['upload']}).", + parameters, + ) + + @staticmethod + def build_action(parameters): + if parameters["dept_key"] == GLOBAL: + parameters["dept_id"] = None + if parameters["upload"] and parameters["name"]: + logo = find_logo( + logoname=parameters["name"], dept_id=parameters["dept_key"] + ) + if logo is None: + return LogoInsert(parameters) + return None + + def execute(self): + dept_id = self.parameters["dept_key"] + if dept_id == GLOBAL: + dept_id = None + current_app.logger.info(self.message) + write_logo( + stream=self.parameters["upload"], + name=self.parameters["name"], + dept_id=dept_id, + ) + + +class BonusSportUpdate(Action): + """Action: Change bonus_sport_function_name. + bonus_sport_function_name: the new value""" + + def __init__(self, parameters): + super().__init__( + f"Changement du calcul de bonus sport pour ({parameters['bonus_sport_func_name']}).", + parameters, + ) + + @staticmethod + def build_action(parameters): + if ( + parameters["bonus_sport_func_name"] + != ScoDocSiteConfig.get_bonus_sport_func_name() + ): + return [BonusSportUpdate(parameters)] + return [] + + def execute(self): + current_app.logger.info(self.message) + ScoDocSiteConfig.set_bonus_sport_func(self.parameters["bonus_sport_func_name"]) + app.clear_scodoc_cache() diff --git a/app/scodoc/sco_config_form.py b/app/scodoc/sco_config_form.py new file mode 100644 index 00000000..d5ee87a9 --- /dev/null +++ b/app/scodoc/sco_config_form.py @@ -0,0 +1,402 @@ +# -*- mode: python -*- +# -*- coding: utf-8 -*- + +############################################################################## +# +# ScoDoc +# +# Copyright (c) 1999 - 2021 Emmanuel Viennet. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Emmanuel Viennet emmanuel.viennet@viennet.net +# +############################################################################## + +""" +Module main: page d'accueil, avec liste des départements + +Emmanuel Viennet, 2021 +""" +import re + +from flask import flash, url_for, redirect, render_template +from flask_wtf import FlaskForm +from flask_wtf.file import FileField, FileAllowed +from wtforms import SelectField, SubmitField, FormField, validators, FieldList +from wtforms.fields.simple import BooleanField, StringField, HiddenField + +from app import AccessDenied +from app.models import Departement +from app.models import ScoDocSiteConfig +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, + BonusSportUpdate, +) + +from flask_login import current_user + +from app.scodoc.sco_logos import find_logo + +JAVASCRIPTS = html_sco_header.BOOTSTRAP_MULTISELECT_JS + [] + +CSSSTYLES = html_sco_header.BOOTSTRAP_MULTISELECT_CSS + +# class ItemForm(FlaskForm): +# """Unused Generic class to document common behavior for classes +# * ScoConfigurationForm +# * DeptForm +# * LogoForm +# Some or all of these implements: +# * Composite design pattern (ScoConfigurationForm and DeptForm) +# - a FieldList(FormField(ItemForm)) +# - FieldListItem are created by browsing the model +# - index dictionnary to provide direct access to a SubItemForm +# - the direct access method (get_form) +# * have some information added to be displayed +# - information are collected from a model object +# Common methods: +# * build(model) (not for LogoForm who has no child) +# for each child: +# * create en entry in the FieldList for each subitem found +# * update self.index +# * fill_in additional information into the form +# * recursively calls build for each chid +# some spécific information may be added after standard processing +# (typically header/footer description) +# * preview(data) +# check the data from a post and build a list of operations that has to be done. +# for a two phase process: +# * phase 1 (list all opérations) +# * phase 2 (may be confirmation and execure) +# - if no op found: return to the form with a message 'Aucune modification trouvée' +# - only one operation found: execute and go to main page +# - more than 1 operation found. asked form confirmation (and execution if confirmed) +# +# Someday we'll have time to refactor as abstract classes but Abstract FieldList makes this a bit complicated +# """ + +# Terminology: +# dept_id : identifies a dept in modele (= list_logos()). None designates globals logos +# dept_key : identifies a dept in this form only (..index[dept_key], and fields 'dept_key'). +# 'GLOBAL' designates globals logos (we need a string value to set up HiddenField +GLOBAL = "_" + + +def dept_id_to_key(dept_id): + if dept_id is None: + return GLOBAL + return dept_id + + +def dept_key_to_id(dept_key): + if dept_key == GLOBAL: + return None + return dept_key + + +class AddLogoForm(FlaskForm): + """Formulaire permettant l'ajout d'un logo (dans un département)""" + + dept_key = HiddenField() + name = StringField( + label="Nom", + validators=[ + validators.regexp( + r"^[a-zA-Z0-9-]*$", + re.IGNORECASE, + "Ne doit comporter que lettres, chiffres ou -", + ), + validators.Length( + max=20, message="Un nom ne doit pas dépasser 20 caractères" + ), + validators.required("Nom de logo requis (alphanumériques ou '-')"), + ], + ) + upload = FileField( + label="Sélectionner l'image", + validators=[ + FileAllowed( + scu.LOGOS_IMAGES_ALLOWED_TYPES, + f"n'accepte que les fichiers image {', '.join(scu.LOGOS_IMAGES_ALLOWED_TYPES)}", + ), + validators.required("Fichier image manquant"), + ], + ) + do_insert = SubmitField("ajouter une image") + + def __init__(self, *args, **kwargs): + kwargs["meta"] = {"csrf": False} + super().__init__(*args, **kwargs) + + def validate_name(self, name): + dept_id = dept_key_to_id(self.dept_key.data) + if dept_id == GLOBAL: + dept_id = None + if find_logo(logoname=name.data, dept_id=dept_id) is not None: + raise validators.ValidationError("Un logo de même nom existe déjà") + + def select_action(self): + if self.data["do_insert"]: + if self.validate(): + return LogoInsert.build_action(self.data) + return None + + +class LogoForm(FlaskForm): + """Embed both presentation of a logo (cf. template file configuration.html) + and all its data and UI action (change, delete)""" + + dept_key = HiddenField() + logo_id = HiddenField() + upload = FileField( + label="Remplacer l'image", + validators=[ + FileAllowed( + scu.LOGOS_IMAGES_ALLOWED_TYPES, + f"n'accepte que les fichiers image {', '.join(scu.LOGOS_IMAGES_ALLOWED_TYPES)}", + ) + ], + ) + do_delete = SubmitField("Supprimer l'image") + + def __init__(self, *args, **kwargs): + kwargs["meta"] = {"csrf": False} + super().__init__(*args, **kwargs) + self.logo = find_logo( + logoname=self.logo_id.data, dept_id=dept_key_to_id(self.dept_key.data) + ).select() + self.description = None + self.titre = None + self.can_delete = True + if self.dept_key.data == GLOBAL: + if self.logo_id.data == "header": + self.can_delete = False + self.description = "" + self.titre = "Logo en-tête" + if self.logo_id.data == "footer": + self.can_delete = False + self.titre = "Logo pied de page" + self.description = "" + else: + if self.logo_id.data == "header": + self.description = "Se substitue au header défini au niveau global" + self.titre = "Logo en-tête" + if self.logo_id.data == "footer": + self.description = "Se substitue au footer défini au niveau global" + self.titre = "Logo pied de page" + + def select_action(self): + 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) + return None + + +class DeptForm(FlaskForm): + dept_key = HiddenField() + dept_name = HiddenField() + add_logo = FormField(AddLogoForm) + logos = FieldList(FormField(LogoForm)) + + def __init__(self, *args, **kwargs): + kwargs["meta"] = {"csrf": False} + super().__init__(*args, **kwargs) + + def is_local(self): + if self.dept_key.data == GLOBAL: + return None + return True + + def select_action(self): + action = self.add_logo.form.select_action() + if action: + return action + for logo_entry in self.logos.entries: + logo_form = logo_entry.form + action = logo_form.select_action() + if action: + return action + return None + + def get_form(self, logoname=None): + """Retourne le formulaire associé à un logo. None si pas trouvé""" + if logoname is None: # recherche de département + return self + return self.index.get(logoname, None) + + +def _make_dept_id_name(): + """Cette section assute que tous les départements sont traités (y compris ceux qu'ont pas de logo au départ) + et détermine l'ordre d'affichage des DeptForm (GLOBAL d'abord, puis par ordre alpha de nom de département) + -> [ (None, None), (dept_id, dept_name)... ]""" + depts = [(None, GLOBAL)] + for dept in ( + Departement.query.filter_by(visible=True).order_by(Departement.acronym).all() + ): + depts.append((dept.id, dept.acronym)) + return depts + + +def _ordered_logos(modele): + """sort logoname alphabetically but header and footer moved at start. (since there is no space in logoname)""" + + def sort(name): + if name == "header": + return " 0" + if name == "footer": + return " 1" + return name + + order = sorted(modele.keys(), key=sort) + return order + + +def _make_dept_data(dept_id, dept_name, modele): + dept_key = dept_id_to_key(dept_id) + data = { + "dept_key": dept_key, + "dept_name": dept_name, + "add_logo": {"dept_key": dept_key}, + } + logos = [] + if modele is not None: + for name in _ordered_logos(modele): + logos.append({"dept_key": dept_key, "logo_id": name}) + data["logos"] = logos + return data + + +def _make_depts_data(modele): + data = [] + for dept_id, dept_name in _make_dept_id_name(): + data.append( + _make_dept_data( + dept_id=dept_id, dept_name=dept_name, modele=modele.get(dept_id, None) + ) + ) + return data + + +def _make_data(bonus_sport, modele): + data = { + "bonus_sport_func_name": bonus_sport, + "depts": _make_depts_data(modele=modele), + } + return data + + +class ScoDocConfigurationForm(FlaskForm): + "Panneau de configuration général" + bonus_sport_func_name = SelectField( + label="Fonction de calcul des bonus sport&culture", + choices=[ + (x, x if x else "Aucune") + for x in ScoDocSiteConfig.get_bonus_sport_func_names() + ], + ) + depts = FieldList(FormField(DeptForm)) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # def _set_global_logos_infos(self): + # "specific processing for globals items" + # global_header = self.get_form(logoname="header") + # global_header.description = ( + # "image placée en haut de certains documents documents PDF." + # ) + # global_header.titre = "Logo en-tête" + # global_header.can_delete = False + # global_footer = self.get_form(logoname="footer") + # global_footer.description = ( + # "image placée en pied de page de certains documents documents PDF." + # ) + # global_footer.titre = "Logo pied de page" + # global_footer.can_delete = False + + # def _build_dept(self, dept_id, dept_name, modele): + # dept_key = dept_id or GLOBAL + # data = {"dept_key": dept_key} + # entry = self.depts.append_entry(data) + # entry.form.build(dept_name, modele.get(dept_id, {})) + # self.index[str(dept_key)] = entry.form + + # def build(self, modele): + # "Build the Form hierachy (DeptForm, LogoForm) and add extra data (from modele)" + # # if entries already initialized (POST). keep subforms + # self.index = {} + # # create entries in FieldList (one entry per dept + # for dept_id, dept_name in self.dept_id_name: + # self._build_dept(dept_id=dept_id, dept_name=dept_name, modele=modele) + # self._set_global_logos_infos() + + def get_form(self, dept_key=GLOBAL, logoname=None): + """Retourne un formulaire: + * pour un département (get_form(dept_id)) ou à un logo (get_form(dept_id, logname)) + * propre à un département (get_form(dept_id, logoname) ou global (get_form(logoname)) + retourne None si le formulaire cherché ne peut être trouvé + """ + dept_form = self.index.get(dept_key, None) + if dept_form is None: # département non trouvé + return None + return dept_form.get_form(logoname) + + def select_action(self): + if ( + self.data["bonus_sport_func_name"] + != ScoDocSiteConfig.get_bonus_sport_func_name() + ): + return BonusSportUpdate(self.data) + for dept_entry in self.depts: + dept_form = dept_entry.form + action = dept_form.select_action() + if action: + return action + return None + + +def configuration(): + """Panneau de configuration général""" + auth_name = str(current_user) + if not current_user.is_administrator(): + raise AccessDenied("invalid user (%s) must be SuperAdmin" % auth_name) + form = ScoDocConfigurationForm( + data=_make_data( + bonus_sport=ScoDocSiteConfig.get_bonus_sport_func_name(), + modele=sco_logos.list_logos(), + ) + ) + if form.is_submitted(): + action = form.select_action() + if action: + action.execute() + flash(action.message) + return redirect( + url_for( + "scodoc.configuration", + ) + ) + return render_template( + "configuration.html", + scodoc_dept=None, + title="Configuration ScoDoc", + form=form, + ) diff --git a/app/scodoc/sco_logos.py b/app/scodoc/sco_logos.py index 5808945f..3f5917bb 100644 --- a/app/scodoc/sco_logos.py +++ b/app/scodoc/sco_logos.py @@ -46,7 +46,7 @@ from app import Departement, ScoValueError from app.scodoc import sco_utils as scu from PIL import Image as PILImage -GLOBAL = "_GLOBAL" # category for server level logos +GLOBAL = "_" # category for server level logos def find_logo(logoname, dept_id=None, strict=False, prefix=scu.LOGO_FILE_PREFIX): @@ -70,6 +70,18 @@ def find_logo(logoname, dept_id=None, strict=False, prefix=scu.LOGO_FILE_PREFIX) return logo +def delete_logo(name, dept_id=None): + """Delete all files matching logo (dept_id, name) (including all allowed extensions) + Args: + name: The name of the logo + dept_id: the dept_id (if local). Use None to destroy globals logos + """ + logo = find_logo(logoname=name, dept_id=dept_id) + while logo is not None: + os.unlink(logo.select().filepath) + logo = find_logo(logoname=name, dept_id=dept_id) + + def write_logo(stream, name, dept_id=None): """Crée le fichier logo sur le serveur. Le suffixe du fichier (parmi LOGO_IMAGES_ALLOWED_TYPES) est déduit du contenu du stream""" @@ -79,14 +91,15 @@ def write_logo(stream, name, dept_id=None): def list_logos(): """Crée l'inventaire de tous les logos existants. L'inventaire se présente comme un dictionnaire de dictionnaire de Logo: - [GLOBAL][name] pour les logos globaux + [None][name] pour les logos globaux [dept_id][name] pour les logos propres à un département (attention id numérique du dept) + Les départements sans logos sont absents du résultat """ - inventory = {GLOBAL: _list_dept_logos()} # logos globaux (header / footer) + inventory = {None: _list_dept_logos()} # logos globaux (header / footer) for dept in Departement.query.filter_by(visible=True).all(): logos_dept = _list_dept_logos(dept_id=dept.id) if logos_dept: - inventory[dept.acronym] = _list_dept_logos(dept.id) + inventory[dept.id] = _list_dept_logos(dept.id) return inventory @@ -236,7 +249,7 @@ class Logo: """Retourne l'URL permettant d'obtenir l'image du logo""" return url_for( "scodoc.get_logo", - scodoc_dept=self.scodoc_dept_id, + dept_id=self.scodoc_dept_id, name=self.logoname, global_if_not_found=False, ) @@ -245,7 +258,7 @@ class Logo: """Retourne l'URL permettant d'obtenir l'image du logo sous forme de miniature""" return url_for( "scodoc.get_logo_small", - scodoc_dept=self.scodoc_dept_id, + dept_id=self.scodoc_dept_id, name=self.logoname, global_if_not_found=False, ) @@ -254,7 +267,7 @@ class Logo: if self.mm is None: return f'' else: - return f'' + return f'' def guess_image_type(stream) -> str: @@ -268,7 +281,6 @@ def guess_image_type(stream) -> str: def make_logo_local(logoname, dept_name): - breakpoint() depts = Departement.query.filter_by(acronym=dept_name).all() if len(depts) == 0: print(f"no dept {dept_name} found. aborting") diff --git a/app/scodoc/sco_pdf.py b/app/scodoc/sco_pdf.py index 54ed29b2..85ead167 100755 --- a/app/scodoc/sco_pdf.py +++ b/app/scodoc/sco_pdf.py @@ -60,7 +60,6 @@ from reportlab.lib.pagesizes import letter, A4, landscape from flask import g import app.scodoc.sco_utils as scu -from app.scodoc.sco_logos import find_logo from app.scodoc.sco_utils import CONFIG from app import log from app.scodoc.sco_exceptions import ScoGenError, ScoValueError @@ -193,6 +192,10 @@ class ScolarsPageTemplate(PageTemplate): preferences=None, # dictionnary with preferences, required ): """Initialise our page template.""" + from app.scodoc.sco_logos import ( + find_logo, + ) # defered import (solve circular dependency ->sco_logo ->scodoc, ->sco_pdf + self.preferences = preferences self.pagesbookmarks = pagesbookmarks self.pdfmeta_author = author diff --git a/app/scodoc/sco_preferences.py b/app/scodoc/sco_preferences.py index d83ca14f..7e08d355 100644 --- a/app/scodoc/sco_preferences.py +++ b/app/scodoc/sco_preferences.py @@ -2017,10 +2017,10 @@ class BasePreferences(object): H = [ html_sco_header.sco_header(page_title="Préférences"), "

Préférences globales pour %s

" % scu.ScoURL(), - f"""

modification des logos du département (pour documents pdf)

""" - if current_user.is_administrator() - else "", + # f"""

modification des logos du département (pour documents pdf)

""" + # if current_user.is_administrator() + # else "", """

Ces paramètres s'appliquent par défaut à tous les semestres, sauf si ceux-ci définissent des valeurs spécifiques.

Attention: cliquez sur "Enregistrer les modifications" en bas de page pour appliquer vos changements !

""", diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css index cc2ea27a..8dcfc779 100644 --- a/app/static/css/scodoc.css +++ b/app/static/css/scodoc.css @@ -867,6 +867,9 @@ div.sco_help { span.wtf-field ul.errors li { color: red; +} +.configuration_logo div.img { + } .configuration_logo div.img-container { width: 256px; @@ -874,6 +877,20 @@ span.wtf-field ul.errors li { .configuration_logo div.img-container img { max-width: 100%; } +.configuration_logo div.img-data { + vertical-align: top; +} +.configuration_logo logo-edit titre { + background-color:lightblue; +} +.configuration_logo logo-edit nom { + float: left; + vertical-align: baseline; +} +.configuration_logo logo-edit description { + float:right; + vertical-align:baseline; +} p.indent { padding-left: 2em; diff --git a/app/static/js/configuration.js b/app/static/js/configuration.js new file mode 100644 index 00000000..b537d572 --- /dev/null +++ b/app/static/js/configuration.js @@ -0,0 +1,6 @@ +function submit_form() { + $("#configuration_form").submit(); +} + +$(function () { +}) \ No newline at end of file diff --git a/app/templates/config_dept.html b/app/templates/config_dept.html new file mode 100644 index 00000000..c602c5f3 --- /dev/null +++ b/app/templates/config_dept.html @@ -0,0 +1,81 @@ +{% macro render_field(field) %} +
+ {{ field.label }} : + {{ field()|safe }} + {% if field.errors %} +
    + {% for error in field.errors %} +
  • {{ error }}
  • + {% endfor %} +
+ {% endif %} +
+
+{% endmacro %} + +{% macro render_logo(logo_form, titre=None) %} + {% if titre %} + + +

{{ titre }}

+
+ + + {% endif %} + + +

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

+
pas de logo chargé
+ + + {{ logo_form.form.dept_id() }} + {{ logo_form.form.logo_id() }} + 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() }} +
+ {{ 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

+{% 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)}} + + {% endif %} + + + +
{{ form.submit() }}
+
+{#{% endblock %}#} \ No newline at end of file diff --git a/app/templates/configuration.html b/app/templates/configuration.html index 077c094d..b874d48d 100644 --- a/app/templates/configuration.html +++ b/app/templates/configuration.html @@ -1,10 +1,12 @@ {% extends 'base.html' %} {% import 'bootstrap/wtf.html' as wtf %} -{% macro render_field(field) %} +{% macro render_field(field, with_label=True) %}
- {{ field.label }} : - {{ field()|safe }} + {% if with_label %} + {{ field.label }} : + {% endif %} + {{ field(**kwargs)|safe }} {% if field.errors %}
    {% for error in field.errors %} @@ -16,66 +18,102 @@
{% 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 %} - - +{% macro render_add_logo(add_logo_form) %} +
+

Ajouter un logo

+ {{ add_logo_form.hidden_tag() }} + {{ render_field(add_logo_form.name) }} + {{ render_field(add_logo_form.upload) }} + {{ render_field(add_logo_form.do_insert, False, onSubmit="submit_form") }} +
{% endmacro %} +{% macro render_logo(dept_form, logo_form) %} +
+ {{ logo_form.hidden_tag() }} + {% if logo_form.titre %} + + +

{{ logo_form.titre }}

+
{{ logo_form.description or "" }}
+ + + {% else %} + + +

Logo personalisé: {{ logo_form.logo_id.data }}

+ {{ logo_form.description or "" }} + + + {% endif %} + + +
+ pas de logo chargé
+ +

{{ logo_form.logo.logoname }} (Format: {{ logo_form.logo.suffix }})

+ Taille: {{ logo_form.logo.size }} px + {% if logo_form.logo.mm %}   /   {{ logo_form.logo.mm }} mm {% endif %}
+ Aspect ratio: {{ logo_form.logo.aspect_ratio }}
+ Usage: {{ logo_form.logo.get_usage() }} + +

Modifier l'image

+ {{ render_field(logo_form.upload, False, onchange="submit_form()") }} + {% if logo_form.can_delete %} +

Supprimer l'image

+ {{ render_field(logo_form.do_delete, False, onSubmit="submit_form()") }} + {% endif %} + + +
+{% endmacro %} + +{% macro render_logos(dept_form) %} + + {% for logo_entry in dept_form.logos.entries %} + {% set logo_form = logo_entry.form %} + {{ render_logo(dept_form, logo_form) }} + {% else %} +

Aucun logo défini en propre à ce département

+ {% endfor %} +
+{% endmacro %} {% block app_content %} -{% if scodoc_dept %} -

Logos du département {{ scodoc_dept }}

-{% else %} -

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)}} - - {% endif %} - +
{% endblock %} \ No newline at end of file diff --git a/app/views/scodoc.py b/app/views/scodoc.py index 70433025..d875dc8e 100644 --- a/app/views/scodoc.py +++ b/app/views/scodoc.py @@ -46,7 +46,7 @@ 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, FormField, validators, Form +from wtforms import SelectField, SubmitField, FormField, validators, Form, FieldList from wtforms.fields import IntegerField from wtforms.fields.simple import BooleanField, StringField, TextAreaField, HiddenField from wtforms.validators import ValidationError, DataRequired, Email, EqualTo @@ -56,7 +56,7 @@ from app.models import Departement, Identite from app.models import FormSemestre, FormsemestreInscription from app.models import ScoDocSiteConfig import sco_version -from app.scodoc import sco_logos +from app.scodoc import sco_logos, sco_config_form from app.scodoc import sco_find_etud from app.scodoc import sco_utils as scu from app.decorators import ( @@ -64,7 +64,9 @@ from app.decorators import ( scodoc7func, scodoc, permission_required_compat_scodoc7, + permission_required, ) +from app.scodoc.sco_config_form import configuration from app.scodoc.sco_exceptions import AccessDenied from app.scodoc.sco_logos import find_logo from app.scodoc.sco_permissions import Permission @@ -180,64 +182,6 @@ 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" - - bonus_sport_func_name = SelectField( - label="Fonction de calcul des bonus sport&culture", - choices=[ - (x, x if x else "Aucune") - for x in ScoDocSiteConfig.get_bonus_sport_func_names() - ], - ) - 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 # SCOLAR_FONT = "Helvetica" @@ -259,29 +203,13 @@ class ScoDocConfigurationForm(FlaskForm): @bp.route("/ScoDoc/configuration", methods=["GET", "POST"]) @admin_required def configuration(): - "Panneau de configuration général" - form = ScoDocConfigurationForm( - bonus_sport_func_name=ScoDocSiteConfig.get_bonus_sport_func_name(), - ) - if form.validate_on_submit(): - ScoDocSiteConfig.set_bonus_sport_func(form.bonus_sport_func_name.data) - 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")) - - return render_template( - "configuration.html", - title="Configuration ScoDoc", - form=form, - scodoc_dept=None, - ) + auth_name = str(current_user) + if not current_user.is_administrator(): + raise AccessDenied("invalid user (%s) must be SuperAdmin" % auth_name) + return sco_config_form.configuration() -SMALL_SIZE = (300, 300) +SMALL_SIZE = (200, 200) def _return_logo(name="header", dept_id="", small=False, strict: bool = True): diff --git a/app/views/scolar.py b/app/views/scolar.py index c708495a..ebfd4d1a 100644 --- a/app/views/scolar.py +++ b/app/views/scolar.py @@ -174,7 +174,7 @@ class DeptLogosConfigurationForm(FlaskForm): validators=[ FileAllowed( scu.LOGOS_IMAGES_ALLOWED_TYPES, - f"n'accepte que les fichiers image {','.join([e for e in scu.LOGOS_IMAGES_ALLOWED_TYPES])}", + f"n'accepte que les fichiers image {','.join(scu.LOGOS_IMAGES_ALLOWED_TYPES)}", ) ], ) @@ -185,7 +185,7 @@ class DeptLogosConfigurationForm(FlaskForm): validators=[ FileAllowed( scu.LOGOS_IMAGES_ALLOWED_TYPES, - f"n'accepte que les fichiers image {','.join([e for e in scu.LOGOS_IMAGES_ALLOWED_TYPES])}", + f"n'accepte que les fichiers image {','.join(scu.LOGOS_IMAGES_ALLOWED_TYPES)}", ) ], ) @@ -193,36 +193,96 @@ class DeptLogosConfigurationForm(FlaskForm): 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)) +# @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, +# ) +# +# +# 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") - return render_template( - "configuration.html", - title="Configuration Logos du département", - form=form, - scodoc_dept=scodoc_dept, - ) + +# @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, +# ) # -------------------------------------------------------------------- diff --git a/tests/ressources/test_logos/logo_A.jpg b/tests/ressources/test_logos/logo_A.jpg index 7f107a05b6075d40551a7f7e695b06ec9f0763bf..7770372c7fe210abc450119be75920133a5eba98 100644 GIT binary patch literal 3755 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 literal 39157 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 literal 0 HcmV?d00001 diff --git a/tests/ressources/test_logos/logo_C.jpg b/tests/ressources/test_logos/logo_C.jpg index bdca2b7360bc69c8a9fdbb0950233b369416d7a4..108afc713d582959a8d58d469e96c04bf5a38c9d 100644 GIT binary patch literal 3071 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 literal 2417 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�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 literal 15640 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 F{{>~3qf!6> diff --git a/tests/ressources/test_logos/logo_F.jpeg b/tests/ressources/test_logos/logo_F.jpeg index c3750e29f2e44516d028f96c0a1a3ce181a42f63..20728130a97fdc5af7463fcd4e7ccf4da3038c64 100644 GIT binary patch literal 3002 zcmb7Fc|25m8$Yv{8JQ2ql8~6mHcFTo*9r8Z9i0*@TtCiilukB_ze9w#g|fY?G6h$0=*7;kIii$;%V;)HSq; zIyyRvY6iyoBqL3-4r%=#FkxX~tO!;{hJ=^Llm2g7dj^POfJh(#0oxA1#bF3>*jh6n z2LNycg!CVRBLEl*DFo?cAQRTD_=n&y0D)W^07 ztz)C#o6`H{zx1y+=!d{;zcQ%AJ2&%*-rAKRLqJ5t0Mbaf+S->B#$pFHH8JS7!tJgj2j zW}$mWwb!DuL$_A-jjxwGz8>?CiRsFplYe5`RIf%DU@uCYf4Et<)Z|-Os1*Ry_VLUS=_6=gLv# z?3YnW2bcNtCuG{HJUtKcPG)uWNzZUn@ff;z(fO|zWLk+cDXUqZq9DO;v8PE*kRW}2 zcHm|i2#NYBKd9IfG7AwH?yvWavzuBa!@UD}mg9JB=N(qzl`Ki8% zjOPZXcFZ2=knQ473LxQ7sr@P@C

l35YA)eN30pt$NFH0h)O37v zoElin(7$v%_NhJL=H&XKHg`Qv_4|=LpFbD&rWVNu|53_2&`T=@q03Gdbcj(hJXg&d`B+hCKO4Z~DqC7{ zS0kRh;}bH9%iKTioGCD@_Ivv7X2>7C*^agE#1SE6Id`sZ>J+!9p$d9-3*6E@zN972 zROCC>j(ju>0S7au6OMu$oAMI6r-%dpN`=K|;j0PuEn;#jk~yNd=myu3F5WGEPTgLn z7vc46K%Gf+P3f6SpJpN!YWT`mU__pnqi9R4rSHC`e2mGMt}7$z_op1Sp(R^`X+s~~ zRL=mizxDaZY4sxQrV5jD4|1ke1|Hq6dG@uuaAhz3%PGi6icp1;0@6&tQ98axql4gg){F|1m zsN9FEGi{4L)S4l~*7?`EqNPuFr<-Fs+O&A~@fxkfMSzag=H}b`c50M$oo@hLqPJE} zJs-5vC|5j%p+(C&UA7My39^Ee?$Ios*ldqekKL5QznW>$HrL;t^GdmIlUmj_Qm>GU zlC|oesjC`$!?#H-C|!}v=BPi{F>rbzB5k-{lDrD+(JXmeo zs}ONL1~10iAcuv6`b=ct0H}J3U)`0!xxM zKN_$8X}<=2P^p4biF^9+ zyfDS~sUY)FQE*X;D@VgSp+^>g3ygYWOt z9}I(LXkm@APFw`I!_&Xo)1M37)gkKfKIpi(D!FScMOr{` zOk+~3pHxBb(MbY6X|ZR@&&B=cbDMkA8&20aXdm-st+4t>hlo}Kx59{`xe3QR#*(F2 zj+!D~jb1fX!;an}ZjEOG@hp?lFbJv=2>ETDehm!Bb2vOmq%mB=wb|ElOMlfG7_4%8 z6hs0DQ)K%Inu3fj!aV@BvIZV4>(O3I&@O(tLI5; zfRNd2o7M|TrJYH4YIfJ=?bTk_D?>la{Z6t``LRDE_WiTaFCO1y0Y1unsVMtxCBLa1 z*R^Fl&;Pi2q!=zzTQTnP(#Zq%iTw+u%yF&Z&OGOggH7_peFt~M$Ty6``bX=ch9(Dg N_-{6;T*+A*{0|En0fhhn literal 2882 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 AEdT%j literal 2730 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 diff --git a/tests/ressources/test_logos/logos_1/logo_B.jpg b/tests/ressources/test_logos/logos_1/logo_B.jpg index 2ebb82823e3db7f757b5d29322b1e9efb0db2c94..2428dc4521df51b21fd3279a7dbcf4edf90dbdd9 100644 GIT binary patch literal 3061 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 literal 2832 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 Xrl?*&eLha9q*r$u@mGi+S9|{lD=b$E diff --git a/tests/ressources/test_logos/logos_2/logo_A1.jpg b/tests/ressources/test_logos/logos_2/logo_A1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5bdf7500cc42ae84339f70eb11df4ad8731df05d GIT binary patch literal 3501 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 literal 0 HcmV?d00001 diff --git a/tests/unit/test_logos.py b/tests/unit/test_logos.py index 1ed62a49..6af36648 100644 --- a/tests/unit/test_logos.py +++ b/tests/unit/test_logos.py @@ -7,7 +7,6 @@ Utiliser comme: pytest tests/unit/test_logos.py """ -from io import BytesIO from pathlib import Path from shutil import copytree, copy, rmtree @@ -18,7 +17,14 @@ import app from app import db from app.models import Departement import app.scodoc.sco_utils as scu -from app.scodoc.sco_logos import find_logo, Logo, list_logos +from app.scodoc.sco_logos import ( + find_logo, + Logo, + list_logos, + GLOBAL, + write_logo, + delete_logo, +) RESOURCES_DIR = "/opt/scodoc/tests/ressources/test_logos" @@ -30,12 +36,15 @@ def create_dept(test_client): """ dept1 = Departement(acronym="RT") dept2 = Departement(acronym="INFO") + dept3 = Departement(acronym="GEA") db.session.add(dept1) db.session.add(dept2) + db.session.add(dept3) db.session.commit() - yield dept1, dept2 + yield dept1, dept2, dept3 db.session.delete(dept1) db.session.delete(dept2) + db.session.delete(dept3) db.session.commit() @@ -52,9 +61,10 @@ def create_logos(create_dept): +-- logos_{d2} --+-- logo_A.jpg """ - dept1, dept2 = create_dept + dept1, dept2, dept3 = create_dept d1 = dept1.id d2 = dept2.id + d3 = dept3.id FILE_LIST = ["logo_A.jpg", "logo_C.jpg", "logo_D.png", "logo_E.jpg", "logo_F.jpeg"] for fn in FILE_LIST: from_path = Path(RESOURCES_DIR).joinpath(fn) @@ -83,33 +93,33 @@ def test_select_global_only(create_logos): def test_select_local_only(create_dept, create_logos): - dept1, dept2 = create_dept + dept1, dept2, dept3 = create_dept B_logo = app.scodoc.sco_logos.find_logo(logoname="B", dept_id=dept1.id) assert B_logo.filepath == f"{scu.SCODOC_LOGOS_DIR}/logos_{dept1.id}/logo_B.jpg" def test_select_local_override_global(create_dept, create_logos): - dept1, dept2 = create_dept + dept1, dept2, dept3 = create_dept A1_logo = app.scodoc.sco_logos.find_logo(logoname="A", dept_id=dept1.id) assert A1_logo.filepath == f"{scu.SCODOC_LOGOS_DIR}/logos_{dept1.id}/logo_A.jpg" def test_select_global_with_strict(create_dept, create_logos): - dept1, dept2 = create_dept + dept1, dept2, dept3 = create_dept A_logo = app.scodoc.sco_logos.find_logo(logoname="A", dept_id=dept1.id, strict=True) assert A_logo.filepath == f"{scu.SCODOC_LOGOS_DIR}/logos_{dept1.id}/logo_A.jpg" def test_looks_for_non_existant_should_give_none(create_dept, create_logos): # search for a local non-existant logo returns None - dept1, dept2 = create_dept + dept1, dept2, dept3 = create_dept no_logo = app.scodoc.sco_logos.find_logo(logoname="Z", dept_id=dept1.id) assert no_logo is None def test_looks_localy_for_a_global_should_give_none(create_dept, create_logos): # search for a local non-existant logo returns None - dept1, dept2 = create_dept + dept1, dept2, dept3 = create_dept no_logo = app.scodoc.sco_logos.find_logo( logoname="C", dept_id=dept1.id, strict=True ) @@ -123,8 +133,8 @@ def test_get_jpg_data(create_dept, create_logos): assert logo.logoname == "A" assert logo.suffix == "jpg" assert logo.filename == "A.jpg" - assert logo.size == (1200, 600) - assert logo.mm == approx((40, 30), 0.1) + assert logo.size == (140, 121) + assert logo.mm == approx((5.74, 4.96), 0.1) def test_get_png_without_data(create_dept, create_logos): @@ -139,10 +149,59 @@ def test_get_png_without_data(create_dept, create_logos): assert logo.mm is None -def test_create_globale_jpg_logo(create_dept, create_logos): +def test_delete_unique_global_jpg_logo(create_dept, create_logos): + from_path = Path(RESOURCES_DIR).joinpath("logo_A.jpg") + to_path = Path(scu.SCODOC_LOGOS_DIR).joinpath("logo_W.jpg") + copy(from_path.absolute(), to_path.absolute()) + assert to_path.exists() + delete_logo(name="W") + assert not to_path.exists() + + +def test_delete_unique_local_jpg_logo(create_dept, create_logos): + dept1, dept2, dept3 = create_dept + from_path = Path(RESOURCES_DIR).joinpath("logo_A.jpg") + to_path = Path(scu.SCODOC_LOGOS_DIR).joinpath(f"logos_{dept1.id}", "logo_W.jpg") + copy(from_path.absolute(), to_path.absolute()) + assert to_path.exists() + delete_logo(name="W", dept_id=dept1.id) + assert not to_path.exists() + + +def test_delete_multiple_local_jpg_logo(create_dept, create_logos): + dept1, dept2, dept3 = create_dept + from_path_A = Path(RESOURCES_DIR).joinpath("logo_A.jpg") + to_path_A = Path(scu.SCODOC_LOGOS_DIR).joinpath(f"logos_{dept1.id}", "logo_V.jpg") + from_path_B = Path(RESOURCES_DIR).joinpath("logo_D.png") + to_path_B = Path(scu.SCODOC_LOGOS_DIR).joinpath(f"logos_{dept1.id}", "logo_V.png") + copy(from_path_A.absolute(), to_path_A.absolute()) + copy(from_path_B.absolute(), to_path_B.absolute()) + assert to_path_A.exists() + assert to_path_B.exists() + delete_logo(name="V", dept_id=dept1.id) + assert not to_path_A.exists() + assert not to_path_B.exists() + + +def test_create_global_jpg_logo(create_dept, create_logos): path = Path(f"{RESOURCES_DIR}/logo_C.jpg") - logo = Logo("X") # create global logo stream = path.open("rb") + logo_path = Path(scu.SCODOC_LOGOS_DIR).joinpath("logo_X.jpg") + assert not logo_path.exists() + write_logo(stream, name="X") # create global logo + assert logo_path.exists() + logo_path.unlink(missing_ok=True) + + +def test_create_locale_jpg_logo(create_dept, create_logos): + dept1, dept2, dept3 = create_dept + path = Path(f"{RESOURCES_DIR}/logo_C.jpg") + stream = path.open("rb") + logo_path = Path(scu.SCODOC_LOGOS_DIR).joinpath(f"logos_{dept1.id}", "logo_Y.jpg") + assert not logo_path.exists() + write_logo(stream, name="Y", dept_id=dept1.id) # create global logo + assert logo_path.exists() + logo_path.unlink(missing_ok=True) def test_create_jpg_instead_of_png_logo(create_dept, create_logos): @@ -169,15 +228,17 @@ def test_create_jpg_instead_of_png_logo(create_dept, create_logos): def test_list_logo(create_dept, create_logos): # test only existence of copied logos. We assumes that they are OK - dept1, dept2 = create_dept + dept1, dept2, dept3 = create_dept logos = list_logos() - assert logos.keys() == {"_GLOBAL", "RT", "INFO"} + assert set(logos.keys()) == {dept1.id, dept2.id, None} assert {"A", "C", "D", "E", "F", "header", "footer"}.issubset( - set(logos["_GLOBAL"].keys()) + set(logos[None].keys()) ) - rt = logos.get("RT", None) + rt = logos.get(dept1.id, None) assert rt is not None assert {"A", "B"}.issubset(set(rt.keys())) - info = logos.get("INFO", None) + info = logos.get(dept2.id, None) assert info is not None assert {"A"}.issubset(set(rt.keys())) + gea = logos.get(dept3.id, None) + assert gea is None