Configuration des logos via formulaires
This commit is contained in:
parent
381e081844
commit
72dfc4f49b
@ -33,6 +33,17 @@ class ScoDocSiteConfig(db.Model):
|
|||||||
value = db.Column(db.Text())
|
value = db.Column(db.Text())
|
||||||
|
|
||||||
BONUS_SPORT = "bonus_sport_func_name"
|
BONUS_SPORT = "bonus_sport_func_name"
|
||||||
|
NAMES = {
|
||||||
|
BONUS_SPORT: str,
|
||||||
|
"always_require_ine": bool,
|
||||||
|
"SCOLAR_FONT": str,
|
||||||
|
"SCOLAR_FONT_SIZE": str,
|
||||||
|
"SCOLAR_FONT_SIZE_FOOT": str,
|
||||||
|
"INSTITUTION_NAME": str,
|
||||||
|
"INSTITUTION_ADDRESS": str,
|
||||||
|
"INSTITUTION_CITY": str,
|
||||||
|
"DEFAULT_PDF_FOOTER_TEMPLATE": str,
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, name, value):
|
def __init__(self, name, value):
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -41,6 +52,13 @@ class ScoDocSiteConfig(db.Model):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__}('{self.name}', '{self.value}')>"
|
return f"<{self.__class__.__name__}('{self.name}', '{self.value}')>"
|
||||||
|
|
||||||
|
def get_dict(self) -> dict:
|
||||||
|
"Returns all data as a dict name = value"
|
||||||
|
return {
|
||||||
|
c.name: self.NAMES.get(c.name, lambda x: x)(c.value)
|
||||||
|
for c in ScoDocSiteConfig.query.all()
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def set_bonus_sport_func(cls, func_name):
|
def set_bonus_sport_func(cls, func_name):
|
||||||
"""Record bonus_sport config.
|
"""Record bonus_sport config.
|
||||||
|
95
app/scodoc/sco_logos.py
Normal file
95
app/scodoc/sco_logos.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# -*- mode: python -*-
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gestion scolarite IUT
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
"""Gestion des images logos (nouveau ScoDoc 9)
|
||||||
|
|
||||||
|
Les logos sont `logo_header.<ext>` et `logo_footer.<ext>`
|
||||||
|
avec `ext` membre de LOGOS_IMAGES_ALLOWED_TYPES (= jpg, png)
|
||||||
|
|
||||||
|
SCODOC_LOGOS_DIR /opt/scodoc-data/config/logos
|
||||||
|
"""
|
||||||
|
import imghdr
|
||||||
|
import os
|
||||||
|
|
||||||
|
from flask import abort, current_app
|
||||||
|
|
||||||
|
from app.scodoc import sco_utils as scu
|
||||||
|
|
||||||
|
|
||||||
|
def get_logo_filename(logo_type: str, scodoc_dept: str) -> str:
|
||||||
|
"""return full filename for this logo, or "" if not found
|
||||||
|
an existing file with extension.
|
||||||
|
logo_type: "header" or "footer"
|
||||||
|
scodoc-dept: acronym
|
||||||
|
"""
|
||||||
|
# Search logos in dept specific dir (/opt/scodoc-data/config/logos/logos_<dept>),
|
||||||
|
# then in config dir /opt/scodoc-data/config/logos/
|
||||||
|
for image_dir in (
|
||||||
|
scu.SCODOC_LOGOS_DIR + "/logos_" + scodoc_dept,
|
||||||
|
scu.SCODOC_LOGOS_DIR, # global logos
|
||||||
|
):
|
||||||
|
for suffix in scu.LOGOS_IMAGES_ALLOWED_TYPES:
|
||||||
|
filename = os.path.join(image_dir, f"logo_{logo_type}.{suffix}")
|
||||||
|
if os.path.isfile(filename) and os.access(filename, os.R_OK):
|
||||||
|
return filename
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def guess_image_type(stream) -> str:
|
||||||
|
"guess image type from header in stream"
|
||||||
|
header = stream.read(512)
|
||||||
|
stream.seek(0)
|
||||||
|
fmt = imghdr.what(None, header)
|
||||||
|
if not fmt:
|
||||||
|
return None
|
||||||
|
return fmt if fmt != "jpeg" else "jpg"
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_directory_exists(filename):
|
||||||
|
"create enclosing directory if necessary"
|
||||||
|
directory = os.path.split(filename)[0]
|
||||||
|
if not os.path.exists(directory):
|
||||||
|
current_app.logger.info(f"sco_logos creating directory %s", directory)
|
||||||
|
os.mkdir(directory)
|
||||||
|
|
||||||
|
|
||||||
|
def store_image(stream, basename):
|
||||||
|
img_type = guess_image_type(stream)
|
||||||
|
if img_type not in scu.LOGOS_IMAGES_ALLOWED_TYPES:
|
||||||
|
abort(400, "type d'image invalide")
|
||||||
|
filename = basename + "." + img_type
|
||||||
|
_ensure_directory_exists(filename)
|
||||||
|
with open(filename, "wb") as f:
|
||||||
|
f.write(stream.read())
|
||||||
|
current_app.logger.info(f"sco_logos.store_image %s", filename)
|
||||||
|
# erase other formats if they exists
|
||||||
|
for extension in set(scu.LOGOS_IMAGES_ALLOWED_TYPES) - set([img_type]):
|
||||||
|
try:
|
||||||
|
os.unlink(basename + "." + extension)
|
||||||
|
except IOError:
|
||||||
|
pass
|
@ -111,7 +111,7 @@ get_base_preferences(formsemestre_id)
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
import flask
|
import flask
|
||||||
from flask import g
|
from flask import g, url_for
|
||||||
|
|
||||||
from app.models import Departement
|
from app.models import Departement
|
||||||
from app.scodoc import sco_cache
|
from app.scodoc import sco_cache
|
||||||
@ -2021,6 +2021,8 @@ class BasePreferences(object):
|
|||||||
H = [
|
H = [
|
||||||
html_sco_header.sco_header(page_title="Préférences"),
|
html_sco_header.sco_header(page_title="Préférences"),
|
||||||
"<h2>Préférences globales pour %s</h2>" % scu.ScoURL(),
|
"<h2>Préférences globales pour %s</h2>" % scu.ScoURL(),
|
||||||
|
f"""<p><a href="{url_for("scolar.config_logos", scodoc_dept=g.scodoc_dept)
|
||||||
|
}">modification des logos du département (pour documents pdf)</a></p>""",
|
||||||
"""<p class="help">Ces paramètres s'appliquent par défaut à tous les semestres, sauf si ceux-ci définissent des valeurs spécifiques.</p>
|
"""<p class="help">Ces paramètres s'appliquent par défaut à tous les semestres, sauf si ceux-ci définissent des valeurs spécifiques.</p>
|
||||||
<p class="msg">Attention: cliquez sur "Enregistrer les modifications" en bas de page pour appliquer vos changements !</p>
|
<p class="msg">Attention: cliquez sur "Enregistrer les modifications" en bas de page pour appliquer vos changements !</p>
|
||||||
""",
|
""",
|
||||||
|
@ -232,6 +232,8 @@ if not os.path.exists(SCO_TMP_DIR):
|
|||||||
os.mkdir(SCO_TMP_DIR, 0o755)
|
os.mkdir(SCO_TMP_DIR, 0o755)
|
||||||
# ----- Les logos: /opt/scodoc-data/config/logos
|
# ----- Les logos: /opt/scodoc-data/config/logos
|
||||||
SCODOC_LOGOS_DIR = os.path.join(SCODOC_CFG_DIR, "logos")
|
SCODOC_LOGOS_DIR = os.path.join(SCODOC_CFG_DIR, "logos")
|
||||||
|
LOGOS_IMAGES_ALLOWED_TYPES = ("jpg", "jpeg", "png") # remind that PIL does not read pdf
|
||||||
|
|
||||||
|
|
||||||
# ----- Les outils distribués
|
# ----- Les outils distribués
|
||||||
SCO_TOOLS_DIR = os.path.join(Config.SCODOC_DIR, "tools")
|
SCO_TOOLS_DIR = os.path.join(Config.SCODOC_DIR, "tools")
|
||||||
@ -305,8 +307,6 @@ PDF_MIMETYPE = "application/pdf"
|
|||||||
XML_MIMETYPE = "text/xml"
|
XML_MIMETYPE = "text/xml"
|
||||||
JSON_MIMETYPE = "application/json"
|
JSON_MIMETYPE = "application/json"
|
||||||
|
|
||||||
LOGOS_IMAGES_ALLOWED_TYPES = ("jpg", "png") # remind that PIL does not read pdf
|
|
||||||
|
|
||||||
# Admissions des étudiants
|
# Admissions des étudiants
|
||||||
# Différents types de voies d'admission:
|
# Différents types de voies d'admission:
|
||||||
# (stocké en texte libre dans la base, mais saisie par menus pour harmoniser)
|
# (stocké en texte libre dans la base, mais saisie par menus pour harmoniser)
|
||||||
|
@ -816,11 +816,22 @@ a.discretelink:hover {
|
|||||||
|
|
||||||
div.sco_help {
|
div.sco_help {
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
|
margin-bottom: 3px;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
color: navy;
|
color: navy;
|
||||||
background-color: rgb(200,200,220);
|
background-color: rgb(200,200,220);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
span.wtf-field ul.errors li {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
.configuration_logo div.img-container {
|
||||||
|
width: 256px;
|
||||||
|
}
|
||||||
|
.configuration_logo div.img-container img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
p.indent {
|
p.indent {
|
||||||
padding-left: 2em;
|
padding-left: 2em;
|
||||||
}
|
}
|
||||||
|
@ -2,32 +2,52 @@
|
|||||||
{% import 'bootstrap/wtf.html' as wtf %}
|
{% import 'bootstrap/wtf.html' as wtf %}
|
||||||
|
|
||||||
{% macro render_field(field) %}
|
{% macro render_field(field) %}
|
||||||
<div>
|
<div>
|
||||||
<span class="wtf-field">{{ field.label }} :</span>
|
<span class="wtf-field">{{ field.label }} :</span>
|
||||||
<span class="wtf-field">{{ field()|safe }}
|
<span class="wtf-field">{{ field()|safe }}
|
||||||
{% if field.errors %}
|
{% if field.errors %}
|
||||||
<ul class=errors>
|
<ul class=errors>
|
||||||
{% for error in field.errors %}
|
{% for error in field.errors %}
|
||||||
<li>{{ error }}</li>
|
<li>{{ error }}</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
{% block app_content %}
|
{% block app_content %}
|
||||||
<h1>Configuration générale</h1>
|
|
||||||
|
|
||||||
<p class="help">Les paramètres donnés ici s'appliquent à tout ScoDoc (tous les départements).</p>
|
{% if scodoc_dept %}
|
||||||
|
<h1>Logos du département {{ scodoc_dept }}</h1>
|
||||||
|
{% else %}
|
||||||
|
<h1>Configuration générale {{ scodoc_dept }}</h1>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<form class="sco-form" action="" method="post" novalidate>
|
<form class="sco-form" action="" method="post" enctype="multipart/form-data" novalidate>
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
|
|
||||||
|
{% if not scodoc_dept %}
|
||||||
|
<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)}}
|
||||||
{# <p>
|
{% endif %}
|
||||||
{{ form.bonus_sport_func_name.label }}<br>
|
|
||||||
{{ form.bonus_sport_func_name() }}
|
<div class="configuration_logo">
|
||||||
</p> #}
|
<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.logo_header', scodoc_dept=scodoc_dept) }}"
|
||||||
|
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.logo_footer', scodoc_dept=g.scodoc_dept) }}"
|
||||||
|
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
|
||||||
|
(paramétrage).<br />On indique ici les valeurs initiales par défaut:
|
||||||
|
</div> -->
|
||||||
<div class="sco-submit">{{ form.submit() }}</div>
|
<div class="sco-submit">{{ form.submit() }}</div>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -30,19 +30,29 @@ Module main: page d'accueil, avec liste des départements
|
|||||||
|
|
||||||
Emmanuel Viennet, 2021
|
Emmanuel Viennet, 2021
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import flash, url_for, redirect, render_template
|
from flask import abort, flash, url_for, redirect, render_template, send_file
|
||||||
from flask import request
|
from flask import request
|
||||||
from flask.app import Flask
|
from flask.app import Flask
|
||||||
from flask_login.utils import login_required
|
from flask_login.utils import login_required
|
||||||
from flask_wtf import FlaskForm
|
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
|
||||||
|
from wtforms.fields import IntegerField
|
||||||
|
from wtforms.fields.simple import BooleanField, StringField, TextAreaField
|
||||||
|
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
|
||||||
|
|
||||||
# from wtforms.validators import DataRequired
|
import app
|
||||||
|
from app.models import Departement, Identite
|
||||||
from app.models import Departement, ScoDocSiteConfig
|
from app.models import FormSemestre, NotesFormsemestreInscription
|
||||||
|
from app.models import ScoDocSiteConfig
|
||||||
import sco_version
|
import sco_version
|
||||||
|
from app.scodoc import sco_logos
|
||||||
from app.scodoc import sco_find_etud
|
from app.scodoc import sco_find_etud
|
||||||
|
from app.scodoc import sco_utils as scu
|
||||||
from app.decorators import admin_required
|
from app.decorators import admin_required
|
||||||
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
|
||||||
@ -72,13 +82,56 @@ def table_etud_in_accessible_depts():
|
|||||||
return sco_find_etud.table_etud_in_accessible_depts(expnom=request.form["expnom"])
|
return sco_find_etud.table_etud_in_accessible_depts(expnom=request.form["expnom"])
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/ScoDoc/get_etud_dept")
|
||||||
|
@login_required
|
||||||
|
def get_etud_dept():
|
||||||
|
"""Returns the dept acronym (eg "GEII") of an etud (identified by etudid,
|
||||||
|
code_nip ou code_ine in the request).
|
||||||
|
API: ramène la chaine brute, sans JSON ou XML.
|
||||||
|
"""
|
||||||
|
if "etudid" in request.args:
|
||||||
|
# zero ou une réponse:
|
||||||
|
etuds = [Identite.query.get(request.args["etudid"])]
|
||||||
|
elif "code_nip" in request.args:
|
||||||
|
# il peut y avoir plusieurs réponses si l'étudiant est passé par plusieurs départements
|
||||||
|
etuds = Identite.query.filter_by(code_nip=request.args["code_nip"]).all()
|
||||||
|
elif "code_ine" in request.args:
|
||||||
|
etuds = Identite.query.filter_by(code_nip=request.args["code_ine"]).all()
|
||||||
|
else:
|
||||||
|
raise BadRequest(
|
||||||
|
"missing argument (expected one among: etudid, code_nip or code_ine)"
|
||||||
|
)
|
||||||
|
if not etuds:
|
||||||
|
raise NotFound("student not found")
|
||||||
|
elif len(etuds) == 1:
|
||||||
|
last_etud = etuds[0]
|
||||||
|
else:
|
||||||
|
# inscriptions dans plusieurs departements: cherche la plus recente
|
||||||
|
last_etud = None
|
||||||
|
last_date = None
|
||||||
|
for etud in etuds:
|
||||||
|
inscriptions = NotesFormsemestreInscription.query.filter_by(
|
||||||
|
etudid=etud.id
|
||||||
|
).all()
|
||||||
|
for ins in inscriptions:
|
||||||
|
date_fin = FormSemestre.query.get(ins.formsemestre_id).date_fin
|
||||||
|
if (last_date is None) or date_fin > last_date:
|
||||||
|
last_date = date_fin
|
||||||
|
last_etud = etud
|
||||||
|
if not last_etud:
|
||||||
|
# est présent dans plusieurs semestres mais inscrit dans aucun !
|
||||||
|
# le choix a peu d'importance...
|
||||||
|
last_etud = etuds[-1]
|
||||||
|
|
||||||
|
return Departement.query.get(last_etud.dept_id).acronym
|
||||||
|
|
||||||
|
|
||||||
# ---- CONFIGURATION
|
# ---- CONFIGURATION
|
||||||
|
|
||||||
|
|
||||||
class ScoDocConfigurationForm(FlaskForm):
|
class ScoDocConfigurationForm(FlaskForm):
|
||||||
"Panneau de configuration général"
|
"Panneau de configuration général"
|
||||||
# très préliminaire ;-)
|
|
||||||
# On veut y mettre la fonction bonus et ensuite les logos
|
|
||||||
bonus_sport_func_name = SelectField(
|
bonus_sport_func_name = SelectField(
|
||||||
label="Fonction de calcul des bonus sport&culture",
|
label="Fonction de calcul des bonus sport&culture",
|
||||||
choices=[
|
choices=[
|
||||||
@ -86,28 +139,104 @@ class ScoDocConfigurationForm(FlaskForm):
|
|||||||
for x in ScoDocSiteConfig.get_bonus_sport_func_names()
|
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 <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")
|
||||||
|
|
||||||
|
|
||||||
|
# Notes pour variables config: (valeurs par défaut des paramètres de département)
|
||||||
|
# Chaines simples
|
||||||
|
# SCOLAR_FONT = "Helvetica"
|
||||||
|
# SCOLAR_FONT_SIZE = 10
|
||||||
|
# SCOLAR_FONT_SIZE_FOOT = 6
|
||||||
|
# INSTITUTION_NAME = "<b>Institut Universitaire de Technologie - Université Georges Perec</b>"
|
||||||
|
# INSTITUTION_ADDRESS = "Web <b>www.sor.bonne.top</b> - 11, rue Simon Crubelier - 75017 Paris"
|
||||||
|
# INSTITUTION_CITY = "Paris"
|
||||||
|
# Textareas:
|
||||||
|
# DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(month)s/%(year)s à %(hour)sh%(minute)s sur %(server_url)s"
|
||||||
|
|
||||||
|
# Booléens
|
||||||
|
# always_require_ine
|
||||||
|
|
||||||
|
# Logos:
|
||||||
|
# LOGO_FOOTER*, LOGO_HEADER*
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/ScoDoc/configuration", methods=["GET", "POST"])
|
@bp.route("/ScoDoc/configuration", methods=["GET", "POST"])
|
||||||
@admin_required
|
@admin_required
|
||||||
def configuration():
|
def configuration():
|
||||||
"Panneau de configuration général"
|
"Panneau de configuration général"
|
||||||
form = ScoDocConfigurationForm(
|
form = ScoDocConfigurationForm(
|
||||||
bonus_sport_func_name=ScoDocSiteConfig.get_bonus_sport_func_name()
|
bonus_sport_func_name=ScoDocSiteConfig.get_bonus_sport_func_name(),
|
||||||
)
|
)
|
||||||
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:
|
||||||
|
sco_logos.store_image(
|
||||||
|
form.logo_header.data, os.path.join(scu.SCODOC_LOGOS_DIR, "logo_header")
|
||||||
|
)
|
||||||
|
if form.logo_footer.data:
|
||||||
|
sco_logos.store_image(
|
||||||
|
form.logo_footer.data, os.path.join(scu.SCODOC_LOGOS_DIR, "logo_footer")
|
||||||
|
)
|
||||||
|
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"))
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"configuration.html",
|
"configuration.html",
|
||||||
title="Configuration ScoDoc",
|
title="Configuration ScoDoc",
|
||||||
form=form,
|
form=form,
|
||||||
# bonus_sport_func_name=ScoDocSiteConfig.get_bonus_sport_func(),
|
scodoc_dept=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _return_logo(logo_type="header", scodoc_dept=""):
|
||||||
|
# stockée dans /opt/scodoc-data/config/logos donc servie manuellement ici
|
||||||
|
filename = sco_logos.get_logo_filename(logo_type, scodoc_dept)
|
||||||
|
if filename:
|
||||||
|
extension = os.path.splitext(filename)[1]
|
||||||
|
return send_file(filename, mimetype=f"image/{extension}")
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/ScoDoc/logo_header")
|
||||||
|
@bp.route("/ScoDoc/<scodoc_dept>/logo_header")
|
||||||
|
def logo_header(scodoc_dept=""):
|
||||||
|
"Image logo header"
|
||||||
|
# "/opt/scodoc-data/config/logos/logo_header")
|
||||||
|
return _return_logo(logo_type="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(logo_type="footer", scodoc_dept=scodoc_dept)
|
||||||
|
|
||||||
|
|
||||||
# essais
|
# essais
|
||||||
# @bp.route("/testlog")
|
# @bp.route("/testlog")
|
||||||
# def testlog():
|
# def testlog():
|
||||||
|
@ -30,7 +30,7 @@ issu de ScoDoc7 / ZScolar.py
|
|||||||
|
|
||||||
Emmanuel Viennet, 2021
|
Emmanuel Viennet, 2021
|
||||||
"""
|
"""
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@ -40,9 +40,12 @@ from zipfile import ZipFile
|
|||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import jsonify, url_for
|
from flask import jsonify, url_for, flash, redirect, render_template
|
||||||
from flask import current_app, g, request
|
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.file import FileField, FileAllowed
|
||||||
|
from wtforms import SubmitField
|
||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from app.decorators import (
|
from app.decorators import (
|
||||||
@ -71,8 +74,8 @@ from app.scodoc.sco_exceptions import (
|
|||||||
)
|
)
|
||||||
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
from app.scodoc.TrivialFormulator import TrivialFormulator, tf_error_message
|
||||||
import sco_version
|
import sco_version
|
||||||
|
import app
|
||||||
from app.scodoc.gen_tables import GenTable
|
from app.scodoc.gen_tables import GenTable
|
||||||
|
|
||||||
from app.scodoc import html_sco_header
|
from app.scodoc import html_sco_header
|
||||||
from app.scodoc import html_sidebar
|
from app.scodoc import html_sidebar
|
||||||
from app.scodoc import imageresize
|
from app.scodoc import imageresize
|
||||||
@ -94,6 +97,7 @@ from app.scodoc import sco_formsemestre_inscriptions
|
|||||||
from app.scodoc import sco_groups
|
from app.scodoc import sco_groups
|
||||||
from app.scodoc import sco_groups_edit
|
from app.scodoc import sco_groups_edit
|
||||||
from app.scodoc import sco_groups_view
|
from app.scodoc import sco_groups_view
|
||||||
|
from app.scodoc import sco_logos
|
||||||
from app.scodoc import sco_news
|
from app.scodoc import sco_news
|
||||||
from app.scodoc import sco_page_etud
|
from app.scodoc import sco_page_etud
|
||||||
from app.scodoc import sco_parcours_dut
|
from app.scodoc import sco_parcours_dut
|
||||||
@ -201,6 +205,66 @@ def doc_preferences(REQUEST):
|
|||||||
return sco_preferences.doc_preferences()
|
return sco_preferences.doc_preferences()
|
||||||
|
|
||||||
|
|
||||||
|
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 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
|
||||||
|
@ -30,9 +30,9 @@ class Config:
|
|||||||
SCODOC_DIR = os.environ.get("SCODOC_DIR", "/opt/scodoc")
|
SCODOC_DIR = os.environ.get("SCODOC_DIR", "/opt/scodoc")
|
||||||
SCODOC_VAR_DIR = os.environ.get("SCODOC_VAR_DIR", "/opt/scodoc-data")
|
SCODOC_VAR_DIR = os.environ.get("SCODOC_VAR_DIR", "/opt/scodoc-data")
|
||||||
SCODOC_LOG_FILE = os.path.join(SCODOC_VAR_DIR, "log", "scodoc.log")
|
SCODOC_LOG_FILE = os.path.join(SCODOC_VAR_DIR, "log", "scodoc.log")
|
||||||
# For legacy ScoDoc7 installs: postgresql user
|
#
|
||||||
SCODOC7_SQL_USER = os.environ.get("SCODOC7_SQL_USER", "www-data")
|
MAX_CONTENT_LENGTH = 10 * 1024 * 1024 # Flask uploads
|
||||||
DEFAULT_SQL_PORT = os.environ.get("DEFAULT_SQL_PORT", "5432")
|
|
||||||
# STATIC_URL_PATH = "/ScoDoc/static"
|
# STATIC_URL_PATH = "/ScoDoc/static"
|
||||||
# static_folder = "stat"
|
# static_folder = "stat"
|
||||||
# SERVER_NAME = os.environ.get("SERVER_NAME")
|
# SERVER_NAME = os.environ.get("SERVER_NAME")
|
||||||
|
@ -23,10 +23,6 @@ CONFIG = CFG()
|
|||||||
|
|
||||||
CONFIG.always_require_ine = 0 # set to 1 if you want to require INE
|
CONFIG.always_require_ine = 0 # set to 1 if you want to require INE
|
||||||
|
|
||||||
# The base URL, use only if you are behind a proxy
|
|
||||||
# eg "https://scodoc.example.net/ScoDoc"
|
|
||||||
CONFIG.ABSOLUTE_URL = ""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ------------- Documents PDF -------------
|
# ------------- Documents PDF -------------
|
||||||
#
|
#
|
||||||
@ -78,6 +74,7 @@ CONFIG.DEFAULT_PDF_FOOTER_TEMPLATE = "Edité par %(scodoc_name)s le %(day)s/%(mo
|
|||||||
#
|
#
|
||||||
# - règle "LMD": capitalisation uniquement des UE avec moy. > 10
|
# - règle "LMD": capitalisation uniquement des UE avec moy. > 10
|
||||||
|
|
||||||
|
# XXX à revoir pour le BUT: variable à intégrer aux parcours
|
||||||
CONFIG.CAPITALIZE_ALL_UES = (
|
CONFIG.CAPITALIZE_ALL_UES = (
|
||||||
True # si vrai, capitalise toutes les UE des semestres validés (règle "LMD").
|
True # si vrai, capitalise toutes les UE des semestres validés (règle "LMD").
|
||||||
)
|
)
|
||||||
@ -86,7 +83,7 @@ CONFIG.CAPITALIZE_ALL_UES = (
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------
|
# -----------------------------------------------------
|
||||||
#
|
#
|
||||||
# -------------- Personnalisation des pages
|
# -------------- Personnalisation des pages (DEPRECATED)
|
||||||
#
|
#
|
||||||
# -----------------------------------------------------
|
# -----------------------------------------------------
|
||||||
# Nom (chemin complet) d'un fichier .html à inclure juste après le <body>
|
# Nom (chemin complet) d'un fichier .html à inclure juste après le <body>
|
||||||
|
Loading…
Reference in New Issue
Block a user