# -*- 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 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, ApcReferentielCompetences, ApcCompetence, Absence, FormSemestreEtape, ) from app import db from app.models.but_refcomp import ( ApcParcours, ApcAnneeParcours, ApcSituationPro, ApcComposanteEssentielle, ApcNiveau, ApcAppCritique, ) 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_sco_view = Permission.get_by_name("ScoView") role.add_permission(perm_sco_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: aleatoire = random.randint(0, 10) if aleatoire <= 3: sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( formsemestre.id, etud.id, group_ids=[], etat="I", method="init db test", ) elif 3 < aleatoire <= 6: sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( formsemestre.id, etud.id, group_ids=[], etat="D", method="init db test", ) else: sco_formsemestre_inscriptions.do_formsemestre_inscription_with_modules( formsemestre.id, etud.id, group_ids=[], etat="DEF", 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 create_ref_comp(formation: Formation): """ Créer un referentiel de competences """ # ### ApcSituationPro ### # apc_situation_pro_id = 1 # apc_situation_pro_competence_id = 1 # apc_situation_pro_libelle = "" # # apc_situation_pro = ApcSituationPro( # apc_situation_pro_id, apc_situation_pro_competence_id, apc_situation_pro_libelle # ) # db.session.add(apc_situation_pro) # db.session.commit() # # ### ApcComposanteEssentielle ### # apc_composante_essentielle_id = 1 # apc_composante_essentielle_competence_id = 1 # apc_composante_essentielle_libelle = "" # # apc_composante_essentielle = ApcComposanteEssentielle( # apc_composante_essentielle_id, # apc_composante_essentielle_competence_id, # apc_composante_essentielle_libelle, # ) # db.session.add(apc_composante_essentielle) # db.session.commit() # # ### ApcAppCritique ### # apc_app_critique_id = 1 # apc_app_critique_niveau_id = 1 # apc_app_critique_code = "" # apc_app_critique_libelle = "" # apc_app_critique_modules = formation.modules # # apc_app_critique = ApcAppCritique( # apc_app_critique_id, # apc_app_critique_niveau_id, # apc_app_critique_code, # apc_app_critique_libelle, # apc_app_critique_modules, # ) # db.session.add(apc_app_critique) # db.session.commit() # # ### ApcNiveau ### # apc_niveau_id = 1 # apc_niveau_competence_id = 1 # apc_niveau_libelle = "" # apc_niveau_annee = "" # apc_niveau_ordre = 1 # apc_niveau_app_critiques = apc_app_critique # # apc_niveau = ApcNiveau( # apc_niveau_id, # apc_niveau_competence_id, # apc_niveau_libelle, # apc_niveau_annee, # apc_niveau_ordre, # apc_niveau_app_critiques, # ) # db.session.add(apc_niveau) # db.session.commit() # # ### ApcCompetence ### # apc_competence_id = 1 # apc_competence_referentiel_id = 1 # apc_competence_id_orebut = "" # apc_competence_titre = "" # apc_competence_titre_long = "" # apc_competence_couleur = "" # apc_competence_numero = 1 # apc_competence_xml_attribs = { # xml_attrib : attribute # "id": "id_orebut", # "nom_court": "titre", # was name # "libelle_long": "titre_long", # } # apc_competence_situations = apc_situation_pro # apc_competence_composantes_essentielles = apc_composante_essentielle # apc_competence_niveaux = apc_niveau # # apc_competence = ApcCompetence( # apc_competence_id, # apc_competence_referentiel_id, # apc_competence_id_orebut, # apc_competence_titre, # apc_competence_titre_long, # apc_competence_couleur, # apc_competence_numero, # apc_competence_xml_attribs, # apc_competence_situations, # apc_competence_composantes_essentielles, # apc_competence_niveaux, # ) # db.session.add(apc_competence) # db.session.commit() # # ### ApcAnneeParcours ### # apc_annee_parcours_id = 1 # apc_annee_parcours_parcours_id = 1 # apc_annee_parcours_ordre = 1 # # ap_annee_parcours = ApcAnneeParcours( # apc_annee_parcours_id, apc_annee_parcours_parcours_id, apc_annee_parcours_ordre # ) # # ### ApcParcours ### # apc_parcours_id = 1 # apc_parcours_referentiel_id = 1 # apc_parcours_numero = 1 # apc_parcours_code = "" # apc_parcours_libelle = "" # apc_parcours_annees = ap_annee_parcours # # apc_parcours = ApcParcours( # apc_parcours_id, # apc_parcours_referentiel_id, # apc_parcours_numero, # apc_parcours_code, # apc_parcours_libelle, # apc_parcours_annees, # ) # db.session.add(apc_parcours) # db.session.commit() ### ApcReferentielCompetences ### apc_referentiel_competences_id = 1 apc_referentiel_competences_dept_id = 1 apc_referentiel_competences_annexe = "" apc_referentiel_competences_specialite = "" apc_referentiel_competences_specialite_long = "" apc_referentiel_competences_type_titre = "" apc_referentiel_competences_type_structure = "" apc_referentiel_competences_type_departement = "" apc_referentiel_competences_version_orebut = "" apc_referentiel_competences_xml_attribs = { "type": "type_titre", "version": "version_orebut", } apc_referentiel_competences_scodoc_date_loaded = "" apc_referentiel_competences_scodoc_orig_filename = "" # apc_referentiel_competences_competences = apc_competence # apc_referentiel_competences_parcours = apc_parcours # apc_referentiel_competences_formations = formation apc_referentiel_competences = ApcReferentielCompetences( apc_referentiel_competences_id, apc_referentiel_competences_dept_id, apc_referentiel_competences_annexe, apc_referentiel_competences_specialite, apc_referentiel_competences_specialite_long, apc_referentiel_competences_type_titre, apc_referentiel_competences_type_structure, apc_referentiel_competences_type_departement, apc_referentiel_competences_version_orebut, apc_referentiel_competences_xml_attribs, # apc_referentiel_competences_scodoc_date_loaded, apc_referentiel_competences_scodoc_orig_filename, # apc_referentiel_competences_competences, # apc_referentiel_competences_parcours, # apc_referentiel_competences_formations, ) db.session.add(apc_referentiel_competences) db.session.commit() formation.referentiel_competence_id = apc_referentiel_competences.id db.session.commit() def add_absences(formsemestre: FormSemestre): """ Ajoute des absences en base """ date_debut = formsemestre.date_debut date_fin = formsemestre.date_fin etuds = formsemestre.etuds id_db = 1 for etu in etuds: aleatoire = random.randint(0, 1) if aleatoire == 1: nb_absences = random.randint(1, 5) for absence in range(0, nb_absences): id = id_db etudid = etu.id jour = date_debut + random.random() * (date_fin - date_debut) estabs = True estjust = True if random.randint(0, 1) == 1 else False matin = True if random.randint(0, 1) == 1 else False description = "" abs = Absence(id, etudid, jour, estabs, estjust, matin, description) db.session.add(abs) db.session.commit() id_db += 1 def create_etape_apo(formsemestre: FormSemestre): """ Ajoute étape apoge au formsemestre """ etape_apo1 = FormSemestreEtape( id=1, formsemestre_id=formsemestre.id, etape_apo="A1" ) db.session.add(etape_apo1) etape_apo2 = FormSemestreEtape( id=2, formsemestre_id=formsemestre.id, etape_apo="A2" ) db.session.add(etape_apo2) etape_apo3 = FormSemestreEtape( id=3, formsemestre_id=formsemestre.id, etape_apo="A3" ) db.session.add(etape_apo3) list_etapes = [etape_apo1, etape_apo2, etape_apo3] formsemestre.etapes = list_etapes db.session.commit() 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) create_ref_comp(formation) add_absences(formsemestre) create_etape_apo(formsemestre) # à compléter # - groupes # - absences # - notes # - décisions de jury # ...