############################################################################## # ScoDoc # Copyright (c) 1999 - 2022 Emmanuel Viennet. All rights reserved. # See LICENSE ############################################################################## """ API : accès aux étudiants """ from flask import g, jsonify from flask_login import current_user from sqlalchemy import or_ import app from app.api import bp from app.api.errors import error_response from app.api.auth import permission_required_api from app.api import tools from app.models import Departement, FormSemestreInscription, FormSemestre, Identite from app.scodoc import sco_bulletins from app.scodoc import sco_groups from app.scodoc.sco_bulletins import do_formsemestre_bulletinetud from app.scodoc.sco_permissions import Permission @bp.route("/etudiants/courants", defaults={"long": False}) @bp.route("/etudiants/courants/long", defaults={"long": True}) @permission_required_api(Permission.ScoView, Permission.APIView) def etudiants_courants(long=False): """ La liste des étudiants des semestres "courants" (tous département) (date du jour comprise dans la période couverte par le sem.) dans lesquels l'utilisateur a le rôle APIView (donc tous si le dept du rôle est None). Exemple de résultat : [ { "id": 1234, "nip": "12345678", "ine": null, "nom": "JOHN", "nom_usuel": None, "prenom": "DEUF", "civilite": "M", } ... ] En format "long": { "boursier": True, "civilite": "F", "code_ine": "AP987654", "code_nip": "1234567", "codepostaldomicile": "92800", "date_naissance": "21/06/2000", "dept_acronym": "CJ", "dept_id": 1, "dept_naissance": "092", "description": "infos portail", "domicile": "Plaza Condell", "email": "jeanne.dupont@xxx.fr", "emailperso": "", "etudid": 4853, "id": 4863, "lieu_naissance": "SEVRES", "nationalite": "", "nom": "DUPONT", "nomprenom": "Mme Jeanne Dupont", "paysdomicile": "FRANCE", "prenom": "JEANNE", "telephone": "0102030405", "telephonemobile": "", "typeadresse": "domicile", "villedomicile": "VALPARAISO", } """ allowed_depts = current_user.get_depts_with_permission( Permission.APIView | Permission.ScoView ) 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 not None in allowed_depts: # restreint aux départements autorisés: etuds = etuds.join(Departement).filter( or_(Departement.acronym == acronym for acronym in allowed_depts) ) 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/", methods=["GET"]) @bp.route("/etudiant/nip/", methods=["GET"]) @bp.route("/etudiant/ine/", methods=["GET"]) @permission_required_api(Permission.ScoView, 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": "" } """ etud = tools.get_etud(etudid, nip, ine) if etud is None: return error_response( 404, message="étudiant inconnu", ) return jsonify(etud.to_dict_bul(include_urls=False)) @bp.route("/etudiants/etudid/", methods=["GET"]) @bp.route("/etudiants/nip/", methods=["GET"]) @bp.route("/etudiants/ine/", methods=["GET"]) @permission_required_api(Permission.ScoView, 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//formsemestres") @bp.route("/etudiant/nip//formsemestres") @bp.route("/etudiant/ine//formsemestres") @permission_required_api(Permission.ScoView, 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. Attention, si accès via NIP ou INE, les semestres peuvent être de départements différents (si l'étudiant a changé de département). L'id du département est `dept_id`. Accès par etudid, nip ou ine 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", "dept_id": 1, "elt_annee_apo": null, "elt_sem_apo": null, "ens_can_edit_eval": false, "etat": true, "formation_id": 1, "formsemestre_id": 1, "gestion_compensation": false, "gestion_semestrielle": false, "id": 1, "modalite": "FI", "resp_can_change_ens": true, "resp_can_edit": false, "responsables": [] "scodoc7_id": null, "semestre_id": 1, "titre_num": "Semestre test semestre 1", "titre": "Semestre test", }, ... ] """ 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(convert_objects=True) for formsemestre in formsemestres] ) @bp.route( "/etudiant/etudid//formsemestre//bulletin", methods=["GET"], defaults={"version": "long", "pdf": False}, ) @bp.route( "/etudiant/nip//formsemestre//bulletin", methods=["GET"], defaults={"version": "long", "pdf": False}, ) @bp.route( "/etudiant/ine//formsemestre//bulletin", methods=["GET"], defaults={"version": "long", "pdf": False}, ) # Version PDF non fonctionnelle @bp.route( "/etudiant/etudid//formsemestre//bulletin/pdf", methods=["GET"], defaults={"version": "long", "pdf": True}, ) # @bp.route( # "/etudiant/nip//formsemestre//bulletin/pdf", # methods=["GET"], # defaults={"version": "long", "pdf": True}, # ) # @bp.route( # "/etudiant/ine//formsemestre//bulletin/pdf", # methods=["GET"], # defaults={"version": "long", "pdf": True}, # ) @bp.route( "/etudiant/etudid//formsemestre//bulletin/short", methods=["GET"], defaults={"version": "short", "pdf": False}, ) @bp.route( "/etudiant/nip//formsemestre//bulletin/short", methods=["GET"], defaults={"version": "short", "pdf": False}, ) @bp.route( "/etudiant/ine//formsemestre//bulletin/short", methods=["GET"], defaults={"version": "short", "pdf": False}, ) @bp.route( "/etudiant/etudid//formsemestre//bulletin/short/pdf", methods=["GET"], defaults={"version": "short", "pdf": True}, ) @bp.route( "/etudiant/nip//formsemestre//bulletin/short/pdf", methods=["GET"], defaults={"version": "short", "pdf": True}, ) @bp.route( "/etudiant/ine//formsemestre//bulletin/short/pdf", methods=["GET"], defaults={"version": "short", "pdf": True}, ) @permission_required_api(Permission.ScoView, Permission.APIView) def etudiant_bulletin_semestre( # XXX TODO Ajouter la possibilité de retourner en version pdf formsemestre_id, etudid: int = None, nip: str = None, ine: str = None, version="long", pdf: bool = False, ): """ 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 : voir https://scodoc.org/ScoDoc9API/#bulletin """ 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) if pdf: pdf_response, _ = do_formsemestre_bulletinetud( formsemestre, etudid, version=version, format="pdf" ) return pdf_response return sco_bulletins.get_formsemestre_bulletin_etud_json( formsemestre, etud, version=version ) @bp.route( "/etudiant/etudid//formsemestre//groups", methods=["GET"], ) @bp.route( "/etudiant/nip//formsemestre//groups", methods=["GET"], ) @bp.route( "/etudiant/ine//formsemestre//groups", methods=["GET"], ) @permission_required_api(Permission.ScoView, 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)