ScoDoc/app/api/departements.py

258 lines
7.3 KiB
Python

##############################################################################
# ScoDoc
# Copyright (c) 1999 - 2024 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 request
from flask_json import as_json
from flask_login import login_required
import app
from app import db
from app.api import api_bp as bp, API_CLIENT_ERROR
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)
@as_json
def departements_list():
"""Liste les départements"""
return [dept.to_dict(with_dept_name=True) for dept in Departement.query]
@bp.route("/departements_ids")
@login_required
@scodoc
@permission_required(Permission.ScoView)
@as_json
def departements_ids():
"""Liste des ids de départements"""
return [dept.id for dept in Departement.query]
@bp.route("/departement/<string:acronym>")
@login_required
@scodoc
@permission_required(Permission.ScoView)
@as_json
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 dept.to_dict(with_dept_name=True)
@bp.route("/departement/id/<int:dept_id>")
@login_required
@scodoc
@permission_required(Permission.ScoView)
@as_json
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 dept.to_dict()
@bp.route("/departement/create", methods=["POST"])
@login_required
@scodoc
@permission_required(Permission.ScoSuperAdmin)
@as_json
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(API_CLIENT_ERROR, "missing acronym")
visible = bool(data.get("visible", True))
try:
dept = departements.create_dept(acronym, visible=visible)
except ScoValueError as exc:
return json_error(500, exc.args[0] if exc.args else "")
return dept.to_dict()
@bp.route("/departement/<string:acronym>/edit", methods=["POST"])
@login_required
@scodoc
@permission_required(Permission.ScoSuperAdmin)
@as_json
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(API_CLIENT_ERROR, "missing argument: visible")
visible = bool(visible)
dept.visible = visible
db.session.add(dept)
db.session.commit()
return 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 {"OK": True}
@bp.route("/departement/<string:acronym>/etudiants", methods=["GET"])
@login_required
@scodoc
@permission_required(Permission.ScoView)
@as_json
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 [etud.to_dict_short() for etud in dept.etudiants]
@bp.route("/departement/id/<int:dept_id>/etudiants")
@login_required
@scodoc
@permission_required(Permission.ScoView)
@as_json
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 [etud.to_dict_short() for etud in dept.etudiants]
@bp.route("/departement/<string:acronym>/formsemestres_ids")
@login_required
@scodoc
@permission_required(Permission.ScoView)
@as_json
def dept_formsemestres_ids(acronym: str):
"""liste des ids formsemestre du département"""
dept = Departement.query.filter_by(acronym=acronym).first_or_404()
return [formsemestre.id for formsemestre in dept.formsemestres]
@bp.route("/departement/id/<int:dept_id>/formsemestres_ids")
@login_required
@scodoc
@permission_required(Permission.ScoView)
@as_json
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 [formsemestre.id for formsemestre in dept.formsemestres]
@bp.route("/departement/<string:acronym>/formsemestres_courants")
@bp.route("/departement/id/<int:dept_id>/formsemestres_courants")
@login_required
@scodoc
@permission_required(Permission.ScoView)
@as_json
def dept_formsemestres_courants(acronym: str = "", dept_id: int | None = None):
"""
Liste les semestres du département indiqué (par son acronyme ou son id)
contenant la date courante, ou à défaut celle indiquée en argument
(au format ISO).
QUERY
-----
date_courante:<string:date_courante>
"""
dept = (
Departement.query.filter_by(acronym=acronym).first_or_404()
if acronym
else Departement.query.get_or_404(dept_id)
)
date_courante = request.args.get("date_courante")
date_courante = datetime.fromisoformat(date_courante) if date_courante else None
return [
formsemestre.to_dict_api()
for formsemestre in FormSemestre.get_dept_formsemestres_courants(
dept, date_courante
)
]