DocScoDoc/tools/fakedatabase/create_test_api_database.py

280 lines
8.4 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_EVAL
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 time
import sys
from app.auth.models import Role, User
from app import models
from app.models import (
Departement,
Formation,
FormSemestre,
Identite,
ModuleImpl,
NotesNotes,
)
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_notes_evaluations(formsemestre: FormSemestre, user: User):
"""
Saisie les notes des evaluations d'un semestre
"""
etuds = formsemestre.etuds
list_etuds = []
for etu in etuds:
list_etuds.append(etu)
date_debut = formsemestre.date_debut
date_fin = formsemestre.date_fin
list_ues = formsemestre.query_ues()
def saisir_notes(evaluation_id: int, condition: int):
"""
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:
if condition == 0:
for etu in list_etuds:
note = NotesNotes(
etu.id,
evaluation_id,
random.uniform(0, 20),
"",
date_debut + random.random() * (date_fin - date_debut),
user.id,
)
db.session.add(note)
db.session.commit()
else:
percent = 80 / 100
len_etuds = len(list_etuds)
new_list_etuds = random.sample(list_etuds, k=int(percent * len_etuds))
for etu in new_list_etuds:
note = NotesNotes(
etu.id,
evaluation_id,
random.uniform(0, 20),
"",
date_debut + random.random() * (date_fin - date_debut),
user.id,
)
db.session.add(note)
db.session.commit()
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:
condition_saisie_notes = random.randint(0, 2)
saisir_notes(evaluation.id, condition_saisie_notes)
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_notes_evaluations(formsemestre, user_lecteur)
# à compléter
# - groupes
# - absences
# - notes
# - décisions de jury
# ...