DocScoDoc/tools/fakedatabase/create_test_api_database.py

284 lines
9.2 KiB
Python

# -*- coding: utf-8 -*-
"""Initialise une base pour les tests de l'API ScoDoc 9
Création des départements, formations, semestres, étudiants, groupes...
utilisation:
1) modifier /opt/scodoc/.env pour indiquer
FLASK_ENV=test_api
FLASK_DEBUG=1
2) En tant qu'utilisateur scodoc, lancer:
tools/create_database.sh SCODOC_TEST_API
flask db upgrade
flask sco-db-init --erase
flask init-test-database
3) relancer ScoDoc:
flask run --host 0.0.0.0
4) lancer client de test
"""
import datetime
import random
import sys
from app.auth.models import Role, User
from app import models
from app.models import Departement, Formation, FormSemestre, Identite, ModuleImpl
from app import db
from app.scodoc import (
sco_cache,
sco_evaluation_db,
sco_formations,
sco_formsemestre_inscriptions,
sco_groups,
)
from app.scodoc.sco_permissions import Permission
from app.scodoc.sco_saisie_notes import notes_add
from tools.fakeportal.gen_nomprenoms import nomprenom
random.seed(12345678) # tests reproductibles
# La formation à utiliser:
FORMATION_XML_FILENAME = "tests/ressources/formations/scodoc_formation_RT_BUT_RT_v1.xml"
def init_departement(acronym: str) -> Departement:
"Create dept, and switch context into it."
import app as mapp
dept = Departement(acronym=acronym)
db.session.add(dept)
mapp.set_sco_dept(acronym)
db.session.commit()
return dept
def import_formation() -> Formation:
"""Import formation from XML.
Returns formation_id
"""
with open(FORMATION_XML_FILENAME) as f:
doc = f.read()
# --- Création de la formation
f = sco_formations.formation_import_xml(doc)
return Formation.query.get(f[0])
def create_users(dept: Departement) -> tuple:
"""créé les utilisateurs nécessaires aux tests"""
# Un utilisateur "test" (passwd test) pouvant lire l'API
user = User(user_name="test", nom="Doe", prenom="John", dept=dept.acronym)
user.set_password("test")
db.session.add(user)
# Le rôle standard LecteurAPI existe déjà
role = Role.query.filter_by(name="LecteurAPI").first()
if role is None:
print("Erreur: rôle LecteurAPI non existant")
sys.exit(1)
perm_api_view = Permission.get_by_name("APIView")
role.add_permission(perm_api_view)
db.session.add(role)
user.add_role(role, None)
# Un utilisateur "other" n'ayant aucune permission sur l'API
other = User(user_name="other", nom="Sans", prenom="Permission", dept=dept.acronym)
other.set_password("other")
db.session.add(other)
db.session.commit()
return user, other
def create_fake_etud(dept: Departement) -> Identite:
"""Créé un faux étudiant et l'insère dans la base."""
civilite = random.choice(("M", "F", "X"))
nom, prenom = nomprenom(civilite)
etud: Identite = Identite(
civilite=civilite, nom=nom, prenom=prenom, dept_id=dept.id
)
db.session.add(etud)
db.session.commit()
# créé un étudiant sur deux avec un NIP et INE alphanumérique
etud.code_nip = f"{etud.id}" if (etud.id % 2) else f"NIP{etud.id}"
etud.code_ine = f"INE{etud.id}" if (etud.id % 2) else f"{etud.id}"
db.session.add(etud)
db.session.commit()
adresse = models.Adresse(
etudid=etud.id, email=f"{etud.prenom}.{etud.nom}@example.com"
)
db.session.add(adresse)
admission = models.Admission(etudid=etud.id)
db.session.add(admission)
db.session.commit()
return etud
def create_etuds(dept: Departement, nb=16) -> list:
"create nb etuds"
return [create_fake_etud(dept) for _ in range(nb)]
def create_formsemestre(
formation: Formation, responsable: User, semestre_idx=1
) -> FormSemestre:
"""Create formsemestre and moduleimpls
responsable: resp. du formsemestre
"""
formsemestre = FormSemestre(
dept_id=formation.dept_id,
semestre_id=semestre_idx,
titre="Semestre test",
date_debut=datetime.datetime(2021, 9, 1),
date_fin=datetime.datetime(2022, 8, 31),
modalite="FI",
formation=formation,
)
db.session.add(formsemestre)
db.session.commit()
# Crée un modulimpl par module de ce semestre:
for module in formation.modules.filter_by(semestre_id=semestre_idx):
modimpl = models.ModuleImpl(
module_id=module.id,
formsemestre_id=formsemestre.id,
responsable_id=responsable.id,
)
db.session.add(modimpl)
db.session.commit()
partition_id = sco_groups.partition_create(
formsemestre.id, default=True, redirect=False
)
_group_id = sco_groups.create_group(partition_id, default=True)
return formsemestre
def inscrit_etudiants(etuds: list, formsemestre: FormSemestre):
"""Inscrit les etudiants aux semestres et à tous ses modules"""
for etud in etuds:
sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules(
formsemestre.id,
etud.id,
group_ids=[],
etat="I",
method="init db test",
)
def create_evaluations(formsemestre: FormSemestre):
"creation d'une evaluation dans cahque modimpl du semestre"
for modimpl in formsemestre.modimpls:
args = {
"moduleimpl_id": modimpl.id,
"jour": None,
"heure_debut": "8h00",
"heure_fin": "9h00",
"description": None,
"note_max": 20,
"coefficient": 1.0,
"visibulletin": True,
"publish_incomplete": True,
"evaluation_type": None,
"numero": None,
}
evaluation_id = sco_evaluation_db.do_evaluation_create(**args)
def saisie_note_evaluations(formsemestre: FormSemestre, user: User):
"""
Saisie les notes des evaluations d'un semestre
"""
# Récupération des id des étudiants du semestre
list_etudids = [etud.id for etud in formsemestre.etuds]
def add_random_notes(evaluation_id, new_list_notes_eval=None, not_all=False):
"""
Permet d'ajouter des notes aléatoires à une évaluation
"""
if not_all:
percent = 80 / 100
len_list_etudids = len(list_etudids)
new_list_etudids = random.sample(
list_etudids, k=int(percent * len_list_etudids)
)
# new_list_etudids = [note.etudid for note in new_list_notes_eval]
list_tuple_notes = [
(etudid, random.uniform(0.0, 20.0)) for etudid in new_list_etudids
]
notes_add(user, evaluation_id, list_tuple_notes)
else:
list_tuple_notes = [
(etudid, random.uniform(0.0, 20.0)) for etudid in list_etudids
]
notes_add(user, evaluation_id, list_tuple_notes)
def saisir_notes(evaluation_id: int, condition: int, list_notes_eval):
"""
Permet de saisir les notes de manière aléatoire suivant une condition
Définition des valeurs de condition :
0 : all_notes_saisies
1 : all_notes_manquantes
2 : some_notes_manquantes
"""
if condition == 0 or condition == 2:
date_debut = formsemestre.date_debut
date_fin = formsemestre.date_fin
if condition == 0:
add_random_notes(evaluation_id)
for note in list_notes_eval:
note.date = date_debut + random.random() * (date_fin - date_debut)
db.session.add(note)
db.session.commit()
else:
percent = 80 / 100
len_list_notes_eval = len(list_notes_eval)
new_list_notes_eval = random.sample(
list_notes_eval, k=int(percent * len_list_notes_eval)
)
add_random_notes(evaluation_id, new_list_notes_eval, True)
for note in new_list_notes_eval:
note.date = date_debut + random.random() * (date_fin - date_debut)
db.session.add(note)
db.session.commit()
list_ues = formsemestre.query_ues()
for ue in list_ues:
mods = ue.modules
for mod in mods:
moduleimpl = ModuleImpl.query.get_or_404(mod.id)
for evaluation in moduleimpl.evaluations:
# Récupération de toutes les notes de l'évaluation
notes_eval = models.NotesNotes.query.filter_by(
evaluation_id=evaluation.id
).all()
condition_saisie_notes = random.randint(0, 2)
saisir_notes(evaluation.id, condition_saisie_notes, notes_eval)
def init_test_database():
"""Appelé par la commande `flask init-test-database`
Création d'un département et de son contenu pour les tests
"""
dept = init_departement("TAPI")
user_lecteur, user_autre = create_users(dept)
with sco_cache.DeferredSemCacheManager():
etuds = create_etuds(dept)
formation = import_formation()
formsemestre = create_formsemestre(formation, user_lecteur)
create_evaluations(formsemestre)
inscrit_etudiants(etuds, formsemestre)
saisie_note_evaluations(formsemestre, user_lecteur)
# à compléter
# - groupes
# - absences
# - notes
# - décisions de jury
# ...