Morceaux manquants.

This commit is contained in:
Emmanuel Viennet 2022-01-21 10:27:47 +01:00
parent 92bdf1bb8b
commit 51933d057b
4 changed files with 278 additions and 1 deletions

View File

@ -0,0 +1,76 @@
# -*- mode: python -*-
# -*- coding: utf-8 -*-
##############################################################################
#
# ScoDoc
#
# Copyright (c) 1999 - 2022 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
#
##############################################################################
"""
Formulaires configuration Exports Apogée (codes)
"""
import re
from flask import flash, url_for, redirect, render_template
from flask_wtf import FlaskForm
from wtforms import SubmitField, validators
from wtforms.fields.simple import StringField
from app import models
from app.models import ScoDocSiteConfig
from app.models import SHORT_STR_LEN
from app.scodoc import sco_utils as scu
def _build_code_field(code):
return StringField(
label=code,
validators=[
validators.regexp(
r"^[A-Z0-9_]*$",
message="Ne doit comporter que majuscules et des chiffres",
),
validators.Length(
max=SHORT_STR_LEN,
message=f"L'acronyme ne doit pas dépasser {SHORT_STR_LEN} caractères",
),
validators.DataRequired("code requis"),
],
)
class CodesDecisionsForm(FlaskForm):
ADC = _build_code_field("ADC")
ADJ = _build_code_field("ADJ")
ADM = _build_code_field("ADM")
AJ = _build_code_field("AJ")
ATB = _build_code_field("ATB")
ATJ = _build_code_field("ATJ")
ATT = _build_code_field("ATT")
CMP = _build_code_field("CMP")
DEF = _build_code_field("DEF")
DEM = _build_code_field("DEF")
NAR = _build_code_field("NAR")
RAT = _build_code_field("RAT")
submit = SubmitField("Valider")
cancel = SubmitField("Annuler", render_kw={"formnovalidate": True})

178
app/models/config.py Normal file
View File

@ -0,0 +1,178 @@
# -*- coding: UTF-8 -*
"""Model : site config WORK IN PROGRESS #WIP
"""
from app import db, log
from app.scodoc import bonus_sport
from app.scodoc.sco_exceptions import ScoValueError
import functools
from app.scodoc.sco_codes_parcours import (
ADC,
ADJ,
ADM,
AJ,
ATB,
ATJ,
ATT,
CMP,
DEF,
DEM,
NAR,
RAT,
)
CODES_SCODOC_TO_APO = {
ADC: "ADMC",
ADJ: "ADM",
ADM: "ADM",
AJ: "AJ",
ATB: "AJAC",
ATJ: "AJAC",
ATT: "AJAC",
CMP: "COMP",
DEF: "NAR",
DEM: "NAR",
NAR: "NAR",
RAT: "ATT",
}
def code_scodoc_to_apo_default(code):
"""Conversion code jury ScoDoc en code Apogée
(codes par défaut, c'est configurable via ScoDocSiteConfig.get_code_apo)
"""
return CODES_SCODOC_TO_APO.get(code, "DEF")
class ScoDocSiteConfig(db.Model):
"""Config. d'un site
Nouveau en ScoDoc 9: va regrouper les paramètres qui dans les versions
antérieures étaient dans scodoc_config.py
"""
__tablename__ = "scodoc_site_config"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), nullable=False, index=True)
value = db.Column(db.Text())
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):
self.name = name
self.value = value
def __repr__(self):
return f"<{self.__class__.__name__}('{self.name}', '{self.value}')>"
@classmethod
def get_dict(cls) -> dict:
"Returns all data as a dict name = value"
return {
c.name: cls.NAMES.get(c.name, lambda x: x)(c.value)
for c in ScoDocSiteConfig.query.all()
}
@classmethod
def set_bonus_sport_func(cls, func_name):
"""Record bonus_sport config.
If func_name not defined, raise NameError
"""
if func_name not in cls.get_bonus_sport_func_names():
raise NameError("invalid function name for bonus_sport")
c = ScoDocSiteConfig.query.filter_by(name=cls.BONUS_SPORT).first()
if c:
log("setting to " + func_name)
c.value = func_name
else:
c = ScoDocSiteConfig(cls.BONUS_SPORT, func_name)
db.session.add(c)
db.session.commit()
@classmethod
def get_bonus_sport_func_name(cls):
"""Get configured bonus function name, or None if None."""
f = cls.get_bonus_sport_func_from_name()
if f is None:
return ""
else:
return f.__name__
@classmethod
def get_bonus_sport_func(cls):
"""Get configured bonus function, or None if None."""
return cls.get_bonus_sport_func_from_name()
@classmethod
def get_bonus_sport_func_from_name(cls, func_name=None):
"""returns bonus func with specified name.
If name not specified, return the configured function.
None if no bonus function configured.
Raises ScoValueError if func_name not found in module bonus_sport.
"""
if func_name is None:
c = ScoDocSiteConfig.query.filter_by(name=cls.BONUS_SPORT).first()
if c is None:
return None
func_name = c.value
if func_name == "": # pas de bonus défini
return None
try:
return getattr(bonus_sport, func_name)
except AttributeError:
raise ScoValueError(
f"""Fonction de calcul maison inexistante: {func_name}.
(contacter votre administrateur local)."""
)
@classmethod
def get_bonus_sport_func_names(cls):
"""List available functions names
(starting with empty string to represent "no bonus function").
"""
return [""] + sorted(
[
getattr(bonus_sport, name).__name__
for name in dir(bonus_sport)
if name.startswith("bonus_")
]
)
@classmethod
def get_code_apo(cls, code: str) -> str:
"""La représentation d'un code pour les exports Apogée.
Par exemple, à l'iUT du H., le code ADM est réprésenté par VAL
Les codes par défaut sont donnés dans sco_apogee_csv.
"""
cfg = ScoDocSiteConfig.query.filter_by(name=code).first()
if not cfg:
code_apo = code_scodoc_to_apo_default(code)
else:
code_apo = cfg.value
return code_apo
@classmethod
def set_code_apo(cls, code: str, code_apo: str):
"""Enregistre nouvelle représentation du code"""
if code_apo != cls.get_code_apo(code):
cfg = ScoDocSiteConfig.query.filter_by(name=code).first()
if cfg is None:
cfg = ScoDocSiteConfig(code, code_apo)
else:
cfg.value = code_apo
db.session.add(cfg)
db.session.commit()

View File

@ -0,0 +1,23 @@
{% extends "base.html" %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block app_content %}
<h1>Configuration des codes de décision exportés vers Apogée</h1>
<div class="help">
<p>Ces codes (ADM, AJ, ...) sont utilisés pour représenter les décisions de jury
et les validations de semestres ou d'UE. les valeurs indiquées ici sont utilisées
dans les exports Apogée.
<p>
<p>Ne les modifier que si vous savez ce que vous faites !
</p>
</div>
<div class="row">
<div class="col-md-4">
{{ wtf.quick_form(form) }}
</div>
</div>
{% endblock %}

View File

@ -1,7 +1,7 @@
# -*- mode: python -*- # -*- mode: python -*-
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
SCOVERSION = "9.1.29" SCOVERSION = "9.1.30"
SCONAME = "ScoDoc" SCONAME = "ScoDoc"