############################################################################## # ScoDoc # Copyright (c) 1999 - 2023 Emmanuel Viennet. All rights reserved. # See LICENSE ############################################################################## """ ScoDoc 9 API : accès aux départements Note: les routes /departement[s] sont publiées sur l'API (/ScoDoc/api/), mais évidemment pas sur l'API web (/ScoDoc/<dept>/api). """ from datetime import datetime from flask import jsonify, request from flask_login import login_required import app from app import db from app.api import api_bp as bp from app.scodoc.sco_utils import json_error from app.decorators import scodoc, permission_required from app.models import Departement, FormSemestre from app.models import departements from app.scodoc.sco_exceptions import ScoValueError from app.scodoc.sco_permissions import Permission def get_departement(dept_ident: str) -> Departement: "Le departement, par id ou acronyme. Erreur 404 si pas trouvé." try: dept_id = int(dept_ident) except ValueError: dept_id = None if dept_id is None: return Departement.query.filter_by(acronym=dept_ident).first_or_404() return Departement.query.get_or_404(dept_id) @bp.route("/departements") @login_required @scodoc @permission_required(Permission.ScoView) def departements_list(): """Liste les départements""" return jsonify([dept.to_dict(with_dept_name=True) for dept in Departement.query]) @bp.route("/departements_ids") @login_required @scodoc @permission_required(Permission.ScoView) def departements_ids(): """Liste des ids de départements""" return jsonify([dept.id for dept in Departement.query]) @bp.route("/departement/<string:acronym>") @login_required @scodoc @permission_required(Permission.ScoView) def departement(acronym: str): """ Info sur un département. Accès par acronyme. Exemple de résultat : { "id": 1, "acronym": "TAPI", "dept_name" : "TEST", "description": null, "visible": true, "date_creation": "Fri, 15 Apr 2022 12:19:28 GMT" } """ dept = Departement.query.filter_by(acronym=acronym).first_or_404() return jsonify(dept.to_dict(with_dept_name=True)) @bp.route("/departement/id/<int:dept_id>") @login_required @scodoc @permission_required(Permission.ScoView) def departement_by_id(dept_id: int): """ Info sur un département. Accès par id. """ dept = Departement.query.get_or_404(dept_id) return jsonify(dept.to_dict()) @bp.route("/departement/create", methods=["POST"]) @login_required @scodoc @permission_required(Permission.ScoSuperAdmin) def departement_create(): """ Création d'un département. The request content type should be "application/json": { "acronym": str, "visible":bool, } """ data = request.get_json(force=True) # may raise 400 Bad Request acronym = str(data.get("acronym", "")) if not acronym: return json_error(404, "missing acronym") visible = bool(data.get("visible", True)) try: dept = departements.create_dept(acronym, visible=visible) except ScoValueError as exc: return json_error(404, exc.args[0] if exc.args else "") return jsonify(dept.to_dict()) @bp.route("/departement/<string:acronym>/edit", methods=["POST"]) @login_required @scodoc @permission_required(Permission.ScoSuperAdmin) def departement_edit(acronym): """ Edition d'un département: seul visible peut être modifié The request content type should be "application/json": { "visible":bool, } """ dept = Departement.query.filter_by(acronym=acronym).first_or_404() data = request.get_json(force=True) # may raise 400 Bad Request visible = bool(data.get("visible", None)) if visible is None: return json_error(404, "missing argument: visible") visible = bool(visible) dept.visible = visible db.session.add(dept) db.session.commit() return jsonify(dept.to_dict()) @bp.route("/departement/<string:acronym>/delete", methods=["POST"]) @login_required @scodoc @permission_required(Permission.ScoSuperAdmin) def departement_delete(acronym): """ Suppression d'un département. """ dept = Departement.query.filter_by(acronym=acronym).first_or_404() db.session.delete(dept) db.session.commit() return jsonify({"OK": True}) @bp.route("/departement/<string:acronym>/etudiants", methods=["GET"]) @login_required @scodoc @permission_required(Permission.ScoView) def dept_etudiants(acronym: str): """ Retourne la liste des étudiants d'un département acronym: l'acronyme d'un département Exemple de résultat : [ { "civilite": "M", "code_ine": "7899X61616", "code_nip": "F6777H88", "date_naissance": null, "email": "toto@toto.fr", "emailperso": null, "etudid": 18, "nom": "MOREL", "prenom": "JACQUES" }, ... ] """ dept = Departement.query.filter_by(acronym=acronym).first_or_404() return jsonify([etud.to_dict_short() for etud in dept.etudiants]) @bp.route("/departement/id/<int:dept_id>/etudiants") @login_required @scodoc @permission_required(Permission.ScoView) def dept_etudiants_by_id(dept_id: int): """ Retourne la liste des étudiants d'un département d'id donné. """ dept = Departement.query.get_or_404(dept_id) return jsonify([etud.to_dict_short() for etud in dept.etudiants]) @bp.route("/departement/<string:acronym>/formsemestres_ids") @login_required @scodoc @permission_required(Permission.ScoView) def dept_formsemestres_ids(acronym: str): """liste des ids formsemestre du département""" dept = Departement.query.filter_by(acronym=acronym).first_or_404() return jsonify([formsemestre.id for formsemestre in dept.formsemestres]) @bp.route("/departement/id/<int:dept_id>/formsemestres_ids") @login_required @scodoc @permission_required(Permission.ScoView) def dept_formsemestres_ids_by_id(dept_id: int): """liste des ids formsemestre du département""" dept = Departement.query.get_or_404(dept_id) return jsonify([formsemestre.id for formsemestre in dept.formsemestres]) @bp.route("/departement/<string:acronym>/formsemestres_courants") @login_required @scodoc @permission_required(Permission.ScoView) def dept_formsemestres_courants(acronym: str): """ Liste des semestres actifs d'un département d'acronyme donné Exemple de résultat : [ { "titre": "master machine info", "gestion_semestrielle": false, "scodoc7_id": null, "date_debut": "01/09/2021", "bul_bgcolor": null, "date_fin": "15/12/2022", "resp_can_edit": false, "dept_id": 1, "etat": true, "resp_can_change_ens": 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, "block_moyennes": false, "formsemestre_id": 1, "titre_num": "master machine info semestre 1", "date_debut_iso": "2021-09-01", "date_fin_iso": "2022-12-15", "responsables": [ 3, 2 ] }, ... ] """ dept = Departement.query.filter_by(acronym=acronym).first_or_404() date_courante = request.args.get("date_courante") if date_courante: test_date = datetime.fromisoformat(date_courante) else: test_date = app.db.func.now() # Les semestres en cours de ce département formsemestres = FormSemestre.query.filter( FormSemestre.dept_id == dept.id, FormSemestre.date_debut <= test_date, FormSemestre.date_fin >= test_date, ) return jsonify([d.to_dict_api() for d in formsemestres]) @bp.route("/departement/id/<int:dept_id>/formsemestres_courants") @login_required @scodoc @permission_required(Permission.ScoView) def dept_formsemestres_courants_by_id(dept_id: int): """ Liste des semestres actifs d'un département d'id donné """ # Le département, spécifié par un id ou un acronyme dept = Departement.query.get_or_404(dept_id) date_courante = request.args.get("date_courante") if date_courante: test_date = datetime.fromisoformat(date_courante) else: test_date = app.db.func.now() # Les semestres en cours de ce département formsemestres = FormSemestre.query.filter( FormSemestre.dept_id == dept.id, FormSemestre.date_debut <= test_date, FormSemestre.date_fin >= test_date, ) return jsonify([d.to_dict_api() for d in formsemestres])