############################################################################## # 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 flask_login import login_required from sqlalchemy import or_ import app from app.api import api_bp as bp, api_web_bp from app.api.errors import error_response from app.api import tools from app.decorators import scodoc, 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_bulletins import do_formsemestre_bulletinetud from app.scodoc.sco_permissions import Permission # Un exemple: @bp.route("/api_function/") @api_web_bp.route("/api_function/") @login_required @scodoc @permission_required(Permission.ScoView) def api_function(arg: int): """Une fonction quelconque de l'API""" return jsonify( {"current_user": current_user.to_dict(), "arg": arg, "dept": g.scodoc_dept} ) @bp.route("/etudiants/courants", defaults={"long": False}) @bp.route("/etudiants/courants/long", defaults={"long": True}) @api_web_bp.route("/etudiants/courants", defaults={"long": False}) @api_web_bp.route("/etudiants/courants/long", defaults={"long": True}) @login_required @scodoc @permission_required(Permission.ScoView) def etudiants_courants(long=False): """ La liste des étudiants des semestres "courants" (tous départements) (date du jour comprise dans la période couverte par le sem.) dans lesquels l'utilisateur a la permission ScoView (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.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/") @bp.route("/etudiant/nip/") @bp.route("/etudiant/ine/") @api_web_bp.route("/etudiant/etudid/") @api_web_bp.route("/etudiant/nip/") @api_web_bp.route("/etudiant/ine/") @login_required @scodoc @permission_required(Permission.ScoView) 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"]) @api_web_bp.route("/etudiants/etudid/", methods=["GET"]) @api_web_bp.route("/etudiants/nip/", methods=["GET"]) @api_web_bp.route("/etudiants/ine/", methods=["GET"]) @scodoc @permission_required(Permission.ScoView) 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.). """ allowed_depts = current_user.get_depts_with_permission(Permission.ScoView) 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", ) 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) ) 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") @api_web_bp.route("/etudiant/etudid//formsemestres") @api_web_bp.route("/etudiant/nip//formsemestres") @api_web_bp.route("/etudiant/ine//formsemestres") @scodoc @permission_required(Permission.ScoView) 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. 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`. Si accès par département, ne retourne que les formsemestre suivis dans le département. 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", ) if g.scodoc_dept is not None: query = query.filter_by(dept_id=g.scodoc_dept_id) 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 testée @bp.route( "/etudiant/etudid//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}, ) @api_web_bp.route( "/etudiant/etudid//formsemestre//bulletin", methods=["GET"], defaults={"version": "long", "pdf": False}, ) @api_web_bp.route( "/etudiant/nip//formsemestre//bulletin", methods=["GET"], defaults={"version": "long", "pdf": False}, ) @api_web_bp.route( "/etudiant/ine//formsemestre//bulletin", methods=["GET"], defaults={"version": "long", "pdf": False}, ) # Version PDF non testée @api_web_bp.route( "/etudiant/etudid//formsemestre//bulletin/pdf", methods=["GET"], defaults={"version": "long", "pdf": True}, ) @api_web_bp.route( "/etudiant/etudid//formsemestre//bulletin/short", methods=["GET"], defaults={"version": "short", "pdf": False}, ) @api_web_bp.route( "/etudiant/nip//formsemestre//bulletin/short", methods=["GET"], defaults={"version": "short", "pdf": False}, ) @api_web_bp.route( "/etudiant/ine//formsemestre//bulletin/short", methods=["GET"], defaults={"version": "short", "pdf": False}, ) @api_web_bp.route( "/etudiant/etudid//formsemestre//bulletin/short/pdf", methods=["GET"], defaults={"version": "short", "pdf": True}, ) @api_web_bp.route( "/etudiant/nip//formsemestre//bulletin/short/pdf", methods=["GET"], defaults={"version": "short", "pdf": True}, ) @api_web_bp.route( "/etudiant/ine//formsemestre//bulletin/short/pdf", methods=["GET"], defaults={"version": "short", "pdf": True}, ) @scodoc @permission_required(Permission.ScoView) def etudiant_bulletin_semestre( 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 g.scodoc_dept and dept != g.scodoc_dept: return error_response(404, "formsemestre non trouve") 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"], ) @scodoc @permission_required(Permission.ScoView) def etudiant_groups(formsemestre_id: int, etudid: 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 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" } ] """ query = FormSemestre.query.filter_by(id=formsemestre_id) if g.scodoc_dept: query = query.filter_by(dept_id=g.scodoc_dept_id) formsemestre = query.first() if formsemestre is None: return error_response( 404, message="formsemestre inconnu", ) dept = formsemestre.departement etud = Identite.query.filter_by(id=etudid, dept_id=dept.id).first_or_404(etudid) app.set_sco_dept(dept.acronym) data = sco_groups.get_etud_groups(etud.id, formsemestre.id) return jsonify(data)