forked from ScoDoc/ScoDoc
Add get_instance method to all ScoDoc models
This commit is contained in:
parent
98127e7c1d
commit
24ccd8f9f7
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
from flask import abort, g
|
from flask import abort, g
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
|
import app
|
||||||
from app import db
|
from app import db
|
||||||
|
|
||||||
CODE_STR_LEN = 16 # chaine pour les codes
|
CODE_STR_LEN = 16 # chaine pour les codes
|
||||||
@ -133,11 +134,22 @@ class ScoDocModel(db.Model):
|
|||||||
return None
|
return None
|
||||||
abort(404, "oid invalide")
|
abort(404, "oid invalide")
|
||||||
|
|
||||||
query = (
|
if g.scodoc_dept:
|
||||||
cls.query.filter_by(id=oid, dept_id=g.scodoc_dept_id)
|
if hasattr(cls, "_sco_dept_relations"):
|
||||||
if g.scodoc_dept
|
# Quand dept_id n'est pas dans le modèle courant,
|
||||||
else cls.query.filter_by(id=oid)
|
# cet attribut indique la liste des tables à joindre pour
|
||||||
)
|
# obtenir le departement.
|
||||||
|
query = cls.query.filter_by(id=oid)
|
||||||
|
for relation_name in cls._sco_dept_relations:
|
||||||
|
query = query.join(getattr(app.models, relation_name))
|
||||||
|
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
||||||
|
else:
|
||||||
|
# département accessible dans le modèle courant
|
||||||
|
query = cls.query.filter_by(id=oid, dept_id=g.scodoc_dept_id)
|
||||||
|
else:
|
||||||
|
# Pas de département courant (API non départementale)
|
||||||
|
query = cls.query.filter_by(id=oid)
|
||||||
|
|
||||||
if accept_none:
|
if accept_none:
|
||||||
return query.first()
|
return query.first()
|
||||||
return query.first_or_404()
|
return query.first_or_404()
|
||||||
|
@ -7,7 +7,10 @@ from app import db
|
|||||||
|
|
||||||
|
|
||||||
class Absence(db.Model):
|
class Absence(db.Model):
|
||||||
"""une absence (sur une demi-journée)"""
|
"""LEGACY
|
||||||
|
Ce modèle n'est PLUS UTILISE depuis ScoDoc 9.6 et remplacé par assiduité.
|
||||||
|
une absence (sur une demi-journée)
|
||||||
|
"""
|
||||||
|
|
||||||
__tablename__ = "absences"
|
__tablename__ = "absences"
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
@ -61,6 +61,8 @@ class ApcValidationRCUE(ScoDocModel):
|
|||||||
ue2 = db.relationship("UniteEns", foreign_keys=ue2_id)
|
ue2 = db.relationship("UniteEns", foreign_keys=ue2_id)
|
||||||
parcour = db.relationship("ApcParcours")
|
parcour = db.relationship("ApcParcours")
|
||||||
|
|
||||||
|
_sco_dept_relations = ("Identite",) # pour accéder au département
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"""<{self.__class__.__name__} {self.id} {self.etud} {
|
return f"""<{self.__class__.__name__} {self.id} {self.etud} {
|
||||||
self.ue1}/{self.ue2}:{self.code!r}>"""
|
self.ue1}/{self.ue2}:{self.code!r}>"""
|
||||||
@ -154,6 +156,8 @@ class ApcValidationAnnee(ScoDocModel):
|
|||||||
etud = db.relationship("Identite", backref="apc_validations_annees")
|
etud = db.relationship("Identite", backref="apc_validations_annees")
|
||||||
formsemestre = db.relationship("FormSemestre", backref="apc_validations_annees")
|
formsemestre = db.relationship("FormSemestre", backref="apc_validations_annees")
|
||||||
|
|
||||||
|
_sco_dept_relations = ("Identite",) # pour accéder au département
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"""<{self.__class__.__name__} {self.id} {self.etud
|
return f"""<{self.__class__.__name__} {self.id} {self.etud
|
||||||
} BUT{self.ordre}/{self.annee_scolaire}:{self.code!r}>"""
|
} BUT{self.ordre}/{self.annee_scolaire}:{self.code!r}>"""
|
||||||
@ -317,6 +321,8 @@ class ValidationDUT120(ScoDocModel):
|
|||||||
etud = db.relationship("Identite", backref="validations_dut120")
|
etud = db.relationship("Identite", backref="validations_dut120")
|
||||||
formsemestre = db.relationship("FormSemestre", backref="validations_dut120")
|
formsemestre = db.relationship("FormSemestre", backref="validations_dut120")
|
||||||
|
|
||||||
|
_sco_dept_relations = ("Identite",) # pour accéder au département
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"""<ValidationDUT120 {self.etud}>"""
|
return f"""<ValidationDUT120 {self.etud}>"""
|
||||||
|
|
||||||
|
@ -1080,8 +1080,9 @@ class Admission(models.ScoDocModel):
|
|||||||
return args_dict
|
return args_dict
|
||||||
|
|
||||||
|
|
||||||
# Suivi scolarité / débouchés
|
class ItemSuivi(models.ScoDocModel):
|
||||||
class ItemSuivi(db.Model):
|
"""Suivi scolarité / débouchés"""
|
||||||
|
|
||||||
__tablename__ = "itemsuivi"
|
__tablename__ = "itemsuivi"
|
||||||
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
@ -1093,6 +1094,8 @@ class ItemSuivi(db.Model):
|
|||||||
item_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
item_date = db.Column(db.DateTime(timezone=True), server_default=db.func.now())
|
||||||
situation = db.Column(db.Text)
|
situation = db.Column(db.Text)
|
||||||
|
|
||||||
|
_sco_dept_relations = ("Identite",) # accès au dept_id
|
||||||
|
|
||||||
|
|
||||||
class ItemSuiviTag(db.Model):
|
class ItemSuiviTag(db.Model):
|
||||||
__tablename__ = "itemsuivi_tags"
|
__tablename__ = "itemsuivi_tags"
|
||||||
@ -1114,7 +1117,7 @@ itemsuivi_tags_assoc = db.Table(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class EtudAnnotation(db.Model):
|
class EtudAnnotation(models.ScoDocModel):
|
||||||
"""Annotation sur un étudiant"""
|
"""Annotation sur un étudiant"""
|
||||||
|
|
||||||
__tablename__ = "etud_annotations"
|
__tablename__ = "etud_annotations"
|
||||||
@ -1125,6 +1128,8 @@ class EtudAnnotation(db.Model):
|
|||||||
author = db.Column(db.Text) # le pseudo (user_name), was zope_authenticated_user
|
author = db.Column(db.Text) # le pseudo (user_name), was zope_authenticated_user
|
||||||
comment = db.Column(db.Text)
|
comment = db.Column(db.Text)
|
||||||
|
|
||||||
|
_sco_dept_relations = ("Identite",) # accès au dept_id
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
"""Représentation dictionnaire."""
|
"""Représentation dictionnaire."""
|
||||||
e = dict(self.__dict__)
|
e = dict(self.__dict__)
|
||||||
|
@ -60,6 +60,8 @@ class Evaluation(models.ScoDocModel):
|
|||||||
numero = db.Column(db.Integer, nullable=False, default=0)
|
numero = db.Column(db.Integer, nullable=False, default=0)
|
||||||
ues = db.relationship("UniteEns", secondary="evaluation_ue_poids", viewonly=True)
|
ues = db.relationship("UniteEns", secondary="evaluation_ue_poids", viewonly=True)
|
||||||
|
|
||||||
|
_sco_dept_relations = ("ModuleImpl", "FormSemestre") # accès au dept_id
|
||||||
|
|
||||||
EVALUATION_NORMALE = 0 # valeurs stockées en base, ne pas changer !
|
EVALUATION_NORMALE = 0 # valeurs stockées en base, ne pas changer !
|
||||||
EVALUATION_RATTRAPAGE = 1
|
EVALUATION_RATTRAPAGE = 1
|
||||||
EVALUATION_SESSION2 = 2
|
EVALUATION_SESSION2 = 2
|
||||||
|
@ -7,7 +7,7 @@ from flask_sqlalchemy.query import Query
|
|||||||
import app
|
import app
|
||||||
from app import db
|
from app import db
|
||||||
from app.comp import df_cache
|
from app.comp import df_cache
|
||||||
from app.models import SHORT_STR_LEN
|
from app.models import ScoDocModel, SHORT_STR_LEN
|
||||||
from app.models.but_refcomp import (
|
from app.models.but_refcomp import (
|
||||||
ApcAnneeParcours,
|
ApcAnneeParcours,
|
||||||
ApcCompetence,
|
ApcCompetence,
|
||||||
@ -23,7 +23,7 @@ from app.scodoc import sco_utils as scu
|
|||||||
from app.scodoc.codes_cursus import UE_STANDARD
|
from app.scodoc.codes_cursus import UE_STANDARD
|
||||||
|
|
||||||
|
|
||||||
class Formation(db.Model):
|
class Formation(ScoDocModel):
|
||||||
"""Programme pédagogique d'une formation"""
|
"""Programme pédagogique d'une formation"""
|
||||||
|
|
||||||
__tablename__ = "notes_formations"
|
__tablename__ = "notes_formations"
|
||||||
@ -297,7 +297,7 @@ class Formation(db.Model):
|
|||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
class Matiere(db.Model):
|
class Matiere(ScoDocModel):
|
||||||
"""Matières: regroupe les modules d'une UE
|
"""Matières: regroupe les modules d'une UE
|
||||||
La matière a peu d'utilité en dehors de la présentation des modules
|
La matière a peu d'utilité en dehors de la présentation des modules
|
||||||
d'une UE.
|
d'une UE.
|
||||||
@ -313,6 +313,7 @@ class Matiere(db.Model):
|
|||||||
numero = db.Column(db.Integer, nullable=False, default=0) # ordre de présentation
|
numero = db.Column(db.Integer, nullable=False, default=0) # ordre de présentation
|
||||||
|
|
||||||
modules = db.relationship("Module", lazy="dynamic", backref="matiere")
|
modules = db.relationship("Module", lazy="dynamic", backref="matiere")
|
||||||
|
_sco_dept_relations = ("UniteEns", "Formation") # accès au dept_id
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"""<{self.__class__.__name__}(id={self.id}, ue_id={
|
return f"""<{self.__class__.__name__}(id={self.id}, ue_id={
|
||||||
|
@ -54,6 +54,7 @@ class Partition(ScoDocModel):
|
|||||||
cascade="all, delete-orphan",
|
cascade="all, delete-orphan",
|
||||||
order_by="GroupDescr.numero, GroupDescr.group_name",
|
order_by="GroupDescr.numero, GroupDescr.group_name",
|
||||||
)
|
)
|
||||||
|
_sco_dept_relations = ("FormSemestre",)
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(Partition, self).__init__(**kwargs)
|
super(Partition, self).__init__(**kwargs)
|
||||||
@ -225,6 +226,11 @@ class GroupDescr(ScoDocModel):
|
|||||||
numero = db.Column(db.Integer, nullable=False, default=0)
|
numero = db.Column(db.Integer, nullable=False, default=0)
|
||||||
"Numero = ordre de presentation"
|
"Numero = ordre de presentation"
|
||||||
|
|
||||||
|
_sco_dept_relations = (
|
||||||
|
"Partition",
|
||||||
|
"FormSemestre",
|
||||||
|
)
|
||||||
|
|
||||||
etuds = db.relationship(
|
etuds = db.relationship(
|
||||||
"Identite",
|
"Identite",
|
||||||
secondary="group_membership",
|
secondary="group_membership",
|
||||||
|
@ -60,6 +60,8 @@ class ModuleImpl(ScoDocModel):
|
|||||||
)
|
)
|
||||||
"enseignants du module (sans le responsable)"
|
"enseignants du module (sans le responsable)"
|
||||||
|
|
||||||
|
_sco_dept_relations = ("FormSemestre",) # accès au dept_id
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__} {self.id} module={repr(self.module)}>"
|
return f"<{self.__class__.__name__} {self.id} module={repr(self.module)}>"
|
||||||
|
|
||||||
|
@ -75,6 +75,8 @@ class Module(models.ScoDocModel):
|
|||||||
backref=db.backref("modules", lazy=True),
|
backref=db.backref("modules", lazy=True),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_sco_dept_relations = "Formation" # accès au dept_id
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.ue_coefs = []
|
self.ue_coefs = []
|
||||||
super(Module, self).__init__(**kwargs)
|
super(Module, self).__init__(**kwargs)
|
||||||
|
@ -5,11 +5,12 @@
|
|||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from app import db
|
from app import db
|
||||||
|
from app import models
|
||||||
from app.scodoc import safehtml
|
from app.scodoc import safehtml
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
|
||||||
|
|
||||||
class BulAppreciations(db.Model):
|
class BulAppreciations(models.ScoDocModel):
|
||||||
"""Appréciations sur bulletins"""
|
"""Appréciations sur bulletins"""
|
||||||
|
|
||||||
__tablename__ = "notes_appreciations"
|
__tablename__ = "notes_appreciations"
|
||||||
@ -27,6 +28,8 @@ class BulAppreciations(db.Model):
|
|||||||
author = db.Column(db.Text) # le pseudo (user_name), sans contrainte
|
author = db.Column(db.Text) # le pseudo (user_name), sans contrainte
|
||||||
comment = db.Column(db.Text) # texte libre
|
comment = db.Column(db.Text) # texte libre
|
||||||
|
|
||||||
|
_sco_dept_relations = ("Identite",) # accès au dept_id
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_appreciations_list(
|
def get_appreciations_list(
|
||||||
cls, formsemestre_id: int, etudid: int
|
cls, formsemestre_id: int, etudid: int
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
"""Model : preferences
|
"""Model : preferences
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from app import db
|
from app import db, models
|
||||||
|
|
||||||
|
|
||||||
class ScoPreference(db.Model):
|
class ScoPreference(models.ScoDocModel):
|
||||||
"""ScoDoc preferences (par département)"""
|
"""ScoDoc preferences (par département)"""
|
||||||
|
|
||||||
__tablename__ = "sco_prefs"
|
__tablename__ = "sco_prefs"
|
||||||
@ -19,5 +19,8 @@ class ScoPreference(db.Model):
|
|||||||
value = db.Column(db.Text())
|
value = db.Column(db.Text())
|
||||||
formsemestre_id = db.Column(db.Integer, db.ForeignKey("notes_formsemestre.id"))
|
formsemestre_id = db.Column(db.Integer, db.ForeignKey("notes_formsemestre.id"))
|
||||||
|
|
||||||
|
_sco_dept_relations = ("FormSemestre",) # accès au dept_id
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__} {self.id} {self.departement.acronym} {self.name}={self.value}>"
|
return f"""<{self.__class__.__name__} {self.id} {self.departement.acronym
|
||||||
|
} {self.name}={self.value}>"""
|
||||||
|
@ -767,15 +767,16 @@ def scolars_import_admission(
|
|||||||
)
|
)
|
||||||
|
|
||||||
for group_id in group_ids:
|
for group_id in group_ids:
|
||||||
group = db.session.get(GroupDescr, group_id)
|
group: GroupDescr = GroupDescr.get_instance(group_id)
|
||||||
if group.partition.groups_editable:
|
if group.partition.groups_editable:
|
||||||
sco_groups.change_etud_group_in_partition(
|
sco_groups.change_etud_group_in_partition(
|
||||||
args["etudid"], group
|
args["etudid"], group
|
||||||
)
|
)
|
||||||
else:
|
elif not group.partition.is_parcours:
|
||||||
log("scolars_import_admission: partition non editable")
|
log("scolars_import_admission: partition non editable")
|
||||||
diag.append(
|
diag.append(
|
||||||
f"Attention: partition {group.partition} non editable (ignorée)"
|
f"""Attention: partition {
|
||||||
|
group.partition} (g{group.id}) non editable et ignorée"""
|
||||||
)
|
)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# -*- mode: python -*-
|
# -*- mode: python -*-
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
SCOVERSION = "9.7.4"
|
SCOVERSION = "9.7.5"
|
||||||
|
|
||||||
SCONAME = "ScoDoc"
|
SCONAME = "ScoDoc"
|
||||||
|
|
||||||
|
@ -267,9 +267,7 @@ class ScoFake(object):
|
|||||||
responsables = (self.default_user.id,)
|
responsables = (self.default_user.id,)
|
||||||
titre = titre or "sans titre"
|
titre = titre or "sans titre"
|
||||||
oid = sco_formsemestre.do_formsemestre_create(locals())
|
oid = sco_formsemestre.do_formsemestre_create(locals())
|
||||||
oids = sco_formsemestre.do_formsemestre_list(
|
oids = sco_formsemestre.do_formsemestre_list(args={"formsemestre_id": oid})
|
||||||
args={"formsemestre_id": oid}
|
|
||||||
) # API inconsistency
|
|
||||||
if not oids:
|
if not oids:
|
||||||
raise ScoValueError("formsemestre not created !")
|
raise ScoValueError("formsemestre not created !")
|
||||||
return oid
|
return oid
|
||||||
|
@ -42,8 +42,7 @@ DEPT = TestConfig.DEPT_TEST
|
|||||||
def test_formsemestres_associate_new_version(test_client):
|
def test_formsemestres_associate_new_version(test_client):
|
||||||
"""Test association à une nouvelle version du programme"""
|
"""Test association à une nouvelle version du programme"""
|
||||||
app.set_sco_dept(DEPT)
|
app.set_sco_dept(DEPT)
|
||||||
# Construit la base de test GB une seule fois
|
# Construit la base de test GB
|
||||||
# puis lance les tests de jury
|
|
||||||
doc, formation, formsemestre_titres = yaml_setup.setup_from_yaml(
|
doc, formation, formsemestre_titres = yaml_setup.setup_from_yaml(
|
||||||
"tests/ressources/yaml/simple_formsemestres.yaml"
|
"tests/ressources/yaml/simple_formsemestres.yaml"
|
||||||
)
|
)
|
||||||
|
49
tests/unit/test_models.py
Normal file
49
tests/unit/test_models.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
""" Test méthodes génériques sur les modèles ScoDoc
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from flask import g
|
||||||
|
|
||||||
|
import app
|
||||||
|
from app import db
|
||||||
|
from app.models import Departement, GroupDescr
|
||||||
|
|
||||||
|
from config import TestConfig
|
||||||
|
from tests.unit import yaml_setup
|
||||||
|
|
||||||
|
DEPT = TestConfig.DEPT_TEST
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_instance(test_client):
|
||||||
|
"""Test accès instance avec ou sans dept"""
|
||||||
|
assert DEPT
|
||||||
|
app.set_sco_dept(DEPT)
|
||||||
|
# Création d'un autre départment
|
||||||
|
other_dept = Departement(acronym="X666")
|
||||||
|
db.session.add(other_dept)
|
||||||
|
db.session.flush()
|
||||||
|
# Crée qq semestres...
|
||||||
|
doc, formation, formsemestre_titres = yaml_setup.setup_from_yaml(
|
||||||
|
"tests/ressources/yaml/simple_formsemestres.yaml"
|
||||||
|
)
|
||||||
|
for formsemestre_titre in formsemestre_titres:
|
||||||
|
formsemestre = yaml_setup.create_formsemestre_with_etuds(
|
||||||
|
doc, formation, formsemestre_titre
|
||||||
|
)
|
||||||
|
assert formsemestre
|
||||||
|
# prend l'exemple de GroupDescr
|
||||||
|
# Crée un formsemestre et un groupe
|
||||||
|
gr = GroupDescr.query.first()
|
||||||
|
assert gr
|
||||||
|
oid = gr.id
|
||||||
|
# Accès sans département (comme le fait l'API non départementale)
|
||||||
|
g.scodoc_dept = None
|
||||||
|
g.scodoc_dept_id = -1 # invalide
|
||||||
|
assert GroupDescr.get_instance(oid, accept_none=True).id == oid
|
||||||
|
# Accès avec le bon département
|
||||||
|
app.set_sco_dept(DEPT)
|
||||||
|
assert GroupDescr.get_instance(oid, accept_none=True).id == oid
|
||||||
|
# Accès avec un autre département
|
||||||
|
app.set_sco_dept(other_dept.acronym)
|
||||||
|
assert GroupDescr.get_instance(oid, accept_none=True) is None
|
Loading…
Reference in New Issue
Block a user