forked from ScoDoc/ScoDoc
Compare commits
3 Commits
0b7be5d08a
...
188534819b
Author | SHA1 | Date | |
---|---|---|---|
188534819b | |||
b3111769a1 | |||
d37ce3f8d9 |
@ -6,6 +6,11 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
API : billets d'absences
|
API : billets d'absences
|
||||||
|
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
Billets d'absence
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
@ -29,7 +34,7 @@ from app.scodoc.sco_permissions import Permission
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def billets_absence_etudiant(etudid: int):
|
def billets_absence_etudiant(etudid: int):
|
||||||
"""Liste des billets d'absence pour cet étudiant"""
|
"""Liste des billets d'absence pour cet étudiant."""
|
||||||
billets = sco_abs_billets.query_billets_etud(etudid)
|
billets = sco_abs_billets.query_billets_etud(etudid)
|
||||||
return [billet.to_dict() for billet in billets]
|
return [billet.to_dict() for billet in billets]
|
||||||
|
|
||||||
@ -41,7 +46,20 @@ def billets_absence_etudiant(etudid: int):
|
|||||||
@permission_required(Permission.AbsAddBillet)
|
@permission_required(Permission.AbsAddBillet)
|
||||||
@as_json
|
@as_json
|
||||||
def billets_absence_create():
|
def billets_absence_create():
|
||||||
"""Ajout d'un billet d'absence"""
|
"""Ajout d'un billet d'absence. Renvoie le billet créé en json.
|
||||||
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"etudid" : int,
|
||||||
|
"abs_begin" : date_iso,
|
||||||
|
"abs_end" : date_iso,
|
||||||
|
"description" : string,
|
||||||
|
"justified" : bool
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"""
|
||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
etudid = data.get("etudid")
|
etudid = data.get("etudid")
|
||||||
abs_begin = data.get("abs_begin")
|
abs_begin = data.get("abs_begin")
|
||||||
|
@ -9,6 +9,11 @@
|
|||||||
|
|
||||||
Note: les routes /departement[s] sont publiées sur l'API (/ScoDoc/api/),
|
Note: les routes /departement[s] sont publiées sur l'API (/ScoDoc/api/),
|
||||||
mais évidemment pas sur l'API web (/ScoDoc/<dept>/api).
|
mais évidemment pas sur l'API web (/ScoDoc/<dept>/api).
|
||||||
|
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
Département
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
@ -27,24 +32,13 @@ from app.scodoc.sco_permissions import Permission
|
|||||||
from app.scodoc.sco_utils import json_error
|
from app.scodoc.sco_utils import json_error
|
||||||
|
|
||||||
|
|
||||||
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")
|
@bp.route("/departements")
|
||||||
@login_required
|
@login_required
|
||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def departements_list():
|
def departements_list():
|
||||||
"""Liste les départements"""
|
"""Liste tous les départements."""
|
||||||
return [dept.to_dict(with_dept_name=True) for dept in Departement.query]
|
return [dept.to_dict(with_dept_name=True) for dept in Departement.query]
|
||||||
|
|
||||||
|
|
||||||
@ -54,7 +48,7 @@ def departements_list():
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def departements_ids():
|
def departements_ids():
|
||||||
"""Liste des ids de départements"""
|
"""Liste des ids de tous les départements."""
|
||||||
return [dept.id for dept in Departement.query]
|
return [dept.id for dept in Departement.query]
|
||||||
|
|
||||||
|
|
||||||
@ -68,6 +62,7 @@ def departement_by_acronym(acronym: str):
|
|||||||
Info sur un département. Accès par acronyme.
|
Info sur un département. Accès par acronyme.
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"acronym": "TAPI",
|
"acronym": "TAPI",
|
||||||
@ -76,6 +71,7 @@ def departement_by_acronym(acronym: str):
|
|||||||
"visible": true,
|
"visible": true,
|
||||||
"date_creation": "Fri, 15 Apr 2022 12:19:28 GMT"
|
"date_creation": "Fri, 15 Apr 2022 12:19:28 GMT"
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
dept = Departement.query.filter_by(acronym=acronym).first_or_404()
|
dept = Departement.query.filter_by(acronym=acronym).first_or_404()
|
||||||
return dept.to_dict(with_dept_name=True)
|
return dept.to_dict(with_dept_name=True)
|
||||||
@ -102,11 +98,15 @@ def departement_by_id(dept_id: int):
|
|||||||
def departement_create():
|
def departement_create():
|
||||||
"""
|
"""
|
||||||
Création d'un département.
|
Création d'un département.
|
||||||
The request content type should be "application/json":
|
Le content type doit être `application/json`.
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"acronym": str,
|
"acronym": str,
|
||||||
"visible":bool,
|
"visible": bool,
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
acronym = str(data.get("acronym", ""))
|
acronym = str(data.get("acronym", ""))
|
||||||
@ -130,10 +130,12 @@ def departement_create():
|
|||||||
@as_json
|
@as_json
|
||||||
def departement_edit(acronym):
|
def departement_edit(acronym):
|
||||||
"""
|
"""
|
||||||
Edition d'un département: seul visible peut être modifié
|
Édition d'un département: seul le champ `visible` peut être modifié.
|
||||||
The request content type should be "application/json":
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
{
|
{
|
||||||
"visible":bool,
|
"visible": bool,
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
dept = Departement.query.filter_by(acronym=acronym).first_or_404()
|
dept = Departement.query.filter_by(acronym=acronym).first_or_404()
|
||||||
@ -155,7 +157,7 @@ def departement_edit(acronym):
|
|||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
def departement_delete(acronym):
|
def departement_delete(acronym):
|
||||||
"""
|
"""
|
||||||
Suppression d'un département.
|
Suppression d'un département identifié par son acronyme.
|
||||||
"""
|
"""
|
||||||
dept = Departement.query.filter_by(acronym=acronym).first_or_404()
|
dept = Departement.query.filter_by(acronym=acronym).first_or_404()
|
||||||
acronym = dept.acronym
|
acronym = dept.acronym
|
||||||
@ -172,11 +174,14 @@ def departement_delete(acronym):
|
|||||||
@as_json
|
@as_json
|
||||||
def departement_etudiants(acronym: str):
|
def departement_etudiants(acronym: str):
|
||||||
"""
|
"""
|
||||||
Retourne la liste des étudiants d'un département
|
Retourne la liste des étudiants d'un département.
|
||||||
|
|
||||||
acronym: l'acronyme d'un département
|
PARAMS
|
||||||
|
------
|
||||||
|
acronym : l'acronyme d'un département
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
|
```json
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"civilite": "M",
|
"civilite": "M",
|
||||||
@ -191,6 +196,7 @@ def departement_etudiants(acronym: str):
|
|||||||
},
|
},
|
||||||
...
|
...
|
||||||
]
|
]
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
dept = Departement.query.filter_by(acronym=acronym).first_or_404()
|
dept = Departement.query.filter_by(acronym=acronym).first_or_404()
|
||||||
return [etud.to_dict_short() for etud in dept.etudiants]
|
return [etud.to_dict_short() for etud in dept.etudiants]
|
||||||
@ -215,7 +221,7 @@ def departement_etudiants_by_id(dept_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def departement_formsemestres_ids(acronym: str):
|
def departement_formsemestres_ids(acronym: str):
|
||||||
"""liste des ids formsemestre du département"""
|
"""Liste des ids de tous les formsemestres du département."""
|
||||||
dept = Departement.query.filter_by(acronym=acronym).first_or_404()
|
dept = Departement.query.filter_by(acronym=acronym).first_or_404()
|
||||||
return [formsemestre.id for formsemestre in dept.formsemestres]
|
return [formsemestre.id for formsemestre in dept.formsemestres]
|
||||||
|
|
||||||
@ -226,7 +232,7 @@ def departement_formsemestres_ids(acronym: str):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def departement_formsemestres_ids_by_id(dept_id: int):
|
def departement_formsemestres_ids_by_id(dept_id: int):
|
||||||
"""liste des ids formsemestre du département"""
|
"""Liste des ids de tous les formsemestres du département."""
|
||||||
dept = Departement.query.get_or_404(dept_id)
|
dept = Departement.query.get_or_404(dept_id)
|
||||||
return [formsemestre.id for formsemestre in dept.formsemestres]
|
return [formsemestre.id for formsemestre in dept.formsemestres]
|
||||||
|
|
||||||
@ -239,7 +245,7 @@ def departement_formsemestres_ids_by_id(dept_id: int):
|
|||||||
@as_json
|
@as_json
|
||||||
def departement_formsemestres_courants(acronym: str = "", dept_id: int | None = None):
|
def departement_formsemestres_courants(acronym: str = "", dept_id: int | None = None):
|
||||||
"""
|
"""
|
||||||
Liste les semestres du département indiqué (par son acronyme ou son id)
|
Liste les formsemestres du département indiqué (par son acronyme ou son id)
|
||||||
contenant la date courante, ou à défaut celle indiquée en argument
|
contenant la date courante, ou à défaut celle indiquée en argument
|
||||||
(au format ISO).
|
(au format ISO).
|
||||||
|
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
API : accès aux étudiants
|
API : accès aux étudiants
|
||||||
|
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
Étudiants
|
||||||
"""
|
"""
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
@ -38,9 +42,8 @@ from app.scodoc import sco_groups
|
|||||||
from app.scodoc.sco_bulletins import do_formsemestre_bulletinetud
|
from app.scodoc.sco_bulletins import do_formsemestre_bulletinetud
|
||||||
from app.scodoc import sco_etud
|
from app.scodoc import sco_etud
|
||||||
from app.scodoc.sco_permissions import Permission
|
from app.scodoc.sco_permissions import Permission
|
||||||
|
from app.scodoc import sco_photos
|
||||||
from app.scodoc.sco_utils import json_error, suppress_accents
|
from app.scodoc.sco_utils import json_error, suppress_accents
|
||||||
|
|
||||||
import app.scodoc.sco_photos as sco_photos
|
|
||||||
import app.scodoc.sco_utils as scu
|
import app.scodoc.sco_utils as scu
|
||||||
|
|
||||||
# Un exemple:
|
# Un exemple:
|
||||||
@ -103,6 +106,7 @@ def etudiants_courants(long: bool = False):
|
|||||||
date_courante:<string:date_courante>
|
date_courante:<string:date_courante>
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
|
```json
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": 1234,
|
"id": 1234,
|
||||||
@ -115,6 +119,7 @@ def etudiants_courants(long: bool = False):
|
|||||||
}
|
}
|
||||||
...
|
...
|
||||||
]
|
]
|
||||||
|
```
|
||||||
|
|
||||||
En format "long": voir documentation.
|
En format "long": voir documentation.
|
||||||
|
|
||||||
@ -160,10 +165,13 @@ def etudiant(etudid: int = None, nip: str = None, ine: str = None):
|
|||||||
"""
|
"""
|
||||||
Retourne les informations de l'étudiant correspondant, ou 404 si non trouvé.
|
Retourne les informations de l'étudiant correspondant, ou 404 si non trouvé.
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
etudid : l'etudid de l'étudiant
|
etudid : l'etudid de l'étudiant
|
||||||
nip : le code nip de l'étudiant
|
nip : le code nip de l'étudiant
|
||||||
ine : le code ine de l'étudiant
|
ine : le code ine de l'étudiant
|
||||||
|
|
||||||
|
`etudid` est unique dans la base (tous départements).
|
||||||
Les codes INE et NIP sont uniques au sein d'un département.
|
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.
|
Si plusieurs objets ont le même code, on ramène le plus récemment inscrit.
|
||||||
"""
|
"""
|
||||||
@ -197,6 +205,8 @@ def etudiant_get_photo_image(etudid: int = None, nip: str = None, ine: str = Non
|
|||||||
-----
|
-----
|
||||||
size:<string:size>
|
size:<string:size>
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
etudid : l'etudid de l'étudiant
|
etudid : l'etudid de l'étudiant
|
||||||
nip : le code nip de l'étudiant
|
nip : le code nip de l'étudiant
|
||||||
ine : le code ine de l'étudiant
|
ine : le code ine de l'étudiant
|
||||||
@ -269,9 +279,12 @@ def etudiant_set_photo_image(etudid: int = None):
|
|||||||
@as_json
|
@as_json
|
||||||
def etudiants(etudid: int = None, nip: str = None, ine: str = None):
|
def etudiants(etudid: int = None, nip: str = None, ine: str = None):
|
||||||
"""
|
"""
|
||||||
Info sur le ou les étudiants correspondant. Comme /etudiant mais renvoie
|
Info sur le ou les étudiants correspondants.
|
||||||
toujours une liste.
|
|
||||||
|
Comme `/etudiant` mais renvoie toujours une liste.
|
||||||
|
|
||||||
Si non trouvé, liste vide, pas d'erreur.
|
Si non trouvé, liste vide, pas d'erreur.
|
||||||
|
|
||||||
Dans 99% des cas, la liste contient un seul étudiant, mais si l'étudiant a
|
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.).
|
été inscrit dans plusieurs départements, on a plusieurs objets (1 par dept.).
|
||||||
"""
|
"""
|
||||||
@ -304,8 +317,9 @@ def etudiants(etudid: int = None, nip: str = None, ine: str = None):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def etudiants_by_name(start: str = "", min_len=3, limit=32):
|
def etudiants_by_name(start: str = "", min_len=3, limit=32):
|
||||||
"""Liste des étudiants dont le nom débute par start.
|
"""Liste des étudiants dont le nom débute par `start`.
|
||||||
Si start fait moins de min_len=3 caractères, liste vide.
|
|
||||||
|
Si `start` fait moins de `min_len=3` caractères, liste vide.
|
||||||
La casse et les accents sont ignorés.
|
La casse et les accents sont ignorés.
|
||||||
"""
|
"""
|
||||||
if len(start) < min_len:
|
if len(start) < min_len:
|
||||||
@ -340,13 +354,13 @@ def etudiants_by_name(start: str = "", min_len=3, limit=32):
|
|||||||
@as_json
|
@as_json
|
||||||
def etudiant_formsemestres(etudid: int = None, nip: int = None, ine: int = None):
|
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.
|
Liste des formsemestres qu'un étudiant a suivi, triés par ordre chronologique.
|
||||||
Accès par etudid, nip ou ine.
|
Accès par etudid, nip ou ine.
|
||||||
|
|
||||||
Attention, si accès via NIP ou INE, les semestres peuvent être de départements
|
Attention, si accès via NIP ou INE, les formsemestres peuvent être de départements
|
||||||
différents (si l'étudiant a changé de département). L'id du département est `dept_id`.
|
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.
|
Si accès par département, ne retourne que les formsemestres suivis dans le département.
|
||||||
"""
|
"""
|
||||||
if etudid is not None:
|
if etudid is not None:
|
||||||
q_etud = Identite.query.filter_by(id=etudid)
|
q_etud = Identite.query.filter_by(id=etudid)
|
||||||
@ -475,10 +489,13 @@ def etudiant_groups(formsemestre_id: int, etudid: int = None):
|
|||||||
"""
|
"""
|
||||||
Retourne la liste des groupes auxquels appartient l'étudiant dans le formsemestre indiqué
|
Retourne la liste des groupes auxquels appartient l'étudiant dans le formsemestre indiqué
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
formsemestre_id : l'id d'un formsemestre
|
formsemestre_id : l'id d'un formsemestre
|
||||||
etudid : l'etudid d'un étudiant
|
etudid : l'etudid d'un étudiant
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
|
```json
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"partition_id": 1,
|
"partition_id": 1,
|
||||||
@ -503,6 +520,7 @@ def etudiant_groups(formsemestre_id: int, etudid: int = None):
|
|||||||
"group_name": "A"
|
"group_name": "A"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -530,9 +548,12 @@ def etudiant_groups(formsemestre_id: int, etudid: int = None):
|
|||||||
@permission_required(Permission.EtudInscrit)
|
@permission_required(Permission.EtudInscrit)
|
||||||
@as_json
|
@as_json
|
||||||
def etudiant_create(force=False):
|
def etudiant_create(force=False):
|
||||||
"""Création d'un nouvel étudiant
|
"""Création d'un nouvel étudiant.
|
||||||
|
|
||||||
Si force, crée même si homonymie détectée.
|
Si force, crée même si homonymie détectée.
|
||||||
|
|
||||||
L'étudiant créé n'est pas inscrit à un semestre.
|
L'étudiant créé n'est pas inscrit à un semestre.
|
||||||
|
|
||||||
Champs requis: nom, prenom (sauf si config sans prénom), dept (string:acronyme)
|
Champs requis: nom, prenom (sauf si config sans prénom), dept (string:acronyme)
|
||||||
"""
|
"""
|
||||||
args = request.get_json(force=True) # may raise 400 Bad Request
|
args = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
@ -602,7 +623,10 @@ def etudiant_edit(
|
|||||||
):
|
):
|
||||||
"""Édition des données étudiant (identité, admission, adresses).
|
"""Édition des données étudiant (identité, admission, adresses).
|
||||||
|
|
||||||
`code_type`: `etudid`, `ine` ou `nip`.
|
PARAMS
|
||||||
|
------
|
||||||
|
`code_type`: le type du code, `etudid`, `ine` ou `nip`.
|
||||||
|
`code`: la valeur du code
|
||||||
"""
|
"""
|
||||||
ok, etud = _get_etud_by_code(code_type, code, g.scodoc_dept)
|
ok, etud = _get_etud_by_code(code_type, code, g.scodoc_dept)
|
||||||
if not ok:
|
if not ok:
|
||||||
@ -642,7 +666,23 @@ def etudiant_annotation(
|
|||||||
code_type: str = "etudid",
|
code_type: str = "etudid",
|
||||||
code: str = None,
|
code: str = None,
|
||||||
):
|
):
|
||||||
"""Ajout d'une annotation sur un étudiant"""
|
"""Ajout d'une annotation sur un étudiant.
|
||||||
|
|
||||||
|
Renvoie l'annotation créée.
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
|
`code_type`: le type du code, `etudid`, `ine` ou `nip`.
|
||||||
|
`code`: la valeur du code
|
||||||
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"comment" : string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"""
|
||||||
if not current_user.has_permission(Permission.ViewEtudData):
|
if not current_user.has_permission(Permission.ViewEtudData):
|
||||||
return json_error(403, "non autorisé (manque ViewEtudData)")
|
return json_error(403, "non autorisé (manque ViewEtudData)")
|
||||||
ok, etud = _get_etud_by_code(code_type, code, g.scodoc_dept)
|
ok, etud = _get_etud_by_code(code_type, code, g.scodoc_dept)
|
||||||
@ -679,7 +719,13 @@ def etudiant_annotation_delete(
|
|||||||
code_type: str = "etudid", code: str = None, annotation_id: int = None
|
code_type: str = "etudid", code: str = None, annotation_id: int = None
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Suppression d'une annotation
|
Suppression d'une annotation. On spécifie l'étudiant et l'id de l'annotation.
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
|
`code_type`: le type du code, `etudid`, `ine` ou `nip`.
|
||||||
|
`code`: la valeur du code
|
||||||
|
`annotation_id` : id de l'annotation
|
||||||
"""
|
"""
|
||||||
ok, etud = _get_etud_by_code(code_type, code, g.scodoc_dept)
|
ok, etud = _get_etud_by_code(code_type, code, g.scodoc_dept)
|
||||||
if not ok:
|
if not ok:
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
ScoDoc 9 API : accès aux évaluations
|
ScoDoc 9 API : accès aux évaluations
|
||||||
|
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
Évaluations
|
||||||
"""
|
"""
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
from flask_json import as_json
|
from flask_json import as_json
|
||||||
@ -32,24 +36,28 @@ import app.scodoc.sco_utils as scu
|
|||||||
def get_evaluation(evaluation_id: int):
|
def get_evaluation(evaluation_id: int):
|
||||||
"""Description d'une évaluation.
|
"""Description d'une évaluation.
|
||||||
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
'coefficient': 1.0,
|
'coefficient': 1.0,
|
||||||
'date_debut': '2016-01-04T08:30:00',
|
'date_debut': '2016-01-04T08:30:00',
|
||||||
'date_fin': '2016-01-04T12:30:00',
|
'date_fin': '2016-01-04T12:30:00',
|
||||||
'description': 'TP NI9219 Température',
|
'description': 'TP Température',
|
||||||
'evaluation_type': 0,
|
'evaluation_type': 0,
|
||||||
'id': 15797,
|
'id': 15797,
|
||||||
'moduleimpl_id': 1234,
|
'moduleimpl_id': 1234,
|
||||||
'note_max': 20.0,
|
'note_max': 20.0,
|
||||||
'numero': 3,
|
'numero': 3,
|
||||||
'poids': {
|
'poids': {
|
||||||
'UE1.1': 1.0,
|
'UE1.1': 1.0,
|
||||||
'UE1.2': 1.0,
|
'UE1.2': 1.0,
|
||||||
'UE1.3': 1.0
|
'UE1.3': 1.0
|
||||||
},
|
},
|
||||||
'publish_incomplete': False,
|
'publish_incomplete': False,
|
||||||
'visibulletin': True
|
'visibulletin': True
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = Evaluation.query.filter_by(id=evaluation_id)
|
query = Evaluation.query.filter_by(id=evaluation_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -70,11 +78,13 @@ def get_evaluation(evaluation_id: int):
|
|||||||
@as_json
|
@as_json
|
||||||
def moduleimpl_evaluations(moduleimpl_id: int):
|
def moduleimpl_evaluations(moduleimpl_id: int):
|
||||||
"""
|
"""
|
||||||
Retourne la liste des évaluations d'un moduleimpl
|
Retourne la liste des évaluations d'un moduleimpl.
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
moduleimpl_id : l'id d'un moduleimpl
|
moduleimpl_id : l'id d'un moduleimpl
|
||||||
|
|
||||||
Exemple de résultat : voir /evaluation
|
Exemple de résultat : voir `/evaluation`.
|
||||||
"""
|
"""
|
||||||
modimpl = ModuleImpl.get_modimpl(moduleimpl_id)
|
modimpl = ModuleImpl.get_modimpl(moduleimpl_id)
|
||||||
return [evaluation.to_dict_api() for evaluation in modimpl.evaluations]
|
return [evaluation.to_dict_api() for evaluation in modimpl.evaluations]
|
||||||
@ -88,30 +98,36 @@ def moduleimpl_evaluations(moduleimpl_id: int):
|
|||||||
@as_json
|
@as_json
|
||||||
def evaluation_notes(evaluation_id: int):
|
def evaluation_notes(evaluation_id: int):
|
||||||
"""
|
"""
|
||||||
Retourne la liste des notes de l'évaluation
|
Retourne la liste des notes de l'évaluation.
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
evaluation_id : l'id de l'évaluation
|
evaluation_id : l'id de l'évaluation
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
{
|
```json
|
||||||
"11": {
|
{
|
||||||
|
"11": {
|
||||||
"etudid": 11,
|
"etudid": 11,
|
||||||
"evaluation_id": 1,
|
"evaluation_id": 1,
|
||||||
"value": 15.0,
|
"value": 15.0,
|
||||||
|
"note_max" : 20.0,
|
||||||
"comment": "",
|
"comment": "",
|
||||||
"date": "Wed, 20 Apr 2022 06:49:05 GMT",
|
"date": "2024-07-19T19:08:44+02:00",
|
||||||
"uid": 2
|
"uid": 2
|
||||||
},
|
},
|
||||||
"12": {
|
"12": {
|
||||||
"etudid": 12,
|
"etudid": 12,
|
||||||
"evaluation_id": 1,
|
"evaluation_id": 1,
|
||||||
"value": 12.0,
|
"value": "ABS",
|
||||||
|
"note_max" : 20.0,
|
||||||
"comment": "",
|
"comment": "",
|
||||||
"date": "Wed, 20 Apr 2022 06:49:06 GMT",
|
"date": "2024-07-19T19:08:44+02:00",
|
||||||
"uid": 2
|
"uid": 2
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = Evaluation.query.filter_by(id=evaluation_id)
|
query = Evaluation.query.filter_by(id=evaluation_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -145,13 +161,18 @@ def evaluation_notes(evaluation_id: int):
|
|||||||
@as_json
|
@as_json
|
||||||
def evaluation_set_notes(evaluation_id: int): # evaluation-notes-set
|
def evaluation_set_notes(evaluation_id: int): # evaluation-notes-set
|
||||||
"""Écriture de notes dans une évaluation.
|
"""Écriture de notes dans une évaluation.
|
||||||
The request content type should be "application/json",
|
|
||||||
and contains:
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
'notes' : [ [etudid, value], ... ],
|
'notes' : [ [etudid, value], ... ],
|
||||||
'comment' : optional string
|
'comment' : optional string
|
||||||
}
|
}
|
||||||
Result:
|
```
|
||||||
|
|
||||||
|
Résultat:
|
||||||
|
|
||||||
- nb_changed: nombre de notes changées
|
- nb_changed: nombre de notes changées
|
||||||
- nb_suppress: nombre de notes effacées
|
- nb_suppress: nombre de notes effacées
|
||||||
- etudids_with_decision: liste des etudiants dont la note a changé
|
- etudids_with_decision: liste des etudiants dont la note a changé
|
||||||
@ -186,8 +207,9 @@ def evaluation_set_notes(evaluation_id: int): # evaluation-notes-set
|
|||||||
@as_json
|
@as_json
|
||||||
def evaluation_create(moduleimpl_id: int):
|
def evaluation_create(moduleimpl_id: int):
|
||||||
"""Création d'une évaluation.
|
"""Création d'une évaluation.
|
||||||
The request content type should be "application/json",
|
|
||||||
and contains:
|
DATA
|
||||||
|
----
|
||||||
{
|
{
|
||||||
"description" : str,
|
"description" : str,
|
||||||
"evaluation_type" : int, // {0,1,2} default 0 (normale)
|
"evaluation_type" : int, // {0,1,2} default 0 (normale)
|
||||||
@ -200,7 +222,8 @@ def evaluation_create(moduleimpl_id: int):
|
|||||||
"coefficient" : float, // si non spécifié, 1.0
|
"coefficient" : float, // si non spécifié, 1.0
|
||||||
"poids" : { ue_id : poids } // optionnel
|
"poids" : { ue_id : poids } // optionnel
|
||||||
}
|
}
|
||||||
Result: l'évaluation créée.
|
|
||||||
|
Résultat: l'évaluation créée.
|
||||||
"""
|
"""
|
||||||
moduleimpl: ModuleImpl = ModuleImpl.query.get_or_404(moduleimpl_id)
|
moduleimpl: ModuleImpl = ModuleImpl.query.get_or_404(moduleimpl_id)
|
||||||
if not moduleimpl.can_edit_evaluation(current_user):
|
if not moduleimpl.can_edit_evaluation(current_user):
|
||||||
@ -250,7 +273,7 @@ def evaluation_create(moduleimpl_id: int):
|
|||||||
@as_json
|
@as_json
|
||||||
def evaluation_delete(evaluation_id: int):
|
def evaluation_delete(evaluation_id: int):
|
||||||
"""Suppression d'une évaluation.
|
"""Suppression d'une évaluation.
|
||||||
Efface aussi toutes ses notes
|
Efface aussi toutes ses notes.
|
||||||
"""
|
"""
|
||||||
query = Evaluation.query.filter_by(id=evaluation_id)
|
query = Evaluation.query.filter_by(id=evaluation_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
ScoDoc 9 API : accès aux formations
|
ScoDoc 9 API : accès aux formations
|
||||||
|
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
Formations
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from flask import flash, g, request
|
from flask import flash, g, request
|
||||||
@ -38,7 +42,8 @@ from app.scodoc.sco_permissions import Permission
|
|||||||
@as_json
|
@as_json
|
||||||
def formations():
|
def formations():
|
||||||
"""
|
"""
|
||||||
Retourne la liste de toutes les formations (tous départements)
|
Retourne la liste de toutes les formations (tous départements,
|
||||||
|
sauf si route départementale).
|
||||||
"""
|
"""
|
||||||
query = Formation.query
|
query = Formation.query
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -58,7 +63,7 @@ def formations_ids():
|
|||||||
Retourne la liste de toutes les id de formations
|
Retourne la liste de toutes les id de formations
|
||||||
(tous départements, ou du département indiqué dans la route)
|
(tous départements, ou du département indiqué dans la route)
|
||||||
|
|
||||||
Exemple de résultat : [ 17, 99, 32 ]
|
Exemple de résultat : `[ 17, 99, 32 ]`.
|
||||||
"""
|
"""
|
||||||
query = Formation.query
|
query = Formation.query
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -74,24 +79,26 @@ def formations_ids():
|
|||||||
@as_json
|
@as_json
|
||||||
def formation_by_id(formation_id: int):
|
def formation_by_id(formation_id: int):
|
||||||
"""
|
"""
|
||||||
La formation d'id donné
|
La formation d'id donné.
|
||||||
|
|
||||||
formation_id : l'id d'une formation
|
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
{
|
|
||||||
"id": 1,
|
```json
|
||||||
"acronyme": "BUT R&T",
|
{
|
||||||
"titre_officiel": "Bachelor technologique réseaux et télécommunications",
|
"id": 1,
|
||||||
"formation_code": "V1RET",
|
"acronyme": "BUT R&T",
|
||||||
"code_specialite": null,
|
"titre_officiel": "Bachelor technologique réseaux et télécommunications",
|
||||||
"dept_id": 1,
|
"formation_code": "V1RET",
|
||||||
"titre": "BUT R&T",
|
"code_specialite": null,
|
||||||
"version": 1,
|
"dept_id": 1,
|
||||||
"type_parcours": 700,
|
"titre": "BUT R&T",
|
||||||
"referentiel_competence_id": null,
|
"version": 1,
|
||||||
"formation_id": 1
|
"type_parcours": 700,
|
||||||
}
|
"referentiel_competence_id": null,
|
||||||
|
"formation_id": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = Formation.query.filter_by(id=formation_id)
|
query = Formation.query.filter_by(id=formation_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -123,97 +130,102 @@ def formation_export_by_formation_id(formation_id: int, export_ids=False):
|
|||||||
"""
|
"""
|
||||||
Retourne la formation, avec UE, matières, modules
|
Retourne la formation, avec UE, matières, modules
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
formation_id : l'id d'une formation
|
formation_id : l'id d'une formation
|
||||||
export_ids : True ou False, si l'on veut ou non exporter les ids
|
export_with_ids : si présent, exporte aussi les ids des objets ScoDoc de la formation.
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"acronyme": "BUT R&T",
|
||||||
|
"titre_officiel": "Bachelor technologique r\u00e9seaux et t\u00e9l\u00e9communications",
|
||||||
|
"formation_code": "V1RET",
|
||||||
|
"code_specialite": null,
|
||||||
|
"dept_id": 1,
|
||||||
|
"titre": "BUT R&T",
|
||||||
|
"version": 1,
|
||||||
|
"type_parcours": 700,
|
||||||
|
"referentiel_competence_id": null,
|
||||||
|
"formation_id": 1,
|
||||||
|
"ue": [
|
||||||
{
|
{
|
||||||
"id": 1,
|
"acronyme": "RT1.1",
|
||||||
"acronyme": "BUT R&T",
|
"numero": 1,
|
||||||
"titre_officiel": "Bachelor technologique r\u00e9seaux et t\u00e9l\u00e9communications",
|
"titre": "Administrer les r\u00e9seaux et l\u2019Internet",
|
||||||
"formation_code": "V1RET",
|
"type": 0,
|
||||||
"code_specialite": null,
|
"ue_code": "UCOD11",
|
||||||
"dept_id": 1,
|
"ects": 12.0,
|
||||||
"titre": "BUT R&T",
|
"is_external": false,
|
||||||
"version": 1,
|
"code_apogee": "",
|
||||||
"type_parcours": 700,
|
"coefficient": 0.0,
|
||||||
"referentiel_competence_id": null,
|
"semestre_idx": 1,
|
||||||
"formation_id": 1,
|
"color": "#B80004",
|
||||||
"ue": [
|
"reference": 1,
|
||||||
|
"matiere": [
|
||||||
{
|
{
|
||||||
"acronyme": "RT1.1",
|
"titre": "Administrer les r\u00e9seaux et l\u2019Internet",
|
||||||
"numero": 1,
|
"numero": 1,
|
||||||
"titre": "Administrer les r\u00e9seaux et l\u2019Internet",
|
"module": [
|
||||||
"type": 0,
|
|
||||||
"ue_code": "UCOD11",
|
|
||||||
"ects": 12.0,
|
|
||||||
"is_external": false,
|
|
||||||
"code_apogee": "",
|
|
||||||
"coefficient": 0.0,
|
|
||||||
"semestre_idx": 1,
|
|
||||||
"color": "#B80004",
|
|
||||||
"reference": 1,
|
|
||||||
"matiere": [
|
|
||||||
{
|
{
|
||||||
"titre": "Administrer les r\u00e9seaux et l\u2019Internet",
|
"titre": "Initiation aux r\u00e9seaux informatiques",
|
||||||
"numero": 1,
|
"abbrev": "Init aux r\u00e9seaux informatiques",
|
||||||
"module": [
|
"code": "R101",
|
||||||
|
"heures_cours": 0.0,
|
||||||
|
"heures_td": 0.0,
|
||||||
|
"heures_tp": 0.0,
|
||||||
|
"coefficient": 1.0,
|
||||||
|
"ects": "",
|
||||||
|
"semestre_id": 1,
|
||||||
|
"numero": 10,
|
||||||
|
"code_apogee": "",
|
||||||
|
"module_type": 2,
|
||||||
|
"coefficients": [
|
||||||
{
|
{
|
||||||
"titre": "Initiation aux r\u00e9seaux informatiques",
|
"ue_reference": "1",
|
||||||
"abbrev": "Init aux r\u00e9seaux informatiques",
|
"coef": "12.0"
|
||||||
"code": "R101",
|
|
||||||
"heures_cours": 0.0,
|
|
||||||
"heures_td": 0.0,
|
|
||||||
"heures_tp": 0.0,
|
|
||||||
"coefficient": 1.0,
|
|
||||||
"ects": "",
|
|
||||||
"semestre_id": 1,
|
|
||||||
"numero": 10,
|
|
||||||
"code_apogee": "",
|
|
||||||
"module_type": 2,
|
|
||||||
"coefficients": [
|
|
||||||
{
|
|
||||||
"ue_reference": "1",
|
|
||||||
"coef": "12.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ue_reference": "2",
|
|
||||||
"coef": "4.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ue_reference": "3",
|
|
||||||
"coef": "4.0"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"titre": "Se sensibiliser \u00e0 l'hygi\u00e8ne informatique...",
|
"ue_reference": "2",
|
||||||
"abbrev": "Hygi\u00e8ne informatique",
|
"coef": "4.0"
|
||||||
"code": "SAE11",
|
|
||||||
"heures_cours": 0.0,
|
|
||||||
"heures_td": 0.0,
|
|
||||||
"heures_tp": 0.0,
|
|
||||||
"coefficient": 1.0,
|
|
||||||
"ects": "",
|
|
||||||
"semestre_id": 1,
|
|
||||||
"numero": 10,
|
|
||||||
"code_apogee": "",
|
|
||||||
"module_type": 3,
|
|
||||||
"coefficients": [
|
|
||||||
{
|
|
||||||
"ue_reference": "1",
|
|
||||||
"coef": "16.0"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
...
|
{
|
||||||
]
|
"ue_reference": "3",
|
||||||
|
"coef": "4.0"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"titre": "Se sensibiliser \u00e0 l'hygi\u00e8ne informatique...",
|
||||||
|
"abbrev": "Hygi\u00e8ne informatique",
|
||||||
|
"code": "SAE11",
|
||||||
|
"heures_cours": 0.0,
|
||||||
|
"heures_td": 0.0,
|
||||||
|
"heures_tp": 0.0,
|
||||||
|
"coefficient": 1.0,
|
||||||
|
"ects": "",
|
||||||
|
"semestre_id": 1,
|
||||||
|
"numero": 10,
|
||||||
|
"code_apogee": "",
|
||||||
|
"module_type": 3,
|
||||||
|
"coefficients": [
|
||||||
|
{
|
||||||
|
"ue_reference": "1",
|
||||||
|
"coef": "16.0"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
]
|
...
|
||||||
}
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = Formation.query.filter_by(id=formation_id)
|
query = Formation.query.filter_by(id=formation_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -236,11 +248,8 @@ def formation_export_by_formation_id(formation_id: int, export_ids=False):
|
|||||||
@as_json
|
@as_json
|
||||||
def referentiel_competences(formation_id: int):
|
def referentiel_competences(formation_id: int):
|
||||||
"""
|
"""
|
||||||
Retourne le référentiel de compétences
|
Retourne le référentiel de compétences de la formation
|
||||||
|
ou null si pas de référentiel associé.
|
||||||
formation_id : l'id d'une formation
|
|
||||||
|
|
||||||
return null si pas de référentiel associé.
|
|
||||||
"""
|
"""
|
||||||
query = Formation.query.filter_by(id=formation_id)
|
query = Formation.query.filter_by(id=formation_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -259,8 +268,14 @@ def referentiel_competences(formation_id: int):
|
|||||||
@as_json
|
@as_json
|
||||||
def ue_set_parcours(ue_id: int):
|
def ue_set_parcours(ue_id: int):
|
||||||
"""Associe UE et parcours BUT.
|
"""Associe UE et parcours BUT.
|
||||||
|
|
||||||
La liste des ids de parcours est passée en argument JSON.
|
La liste des ids de parcours est passée en argument JSON.
|
||||||
JSON arg: [parcour_id1, parcour_id2, ...]
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
|
[ parcour_id1, parcour_id2, ... ]
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = UniteEns.query.filter_by(id=ue_id)
|
query = UniteEns.query.filter_by(id=ue_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -293,7 +308,7 @@ def ue_set_parcours(ue_id: int):
|
|||||||
@permission_required(Permission.EditFormation)
|
@permission_required(Permission.EditFormation)
|
||||||
@as_json
|
@as_json
|
||||||
def ue_assoc_niveau(ue_id: int, niveau_id: int):
|
def ue_assoc_niveau(ue_id: int, niveau_id: int):
|
||||||
"""Associe l'UE au niveau de compétence"""
|
"""Associe l'UE au niveau de compétence."""
|
||||||
query = UniteEns.query.filter_by(id=ue_id)
|
query = UniteEns.query.filter_by(id=ue_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.join(Formation).filter_by(dept_id=g.scodoc_dept_id)
|
query = query.join(Formation).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
@ -323,7 +338,7 @@ def ue_assoc_niveau(ue_id: int, niveau_id: int):
|
|||||||
@as_json
|
@as_json
|
||||||
def ue_desassoc_niveau(ue_id: int):
|
def ue_desassoc_niveau(ue_id: int):
|
||||||
"""Désassocie cette UE de son niveau de compétence
|
"""Désassocie cette UE de son niveau de compétence
|
||||||
(si elle n'est pas associée, ne fait rien)
|
(si elle n'est pas associée, ne fait rien).
|
||||||
"""
|
"""
|
||||||
query = UniteEns.query.filter_by(id=ue_id)
|
query = UniteEns.query.filter_by(id=ue_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -345,7 +360,7 @@ def ue_desassoc_niveau(ue_id: int):
|
|||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def get_ue(ue_id: int):
|
def get_ue(ue_id: int):
|
||||||
"""Renvoie l'UE"""
|
"""Renvoie l'UE."""
|
||||||
query = UniteEns.query.filter_by(id=ue_id)
|
query = UniteEns.query.filter_by(id=ue_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.join(Formation).filter_by(dept_id=g.scodoc_dept_id)
|
query = query.join(Formation).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
@ -359,7 +374,7 @@ def get_ue(ue_id: int):
|
|||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def formation_module_get(module_id: int):
|
def formation_module_get(module_id: int):
|
||||||
"""Renvoie le module"""
|
"""Renvoie le module."""
|
||||||
query = Module.query.filter_by(id=module_id)
|
query = Module.query.filter_by(id=module_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.join(Formation).filter_by(dept_id=g.scodoc_dept_id)
|
query = query.join(Formation).filter_by(dept_id=g.scodoc_dept_id)
|
||||||
@ -390,15 +405,17 @@ def formation_module_get(module_id: int):
|
|||||||
@permission_required(Permission.EditFormation)
|
@permission_required(Permission.EditFormation)
|
||||||
def ue_set_code_apogee(ue_id: int | None = None, code_apogee: str = ""):
|
def ue_set_code_apogee(ue_id: int | None = None, code_apogee: str = ""):
|
||||||
"""Change le code Apogée de l'UE.
|
"""Change le code Apogée de l'UE.
|
||||||
|
|
||||||
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
||||||
par des virgules.
|
par des virgules.
|
||||||
(Ce changement peut être fait sur formation verrouillée)
|
|
||||||
|
|
||||||
Si ue_id n'est pas spécifié, utilise l'argument oid du POST.
|
Ce changement peut être fait sur formation verrouillée.
|
||||||
Si code_apogee n'est pas spécifié ou vide,
|
|
||||||
utilise l'argument value du POST
|
|
||||||
|
|
||||||
Le retour est une chaîne (le code enregistré), pas json.
|
Si `ue_id` n'est pas spécifié, utilise l'argument oid du POST.
|
||||||
|
Si `code_apogee` n'est pas spécifié ou vide,
|
||||||
|
utilise l'argument value du POST.
|
||||||
|
|
||||||
|
Le retour est une chaîne (le code enregistré), pas du json.
|
||||||
"""
|
"""
|
||||||
if ue_id is None:
|
if ue_id is None:
|
||||||
ue_id = request.form.get("oid")
|
ue_id = request.form.get("oid")
|
||||||
@ -444,14 +461,16 @@ def ue_set_code_apogee(ue_id: int | None = None, code_apogee: str = ""):
|
|||||||
@permission_required(Permission.EditFormation)
|
@permission_required(Permission.EditFormation)
|
||||||
def ue_set_code_apogee_rcue(ue_id: int, code_apogee: str = ""):
|
def ue_set_code_apogee_rcue(ue_id: int, code_apogee: str = ""):
|
||||||
"""Change le code Apogée du RCUE de l'UE.
|
"""Change le code Apogée du RCUE de l'UE.
|
||||||
|
|
||||||
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
||||||
par des virgules.
|
par des virgules.
|
||||||
(Ce changement peut être fait sur formation verrouillée)
|
|
||||||
|
Ce changement peut être fait sur formation verrouillée.
|
||||||
|
|
||||||
Si code_apogee n'est pas spécifié ou vide,
|
Si code_apogee n'est pas spécifié ou vide,
|
||||||
utilise l'argument value du POST (utilisé par jinplace.js)
|
utilise l'argument value du POST (utilisé par `jinplace.js`)
|
||||||
|
|
||||||
Le retour est une chaîne (le code enregistré), pas json.
|
Le retour est une chaîne (le code enregistré), pas du json.
|
||||||
"""
|
"""
|
||||||
if not code_apogee:
|
if not code_apogee:
|
||||||
code_apogee = request.form.get("value", "")
|
code_apogee = request.form.get("value", "")
|
||||||
@ -497,15 +516,17 @@ def formation_module_set_code_apogee(
|
|||||||
module_id: int | None = None, code_apogee: str = ""
|
module_id: int | None = None, code_apogee: str = ""
|
||||||
):
|
):
|
||||||
"""Change le code Apogée du module.
|
"""Change le code Apogée du module.
|
||||||
|
|
||||||
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
||||||
par des virgules.
|
par des virgules.
|
||||||
(Ce changement peut être fait sur formation verrouillée)
|
|
||||||
|
|
||||||
Si module_id n'est pas spécifié, utilise l'argument oid du POST.
|
Ce changement peut être fait sur formation verrouillée.
|
||||||
Si code_apogee n'est pas spécifié ou vide,
|
|
||||||
|
Si `module_id` n'est pas spécifié, utilise l'argument `oid` du POST.
|
||||||
|
Si `code_apogee` n'est pas spécifié ou vide,
|
||||||
utilise l'argument value du POST (utilisé par jinplace.js)
|
utilise l'argument value du POST (utilisé par jinplace.js)
|
||||||
|
|
||||||
Le retour est une chaîne (le code enregistré), pas json.
|
Le retour est une chaîne (le code enregistré), pas du json.
|
||||||
"""
|
"""
|
||||||
if module_id is None:
|
if module_id is None:
|
||||||
module_id = request.form.get("oid")
|
module_id = request.form.get("oid")
|
||||||
|
@ -6,6 +6,12 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
ScoDoc 9 API : accès aux formsemestres
|
ScoDoc 9 API : accès aux formsemestres
|
||||||
|
|
||||||
|
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
FormSemestre
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from operator import attrgetter, itemgetter
|
from operator import attrgetter, itemgetter
|
||||||
|
|
||||||
@ -55,36 +61,37 @@ def formsemestre_infos(formsemestre_id: int):
|
|||||||
formsemestre_id : l'id du formsemestre
|
formsemestre_id : l'id du formsemestre
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
{
|
```json
|
||||||
"block_moyennes": false,
|
{
|
||||||
"bul_bgcolor": "white",
|
"block_moyennes": false,
|
||||||
"bul_hide_xml": false,
|
"bul_bgcolor": "white",
|
||||||
"date_debut_iso": "2021-09-01",
|
"bul_hide_xml": false,
|
||||||
"date_debut": "01/09/2021",
|
"date_debut_iso": "2021-09-01",
|
||||||
"date_fin_iso": "2022-08-31",
|
"date_debut": "01/09/2021",
|
||||||
"date_fin": "31/08/2022",
|
"date_fin_iso": "2022-08-31",
|
||||||
"dept_id": 1,
|
"date_fin": "31/08/2022",
|
||||||
"elt_annee_apo": null,
|
"dept_id": 1,
|
||||||
"elt_passage_apo" : null,
|
"elt_annee_apo": null,
|
||||||
"elt_sem_apo": null,
|
"elt_passage_apo" : null,
|
||||||
"ens_can_edit_eval": false,
|
"elt_sem_apo": null,
|
||||||
"etat": true,
|
"ens_can_edit_eval": false,
|
||||||
"formation_id": 1,
|
"etat": true,
|
||||||
"formsemestre_id": 1,
|
"formation_id": 1,
|
||||||
"gestion_compensation": false,
|
"formsemestre_id": 1,
|
||||||
"gestion_semestrielle": false,
|
"gestion_compensation": false,
|
||||||
"id": 1,
|
"gestion_semestrielle": false,
|
||||||
"modalite": "FI",
|
"id": 1,
|
||||||
"resp_can_change_ens": true,
|
"modalite": "FI",
|
||||||
"resp_can_edit": false,
|
"resp_can_change_ens": true,
|
||||||
"responsables": [1, 99], // uids
|
"resp_can_edit": false,
|
||||||
"scodoc7_id": null,
|
"responsables": [1, 99], // uids
|
||||||
"semestre_id": 1,
|
"scodoc7_id": null,
|
||||||
"titre_formation" : "BUT GEA",
|
"semestre_id": 1,
|
||||||
"titre_num": "BUT GEA semestre 1",
|
"titre_formation" : "BUT GEA",
|
||||||
"titre": "BUT GEA",
|
"titre_num": "BUT GEA semestre 1",
|
||||||
}
|
"titre": "BUT GEA",
|
||||||
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -101,8 +108,8 @@ def formsemestre_infos(formsemestre_id: int):
|
|||||||
@as_json
|
@as_json
|
||||||
def formsemestres_query():
|
def formsemestres_query():
|
||||||
"""
|
"""
|
||||||
Retourne les formsemestres filtrés par
|
Retourne les formsemestres filtrés par étape Apogée ou année scolaire
|
||||||
étape Apogée ou année scolaire ou département (acronyme ou id) ou état ou code étudiant
|
ou département (acronyme ou id) ou état ou code étudiant.
|
||||||
|
|
||||||
PARAMS
|
PARAMS
|
||||||
------
|
------
|
||||||
@ -192,7 +199,36 @@ def formsemestres_query():
|
|||||||
@permission_required(Permission.EditFormSemestre)
|
@permission_required(Permission.EditFormSemestre)
|
||||||
@as_json
|
@as_json
|
||||||
def formsemestre_edit(formsemestre_id: int):
|
def formsemestre_edit(formsemestre_id: int):
|
||||||
"""Modifie les champs d'un formsemestre."""
|
"""Modifie les champs d'un formsemestre.
|
||||||
|
|
||||||
|
On peut spécifier un ou plusieurs champs.
|
||||||
|
|
||||||
|
DATA
|
||||||
|
---
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"semestre_id" : string,
|
||||||
|
"titre" : string,
|
||||||
|
"date_debut" : date iso,
|
||||||
|
"date_fin" : date iso,
|
||||||
|
"edt_id" : string,
|
||||||
|
"etat" : string,
|
||||||
|
"modalite" : string,
|
||||||
|
"gestion_compensation" : bool,
|
||||||
|
"bul_hide_xml" : bool,
|
||||||
|
"block_moyennes" : bool,
|
||||||
|
"block_moyenne_generale" : bool,
|
||||||
|
"mode_calcul_moyennes" : string,
|
||||||
|
"gestion_semestrielle" : string,
|
||||||
|
"bul_bgcolor" : string,
|
||||||
|
"resp_can_edit" : bool,
|
||||||
|
"resp_can_change_ens" : bool,
|
||||||
|
"ens_can_edit_eval" : bool,
|
||||||
|
"elt_sem_apo" : string,
|
||||||
|
"elt_annee_apo : string,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
"""
|
||||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
args = request.get_json(force=True) # may raise 400 Bad Request
|
args = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
editable_keys = {
|
editable_keys = {
|
||||||
@ -230,13 +266,19 @@ def formsemestre_edit(formsemestre_id: int):
|
|||||||
@permission_required(Permission.EditApogee)
|
@permission_required(Permission.EditApogee)
|
||||||
def formsemestre_set_apo_etapes():
|
def formsemestre_set_apo_etapes():
|
||||||
"""Change les codes étapes du semestre indiqué.
|
"""Change les codes étapes du semestre indiqué.
|
||||||
|
|
||||||
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
||||||
par des virgules.
|
par des virgules.
|
||||||
(Ce changement peut être fait sur un semestre verrouillé)
|
|
||||||
|
|
||||||
Args:
|
Ce changement peut être fait sur un semestre verrouillé
|
||||||
oid=int, le formsemestre_id
|
|
||||||
value=chaine "V1RT, V1RT2", codes séparés par des virgules
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
oid : int, le formsemestre_id
|
||||||
|
value : string, eg "V1RT, V1RT2", codes séparés par des virgules
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
formsemestre_id = int(request.form.get("oid"))
|
formsemestre_id = int(request.form.get("oid"))
|
||||||
etapes_apo_str = request.form.get("value")
|
etapes_apo_str = request.form.get("value")
|
||||||
@ -267,13 +309,20 @@ def formsemestre_set_apo_etapes():
|
|||||||
@permission_required(Permission.EditApogee)
|
@permission_required(Permission.EditApogee)
|
||||||
def formsemestre_set_elt_sem_apo():
|
def formsemestre_set_elt_sem_apo():
|
||||||
"""Change les codes étapes du semestre indiqué.
|
"""Change les codes étapes du semestre indiqué.
|
||||||
|
|
||||||
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
||||||
par des virgules.
|
par des virgules.
|
||||||
(Ce changement peut être fait sur un semestre verrouillé)
|
|
||||||
|
|
||||||
Args:
|
Ce changement peut être fait sur un semestre verrouillé.
|
||||||
oid=int, le formsemestre_id
|
|
||||||
value=chaine "V3ONM, V3ONM1, V3ONM2", codes séparés par des virgules
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
oid : int, le formsemestre_id
|
||||||
|
value : string, eg "V3ONM, V3ONM1, V3ONM2", codes séparés par des virgules
|
||||||
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
oid = int(request.form.get("oid"))
|
oid = int(request.form.get("oid"))
|
||||||
value = (request.form.get("value") or "").strip()
|
value = (request.form.get("value") or "").strip()
|
||||||
@ -295,13 +344,20 @@ def formsemestre_set_elt_sem_apo():
|
|||||||
@permission_required(Permission.EditApogee)
|
@permission_required(Permission.EditApogee)
|
||||||
def formsemestre_set_elt_annee_apo():
|
def formsemestre_set_elt_annee_apo():
|
||||||
"""Change les codes étapes du semestre indiqué (par le champ oid).
|
"""Change les codes étapes du semestre indiqué (par le champ oid).
|
||||||
|
|
||||||
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
||||||
par des virgules.
|
par des virgules.
|
||||||
(Ce changement peut être fait sur un semestre verrouillé)
|
|
||||||
|
|
||||||
Args:
|
Ce changement peut être fait sur un semestre verrouillé.
|
||||||
oid=int, le formsemestre_id
|
|
||||||
value=chaine "V3ONM, V3ONM1, V3ONM2", codes séparés par des virgules
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
oid : int, le formsemestre_id
|
||||||
|
value : string, eg "V3ONM, V3ONM1, V3ONM2", codes séparés par des virgules
|
||||||
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
oid = int(request.form.get("oid"))
|
oid = int(request.form.get("oid"))
|
||||||
value = (request.form.get("value") or "").strip()
|
value = (request.form.get("value") or "").strip()
|
||||||
@ -323,13 +379,20 @@ def formsemestre_set_elt_annee_apo():
|
|||||||
@permission_required(Permission.EditApogee)
|
@permission_required(Permission.EditApogee)
|
||||||
def formsemestre_set_elt_passage_apo():
|
def formsemestre_set_elt_passage_apo():
|
||||||
"""Change les codes apogée de passage du semestre indiqué (par le champ oid).
|
"""Change les codes apogée de passage du semestre indiqué (par le champ oid).
|
||||||
|
|
||||||
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
Le code est une chaîne, avec éventuellement plusieurs valeurs séparées
|
||||||
par des virgules.
|
par des virgules.
|
||||||
(Ce changement peut être fait sur un semestre verrouillé)
|
|
||||||
|
|
||||||
Args:
|
Ce changement peut être fait sur un semestre verrouillé.
|
||||||
oid=int, le formsemestre_id
|
|
||||||
value=chaine "V3ONM, V3ONM1, V3ONM2", codes séparés par des virgules
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
oid : int, le formsemestre_id
|
||||||
|
value : string, eg "V3ONM, V3ONM1, V3ONM2", codes séparés par des virgules
|
||||||
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
oid = int(request.form.get("oid"))
|
oid = int(request.form.get("oid"))
|
||||||
value = (request.form.get("value") or "").strip()
|
value = (request.form.get("value") or "").strip()
|
||||||
@ -355,9 +418,12 @@ def formsemestre_set_elt_passage_apo():
|
|||||||
@as_json
|
@as_json
|
||||||
def bulletins(formsemestre_id: int, version: str = "long"):
|
def bulletins(formsemestre_id: int, version: str = "long"):
|
||||||
"""
|
"""
|
||||||
Retourne les bulletins d'un formsemestre donné
|
Retourne les bulletins d'un formsemestre.
|
||||||
|
|
||||||
formsemestre_id : l'id d'un formesemestre
|
PARAMS
|
||||||
|
------
|
||||||
|
formsemestre_id : int
|
||||||
|
version : string ("long", "short", "selectedevals")
|
||||||
|
|
||||||
Exemple de résultat : liste, voir https://scodoc.org/ScoDoc9API/#bulletin
|
Exemple de résultat : liste, voir https://scodoc.org/ScoDoc9API/#bulletin
|
||||||
"""
|
"""
|
||||||
@ -389,66 +455,67 @@ def formsemestre_programme(formsemestre_id: int):
|
|||||||
"""
|
"""
|
||||||
Retourne la liste des UEs, ressources et SAEs d'un semestre
|
Retourne la liste des UEs, ressources et SAEs d'un semestre
|
||||||
|
|
||||||
formsemestre_id : l'id d'un formsemestre
|
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ues": [
|
||||||
{
|
{
|
||||||
"ues": [
|
"type": 0,
|
||||||
{
|
"formation_id": 1,
|
||||||
"type": 0,
|
"ue_code": "UCOD11",
|
||||||
"formation_id": 1,
|
"id": 1,
|
||||||
"ue_code": "UCOD11",
|
"ects": 12.0,
|
||||||
"id": 1,
|
"acronyme": "RT1.1",
|
||||||
"ects": 12.0,
|
"is_external": false,
|
||||||
"acronyme": "RT1.1",
|
"numero": 1,
|
||||||
"is_external": false,
|
"code_apogee": "",
|
||||||
"numero": 1,
|
"titre": "Administrer les r\u00e9seaux et l\u2019Internet",
|
||||||
"code_apogee": "",
|
"coefficient": 0.0,
|
||||||
"titre": "Administrer les r\u00e9seaux et l\u2019Internet",
|
"semestre_idx": 1,
|
||||||
"coefficient": 0.0,
|
"color": "#B80004",
|
||||||
"semestre_idx": 1,
|
"ue_id": 1
|
||||||
"color": "#B80004",
|
},
|
||||||
"ue_id": 1
|
...
|
||||||
},
|
],
|
||||||
...
|
"ressources": [
|
||||||
],
|
{
|
||||||
"ressources": [
|
"ens": [ 10, 18 ],
|
||||||
{
|
"formsemestre_id": 1,
|
||||||
"ens": [ 10, 18 ],
|
"id": 15,
|
||||||
"formsemestre_id": 1,
|
"module": {
|
||||||
|
"abbrev": "Programmer",
|
||||||
|
"code": "SAE15",
|
||||||
|
"code_apogee": "V7GOP",
|
||||||
|
"coefficient": 1.0,
|
||||||
|
"formation_id": 1,
|
||||||
|
"heures_cours": 0.0,
|
||||||
|
"heures_td": 0.0,
|
||||||
|
"heures_tp": 0.0,
|
||||||
"id": 15,
|
"id": 15,
|
||||||
"module": {
|
"matiere_id": 3,
|
||||||
"abbrev": "Programmer",
|
|
||||||
"code": "SAE15",
|
|
||||||
"code_apogee": "V7GOP",
|
|
||||||
"coefficient": 1.0,
|
|
||||||
"formation_id": 1,
|
|
||||||
"heures_cours": 0.0,
|
|
||||||
"heures_td": 0.0,
|
|
||||||
"heures_tp": 0.0,
|
|
||||||
"id": 15,
|
|
||||||
"matiere_id": 3,
|
|
||||||
"module_id": 15,
|
|
||||||
"module_type": 3,
|
|
||||||
"numero": 50,
|
|
||||||
"semestre_id": 1,
|
|
||||||
"titre": "Programmer en Python",
|
|
||||||
"ue_id": 3
|
|
||||||
},
|
|
||||||
"module_id": 15,
|
"module_id": 15,
|
||||||
"moduleimpl_id": 15,
|
"module_type": 3,
|
||||||
"responsable_id": 2
|
"numero": 50,
|
||||||
},
|
"semestre_id": 1,
|
||||||
|
"titre": "Programmer en Python",
|
||||||
|
"ue_id": 3
|
||||||
|
},
|
||||||
|
"module_id": 15,
|
||||||
|
"moduleimpl_id": 15,
|
||||||
|
"responsable_id": 2
|
||||||
|
},
|
||||||
|
...
|
||||||
|
],
|
||||||
|
"saes": [
|
||||||
|
{
|
||||||
...
|
...
|
||||||
],
|
},
|
||||||
"saes": [
|
...
|
||||||
{
|
],
|
||||||
...
|
"modules" : [ ... les modules qui ne sont ni des SAEs ni des ressources ... ]
|
||||||
},
|
}
|
||||||
...
|
```
|
||||||
],
|
|
||||||
"modules" : [ ... les modules qui ne sont ni des SAEs ni des ressources ... ]
|
|
||||||
}
|
|
||||||
"""
|
"""
|
||||||
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -567,9 +634,9 @@ def formsemestre_etat_evaluations(formsemestre_id: int):
|
|||||||
"""
|
"""
|
||||||
Informations sur l'état des évaluations d'un formsemestre.
|
Informations sur l'état des évaluations d'un formsemestre.
|
||||||
|
|
||||||
formsemestre_id : l'id d'un semestre
|
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
|
|
||||||
|
```json
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"id": 1, // moduleimpl_id
|
"id": 1, // moduleimpl_id
|
||||||
@ -597,6 +664,7 @@ def formsemestre_etat_evaluations(formsemestre_id: int):
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
app.set_sco_dept(formsemestre.departement.acronym)
|
app.set_sco_dept(formsemestre.departement.acronym)
|
||||||
@ -671,7 +739,8 @@ def formsemestre_etat_evaluations(formsemestre_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def formsemestre_resultat(formsemestre_id: int):
|
def formsemestre_resultat(formsemestre_id: int):
|
||||||
"""Tableau récapitulatif des résultats
|
"""Tableau récapitulatif des résultats.
|
||||||
|
|
||||||
Pour chaque étudiant, son état, ses groupes, ses moyennes d'UE et de modules.
|
Pour chaque étudiant, son état, ses groupes, ses moyennes d'UE et de modules.
|
||||||
|
|
||||||
Si `format=raw`, ne converti pas les valeurs.
|
Si `format=raw`, ne converti pas les valeurs.
|
||||||
@ -726,7 +795,7 @@ def formsemestre_resultat(formsemestre_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def groups_get_auto_assignment(formsemestre_id: int):
|
def groups_get_auto_assignment(formsemestre_id: int):
|
||||||
"""rend les données stockées par"""
|
"""Rend les données stockées par `groups_save_auto_assignment`."""
|
||||||
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
||||||
@ -747,12 +816,17 @@ def groups_get_auto_assignment(formsemestre_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def groups_save_auto_assignment(formsemestre_id: int):
|
def groups_save_auto_assignment(formsemestre_id: int):
|
||||||
"""enregistre les données"""
|
"""Enregistre les données, associées à ce formsemestre.
|
||||||
|
Usage réservé aux fonctions de gestion des groupes, ne pas utiliser ailleurs.
|
||||||
|
"""
|
||||||
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
query = query.filter_by(dept_id=g.scodoc_dept_id)
|
||||||
formsemestre: FormSemestre = query.first_or_404(formsemestre_id)
|
formsemestre: FormSemestre = query.first_or_404(formsemestre_id)
|
||||||
|
|
||||||
|
if not formsemestre.can_change_groups():
|
||||||
|
return json_error(403, "non autorisé (can_change_groups)")
|
||||||
|
|
||||||
if len(request.data) > GROUPS_AUTO_ASSIGNMENT_DATA_MAX:
|
if len(request.data) > GROUPS_AUTO_ASSIGNMENT_DATA_MAX:
|
||||||
return json_error(413, "data too large")
|
return json_error(413, "data too large")
|
||||||
formsemestre.groups_auto_assignment_data = request.data
|
formsemestre.groups_auto_assignment_data = request.data
|
||||||
@ -767,17 +841,16 @@ def groups_save_auto_assignment(formsemestre_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def formsemestre_edt(formsemestre_id: int):
|
def formsemestre_edt(formsemestre_id: int):
|
||||||
"""l'emploi du temps du semestre.
|
"""L'emploi du temps du semestre.
|
||||||
|
|
||||||
Si ok, une liste d'évènements. Sinon, une chaine indiquant un message d'erreur.
|
Si ok, une liste d'évènements. Sinon, une chaine indiquant un message d'erreur.
|
||||||
|
|
||||||
group_ids permet de filtrer sur les groupes ScoDoc.
|
Expérimental, ne pas utiliser hors ScoDoc.
|
||||||
show_modules_titles affiche le titre complet du module (défaut), sinon juste le code.
|
|
||||||
|
|
||||||
QUERY
|
QUERY
|
||||||
-----
|
-----
|
||||||
group_ids:<string:group_ids>
|
group_ids : string (optionnel) filtre sur les groupes ScoDoc.
|
||||||
show_modules_titles:<bool:show_modules_titles>
|
show_modules_titles: show_modules_titles affiche le titre complet du module (défaut), sinon juste le code.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
|
@ -5,7 +5,12 @@
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
"""
|
"""
|
||||||
ScoDoc 9 API : jury WIP à compléter avec enregistrement décisions
|
ScoDoc 9 API : jury WIP à compléter avec enregistrement décisions.
|
||||||
|
|
||||||
|
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
Jury
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
@ -91,7 +96,7 @@ def _news_delete_jury_etud(etud: Identite, detail: str = ""):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def validation_ue_delete(etudid: int, validation_id: int):
|
def validation_ue_delete(etudid: int, validation_id: int):
|
||||||
"Efface cette validation"
|
"Efface cette validation d'UE."
|
||||||
return _validation_ue_delete(etudid, validation_id)
|
return _validation_ue_delete(etudid, validation_id)
|
||||||
|
|
||||||
|
|
||||||
@ -108,7 +113,7 @@ def validation_ue_delete(etudid: int, validation_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def validation_formsemestre_delete(etudid: int, validation_id: int):
|
def validation_formsemestre_delete(etudid: int, validation_id: int):
|
||||||
"Efface cette validation"
|
"Efface cette validation de semestre."
|
||||||
# c'est la même chose (formations classiques)
|
# c'est la même chose (formations classiques)
|
||||||
return _validation_ue_delete(etudid, validation_id)
|
return _validation_ue_delete(etudid, validation_id)
|
||||||
|
|
||||||
@ -160,7 +165,7 @@ def _validation_ue_delete(etudid: int, validation_id: int):
|
|||||||
@permission_required(Permission.EtudInscrit)
|
@permission_required(Permission.EtudInscrit)
|
||||||
@as_json
|
@as_json
|
||||||
def autorisation_inscription_delete(etudid: int, validation_id: int):
|
def autorisation_inscription_delete(etudid: int, validation_id: int):
|
||||||
"Efface cette validation"
|
"Efface cette autorisation d'inscription."
|
||||||
etud = tools.get_etud(etudid)
|
etud = tools.get_etud(etudid)
|
||||||
if etud is None:
|
if etud is None:
|
||||||
return "étudiant inconnu", 404
|
return "étudiant inconnu", 404
|
||||||
@ -189,8 +194,12 @@ def autorisation_inscription_delete(etudid: int, validation_id: int):
|
|||||||
@as_json
|
@as_json
|
||||||
def validation_rcue_record(etudid: int):
|
def validation_rcue_record(etudid: int):
|
||||||
"""Enregistre une validation de RCUE.
|
"""Enregistre une validation de RCUE.
|
||||||
|
|
||||||
Si une validation existe déjà pour ce RCUE, la remplace.
|
Si une validation existe déjà pour ce RCUE, la remplace.
|
||||||
The request content type should be "application/json":
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"code" : str,
|
"code" : str,
|
||||||
"ue1_id" : int,
|
"ue1_id" : int,
|
||||||
@ -200,6 +209,7 @@ def validation_rcue_record(etudid: int):
|
|||||||
"date" : date_iso, // si non spécifié, now()
|
"date" : date_iso, // si non spécifié, now()
|
||||||
"parcours_id" :int,
|
"parcours_id" :int,
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
etud = tools.get_etud(etudid)
|
etud = tools.get_etud(etudid)
|
||||||
if etud is None:
|
if etud is None:
|
||||||
@ -314,7 +324,7 @@ def validation_rcue_record(etudid: int):
|
|||||||
@permission_required(Permission.EtudInscrit)
|
@permission_required(Permission.EtudInscrit)
|
||||||
@as_json
|
@as_json
|
||||||
def validation_rcue_delete(etudid: int, validation_id: int):
|
def validation_rcue_delete(etudid: int, validation_id: int):
|
||||||
"Efface cette validation"
|
"Efface cette validation de RCUE."
|
||||||
etud = tools.get_etud(etudid)
|
etud = tools.get_etud(etudid)
|
||||||
if etud is None:
|
if etud is None:
|
||||||
return "étudiant inconnu", 404
|
return "étudiant inconnu", 404
|
||||||
@ -342,7 +352,7 @@ def validation_rcue_delete(etudid: int, validation_id: int):
|
|||||||
@permission_required(Permission.EtudInscrit)
|
@permission_required(Permission.EtudInscrit)
|
||||||
@as_json
|
@as_json
|
||||||
def validation_annee_but_delete(etudid: int, validation_id: int):
|
def validation_annee_but_delete(etudid: int, validation_id: int):
|
||||||
"Efface cette validation"
|
"Efface cette validation d'année BUT."
|
||||||
etud = tools.get_etud(etudid)
|
etud = tools.get_etud(etudid)
|
||||||
if etud is None:
|
if etud is None:
|
||||||
return "étudiant inconnu", 404
|
return "étudiant inconnu", 404
|
||||||
@ -371,7 +381,7 @@ def validation_annee_but_delete(etudid: int, validation_id: int):
|
|||||||
@permission_required(Permission.EtudInscrit)
|
@permission_required(Permission.EtudInscrit)
|
||||||
@as_json
|
@as_json
|
||||||
def validation_dut120_delete(etudid: int, validation_id: int):
|
def validation_dut120_delete(etudid: int, validation_id: int):
|
||||||
"Efface cette validation"
|
"Efface cette validation de DUT120."
|
||||||
etud = tools.get_etud(etudid)
|
etud = tools.get_etud(etudid)
|
||||||
if etud is None:
|
if etud is None:
|
||||||
return "étudiant inconnu", 404
|
return "étudiant inconnu", 404
|
||||||
|
@ -50,7 +50,7 @@ from app.scodoc.sco_utils import json_error
|
|||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def logo_list_globals():
|
def logo_list_globals():
|
||||||
"""Liste tous les logos"""
|
"""Liste des noms des logos définis pour le site ScoDoc."""
|
||||||
logos = list_logos()[None]
|
logos = list_logos()[None]
|
||||||
return list(logos.keys())
|
return list(logos.keys())
|
||||||
|
|
||||||
@ -59,6 +59,11 @@ def logo_list_globals():
|
|||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
def logo_get_global(logoname):
|
def logo_get_global(logoname):
|
||||||
|
"""Renvoie le logo global de nom donné.
|
||||||
|
|
||||||
|
L'image est au format png ou jpg; le format retourné dépend du format sous lequel
|
||||||
|
l'image a été initialement enregistrée.
|
||||||
|
"""
|
||||||
logo = find_logo(logoname=logoname)
|
logo = find_logo(logoname=logoname)
|
||||||
if logo is None:
|
if logo is None:
|
||||||
return json_error(404, message="logo not found")
|
return json_error(404, message="logo not found")
|
||||||
@ -80,6 +85,9 @@ def _core_get_logos(dept_id) -> list:
|
|||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def logo_get_local_by_acronym(departement):
|
def logo_get_local_by_acronym(departement):
|
||||||
|
"""Liste des noms des logos définis pour le département
|
||||||
|
désigné par son acronyme.
|
||||||
|
"""
|
||||||
dept_id = Departement.from_acronym(departement).id
|
dept_id = Departement.from_acronym(departement).id
|
||||||
return _core_get_logos(dept_id)
|
return _core_get_logos(dept_id)
|
||||||
|
|
||||||
@ -89,6 +97,9 @@ def logo_get_local_by_acronym(departement):
|
|||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def logo_get_local_by_id(dept_id):
|
def logo_get_local_by_id(dept_id):
|
||||||
|
"""Liste des noms des logos définis pour le département
|
||||||
|
désigné par son id.
|
||||||
|
"""
|
||||||
return _core_get_logos(dept_id)
|
return _core_get_logos(dept_id)
|
||||||
|
|
||||||
|
|
||||||
@ -108,6 +119,12 @@ def _core_get_logo(dept_id, logoname) -> Response:
|
|||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
def logo_get_local_dept_by_acronym(departement, logoname):
|
def logo_get_local_dept_by_acronym(departement, logoname):
|
||||||
|
"""Le logo: image (format png ou jpg).
|
||||||
|
|
||||||
|
**Exemple d'utilisation:**
|
||||||
|
|
||||||
|
* `/ScoDoc/api/departement/MMI/logo/header`
|
||||||
|
"""
|
||||||
dept_id = Departement.from_acronym(departement).id
|
dept_id = Departement.from_acronym(departement).id
|
||||||
return _core_get_logo(dept_id, logoname)
|
return _core_get_logo(dept_id, logoname)
|
||||||
|
|
||||||
@ -116,4 +133,10 @@ def logo_get_local_dept_by_acronym(departement, logoname):
|
|||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
def logo_get_local_dept_by_id(dept_id, logoname):
|
def logo_get_local_dept_by_id(dept_id, logoname):
|
||||||
|
"""Le logo: image (format png ou jpg).
|
||||||
|
|
||||||
|
**Exemple d'utilisation:**
|
||||||
|
|
||||||
|
* `/ScoDoc/api/departement/id/3/logo/header`
|
||||||
|
"""
|
||||||
return _core_get_logo(dept_id, logoname)
|
return _core_get_logo(dept_id, logoname)
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
ScoDoc 9 API : accès aux moduleimpl
|
ScoDoc 9 API : accès aux moduleimpl
|
||||||
|
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
ModuleImpl
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from flask_json import as_json
|
from flask_json import as_json
|
||||||
@ -28,38 +32,43 @@ from app.scodoc.sco_permissions import Permission
|
|||||||
@as_json
|
@as_json
|
||||||
def moduleimpl(moduleimpl_id: int):
|
def moduleimpl(moduleimpl_id: int):
|
||||||
"""
|
"""
|
||||||
Retourne un moduleimpl en fonction de son id
|
Retourne le moduleimpl.
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
moduleimpl_id : l'id d'un moduleimpl
|
moduleimpl_id : l'id d'un moduleimpl
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
{
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"formsemestre_id": 1,
|
||||||
|
"module_id": 1,
|
||||||
|
"responsable_id": 2,
|
||||||
|
"moduleimpl_id": 1,
|
||||||
|
"ens": [],
|
||||||
|
"module": {
|
||||||
|
"heures_tp": 0,
|
||||||
|
"code_apogee": "",
|
||||||
|
"titre": "Initiation aux réseaux informatiques",
|
||||||
|
"coefficient": 1,
|
||||||
|
"module_type": 2,
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"formsemestre_id": 1,
|
"ects": null,
|
||||||
"module_id": 1,
|
"abbrev": "Init aux réseaux informatiques",
|
||||||
"responsable_id": 2,
|
"ue_id": 1,
|
||||||
"moduleimpl_id": 1,
|
"code": "R101",
|
||||||
"ens": [],
|
"formation_id": 1,
|
||||||
"module": {
|
"heures_cours": 0,
|
||||||
"heures_tp": 0,
|
"matiere_id": 1,
|
||||||
"code_apogee": "",
|
"heures_td": 0,
|
||||||
"titre": "Initiation aux réseaux informatiques",
|
"semestre_id": 1,
|
||||||
"coefficient": 1,
|
"numero": 10,
|
||||||
"module_type": 2,
|
"module_id": 1
|
||||||
"id": 1,
|
|
||||||
"ects": null,
|
|
||||||
"abbrev": "Init aux réseaux informatiques",
|
|
||||||
"ue_id": 1,
|
|
||||||
"code": "R101",
|
|
||||||
"formation_id": 1,
|
|
||||||
"heures_cours": 0,
|
|
||||||
"matiere_id": 1,
|
|
||||||
"heures_td": 0,
|
|
||||||
"semestre_id": 1,
|
|
||||||
"numero": 10,
|
|
||||||
"module_id": 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
modimpl = ModuleImpl.get_modimpl(moduleimpl_id)
|
modimpl = ModuleImpl.get_modimpl(moduleimpl_id)
|
||||||
return modimpl.to_dict(convert_objects=True)
|
return modimpl.to_dict(convert_objects=True)
|
||||||
@ -72,16 +81,20 @@ def moduleimpl(moduleimpl_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def moduleimpl_inscriptions(moduleimpl_id: int):
|
def moduleimpl_inscriptions(moduleimpl_id: int):
|
||||||
"""Liste des inscriptions à ce moduleimpl
|
"""Liste des inscriptions à ce moduleimpl.
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
[
|
|
||||||
{
|
```json
|
||||||
"id": 1,
|
[
|
||||||
"etudid": 666,
|
{
|
||||||
"moduleimpl_id": 1234,
|
"id": 1,
|
||||||
},
|
"etudid": 666,
|
||||||
...
|
"moduleimpl_id": 1234,
|
||||||
]
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
modimpl = ModuleImpl.get_modimpl(moduleimpl_id)
|
modimpl = ModuleImpl.get_modimpl(moduleimpl_id)
|
||||||
return [i.to_dict() for i in modimpl.inscriptions]
|
return [i.to_dict() for i in modimpl.inscriptions]
|
||||||
@ -93,22 +106,26 @@ def moduleimpl_inscriptions(moduleimpl_id: int):
|
|||||||
@scodoc
|
@scodoc
|
||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
def moduleimpl_notes(moduleimpl_id: int):
|
def moduleimpl_notes(moduleimpl_id: int):
|
||||||
"""Liste des notes dans ce moduleimpl
|
"""Liste des notes dans ce moduleimpl.
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
[
|
|
||||||
{
|
```json
|
||||||
"etudid": 17776, // code de l'étudiant
|
[
|
||||||
"nom": "DUPONT",
|
{
|
||||||
"prenom": "Luz",
|
"etudid": 17776, // code de l'étudiant
|
||||||
"38411": 16.0, // Note dans l'évaluation d'id 38411
|
"nom": "DUPONT",
|
||||||
"38410": 15.0,
|
"prenom": "Luz",
|
||||||
"moymod": 15.5, // Moyenne INDICATIVE module
|
"38411": 16.0, // Note dans l'évaluation d'id 38411
|
||||||
"moy_ue_2875": 15.5, // Moyenne vers l'UE 2875
|
"38410": 15.0,
|
||||||
"moy_ue_2876": 15.5, // Moyenne vers l'UE 2876
|
"moymod": 15.5, // Moyenne INDICATIVE module
|
||||||
"moy_ue_2877": 15.5 // Moyenne vers l'UE 2877
|
"moy_ue_2875": 15.5, // Moyenne vers l'UE 2875
|
||||||
},
|
"moy_ue_2876": 15.5, // Moyenne vers l'UE 2876
|
||||||
...
|
"moy_ue_2877": 15.5 // Moyenne vers l'UE 2877
|
||||||
]
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
modimpl = ModuleImpl.get_modimpl(moduleimpl_id)
|
modimpl = ModuleImpl.get_modimpl(moduleimpl_id)
|
||||||
app.set_sco_dept(modimpl.formsemestre.departement.acronym)
|
app.set_sco_dept(modimpl.formsemestre.departement.acronym)
|
||||||
|
@ -6,6 +6,11 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
ScoDoc 9 API : partitions
|
ScoDoc 9 API : partitions
|
||||||
|
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
Groupes et Partitions
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
|
|
||||||
@ -41,7 +46,8 @@ def partition_info(partition_id: int):
|
|||||||
"""Info sur une partition.
|
"""Info sur une partition.
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
```
|
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
'bul_show_rank': False,
|
'bul_show_rank': False,
|
||||||
'formsemestre_id': 39,
|
'formsemestre_id': 39,
|
||||||
@ -71,10 +77,11 @@ def partition_info(partition_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def formsemestre_partitions(formsemestre_id: int):
|
def formsemestre_partitions(formsemestre_id: int):
|
||||||
"""Liste de toutes les partitions d'un formsemestre
|
"""Liste de toutes les partitions d'un formsemestre.
|
||||||
|
|
||||||
formsemestre_id : l'id d'un formsemestre
|
Exemple de résultat :
|
||||||
|
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
partition_id : {
|
partition_id : {
|
||||||
"bul_show_rank": False,
|
"bul_show_rank": False,
|
||||||
@ -88,7 +95,7 @@ def formsemestre_partitions(formsemestre_id: int):
|
|||||||
},
|
},
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -112,9 +119,14 @@ def group_etudiants(group_id: int):
|
|||||||
"""
|
"""
|
||||||
Retourne la liste des étudiants dans un groupe
|
Retourne la liste des étudiants dans un groupe
|
||||||
(inscrits au groupe et inscrits au semestre).
|
(inscrits au groupe et inscrits au semestre).
|
||||||
|
|
||||||
|
PARAMS
|
||||||
|
------
|
||||||
group_id : l'id d'un groupe
|
group_id : l'id d'un groupe
|
||||||
|
|
||||||
Exemple de résultat :
|
Exemple de résultat :
|
||||||
|
|
||||||
|
```json
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
'civilite': 'M',
|
'civilite': 'M',
|
||||||
@ -127,6 +139,7 @@ def group_etudiants(group_id: int):
|
|||||||
},
|
},
|
||||||
...
|
...
|
||||||
]
|
]
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = GroupDescr.query.filter_by(id=group_id)
|
query = GroupDescr.query.filter_by(id=group_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -152,11 +165,11 @@ def group_etudiants(group_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def group_etudiants_query(group_id: int):
|
def group_etudiants_query(group_id: int):
|
||||||
"""Étudiants du groupe, filtrés par état (aucun, I, D, DEF)
|
"""Étudiants du groupe, filtrés par état (aucun, `I`, `D`, `DEF`)
|
||||||
|
|
||||||
QUERY
|
QUERY
|
||||||
-----
|
-----
|
||||||
etat:<string:etat>
|
etat : string
|
||||||
|
|
||||||
"""
|
"""
|
||||||
etat = request.args.get("etat")
|
etat = request.args.get("etat")
|
||||||
@ -186,7 +199,7 @@ def group_etudiants_query(group_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def group_set_etudiant(group_id: int, etudid: int):
|
def group_set_etudiant(group_id: int, etudid: int):
|
||||||
"""Affecte l'étudiant au groupe indiqué"""
|
"""Affecte l'étudiant au groupe indiqué."""
|
||||||
etud = Identite.query.get_or_404(etudid)
|
etud = Identite.query.get_or_404(etudid)
|
||||||
query = GroupDescr.query.filter_by(id=group_id)
|
query = GroupDescr.query.filter_by(id=group_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -248,7 +261,8 @@ def group_remove_etud(group_id: int, etudid: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def partition_remove_etud(partition_id: int, etudid: int):
|
def partition_remove_etud(partition_id: int, etudid: int):
|
||||||
"""Enlève l'étudiant de tous les groupes de cette partition
|
"""Enlève l'étudiant de tous les groupes de cette partition.
|
||||||
|
|
||||||
(NB: en principe, un étudiant ne doit être que dans 0 ou 1 groupe d'une partition)
|
(NB: en principe, un étudiant ne doit être que dans 0 ou 1 groupe d'une partition)
|
||||||
"""
|
"""
|
||||||
etud = Identite.query.get_or_404(etudid)
|
etud = Identite.query.get_or_404(etudid)
|
||||||
@ -293,12 +307,15 @@ def partition_remove_etud(partition_id: int, etudid: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def group_create(partition_id: int): # partition-group-create
|
def group_create(partition_id: int): # partition-group-create
|
||||||
"""Création d'un groupe dans une partition
|
"""Création d'un groupe dans une partition.
|
||||||
|
|
||||||
The request content type should be "application/json":
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"group_name" : nom_du_groupe,
|
"group_name" : nom_du_groupe,
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = Partition.query.filter_by(id=partition_id)
|
query = Partition.query.filter_by(id=partition_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -345,7 +362,7 @@ def group_create(partition_id: int): # partition-group-create
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def group_delete(group_id: int):
|
def group_delete(group_id: int):
|
||||||
"""Suppression d'un groupe"""
|
"""Suppression d'un groupe."""
|
||||||
query = GroupDescr.query.filter_by(id=group_id)
|
query = GroupDescr.query.filter_by(id=group_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = (
|
query = (
|
||||||
@ -374,7 +391,7 @@ def group_delete(group_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def group_edit(group_id: int):
|
def group_edit(group_id: int):
|
||||||
"""Edit a group"""
|
"""Édition d'un groupe."""
|
||||||
query = GroupDescr.query.filter_by(id=group_id)
|
query = GroupDescr.query.filter_by(id=group_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
query = (
|
query = (
|
||||||
@ -415,9 +432,10 @@ def group_edit(group_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def group_set_edt_id(group_id: int, edt_id: str):
|
def group_set_edt_id(group_id: int, edt_id: str):
|
||||||
"""Set edt_id for this group.
|
"""Set edt_id du groupe.
|
||||||
Contrairement à /edit, peut-être changé pour toute partition
|
|
||||||
ou formsemestre non verrouillé.
|
Contrairement à `/edit`, peut-être changé pour toute partition
|
||||||
|
d'un formsemestre non verrouillé.
|
||||||
"""
|
"""
|
||||||
query = GroupDescr.query.filter_by(id=group_id)
|
query = GroupDescr.query.filter_by(id=group_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -443,16 +461,19 @@ def group_set_edt_id(group_id: int, edt_id: str):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def partition_create(formsemestre_id: int):
|
def partition_create(formsemestre_id: int):
|
||||||
"""Création d'une partition dans un semestre
|
"""Création d'une partition dans un semestre.
|
||||||
|
|
||||||
The request content type should be "application/json":
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"partition_name": str,
|
"partition_name": str,
|
||||||
"numero":int,
|
"numero": int,
|
||||||
"bul_show_rank":bool,
|
"bul_show_rank": bool,
|
||||||
"show_in_lists":bool,
|
"show_in_lists": bool,
|
||||||
"groups_editable":bool
|
"groups_editable": bool
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -508,8 +529,13 @@ def partition_create(formsemestre_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def formsemestre_set_partitions_order(formsemestre_id: int):
|
def formsemestre_set_partitions_order(formsemestre_id: int):
|
||||||
"""Modifie l'ordre des partitions du formsemestre
|
"""Modifie l'ordre des partitions du formsemestre.
|
||||||
JSON args: [partition_id1, partition_id2, ...]
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
|
[ partition_id1, partition_id2, ... ]
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
query = FormSemestre.query.filter_by(id=formsemestre_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -520,7 +546,7 @@ def formsemestre_set_partitions_order(formsemestre_id: int):
|
|||||||
if not formsemestre.can_change_groups():
|
if not formsemestre.can_change_groups():
|
||||||
return json_error(401, "opération non autorisée")
|
return json_error(401, "opération non autorisée")
|
||||||
partition_ids = request.get_json(force=True) # may raise 400 Bad Request
|
partition_ids = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
if not isinstance(partition_ids, int) and not all(
|
if not isinstance(partition_ids, list) and not all(
|
||||||
isinstance(x, int) for x in partition_ids
|
isinstance(x, int) for x in partition_ids
|
||||||
):
|
):
|
||||||
return json_error(
|
return json_error(
|
||||||
@ -549,8 +575,13 @@ def formsemestre_set_partitions_order(formsemestre_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def partition_order_groups(partition_id: int):
|
def partition_order_groups(partition_id: int):
|
||||||
"""Modifie l'ordre des groupes de la partition
|
"""Modifie l'ordre des groupes de la partition.
|
||||||
JSON args: [group_id1, group_id2, ...]
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
|
[ group_id1, group_id2, ... ]
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = Partition.query.filter_by(id=partition_id)
|
query = Partition.query.filter_by(id=partition_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -561,7 +592,7 @@ def partition_order_groups(partition_id: int):
|
|||||||
if not partition.formsemestre.can_change_groups():
|
if not partition.formsemestre.can_change_groups():
|
||||||
return json_error(401, "opération non autorisée")
|
return json_error(401, "opération non autorisée")
|
||||||
group_ids = request.get_json(force=True) # may raise 400 Bad Request
|
group_ids = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
if not isinstance(group_ids, int) and not all(
|
if not isinstance(group_ids, list) and not all(
|
||||||
isinstance(x, int) for x in group_ids
|
isinstance(x, int) for x in group_ids
|
||||||
):
|
):
|
||||||
return json_error(
|
return json_error(
|
||||||
@ -586,10 +617,13 @@ def partition_order_groups(partition_id: int):
|
|||||||
@permission_required(Permission.ScoView)
|
@permission_required(Permission.ScoView)
|
||||||
@as_json
|
@as_json
|
||||||
def partition_edit(partition_id: int):
|
def partition_edit(partition_id: int):
|
||||||
"""Modification d'une partition dans un semestre
|
"""Modification d'une partition dans un semestre.
|
||||||
|
|
||||||
The request content type should be "application/json"
|
Tous les champs sont optionnels.
|
||||||
All fields are optional:
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"partition_name": str,
|
"partition_name": str,
|
||||||
"numero":int,
|
"numero":int,
|
||||||
@ -597,6 +631,7 @@ def partition_edit(partition_id: int):
|
|||||||
"show_in_lists":bool,
|
"show_in_lists":bool,
|
||||||
"groups_editable":bool
|
"groups_editable":bool
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
query = Partition.query.filter_by(id=partition_id)
|
query = Partition.query.filter_by(id=partition_id)
|
||||||
if g.scodoc_dept:
|
if g.scodoc_dept:
|
||||||
@ -660,9 +695,9 @@ def partition_edit(partition_id: int):
|
|||||||
def partition_delete(partition_id: int):
|
def partition_delete(partition_id: int):
|
||||||
"""Suppression d'une partition (et de tous ses groupes).
|
"""Suppression d'une partition (et de tous ses groupes).
|
||||||
|
|
||||||
Note 1: La partition par défaut (tous les étudiants du sem.) ne peut
|
* Note 1: La partition par défaut (tous les étudiants du sem.) ne peut
|
||||||
pas être supprimée.
|
pas être supprimée.
|
||||||
Note 2: Si la partition de parcours est supprimée, les étudiants
|
* Note 2: Si la partition de parcours est supprimée, les étudiants
|
||||||
sont désinscrits des parcours.
|
sont désinscrits des parcours.
|
||||||
"""
|
"""
|
||||||
query = Partition.query.filter_by(id=partition_id)
|
query = Partition.query.filter_by(id=partition_id)
|
||||||
|
@ -3,12 +3,18 @@ from app import db, log
|
|||||||
from app.api import api_bp as bp
|
from app.api import api_bp as bp
|
||||||
from app.auth.logic import basic_auth, token_auth
|
from app.auth.logic import basic_auth, token_auth
|
||||||
|
|
||||||
|
"""
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
Authentification API
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
@bp.route("/tokens", methods=["POST"])
|
@bp.route("/tokens", methods=["POST"])
|
||||||
@basic_auth.login_required
|
@basic_auth.login_required
|
||||||
@as_json
|
@as_json
|
||||||
def token_get():
|
def token_get():
|
||||||
"renvoie un jeton jwt pour l'utilisateur courant"
|
"Renvoie un jeton jwt pour l'utilisateur courant."
|
||||||
token = basic_auth.current_user().get_token()
|
token = basic_auth.current_user().get_token()
|
||||||
log(f"API: giving token to {basic_auth.current_user()}")
|
log(f"API: giving token to {basic_auth.current_user()}")
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
@ -18,7 +24,7 @@ def token_get():
|
|||||||
@bp.route("/tokens", methods=["DELETE"])
|
@bp.route("/tokens", methods=["DELETE"])
|
||||||
@token_auth.login_required
|
@token_auth.login_required
|
||||||
def token_revoke():
|
def token_revoke():
|
||||||
"révoque le jeton de l'utilisateur courant"
|
"Révoque le jeton de l'utilisateur courant."
|
||||||
user = token_auth.current_user()
|
user = token_auth.current_user()
|
||||||
user.revoke_token()
|
user.revoke_token()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
ScoDoc 9 API : accès aux utilisateurs
|
ScoDoc 9 API : accès aux utilisateurs
|
||||||
|
|
||||||
|
CATEGORY
|
||||||
|
--------
|
||||||
|
Utilisateurs
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from flask import g, request
|
from flask import g, request
|
||||||
@ -32,7 +36,7 @@ from app.scodoc.sco_utils import json_error
|
|||||||
@as_json
|
@as_json
|
||||||
def user_info(uid: int):
|
def user_info(uid: int):
|
||||||
"""
|
"""
|
||||||
Info sur un compte utilisateur scodoc
|
Info sur un compte utilisateur ScoDoc.
|
||||||
"""
|
"""
|
||||||
user: User = db.session.get(User, uid)
|
user: User = db.session.get(User, uid)
|
||||||
if user is None:
|
if user is None:
|
||||||
@ -53,7 +57,11 @@ def user_info(uid: int):
|
|||||||
@as_json
|
@as_json
|
||||||
def users_info_query():
|
def users_info_query():
|
||||||
"""Utilisateurs, filtrés par dept, active ou début nom
|
"""Utilisateurs, filtrés par dept, active ou début nom
|
||||||
|
|
||||||
|
Exemple:
|
||||||
|
```
|
||||||
/users/query?departement=dept_acronym&active=1&starts_with=<string:nom>
|
/users/query?departement=dept_acronym&active=1&starts_with=<string:nom>
|
||||||
|
```
|
||||||
|
|
||||||
Seuls les utilisateurs "accessibles" (selon les permissions) sont retournés.
|
Seuls les utilisateurs "accessibles" (selon les permissions) sont retournés.
|
||||||
Si accès via API web, le département de l'URL est ignoré, seules
|
Si accès via API web, le département de l'URL est ignoré, seules
|
||||||
@ -61,9 +69,9 @@ def users_info_query():
|
|||||||
|
|
||||||
QUERY
|
QUERY
|
||||||
-----
|
-----
|
||||||
active:<bool:active>
|
active: bool
|
||||||
departement:<string:departement>
|
departement: string
|
||||||
starts_with:<string:starts_with>
|
starts_with: string
|
||||||
|
|
||||||
"""
|
"""
|
||||||
query = User.query
|
query = User.query
|
||||||
@ -113,7 +121,10 @@ def _is_allowed_user_edit(args: dict) -> tuple[bool, str]:
|
|||||||
@as_json
|
@as_json
|
||||||
def user_create():
|
def user_create():
|
||||||
"""Création d'un utilisateur
|
"""Création d'un utilisateur
|
||||||
The request content type should be "application/json":
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"active":bool (default True),
|
"active":bool (default True),
|
||||||
"dept": str or null,
|
"dept": str or null,
|
||||||
@ -122,6 +133,7 @@ def user_create():
|
|||||||
"user_name": str,
|
"user_name": str,
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
args = request.get_json(force=True) # may raise 400 Bad Request
|
args = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
user_name = args.get("user_name")
|
user_name = args.get("user_name")
|
||||||
@ -158,8 +170,10 @@ def user_create():
|
|||||||
@permission_required(Permission.UsersAdmin)
|
@permission_required(Permission.UsersAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def user_edit(uid: int):
|
def user_edit(uid: int):
|
||||||
"""Modification d'un utilisateur
|
"""Modification d'un utilisateur.
|
||||||
|
|
||||||
Champs modifiables:
|
Champs modifiables:
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"dept": str or null,
|
"dept": str or null,
|
||||||
"nom": str,
|
"nom": str,
|
||||||
@ -167,6 +181,7 @@ def user_edit(uid: int):
|
|||||||
"active":bool
|
"active":bool
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
args = request.get_json(force=True) # may raise 400 Bad Request
|
args = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
user: User = User.query.get_or_404(uid)
|
user: User = User.query.get_or_404(uid)
|
||||||
@ -205,11 +220,15 @@ def user_edit(uid: int):
|
|||||||
@permission_required(Permission.UsersAdmin)
|
@permission_required(Permission.UsersAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def user_password(uid: int):
|
def user_password(uid: int):
|
||||||
"""Modification du mot de passe d'un utilisateur
|
"""Modification du mot de passe d'un utilisateur.
|
||||||
|
|
||||||
Champs modifiables:
|
Champs modifiables:
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"password": str
|
"password": str
|
||||||
}
|
}
|
||||||
|
```.
|
||||||
|
|
||||||
Si le mot de passe ne convient pas, erreur 400.
|
Si le mot de passe ne convient pas, erreur 400.
|
||||||
"""
|
"""
|
||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
@ -243,7 +262,7 @@ def user_password(uid: int):
|
|||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def user_role_add(uid: int, role_name: str, dept: str = None):
|
def user_role_add(uid: int, role_name: str, dept: str = None):
|
||||||
"""Add a role in the given dept to the user"""
|
"""Ajoute un rôle à l'utilisateur dans le département donné."""
|
||||||
user: User = User.query.get_or_404(uid)
|
user: User = User.query.get_or_404(uid)
|
||||||
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
||||||
if dept is not None: # check
|
if dept is not None: # check
|
||||||
@ -272,7 +291,7 @@ def user_role_add(uid: int, role_name: str, dept: str = None):
|
|||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def user_role_remove(uid: int, role_name: str, dept: str = None):
|
def user_role_remove(uid: int, role_name: str, dept: str = None):
|
||||||
"""Remove the role (in the given dept) from the user"""
|
"""Retire le rôle (dans le département donné) à cet utilisateur."""
|
||||||
user: User = User.query.get_or_404(uid)
|
user: User = User.query.get_or_404(uid)
|
||||||
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
||||||
if dept is not None: # check
|
if dept is not None: # check
|
||||||
@ -299,7 +318,7 @@ def user_role_remove(uid: int, role_name: str, dept: str = None):
|
|||||||
@permission_required(Permission.UsersView)
|
@permission_required(Permission.UsersView)
|
||||||
@as_json
|
@as_json
|
||||||
def permissions_list():
|
def permissions_list():
|
||||||
"""Liste des noms de permissions définies"""
|
"""Liste des noms de permissions définies."""
|
||||||
return list(Permission.permission_by_name.keys())
|
return list(Permission.permission_by_name.keys())
|
||||||
|
|
||||||
|
|
||||||
@ -321,7 +340,7 @@ def role_get(role_name: str):
|
|||||||
@permission_required(Permission.UsersView)
|
@permission_required(Permission.UsersView)
|
||||||
@as_json
|
@as_json
|
||||||
def roles_list():
|
def roles_list():
|
||||||
"""Tous les rôles définis"""
|
"""Tous les rôles définis."""
|
||||||
return [role.to_dict() for role in Role.query]
|
return [role.to_dict() for role in Role.query]
|
||||||
|
|
||||||
|
|
||||||
@ -338,7 +357,7 @@ def roles_list():
|
|||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def role_permission_add(role_name: str, perm_name: str):
|
def role_permission_add(role_name: str, perm_name: str):
|
||||||
"""Add permission to role"""
|
"""Ajoute une permission à un rôle."""
|
||||||
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
||||||
permission = Permission.get_by_name(perm_name)
|
permission = Permission.get_by_name(perm_name)
|
||||||
if permission is None:
|
if permission is None:
|
||||||
@ -363,7 +382,7 @@ def role_permission_add(role_name: str, perm_name: str):
|
|||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def role_permission_remove(role_name: str, perm_name: str):
|
def role_permission_remove(role_name: str, perm_name: str):
|
||||||
"""Remove permission from role"""
|
"""Retire une permission d'un rôle."""
|
||||||
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
||||||
permission = Permission.get_by_name(perm_name)
|
permission = Permission.get_by_name(perm_name)
|
||||||
if permission is None:
|
if permission is None:
|
||||||
@ -382,10 +401,15 @@ def role_permission_remove(role_name: str, perm_name: str):
|
|||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def role_create(role_name: str):
|
def role_create(role_name: str):
|
||||||
"""Create a new role with permissions.
|
"""Création d'un nouveau rôle avec les permissions données.
|
||||||
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"permissions" : [ 'ScoView', ... ]
|
"permissions" : [ 'ScoView', ... ]
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
role: Role = Role.query.filter_by(name=role_name).first()
|
role: Role = Role.query.filter_by(name=role_name).first()
|
||||||
if role:
|
if role:
|
||||||
@ -410,11 +434,16 @@ def role_create(role_name: str):
|
|||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def role_edit(role_name: str):
|
def role_edit(role_name: str):
|
||||||
"""Edit a role. On peut spécifier un nom et/ou des permissions.
|
"""Édition d'un rôle. On peut spécifier un nom et/ou des permissions.
|
||||||
|
|
||||||
|
DATA
|
||||||
|
----
|
||||||
|
```json
|
||||||
{
|
{
|
||||||
"name" : name
|
"name" : name
|
||||||
"permissions" : [ 'ScoView', ... ]
|
"permissions" : [ 'ScoView', ... ]
|
||||||
}
|
}
|
||||||
|
```
|
||||||
"""
|
"""
|
||||||
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
||||||
data = request.get_json(force=True) # may raise 400 Bad Request
|
data = request.get_json(force=True) # may raise 400 Bad Request
|
||||||
@ -442,7 +471,7 @@ def role_edit(role_name: str):
|
|||||||
@permission_required(Permission.ScoSuperAdmin)
|
@permission_required(Permission.ScoSuperAdmin)
|
||||||
@as_json
|
@as_json
|
||||||
def role_delete(role_name: str):
|
def role_delete(role_name: str):
|
||||||
"""Delete a role"""
|
"""Suprression d'un rôle."""
|
||||||
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
role: Role = Role.query.filter_by(name=role_name).first_or_404()
|
||||||
db.session.delete(role)
|
db.session.delete(role)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -52,6 +52,17 @@ class Departement(db.Model):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<{self.__class__.__name__}(id={self.id}, acronym='{self.acronym}')>"
|
return f"<{self.__class__.__name__}(id={self.id}, acronym='{self.acronym}')>"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_departement(cls, dept_ident: str | int) -> "Departement":
|
||||||
|
"Le département, 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 cls.query.filter_by(acronym=dept_ident).first_or_404()
|
||||||
|
return cls.query.get_or_404(dept_id)
|
||||||
|
|
||||||
def to_dict(self, with_dept_name=True, with_dept_preferences=False):
|
def to_dict(self, with_dept_name=True, with_dept_preferences=False):
|
||||||
data = {
|
data = {
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
{# Template pour la doc mardown d'un point d'entrée de l'API #}
|
||||||
#### **`{{doc.nom}}`**
|
#### **`{{doc.nom}}`**
|
||||||
|
|
||||||
{% if doc.routes %}
|
{% if doc.routes %}
|
||||||
@ -6,7 +7,7 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
* **Routes:**
|
* **Routes:**
|
||||||
{% for route in doc.routes %}
|
{% for route in doc.routes %}
|
||||||
* `{{route|safe}}`
|
* `{{route|safe}}`
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -15,7 +16,7 @@
|
|||||||
{% if doc.params %}
|
{% if doc.params %}
|
||||||
* **Paramètres:**
|
* **Paramètres:**
|
||||||
{% for param in doc.params %}
|
{% for param in doc.params %}
|
||||||
* `{{param.nom|safe}}` : {{param.description|safe}}
|
* `{{param.nom|safe}}` : {{param.description|safe}}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if doc.description %}
|
{% if doc.description %}
|
@ -547,7 +547,7 @@ def analyze_api_routes(app, endpoint_start: str) -> tuple:
|
|||||||
|
|
||||||
|
|
||||||
# point d'entrée de la commande `flask gen-api-map`
|
# point d'entrée de la commande `flask gen-api-map`
|
||||||
def gen_api_map(app, endpoint_start="api."):
|
def gen_api_map(app, endpoint_start="api.") -> str:
|
||||||
"""
|
"""
|
||||||
Fonction permettant de générer une carte SVG de l'API de ScoDoc
|
Fonction permettant de générer une carte SVG de l'API de ScoDoc
|
||||||
Elle récupère les routes de l'API et les transforme en un arbre de Token
|
Elle récupère les routes de l'API et les transforme en un arbre de Token
|
||||||
@ -566,6 +566,7 @@ def gen_api_map(app, endpoint_start="api."):
|
|||||||
# On génère le tableau à partir de doctable_lines
|
# On génère le tableau à partir de doctable_lines
|
||||||
table = _gen_table(sorted(doctable_lines.values(), key=lambda x: x["nom"]))
|
table = _gen_table(sorted(doctable_lines.values(), key=lambda x: x["nom"]))
|
||||||
_write_gen_table(table)
|
_write_gen_table(table)
|
||||||
|
return table
|
||||||
|
|
||||||
|
|
||||||
def _get_bbox(element, x_offset=0, y_offset=0):
|
def _get_bbox(element, x_offset=0, y_offset=0):
|
||||||
@ -905,7 +906,7 @@ def doc_route(doctable: dict) -> str:
|
|||||||
"href": f"{jinja_obj['nom'].replace('_', '-')}.json.md",
|
"href": f"{jinja_obj['nom'].replace('_', '-')}.json.md",
|
||||||
}
|
}
|
||||||
|
|
||||||
return render_template("apidoc.j2", doc=jinja_obj)
|
return render_template("doc/apidoc.j2", doc=jinja_obj)
|
||||||
|
|
||||||
|
|
||||||
def gen_api_doc(app, endpoint_start="api."):
|
def gen_api_doc(app, endpoint_start="api."):
|
||||||
@ -922,7 +923,7 @@ def gen_api_doc(app, endpoint_start="api."):
|
|||||||
categories[category].append(value)
|
categories[category].append(value)
|
||||||
|
|
||||||
# sort categories by name
|
# sort categories by name
|
||||||
categories: dict = dict(sorted(categories.items(), key=lambda x: x[0]))
|
categories: dict = dict(sorted(categories.items(), key=lambda x: x[0].capitalize()))
|
||||||
|
|
||||||
category: str
|
category: str
|
||||||
routes: list[dict]
|
routes: list[dict]
|
||||||
@ -935,9 +936,12 @@ def gen_api_doc(app, endpoint_start="api."):
|
|||||||
mddoc += doc_route(route)
|
mddoc += doc_route(route)
|
||||||
mddoc += "\n\n"
|
mddoc += "\n\n"
|
||||||
|
|
||||||
fname = "/tmp/apidoc.md"
|
table_api = gen_api_map(app, endpoint_start=endpoint_start)
|
||||||
|
mdpage = render_template("doc/ScoDoc9API.j2", doc_api=mddoc, table_api=table_api)
|
||||||
|
|
||||||
|
fname = "/tmp/ScoDoc9API.md"
|
||||||
with open(fname, "w", encoding="utf-8") as f:
|
with open(fname, "w", encoding="utf-8") as f:
|
||||||
f.write(mddoc)
|
f.write(mdpage)
|
||||||
print(
|
print(
|
||||||
"La documentation API a été générée avec succès. "
|
"La documentation API a été générée avec succès. "
|
||||||
f"Vous pouvez la consulter à l'adresse suivante : {fname}"
|
f"Vous pouvez la consulter à l'adresse suivante : {fname}"
|
||||||
|
Loading…
Reference in New Issue
Block a user