Détails sur la programmation API

This commit is contained in:
Emmanuel Viennet 2022-12-26 19:00:47 -03:00
parent 8934fe840d
commit cedd37d4b4
3 changed files with 97 additions and 14 deletions

View File

@ -141,11 +141,11 @@ peuvent entrainer la validation d'UE a posteriori.
### Capitalisation
Les UE sont capitalisables, c'est à dire qu'un étudiant conserve son UE s'il
arrête temporairement ses études ou redouble un semestre.
Les UE sont capitalisables, c'est à dire qu'un étudiant conserve les UEs
obtenues (avec moyenne > 10/20) s'il arrête temporairement ses études ou redouble un semestre.
En cas de redoublement, l'étudiant qui choisi de répéter une UE conserve le
résultat antérieur sauf s'il obtient mieux.
En cas de redoublement, l'étudiant qui choisi de répéter une UE capitalisée conserve le
résultat antérieur sauf s'il obtient une meilleure moyenne.
### Moyenne générale

View File

@ -1,6 +1,6 @@
# Code de ScoDoc 9
# Quelques informations pour les développeurs
Quelques informations pour les développeurs.
## Composants logiciels
- le code est écrit en Python 3.9 (passage à 3.10 prévu avec Debian 12).
- le code doit être formatté par [black](https://pypi.org/project/black/) qui
@ -17,7 +17,7 @@ Quelques informations pour les développeurs.
- [gunicorn](https://gunicorn.org/) WSGI HTTP server
- et bien sûr Linux (Debian 11 en 2021-2022) et systemd.
# Principaux objets
## Principaux objets
Les objets manipulés par ScoDoc sont pour la plupart stockés en base postgres et
accédé soit directement en SQL (anciennes parties de ScoDoc), soit à travers
@ -41,7 +41,7 @@ Principales classes (les noms des classes Python sont en `CamelCase`).
- Inscriptions: tables d'association avec codes et/ou état (démission,
défaillant): FormsemestreInscription ModuleImplInscription.
# Vues et décorateurs
## Vues et décorateurs
Une vue ordinaire (Web) pourrait ressembler à cela. Noter la présence de
décorateurs:
@ -74,11 +74,92 @@ def un_exemple():
)
```
# Caches
## Vues de l'API et permissions
L'API REST est documentée ici : [ScoDoc9API](ScoDoc9API.md).
Les fonctions de l'API sont donc accessibles via les routes de la forme
`https://scodoc.monsite.tld/ScoDoc/api/fonction`
et aussi `https://scodoc.monsite.tld/ScoDoc/api/<dept_acronyme>/fonction`.
La seconde forme précise un département.
La seconde forme est notamment utilisée par les pages web de ScoDoc. Elle permet
un calcul des permissions liées à un département: l'idée est de donner accès à
l'API à un utilisateur qui n'ait pas la permission (par ex. `ScoView`) dans tous les
départements, ce qui est en général le cas des utilisateurs Web, mais est aussi
utile pour sécuriser certains usages de l'API.
Une vue API (avec accès via token API et/ou cookie Web) se déclare donc ainsi:
```py
@bp.route("/formsemestres/query")
@api_web_bp.route("/formsemestres/query")
@login_required
@scodoc
@permission_required(Permission.ScoView)
def formsemestres_query():
...
```
Son usage par un utilisateur n'ayant accès qu'à un seul département passera par
la route départementale
`http://scodoc.monsite.tld:5000/ScoDoc/<dept_acronyme>/api/formsemestres/query`.
### Exemple complet d'usage
Création du rôle, de l'utilisateur, association à un département, requêtage.
```bash
flask create-role LecteurAPI2 # 2 car LecteurAPi était déjà pris sur mon serveur de test
flask edit-role -a ScoView LecteurAPI2
flask user-create lecteur_rt LecteurAPI2 RT # Seulement dans dept RT
flask user-password lecteur_rt
```
puis
```bash
http -a lecteur_rt:azer POST 'http://localhost:5000/ScoDoc/api/tokens'
# récupérer le token...
http GET http://localhost:5000/ScoDoc/api/RT/formsemestres/query "Authorization:Bearer xxxxxxxxxxx"
# -> réponse ok
http GET http://localhost:5000/ScoDoc/api/formsemestres/query "Authorization:Bearer xxxxxxxxxxx"
# -> 401, "Non autorise (logic)"
```
### Côté programmation serveur
Reprenons le même exemple (voir app/api/formsemestres.py ligne 91,
<https://scodoc.org/git/ScoDoc/ScoDoc/src/branch/master/app/api/formsemestres.py#L91>):
```py
@bp.route("/formsemestres/query")
@api_web_bp.route("/formsemestres/query")
@login_required
@scodoc
@permission_required(Permission.ScoView)
def formsemestres_query():
...
formsemestres = FormSemestre.query
if g.scodoc_dept:
formsemestres = formsemestres.filter_by(dept_id=g.scodoc_dept_id)
...
```
En effet, `g.scodoc_dept` et `g.scodoc_dept_id` sont positionnés par le
décorateur si on a un appel via la route départementale.
Il est donc important, pour toutes les vues API, de prendre soin de ne pas
divulguer d'informations hors du département spécifié, en filtrant la ou les
requêtes si `g.scodoc_dept` est non `None`.
## Caches
Il est bon de savoir que les requêtes SQL de SQLAlchemy ne sont pas cachées: ni
la requête elle même (construction du SQL à partir des appels à l'ORM), ni son
résultat.
résultat.
Le module `sco_cache.py` offre la possibilité de cacher des objets python
identifiés par un id unique dans le cache Redis. Ce cache est persistant, il

View File

@ -61,8 +61,10 @@ flask user-password lecteur_api
...
```
Si vous êtes intéressé par le développement, voir [la section sur les tests
unitaires de l'API](TestsScoDoc.md#tests-de-lapi-scodoc9).
Si vous êtes intéressé par le développement, voir
* [la section sur les tests unitaires de l'API](TestsScoDoc.md#tests-de-lapi-scodoc9);
* [la documentation interne](Internals.md#vues-de-lapi-et-permissions).
## Essais avec HTTPie
@ -125,7 +127,7 @@ version de ScoDoc 9.3.25.
### Accès à l'API REST
L'API est accessible à l'adresse: `https://scodoc.monsite.tld/ScoDoc/api/fonction`
(et aussi `https://scodoc.monsite.tld/ScoDoc/api/<dept_acronyme>/fonction` pour un
(et aussi `https://scodoc.monsite.tld/ScoDoc/<dept_acronyme>/api/fonction` pour un
accès avec des droits restreints au département indiqué).
#### Authentification
@ -1179,7 +1181,7 @@ mais pas JSON compliant à cause des `NaN`.
* **Paramètres:** `dept`, `formsemestre_id`
* **Routes:** `/formsemestre/<int:formsemestre_id>/programme`
* **Exemple d'utilisation:** `/ScoDoc/api/formsemestre/1/programme`
* **Résultat:** Retourne la struture d'un formsemestre sous 5 entrées d'un dictionnaire:
* **Résultat:** Retourne la structure d'un formsemestre sous 5 entrées d'un dictionnaire:
* **`ues`**: liste des UEs,
* **`ressources`**: liste des ressources (BUT),