############################################################################## # ScoDoc # Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved. # See LICENSE ############################################################################## """ API : accès aux étudiants """ from flask import jsonify import app from app.api import bp from app.api.errors import error_response from app.api.auth import token_auth, token_permission_required from app.models import Departement, FormSemestreInscription, FormSemestre, Identite from app.scodoc import sco_bulletins from app.scodoc import sco_groups from app.scodoc.sco_permissions import Permission @bp.route("/etudiants/courant", defaults={"long": False}) @bp.route("/etudiants/courant/long", defaults={"long": True}) @token_auth.login_required @token_permission_required(Permission.APIView) def etudiants_courant(long=False): """ Liste des étudiants inscrits dans un formsemestre actuellement en cours. Exemple de résultat : [ { "id": 1, "nip": 1, "nom": "MOREL", "prenom": "JACQUES", "civilite": "X", }, { "id": 2, "nip": 2, "nom": "GILLES", "prenom": "MAXIME", "civilite": "X", }, ... ] """ etuds = Identite.query.filter( Identite.id == FormSemestreInscription.etudid, FormSemestreInscription.formsemestre_id == FormSemestre.id, FormSemestre.date_debut <= app.db.func.now(), FormSemestre.date_fin >= app.db.func.now(), ) if long: data = [etud.to_dict_bul(include_urls=False) for etud in etuds] else: data = [etud.to_dict_short() for etud in etuds] return jsonify(data) @bp.route("/etudiant/etudid/<int:etudid>", methods=["GET"]) @bp.route("/etudiant/nip/<string:nip>", methods=["GET"]) @bp.route("/etudiant/ine/<string:ine>", methods=["GET"]) @token_auth.login_required @token_permission_required(Permission.APIView) def etudiant(etudid: int = None, nip: str = None, ine: str = None): """ Retourne les informations de l'étudiant correspondant, ou 404 si non trouvé. etudid : l'etudid de l'étudiant nip : le code nip de l'étudiant ine : le code ine de l'étudiant Les codes INE et NIP sont uniques au sein d'un département. Si plusieurs objets ont le même code, on ramène le plus récemment inscrit. Exemple de résultat : { "civilite": "X", "code_ine": "1", "code_nip": "1", "date_naissance": "", "email": "SACHA.COSTA@example.com", "emailperso": "", "etudid": 1, "nom": "COSTA", "prenom": "SACHA", "nomprenom": "Sacha COSTA", "lieu_naissance": "", "dept_naissance": "", "nationalite": "", "boursier": "", "id": 1, "codepostaldomicile": "", "paysdomicile": "", "telephonemobile": "", "typeadresse": "domicile", "domicile": "", "villedomicile": "", "telephone": "", "fax": "", "description": "" } """ if etudid is not None: etud = Identite.query.get(etudid) else: if nip is not None: query = Identite.query.filter_by(code_nip=nip) elif ine is not None: query = Identite.query.filter_by(code_ine=ine) else: return error_response( 404, message="parametre manquant", ) if query.count() > 1: # cas rare d'un étudiant présent dans plusieurs depts etuds = [] for e in query: admission = e.admission.first() etuds.append((((admission.annee or 0) if admission else 0), e)) etuds.sort() etud = etuds[-1][1] else: etud = query.first() if etud is None: return error_response( 404, message="étudiant inconnu", ) return jsonify(etud.to_dict_bul(include_urls=False)) @bp.route("/etudiants/etudid/<int:etudid>", methods=["GET"]) @bp.route("/etudiants/nip/<string:nip>", methods=["GET"]) @bp.route("/etudiants/ine/<string:ine>", methods=["GET"]) @token_auth.login_required @token_permission_required(Permission.APIView) def etudiants(etudid: int = None, nip: str = None, ine: str = None): """ Info sur le ou les étudiants correspondant. Comme /etudiant mais renvoie toujours une liste. Si non trouvé, liste vide, pas d'erreur. Dans 99% des cas, la liste contient un seul étudiant, mais si l'étudiant a été inscrit dans plusieurs départements, on a plusieurs objets (1 par dept.). """ if etudid is not None: query = Identite.query.filter_by(id=etudid) elif nip is not None: query = Identite.query.filter_by(code_nip=nip) elif ine is not None: query = Identite.query.filter_by(code_ine=ine) else: return error_response( 404, message="parametre manquant", ) return jsonify([etud.to_dict_bul(include_urls=False) for etud in query]) @bp.route("/etudiant/etudid/<int:etudid>/formsemestres") @bp.route("/etudiant/nip/<string:nip>/formsemestres") @bp.route("/etudiant/ine/<string:ine>/formsemestres") @token_auth.login_required @token_permission_required(Permission.APIView) def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None): """ Liste des semestres qu'un étudiant a suivi, triés par ordre chronologique. Accès par etudid, nip ou ine Exemple de résultat : [ { "date_fin": "31/08/2022", "resp_can_edit": false, "dept_id": 1, "etat": true, "resp_can_change_ens": true, "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, "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": [] }, ... ] """ if etudid is not None: query = FormSemestre.query.filter( FormSemestreInscription.etudid == etudid, FormSemestreInscription.formsemestre_id == FormSemestre.id, ) elif nip is not None: query = FormSemestre.query.filter( Identite.code_nip == nip, FormSemestreInscription.etudid == Identite.id, FormSemestreInscription.formsemestre_id == FormSemestre.id, ) elif ine is not None: query = FormSemestre.query.filter( Identite.code_ine == ine, FormSemestreInscription.etudid == Identite.id, FormSemestreInscription.formsemestre_id == FormSemestre.id, ) else: return error_response( 404, message="parametre manquant", ) formsemestres = query.order_by(FormSemestre.date_debut) return jsonify([formsemestre.to_dict() for formsemestre in formsemestres]) @bp.route( "/etudiant/etudid/<int:etudid>/formsemestre/<int:formsemestre_id>/bulletin", methods=["GET"], defaults={"version": "long"}, ) @bp.route( "/etudiant/nip/<string:nip>/formsemestre/<int:formsemestre_id>/bulletin", methods=["GET"], defaults={"version": "long"}, ) @bp.route( "/etudiant/ine/<string:ine>/formsemestre/<int:formsemestre_id>/bulletin", methods=["GET"], defaults={"version": "long"}, ) @bp.route( "/etudiant/etudid/<int:etudid>/formsemestre/<int:formsemestre_id>/bulletin/short", methods=["GET"], defaults={"version": "short"}, ) @bp.route( "/etudiant/nip/<string:nip>/formsemestre/<int:formsemestre_id>/bulletin/short", methods=["GET"], defaults={"version": "short"}, ) @bp.route( "/etudiant/ine/<string:ine>/formsemestre/<int:formsemestre_id>/bulletin/short", methods=["GET"], defaults={"version": "short"}, ) @token_auth.login_required @token_permission_required(Permission.APIView) def etudiant_bulletin_semestre( formsemestre_id, etudid: int = None, nip: str = None, ine: str = None, version="long", ): """ Retourne le bulletin d'un étudiant en fonction de son id et d'un semestre donné formsemestre_id : l'id d'un formsemestre etudid : l'etudid d'un étudiant nip : le code nip d'un étudiant ine : le code ine d'un étudiant Exemple de résultat : { "version": "0", "type": "BUT", "date": "2022-04-27T07:18:16.450634Z", "publie": true, "etudiant": { "civilite": "X", "code_ine": "1", "code_nip": "1", "date_naissance": "", "email": "SACHA.COSTA@example.com", "emailperso": "", "etudid": 1, "nom": "COSTA", "prenom": "SACHA", "nomprenom": "Sacha COSTA", "lieu_naissance": "", "dept_naissance": "", "nationalite": "", "boursier": "", "fiche_url": "/ScoDoc/TAPI/Scolarite/ficheEtud?etudid=1", "photo_url": "/ScoDoc/TAPI/Scolarite/get_photo_image?etudid=1&size=small", "id": 1, "codepostaldomicile": "", "paysdomicile": "", "telephonemobile": "", "typeadresse": "domicile", "domicile": "", "villedomicile": "", "telephone": "", "fax": "", "description": "", }, "formation": { "id": 1, "acronyme": "BUT R&T", "titre_officiel": "Bachelor technologique r\u00e9seaux et t\u00e9l\u00e9communications", "titre": "BUT R&T", }, "formsemestre_id": 1, "etat_inscription": "I", "options": { "show_abs": true, "show_abs_modules": false, "show_ects": true, "show_codemodules": false, "show_matieres": false, "show_rangs": true, "show_ue_rangs": true, "show_mod_rangs": true, "show_moypromo": false, "show_minmax": false, "show_minmax_mod": false, "show_minmax_eval": false, "show_coef": true, "show_ue_cap_details": false, "show_ue_cap_current": true, "show_temporary": true, "temporary_txt": "Provisoire", "show_uevalid": true, "show_date_inscr": true, }, "ressources": { "R101": { "id": 1, "titre": "Initiation aux r\u00e9seaux informatiques", "code_apogee": null, "url": "/ScoDoc/TAPI/Scolarite/Notes/moduleimpl_status?moduleimpl_id=1", "moyenne": {}, "evaluations": [ { "id": 1, "description": "eval1", "date": "2022-04-20", "heure_debut": "08:00", "heure_fin": "09:00", "coef": "01.00", "poids": { "RT1.1": 1.0, }, "note": { "value": "12.00", "min": "00.00", "max": "18.00", "moy": "10.88", }, "url": "/ScoDoc/TAPI/Scolarite/Notes/evaluation_listenotes?evaluation_id=1", } ], }, }, "saes": { "SAE11": { "id": 2, "titre": "Se sensibiliser \u00e0 l'hygi\u00e8ne informatique et \u00e0 la cybers\u00e9curit\u00e9", "code_apogee": null, "url": "/ScoDoc/TAPI/Scolarite/Notes/moduleimpl_status?moduleimpl_id=2", "moyenne": {}, "evaluations": [], }, }, "ues": { "RT1.1": { "id": 1, "titre": "Administrer les r\u00e9seaux et l\u2019Internet", "numero": 1, "type": 0, "color": "#B80004", "competence": null, "moyenne": { "value": "08.50", "min": "06.00", "max": "16.50", "moy": "11.31", "rang": "12", "total": 16, }, "bonus": "00.00", "malus": "00.00", "capitalise": null, "ressources": { "R101": {"id": 1, "coef": 12.0, "moyenne": "12.00"}, }, "saes": { "SAE11": {"id": 2, "coef": 16.0, "moyenne": "~"}, }, "ECTS": {"acquis": 0.0, "total": 12.0}, }, "semestre": { "etapes": [], "date_debut": "2021-09-01", "date_fin": "2022-08-31", "annee_universitaire": "2021 - 2022", "numero": 1, "inscription": "", "groupes": [], "absences": {"injustifie": 1, "total": 2}, "ECTS": {"acquis": 0, "total": 30.0}, "notes": {"value": "10.60", "min": "02.40", "moy": "11.05", "max": "17.40"}, "rang": {"value": "10", "total": 16}, }, }, } """ formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first_or_404() dept = Departement.query.filter_by(id=formsemestre.dept_id).first_or_404() if etudid is not None: query = Identite.query.filter_by(id=etudid) elif nip is not None: query = Identite.query.filter_by(code_nip=nip, dept_id=dept.id) elif ine is not None: query = Identite.query.filter_by(code_ine=ine, dept_id=dept.id) else: return error_response( 404, message="parametre manquant", ) etud = query.first() if etud is None: return error_response( 404, message="id de l'étudiant (etudid, nip, ine) inconnu", ) app.set_sco_dept(dept.acronym) return sco_bulletins.get_formsemestre_bulletin_etud_json( formsemestre, etud, version ) @bp.route( "/etudiant/etudid/<int:etudid>/formsemestre/<int:formsemestre_id>/groups", methods=["GET"], ) @bp.route( "/etudiant/nip/<string:nip>/formsemestre/<int:formsemestre_id>/groups", methods=["GET"], ) @bp.route( "/etudiant/ine/<string:ine>/formsemestre/<int:formsemestre_id>/groups", methods=["GET"], ) @token_auth.login_required @token_permission_required(Permission.APIView) def etudiant_groups( formsemestre_id: int, etudid: int = None, nip: int = None, ine: int = None ): """ Retourne la liste des groupes auxquels appartient l'étudiant dans le formsemestre indiqué formsemestre_id : l'id d'un formsemestre etudid : l'etudid d'un étudiant nip : le code nip d'un étudiant ine : le code ine d'un étudiant Exemple de résultat : [ { "partition_id": 1, "id": 1, "formsemestre_id": 1, "partition_name": null, "numero": 0, "bul_show_rank": false, "show_in_lists": true, "group_id": 1, "group_name": null }, { "partition_id": 2, "id": 2, "formsemestre_id": 1, "partition_name": "TD", "numero": 1, "bul_show_rank": false, "show_in_lists": true, "group_id": 2, "group_name": "A" } ] """ formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first() if formsemestre is None: return error_response( 404, message="formsemestre inconnu", ) dept = Departement.query.get(formsemestre.dept_id) if etudid is not None: query = Identite.query.filter_by(id=etudid) elif nip is not None: query = Identite.query.filter_by(code_nip=nip, dept_id=dept.id) elif ine is not None: query = Identite.query.filter_by(code_ine=ine, dept_id=dept.id) else: return error_response( 404, message="parametre manquant", ) etud = query.first() if etud is None: return error_response( 404, message="etudiant inconnu", ) app.set_sco_dept(dept.acronym) data = sco_groups.get_etud_groups(etud.id, formsemestre.id) return jsonify(data)