# -*- 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 # ...