diff --git a/app/models/__init__.py b/app/models/__init__.py
index 4a3328b32..364943aa8 100644
--- a/app/models/__init__.py
+++ b/app/models/__init__.py
@@ -12,7 +12,7 @@ GROUPNAME_STR_LEN = 64
from app.models.raw_sql_init import create_database_functions
from app.models.absences import Absence, AbsenceNotification, BilletAbsence
-
+from app.models.config import ScoDocSiteConfig
from app.models.departements import Departement
from app.models.entreprises import (
@@ -63,7 +63,7 @@ from app.models.notes import (
NotesNotes,
NotesNotesLog,
)
-from app.models.preferences import ScoPreference, ScoDocSiteConfig
+from app.models.preferences import ScoPreference
from app.models.but_refcomp import (
ApcReferentielCompetences,
diff --git a/app/models/preferences.py b/app/models/preferences.py
index 59c82ec80..924f6e604 100644
--- a/app/models/preferences.py
+++ b/app/models/preferences.py
@@ -2,9 +2,8 @@
"""Model : preferences
"""
-from app import db, log
-from app.scodoc import bonus_sport
-from app.scodoc.sco_exceptions import ScoValueError
+
+from app import db
class ScoPreference(db.Model):
@@ -19,108 +18,3 @@ class ScoPreference(db.Model):
name = db.Column(db.String(128), nullable=False, index=True)
value = db.Column(db.Text())
formsemestre_id = db.Column(db.Integer, db.ForeignKey("notes_formsemestre.id"))
-
-
-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}')>"
-
- 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
- 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_")
- ]
- )
diff --git a/app/scodoc/sco_apogee_csv.py b/app/scodoc/sco_apogee_csv.py
index f97cc895e..833a7841f 100644
--- a/app/scodoc/sco_apogee_csv.py
+++ b/app/scodoc/sco_apogee_csv.py
@@ -95,30 +95,21 @@ from flask import send_file
# Pour la détection auto de l'encodage des fichiers Apogée:
from chardet import detect as chardet_detect
+from app.models.config import ScoDocSiteConfig
import app.scodoc.sco_utils as scu
-import app.scodoc.notesdb as ndb
from app import log
from app.scodoc.sco_exceptions import ScoValueError, ScoFormatError
from app.scodoc.gen_tables import GenTable
from app.scodoc.sco_vdi import ApoEtapeVDI
from app.scodoc.sco_codes_parcours import code_semestre_validant
from app.scodoc.sco_codes_parcours import (
- ADC,
- ADJ,
- ADM,
- AJ,
- ATB,
- ATJ,
- ATT,
- CMP,
DEF,
+ DEM,
NAR,
RAT,
)
from app.scodoc import sco_cache
-from app.scodoc import sco_codes_parcours
from app.scodoc import sco_formsemestre
-from app.scodoc import sco_formsemestre_status
from app.scodoc import sco_parcours_dut
from app.scodoc import sco_etud
@@ -132,24 +123,6 @@ APO_SEP = "\t"
APO_NEWLINE = "\r\n"
-def code_scodoc_to_apo(code):
- """Conversion code jury ScoDoc en code Apogée"""
- return {
- ATT: "AJAC",
- ATB: "AJAC",
- ATJ: "AJAC",
- ADM: "ADM",
- ADJ: "ADM",
- ADC: "ADMC",
- AJ: "AJ",
- CMP: "COMP",
- "DEM": "NAR",
- DEF: "NAR",
- NAR: "NAR",
- RAT: "ATT",
- }.get(code, "DEF")
-
-
def _apo_fmt_note(note):
"Formatte une note pour Apogée (séparateur décimal: ',')"
if not note and isinstance(note, float):
@@ -449,7 +422,7 @@ class ApoEtud(dict):
N=_apo_fmt_note(ue_status["moy"]),
B=20,
J="",
- R=code_scodoc_to_apo(code_decision_ue),
+ R=ScoDocSiteConfig.get_code_apo(code_decision_ue),
M="",
)
else:
@@ -475,13 +448,9 @@ class ApoEtud(dict):
def comp_elt_semestre(self, nt, decision, etudid):
"""Calcul résultat apo semestre"""
# resultat du semestre
- decision_apo = code_scodoc_to_apo(decision["code"])
+ decision_apo = ScoDocSiteConfig.get_code_apo(decision["code"])
note = nt.get_etud_moy_gen(etudid)
- if (
- decision_apo == "DEF"
- or decision["code"] == "DEM"
- or decision["code"] == DEF
- ):
+ if decision_apo == "DEF" or decision["code"] == DEM or decision["code"] == DEF:
note_str = "0,01" # note non nulle pour les démissionnaires
else:
note_str = _apo_fmt_note(note)
@@ -520,21 +489,21 @@ class ApoEtud(dict):
# ou jury intermediaire et etudiant non redoublant...
return self.comp_elt_semestre(cur_nt, cur_decision, etudid)
- decision_apo = code_scodoc_to_apo(cur_decision["code"])
+ decision_apo = ScoDocSiteConfig.get_code_apo(cur_decision["code"])
autre_nt = sco_cache.NotesTableCache.get(autre_sem["formsemestre_id"])
autre_decision = autre_nt.get_etud_decision_sem(etudid)
if not autre_decision:
# pas de decision dans l'autre => pas de résultat annuel
return VOID_APO_RES
- autre_decision_apo = code_scodoc_to_apo(autre_decision["code"])
+ autre_decision_apo = ScoDocSiteConfig.get_code_apo(autre_decision["code"])
if (
autre_decision_apo == "DEF"
- or autre_decision["code"] == "DEM"
+ or autre_decision["code"] == DEM
or autre_decision["code"] == DEF
) or (
decision_apo == "DEF"
- or cur_decision["code"] == "DEM"
+ or cur_decision["code"] == DEM
or cur_decision["code"] == DEF
):
note_str = "0,01" # note non nulle pour les démissionnaires
diff --git a/app/scodoc/sco_codes_parcours.py b/app/scodoc/sco_codes_parcours.py
index 4ff29bb79..38d3e4fe8 100644
--- a/app/scodoc/sco_codes_parcours.py
+++ b/app/scodoc/sco_codes_parcours.py
@@ -125,6 +125,7 @@ CMP = "CMP" # utile pour UE seulement (indique UE acquise car semestre acquis)
NAR = "NAR"
RAT = "RAT" # en attente rattrapage, sera ATT dans Apogée
DEF = "DEF" # défaillance (n'est pas un code jury dans scodoc mais un état, comme inscrit ou demission)
+DEM = "DEM"
# codes actions
REDOANNEE = "REDOANNEE" # redouble annee (va en Sn-1)
diff --git a/app/scodoc/sco_groups.py b/app/scodoc/sco_groups.py
index 8248491af..87d50e3f7 100644
--- a/app/scodoc/sco_groups.py
+++ b/app/scodoc/sco_groups.py
@@ -87,8 +87,10 @@ groupEditor = ndb.EditableTable(
group_list = groupEditor.list
-def get_group(group_id):
+def get_group(group_id: int):
"""Returns group object, with partition"""
+ if not isinstance(group_id, int):
+ raise ValueError("invalid group_id (%s)" % group_id)
r = ndb.SimpleDictFetch(
"""SELECT gd.id AS group_id, gd.*, p.id AS partition_id, p.*
FROM group_descr gd, partition p
@@ -687,6 +689,10 @@ def setGroups(
group_id = fs[0].strip()
if not group_id:
continue
+ try:
+ group_id = int(group_id)
+ except ValueError as exc:
+ raise ValueError("invalid group_id: not an integer")
group = get_group(group_id)
# Anciens membres du groupe:
old_members = get_group_members(group_id)
diff --git a/app/scodoc/sco_portal_apogee.py b/app/scodoc/sco_portal_apogee.py
index f78e90034..836be2ed9 100644
--- a/app/scodoc/sco_portal_apogee.py
+++ b/app/scodoc/sco_portal_apogee.py
@@ -169,7 +169,9 @@ def get_inscrits_etape(code_etape, anneeapogee=None, ntrials=2):
if doc:
break
if not doc:
- raise ScoValueError("pas de réponse du portail ! (timeout=%s)" % portal_timeout)
+ raise ScoValueError(
+ f"pas de réponse du portail !
(timeout={portal_timeout}, requête: {req})"
+ )
etuds = _normalize_apo_fields(xml_to_list_of_dicts(doc, req=req))
# Filtre sur annee inscription Apogee:
diff --git a/app/templates/configuration.html b/app/templates/configuration.html
index b874d48db..f9d060ad8 100644
--- a/app/templates/configuration.html
+++ b/app/templates/configuration.html
@@ -92,6 +92,8 @@
configuration des codes de décision