From ba6b275973665054cd6a97d82e626f8f750d92da Mon Sep 17 00:00:00 2001 From: Emmanuel Viennet Date: Thu, 5 May 2022 18:11:44 +0200 Subject: [PATCH] API: WIP --- app/api/departements.py | 131 +++++++++++++-------------- app/api/etudiants.py | 4 +- app/api/formations.py | 69 ++------------ app/api/formsemestres.py | 139 +++++++++++++---------------- tests/api/test_api_departements.py | 20 ++++- tests/api/test_api_formations.py | 22 ++--- 6 files changed, 163 insertions(+), 222 deletions(-) diff --git a/app/api/departements.py b/app/api/departements.py index aaf19426..abea73b3 100644 --- a/app/api/departements.py +++ b/app/api/departements.py @@ -1,57 +1,58 @@ ############################################### Departements ########################################################## -import json from flask import jsonify +import app from app import models from app.api import bp from app.api.auth import token_auth, token_permission_required -from app.api.errors import error_response +from app.models import FormSemestre from app.scodoc.sco_permissions import Permission -@bp.route("/departements", methods=["GET"]) +@bp.route("/departements_ids", methods=["GET"]) @token_auth.login_required @token_permission_required(Permission.APIView) -def departements(): +def departements_ids(): + """Liste des ids de départements""" + return jsonify([dept.id for dept in models.Departement.query]) + + +@bp.route("/departement/", methods=["GET"]) +@token_auth.login_required +@token_permission_required(Permission.APIView) +def departement(dept_id: int): """ - Retourne la liste des ids de départements visibles + Info sur un département. Exemple de résultat : - [ { "id": 1, "acronym": "TAPI", "description": null, "visible": true, "date_creation": "Fri, 15 Apr 2022 12:19:28 GMT" - }, - { - "id": 2, - "acronym": "MMI", - "description": null, - "visible": false, - "date_creation": "Fri, 18 Apr 2022 11:20:8 GMT" - }, - ... - ] + } """ - # Récupération de tous les départements - depts = models.Departement.query.all() - - # Mise en place de la liste avec tous les départements - data = [d.to_dict() for d in depts] - - return jsonify(data) + dept = models.Departement.query.filter_by(dept_id=dept_id).first_or_404() + return jsonify(dept.to_dict()) -@bp.route("/departements//etudiants/list", methods=["GET"]) -@bp.route( - "/departements//etudiants/list/", methods=["GET"] -) +@bp.route("/departements", methods=["GET"]) @token_auth.login_required @token_permission_required(Permission.APIView) -def list_etudiants(dept: str, formsemestre_id=None): +def departements(): + """Liste les départements""" + return jsonify([dept.to_dict() for dept in models.Departement.query]) + + +@bp.route("/departement//etudiants", methods=["GET"]) +# @bp.route( +# "/departement//etudiants/list/", methods=["GET"] +# ) +@token_auth.login_required +@token_permission_required(Permission.APIView) +def list_etudiants(dept_ident: str): """ Retourne la liste des étudiants d'un département @@ -61,54 +62,38 @@ def list_etudiants(dept: str, formsemestre_id=None): Exemple de résultat : [ { - "civilite": "X", - "code_ine": null, - "code_nip": null, + "civilite": "M", + "ine": "7899X61616", + "nip": "F6777H88", "date_naissance": null, - "email": null, + "email": "toto@toto.fr", "emailperso": null, "etudid": 18, "nom": "MOREL", "prenom": "JACQUES" }, - { - "civilite": "X", - "code_ine": null, - "code_nip": null, - "date_naissance": null, - "email": null, - "emailperso": null, - "etudid": 19, - "nom": "FOURNIER", - "prenom": "ANNE" - }, ... ] """ - # Si le formsemestre_id a été renseigné - if formsemestre_id is not None: - # Récupération du formsemestre - formsemestre = models.FormSemestre.query.filter_by( - id=formsemestre_id + # Le département, spécifié par un id ou un acronyme + try: + dept_id = int(dept_ident) + except ValueError: + dept_id = None + if dept_id is None: + departement = models.Departement.query.filter_by( + acronym=dept_ident ).first_or_404() - # Récupération du département - departement = formsemestre.departement - - # Si le formsemestre_id n'a pas été renseigné else: - # Récupération du formsemestre - departement = models.Departement.query.filter_by(acronym=dept).first_or_404() + departement = models.Departement.query.get_or_404(dept_id) - # Mise en forme des données - list_etu = [etu.to_dict_bul(include_urls=False) for etu in departement.etudiants] - - return jsonify(list_etu) + return jsonify([etud.to_dict_short() for etud in departement.etudiants]) -@bp.route("/departements//semestres_courants", methods=["GET"]) +@bp.route("/departement//formsemestres_courants", methods=["GET"]) @token_auth.login_required @token_permission_required(Permission.APIView) -def liste_semestres_courant(dept: str): +def liste_semestres_courant(dept_ident: str): """ Liste des semestres actifs d'un départements donné @@ -149,13 +134,23 @@ def liste_semestres_courant(dept: str): ... ] """ - # Récupération des départements comportant l'acronym mit en paramètre - dept = models.Departement.query.filter_by(acronym=dept).first_or_404() + # Le département, spécifié par un id ou un acronyme + try: + dept_id = int(dept_ident) + except ValueError: + dept_id = None + if dept_id is None: + departement = models.Departement.query.filter_by( + acronym=dept_ident + ).first_or_404() + else: + departement = models.Departement.query.get_or_404(dept_id) - # Récupération des semestres suivant id_dept - semestres = models.FormSemestre.query.filter_by(dept_id=dept.id, etat=True) + # Les semestres en cours de ce département + formsemestres = models.FormSemestre.query.filter( + dept_id == departement.id, + FormSemestre.date_debut <= app.db.func.now(), + FormSemestre.date_fin >= app.db.func.now(), + ) - # Mise en forme des données - data = [d.to_dict() for d in semestres] - - return jsonify(data) + return jsonify([d.to_dict() for d in formsemestres]) diff --git a/app/api/etudiants.py b/app/api/etudiants.py index a6baa2d8..ab41fc31 100644 --- a/app/api/etudiants.py +++ b/app/api/etudiants.py @@ -20,7 +20,8 @@ from app.scodoc.sco_permissions import Permission @token_permission_required(Permission.APIView) def etudiants_courant(long=False): """ - Retourne la liste des étudiants courant + Retourne la liste des étudiants inscrits dans un + formsemestre actuellement en cours. Exemple de résultat : [ @@ -41,7 +42,6 @@ def etudiants_courant(long=False): ... ] """ - # Récupération de tous les étudiants etuds = Identite.query.filter( Identite.id == FormSemestreInscription.etudid, FormSemestreInscription.formsemestre_id == FormSemestre.id, diff --git a/app/api/formations.py b/app/api/formations.py index 3724c96a..f2443817 100644 --- a/app/api/formations.py +++ b/app/api/formations.py @@ -29,10 +29,10 @@ def formations_ids(): return jsonify(data) -@bp.route("/formations/", methods=["GET"]) +@bp.route("/formation/", methods=["GET"]) @token_auth.login_required @token_permission_required(Permission.APIView) -def formations_by_id(formation_id: int): +def formation_by_id(formation_id: int): """ Retourne une formation en fonction d'un id donné @@ -63,12 +63,12 @@ def formations_by_id(formation_id: int): @bp.route( - "/formations/formation_export/", + "/formation/formation_export/", methods=["GET"], defaults={"export_ids": False}, ) @bp.route( - "/formations/formation_export//with_ids", + "/formation/formation_export//with_ids", methods=["GET"], defaults={"export_ids": True}, ) @@ -185,7 +185,7 @@ def formation_export_by_formation_id(formation_id: int, export_ids=False): return jsonify(data) -@bp.route("/formations/moduleimpl/", methods=["GET"]) +@bp.route("/formation/moduleimpl/", methods=["GET"]) @token_auth.login_required @token_permission_required(Permission.APIView) def moduleimpl(moduleimpl_id: int): @@ -198,7 +198,6 @@ def moduleimpl(moduleimpl_id: int): { "id": 1, "formsemestre_id": 1, - "computation_expr": null, "module_id": 1, "responsable_id": 2, "moduleimpl_id": 1, @@ -230,63 +229,7 @@ def moduleimpl(moduleimpl_id: int): @bp.route( - "/formations/moduleimpl/formsemestre//list", - methods=["GET"], -) -@token_auth.login_required -@token_permission_required(Permission.APIView) -def moduleimpls_sem(formsemestre_id: int): - """ - Retourne la liste des moduleimpl d'un semestre - - formsemestre_id : l'id d'un formsemestre - - Exemple d'utilisation : - [ - { - "id": 1, - "formsemestre_id": 1, - "computation_expr": null, - "module_id": 1, - "responsable_id": 2, - "module": { - "heures_tp": 0.0, - "code_apogee": "", - "titre": "Initiation aux r\u00e9seaux informatiques", - "coefficient": 1.0, - "module_type": 2, - "id": 1, - "ects": null, - "abbrev": "Init aux r\u00e9seaux informatiques", - "ue_id": 1, - "code": "R101", - "formation_id": 1, - "heures_cours": 0.0, - "matiere_id": 1, - "heures_td": 0.0, - "semestre_id": 1, - "numero": 10, - "module_id": 1 - }, - "moduleimpl_id": 1, - "ens": [] - }, - ... - ] - """ - formsemestre = models.FormSemestre.query.filter_by( - id=formsemestre_id - ).first_or_404() - - moduleimpls = formsemestre.modimpls_sorted - - data = [moduleimpl.to_dict() for moduleimpl in moduleimpls] - - return jsonify(data) - - -@bp.route( - "/formations//referentiel_competences", + "/formation//referentiel_competences", methods=["GET"], ) @token_auth.login_required diff --git a/app/api/formsemestres.py b/app/api/formsemestres.py index 655250af..8bd5a108 100644 --- a/app/api/formsemestres.py +++ b/app/api/formsemestres.py @@ -22,31 +22,32 @@ def formsemestre(formsemestre_id: int): Exemple de résultat : { + "block_moyennes": false, + "bul_bgcolor": "white", + "bul_hide_xml": false, + "date_debut_iso": "2021-09-01", + "date_debut": "01/09/2021", + "date_fin_iso": "2022-08-31", "date_fin": "31/08/2022", - "resp_can_edit": false, "dept_id": 1, + "elt_annee_apo": null, + "elt_sem_apo": null, + "ens_can_edit_eval": false, "etat": true, - "resp_can_change_ens": true, + "formation_id": 1, + "formsemestre_id": 1, + "gestion_compensation": false, + "gestion_semestrielle": false, "id": 1, "modalite": "FI", - "ens_can_edit_eval": false, - "formation_id": 1, - "gestion_compensation": false, - "elt_sem_apo": null, - "semestre_id": 1, - "bul_hide_xml": false, - "elt_annee_apo": null, - "titre": "Semestre test", - "block_moyennes": false, + "resp_can_change_ens": true, + "resp_can_edit": false, + "responsables": [1, 99], // uids "scodoc7_id": null, - "date_debut": "01/09/2021", - "gestion_semestrielle": false, - "bul_bgcolor": "white", - "formsemestre_id": 1, - "titre_num": "Semestre test semestre 1", - "date_debut_iso": "2021-09-01", - "date_fin_iso": "2022-08-31", - "responsables": [] <<< A DOCUMENTER XXX + "semestre_id": 1, + "titre_formation" : "BUT GEA", + "titre_num": "BUT GEA semestre 1", + "titre": "BUT GEA", } """ @@ -324,7 +325,7 @@ def bulletins(formsemestre_id: int): ) @token_auth.login_required @token_permission_required(Permission.APIView) -def formsemestre_programme(formsemestre_id: int): # XXX nom bizarre ?? +def formsemestre_programme(formsemestre_id: int): """ Retourne la liste des Ues, ressources et SAE d'un semestre @@ -353,49 +354,40 @@ def formsemestre_programme(formsemestre_id: int): # XXX nom bizarre ?? ], "ressources": [ { - "titre": "Fondamentaux de la programmation", - "coefficient": 1.0, - "module_type": 2, - "id": 17, - "ects": null, - "abbrev": null, - "ue_id": 3, - "code": "R107", - "formation_id": 1, - "heures_cours": 0.0, - "matiere_id": 3, - "heures_td": 0.0, - "semestre_id": 1, - "heures_tp": 0.0, - "numero": 70, - "code_apogee": "", - "module_id": 17 + "ens": [ 10, 18 ], + "formsemestre_id": 1, + "id": 15, + "module": { + "abbrev": "Programmer", + "code": "SAE15", + "code_apogee": "V7GOP", + "coefficient": 1.0, + "formation_id": 1, + "heures_cours": 0.0, + "heures_td": 0.0, + "heures_tp": 0.0, + "id": 15, + "matiere_id": 3, + "module_id": 15, + "module_type": 3, + "numero": 50, + "semestre_id": 1, + "titre": "Programmer en Python", + "ue_id": 3 }, + "module_id": 15, + "moduleimpl_id": 15, + "responsable_id": 2 + }, ... ], "saes": [ { - "titre": "Se pr\u00e9senter sur Internet", - "coefficient": 1.0, - "module_type": 3, - "id": 14, - "ects": null, - "abbrev": null, - "ue_id": 3, - "code": "SAE14", - "formation_id": 1, - "heures_cours": 0.0, - "matiere_id": 3, - "heures_td": 0.0, - "semestre_id": 1, - "heures_tp": 0.0, - "numero": 40, - "code_apogee": "", - "module_id": 14 + ... }, ... ], - "modules" : [ ... les modules qui ne sont niu des SAEs ni des ressources ... ] + "modules" : [ ... les modules qui ne sont ni des SAEs ni des ressources ... ] } """ formsemestre: FormSemestre = models.FormSemestre.query.filter_by( @@ -403,27 +395,20 @@ def formsemestre_programme(formsemestre_id: int): # XXX nom bizarre ?? ).first_or_404() ues = formsemestre.query_ues() - ressources = [ - modimpl.module - for modimpl in formsemestre.modimpls_sorted - if modimpl.module.module_type == ModuleType.RESSOURCE - ] - saes = [ - modimpl.module - for modimpl in formsemestre.modimpls_sorted - if modimpl.module.module_type == ModuleType.SAE - ] - modules = [ - modimpl.module - for modimpl in formsemestre.modimpls_sorted - if modimpl.module.module_type == ModuleType.STANDARD - ] - - data = { - "ues": [ue.to_dict() for ue in ues], - "ressources": [m.to_dict() for m in ressources], - "saes": [m.to_dict() for m in saes], - "modules": [m.to_dict() for m in modules], + m_list = { + ModuleType.RESSOURCE: [], + ModuleType.SAE: [], + ModuleType.STANDARD: [], } + for modimpl in formsemestre.modimpls_sorted: + d = modimpl.to_dict() + m_list[modimpl.module.module_type].append(d) - return jsonify(data) + return jsonify( + { + "ues": [ue.to_dict() for ue in ues], + "ressources": m_list[ModuleType.RESSOURCE], + "saes": m_list[ModuleType.SAE], + "modules": m_list[ModuleType.STANDARD], + } + ) diff --git a/tests/api/test_api_departements.py b/tests/api/test_api_departements.py index 872aa104..91bac825 100644 --- a/tests/api/test_api_departements.py +++ b/tests/api/test_api_departements.py @@ -23,8 +23,26 @@ from tests.api.setup_test_api import API_URL, CHECK_CERTIFICATE, api_headers from tests.api.tools_test_api import verify_fields +def test_departements_ids(api_headers): + """ " + Route: /departements_ids + """ + r = requests.get( + API_URL + "/departements_ids", + headers=api_headers, + verify=CHECK_CERTIFICATE, + ) + assert r.status_code == 200 + departements_ids = r.json() + assert isinstance(departements_ids, list) + assert len(departements_ids) > 0 + assert all(isinstance(x, int) for x in departements_ids) + + def test_departements(api_headers): - "check liste de sdépartements" + """ " + Route: /departements + """ fields = [ "id", "acronym", diff --git a/tests/api/test_api_formations.py b/tests/api/test_api_formations.py index b8f159ad..e14fcb2c 100644 --- a/tests/api/test_api_formations.py +++ b/tests/api/test_api_formations.py @@ -44,7 +44,7 @@ def test_formations_ids(api_headers): # formations_by_id def test_formations_by_id(api_headers): """ - Route: /formations/ + Route: /formation/ """ fields = [ "id", @@ -61,7 +61,7 @@ def test_formations_by_id(api_headers): ] r = requests.get( - API_URL + "/formations/1", + API_URL + "/formation/1", headers=api_headers, verify=CHECK_CERTIFICATE, ) @@ -75,7 +75,7 @@ def test_formations_by_id(api_headers): def test_formation_export(api_headers): """ - Route: /formations/formation_export/ + Route: /formation/formation_export/ """ fields = [ "id", @@ -92,7 +92,7 @@ def test_formation_export(api_headers): "ue", ] r = requests.get( - API_URL + "/formations/formation_export/1", + API_URL + "/formation/formation_export/1", headers=api_headers, verify=CHECK_CERTIFICATE, ) @@ -108,7 +108,7 @@ def test_formation_export(api_headers): # TODO # def test_formsemestre_apo(api_headers): # r = requests.get( -# API_URL + "/formations/apo/", +# API_URL + "/formation/apo/", # headers=api_headers, # verify=CHECK_CERTIFICATE, # ) @@ -117,7 +117,7 @@ def test_formation_export(api_headers): def test_moduleimpl(api_headers): """ - Route: /formations/moduleimpl/ + Route: /formation/moduleimpl/ """ fields = [ "id", @@ -131,7 +131,7 @@ def test_moduleimpl(api_headers): ] r = requests.get( - API_URL + "/formations/moduleimpl/1", + API_URL + "/formation/moduleimpl/1", headers=api_headers, verify=CHECK_CERTIFICATE, ) @@ -145,7 +145,7 @@ def test_moduleimpl(api_headers): def test_moduleimpls_sem(api_headers): """ - Route: /formations/moduleimpl/formsemestre//list + Route: /formation/moduleimpl/formsemestre//list """ fields = [ "id", @@ -160,7 +160,7 @@ def test_moduleimpls_sem(api_headers): "ens", ] r = requests.get( - API_URL + "/formations/moduleimpl/formsemestre/1/list", + API_URL + "/formation/moduleimpl/formsemestre/1/list", headers=api_headers, verify=CHECK_CERTIFICATE, ) @@ -175,10 +175,10 @@ def test_moduleimpls_sem(api_headers): def test_referentiel_competences(api_headers): """ - Route: "/formations//referentiel_competences", + Route: "/formation//referentiel_competences", """ r = requests.get( - API_URL + "/formations/1/referentiel_competences", + API_URL + "/formation/1/referentiel_competences", headers=api_headers, verify=CHECK_CERTIFICATE, )