Ajout doc assiduités (Matthias) + corrections + liens avec upgrade

This commit is contained in:
Emmanuel Viennet 2023-07-20 10:41:49 +03:00
commit 8ce4ca0f28
21 changed files with 1567 additions and 78 deletions

260
docs/Assiduites.md Normal file
View File

@ -0,0 +1,260 @@
# Module "Assiduités"
Ce module de ScoDoc remplace l'ancien module de suivi des absences de Scodoc.
En plus de moderniser l'ancien module, le module assiduités met à disposition une API complète.
Ce projet a été développé en 2022-2023, par Matthias Hartmann, apprenti de l'IUT de
Lannion financé par l'Association ScoDoc.
**Ce module est disponible à partir de ScoDoc version 9.6**.
[Vidéo de présentation du module d'assiduités ](#) TODO EV à publier sur la chaîne YT
## Fonctionnalités
Le module fournit:
- Gestion des absences/présences/retards
- Précision des saisies (périodes déterminées par une heure de début et une
heure de fin au lieu de demi-journées)
- Gestion et sauvegarde de justificatifs (documents)
- Une [API complète](ScoDoc9API.md#api-assiduites)
## Guide d'utilisation
- [Module "Assiduités"](#module-assiduités)
- [Fonctionnalités](#fonctionnalités)
- [Guide d'utilisation](#guide-dutilisation)
- [Migration de l'ancien module](#migration-de-lancien-module)
- [Personnalisation du module](#personnalisation-du-module)
- [Saisie des Assiduités](#saisie-des-assiduités)
- [Saisie d'un groupe](#saisie-dun-groupe)
- [Saisie Journalière](#saisie-journalière)
- [Saisie différée](#saisie-différée)
### Migration de l'ancien module
Afin de favoriser la transition de l'ancien module au nouveau, un script de
migration a été développé: à l'installation de ScoDoc 9.6, les anciennes
données d'absences et justificatifs sont traduites pour ce module.
Voir détails dans [la documentation d'installation](UpgradeToDeb12Sco96.md) et
sur la [documentation des commandes de migration des absences](AssiduitesMigration.md).
### Personnalisation du module
Le module possède deux types de configuration, une générale et une par département/semestre.
**La configuration générale permet de configurer la ligne temporelle visible sur certaines pages de saisie d'assiduités.**
![Configuration de l'assiduité : Général](screens/config_assiduites_gen.png)
Route : `/ScoDoc/config_assiduites`
- `Début de la journée` : l'heure de début de la ligne temporelle (par défaut :
8h00)
- `L'heure de midi` : l'heure pivot qui sépare la matinée de l'après-midi (par
défaut : 13h00)
- `Fin de la journée` : l'heure de fin de la ligne temporelle (par défaut :
18h00)
- `Granularité` : La granularité de la ligne temporelle. (par défaut : 15 min)
**La configuration par département/semestre permet de configurer certaines actions liés à l'assiduité**
![Configuration de l'assiduité : département](screens/config_assiduites_dept.png)
Route : `/ScoDoc/<Dept>/Scolarite/edit_preferences`
- `Forcer la déclaration du module` : Forcer les utilisateurs de ScoDoc à
renseigner le module à chaque saisie d'assiduités.
- `Forcer l'appel des présents` : Force les utilisateurs à noter les
présences/absences/retard lors d'une saisie.
- `Durée par défaut d'un créneau` : Détermine la durée classique d'un cours. (Ce
sera la période préenregistrée sur la ligne temporelle)
- `Définir l'état par défaut` : Défini l'état par défaut qui sera appliqué aux
étudiants avant validation d'une saisie d'assiduité.
- `Jours non travaillés` : Défini les jours sur lesquels la saisie d'assiduités
ne sera pas possible.
- `Métrique de l'assiduité` : Défini l'unité de l'assiduité qui sera utilisé par
les autres modules de ScoDoc.
- `1/2 J.` : Demi-Journée
- `J.` : Journées
- `H.` : Heures
### Saisie des Assiduités
La saisie se fait soit sur un groupe soit sur un étudiant. Dans tous les cas il
y a deux façons de saisir l'assiduité. Une saisie `Journalière` et une saisie
`Différée`.
#### Saisie d'un groupe
Comme dans l'ancien système, pour saisir l'assiduité d'un groupe il faut se
rendre sur la page un semestre du département concerné.
![Page du semestre concerné](#)
Au bas de cette page vous retrouverez la liste des groupes du semestre. Si vous
avez la permission de modifier l'assiduité, vous observerez 3 boutons
supplémentaires sur chaque groupe vous permettant de voir ou saisir l'assiduité
du groupe.
#### Saisie Journalière
La première chose à faire lorsque vous êtes arrivés sur la page "Saisie
Journalière" c'est de compléter les informations de la séance :
![Capture des sélecteurs](#)
- Le ou les groupes sélectionnés (dans la plupart des cas, le groupe est déjà
présélectionné)
- Le module concerné (par défaut il n'est pas obligatoire de sélectionner un
module, cependant une configuration permet de forcer la sélection)
- La date de la saisie. Attention, seule les dates comprises dans le semestre
sont valides. (Un message d'erreur vous le signalera si la date n'est pas
valide)
Lorsque vous êtes sûr de vous, appuyer sur le bouton `Valider`.
**Attention : La validation est définitive, si vous avez fait une erreur il faudra recharger la page**
Après la validation, les champs précédents seront grisés.
Explication de l'interface
![Capture de l'interface](#)
1. La ligne temporelle (Timeline) sert à désigner la période de l'assiduité qui sera saisie.
Il est possible de la déplacer en maintenant le clic gauche dessus puis en
bougeant la souris.
Si la période n'est pas de la bonne taille, il est possible de l'agrandir ou
de la réduire en plaçant sa souris à l'extrémité droite.
Votre curseur devrait changer, à partir de ce moment là vous pouvez cliquer
puis bouger l'extrémité pour modifier la taille de la période.
Si la période bouge toujours alors que vous avez lâché le clic gauche,
cliquer à nouveau.
2. Les boutons d'actions de masse `Mettre tout le monde : `. Ces boutons
définirons le même état pour chaque étudiant sur la période sélectionnée.
En cliquant sur un bouton d'état, l'état sera mis pour chaque étudiant, pour
modifier cet état il faut appuyer sur un autre bouton d'état.
Si vous souhaitez retirer les assiduités, il faut cliquer sur le bouton
d'état ayant le même état que les étudiants.
3. Les lignes étudiants sont des lignes montrant les informations d'assiduité de
chaque étudiant. Chaque ligne est composée de 3 parties :
1. Le nom, le prénom et une photo de l'étudiant afin de le reconnaître
facilement
2. Une petite ligne temporelle montrant l'assiduité de l'étudiant sur la
journée.
Le carré au début de la ligne montre la dernière assiduité du jour
précédent.
En passant votre souris au dessus des couleurs, vous aurez accès à plus
d'informations sur l'assiduité de l'étudiant.
Cliquer sur une assiduité positionnera la ligne temporelle globale sur
la période de l'assiduité.
La période globale est représentée par un encadré bleu sur la ligne
temporelle.
Les assiduités justifiées et validés sont représentés par leur couleur
respective + un hachage bleu
Les assiduités justifiées mais non validées sont représentés par leur
couleur respective + un hachage rouge.
3. Les boutons d'assiduités individuels. Ces boutons permettent de déterminer l'état de l'étudiant.
Ils fonctionnent de la même façon que les boutons `mettre tout le monde :`.
Si la ligne de l'étudiant est rouge, cela signifie que la période
sélectionnée rentre en conflit avec les assiduités de l'étudiant.
Cliquer sur un bouton d'assiduité ne modifiera pas l'état de l'étudiant
mais ouvrira un menu de résolution de conflit.
![Résolution de conflit](#)
Les assiduités de la page sont enregistrées en temps réel. Lorsque la saisie est
terminée vous pouvez fermer la page.
#### Saisie différée
La page saisie différée a pour but de faciliter la saisie d'assiduités avec
plusieurs périodes.
![Page différée](#)
La page est composée d'un tableau et d'un bouton valider.
**Cette page ne sauvegarde pas automatiquement les modifications**
Explication du tableau :
- La colonne `Noms` : Vous y retrouverez tous les étudiants du groupe
sélectionné. En cliquant sur le titre de la colonne vous pourrez changer
l'ordre des étudiants (croissant ou décroissant)
- Les colonnes `Assiduités` : Lorsque vous arrivez sur la page, une seule
colonne d'assiduité est présente.
Si vous avez besoins d'autres colonnes, appuyer sur le bouton `+`.
Si vous souhaitez supprimer une colonne appuyer sur la `croix X` de la
colonne.
Il vous faudra remplir la colonne afin de pouvoir saisir l'assiduité des
étudiants :
1. La date de début : Sur la première colonne, la date par défaut sera la
date du jour, sur les nouvelles colonnes, la date par défaut sera la date
de fin de la colonne précédente.
2. La date de fin : La date de fin n'est pas renseignée par défaut,
cependant la première fois que vous changer la date de début de la
colonne, la date de fin sera automatiquement mise à jour de façon à
prendre la taille d'un créneau classique (configuration du
semestre/département).
3. Le module concerné par l'assiduité. Ce sélecteur n'est pas obligatoire
par défaut (configuration du semestre/département).
4. `Sélectionner une assiduité` permet de mettre tous les étudiants à un
certain état. Ce sélecteur n'est pas obligatoire.
- Chaque ligne du tableau correspond à un étudiant. Vous pouvez alors
sélectionner l'état de l'assiduité de chaque étudiant pour chaque colonne.
Après avoir rempli le tableau il faudra valider en cliquant sur `valider les assiduités`.
Après validation, toutes les colonnes seront désactivées, si besoins vous pouvez
les réactiver en cliquant sur `Activer` pour chaque colonne.
Il est possible que des erreurs apparaissent. Les erreurs sont gérées par
colonnes puis par étudiant. Cela signifie qu'une erreur de colonne (ex: une
mauvaise date) désactivera complètement la colonne alors qu'une erreur
d'étudiant (ex: l'étudiant possède déjà une assiduité sur cette période)
désactivera uniquement l'envoie de l'assiduité le concernant.
Vous pouvez obtenir plus d'informations sur l'erreur en plaçant votre souris au dessus du ``.
Il est possible de forcer la mise à jour des assiduités : **Attention, cela ne
fonctionnera que pour les assiduités ayant exactement la même période** (ceci
permet de corriger facilement les saisies où l'on aurait oublié d'indiquer le
module).
Chaque colonne possède un numéro distinctif qui est visible en laissant la
souris au dessus de l'entête de la colonne. Ce numéro est utilisé dans les
messages d'erreurs.
!!! note "Voir aussi"
- [Migration des absences vers les assiduités](AssiduitesMigration.md)
- [API](ScoDoc9API.md) : API pour interfaçage avec d'autres applications
- [FAQ](FAQ.md)
- [Contacts](Contact.md)

View File

@ -0,0 +1,86 @@
# Migration des absences de ScoDoc 9.5 vers les assiduités 9.6
Lors du passage de ScoDoc 9.5 à 9.6, les anciennes données d'absences et
justificatifs sont traduites pour [le module assiduités](Assiduites.md).
## Script de Migration
Le script se nomme `migrate-abs-to-assiduites` et ne peut se lancer qu'en ligne
de commande:
```bash
su scodoc # au besoin
cd /opt/scodoc
source venv/bin/activate
flask migrate-abs-to-assiduites --help
```
Par défaut, la migration s'opérera sur l'ensemble des départements en utilisant
les préférences de ScoDoc.
Néanmoins le script possède 4 options pour modifier son comportement :
- `-d, --dept`
Permet de restreindre la migration à un département à l'aide de son acronyme.
Utilisation : `flask migrate-abs-to-assiduites -d <ACRONYME>`
- `-m, --morning`
Permet de définir l'heure de début des cours.
Utilisation : `flask migrate-abs-to-assiduites -m <hh:mm>`
exemple : `hh:mm` -> `08:30`
- `-n, --noon`
Permet de définir l'heure de fin du matin (= l'heure de début de l'après-midi).
Utilisation : `flask migrate-abs-to-assiduites -n <hh:mm>`
exemple : `hh:mm` -> `13:30`
- `-e, --evening`
Permet de définir l'heure de fin des cours.
Utilisation : `flask migrate-abs-to-assiduites -e <hh:mm>`
exemple : `hh:mm` -> `18:30`
Les options peuvent senchaîner : `flask migrate-abs-to-assiduites -d TEST -m 10:30 -n 14:50 -e 19:45`
Lors du lancement du script, une barre de progression apparaîtra. Celle si vous
indique l'avancée de la transformation des absences en assiduités.
Une fois arrivée à 100%, Un processus de validation et de justification des
assiduités se lancera. Celui-ci peut (suivant les configurations) prendre un
certain temps. Veuillez ne pas le stopper en cours de route.
Lorsque la migration sera finie, un fichier log de la migration sera généré pour
chaque département. Vous recevrez aussi des statistiques sur le nombre de
justificatif et d'assiduités générés.
## Script de Suppression
En cas de problème, ou si vous souhaitez purger la base de donnée, un script de
suppression des assiduités et des justificatifs est disponible.
Le script se nomme `downgrade-assiduites-module`.
Si vous lancer le script sans aucune option, il ne se passera rien.
Voici les options :
- `-d, --dept`
Permet de restreindre la suppression à un département à l'aide de son acronyme.
Utilisation : `flask downgrade-assiduites-module -d <ACRONYME>`
- `-a, --assiduites`
Provoque la suppression de toutes les assiduités
Utilisation : `flask downgrade-assiduites-module -a`
- `-j, --justificatifs`
Provoque la suppression de tous les justificatifs
Utilisation : `flask downgrade-assiduites-module -j`
Quelques exemples :
- Pour tout supprimer : `flask downgrade-assiduites-module -a -j`
- Pour supprimer un département : `flask downgrade-assiduites-module -d DEPT -a -j`
- Pour supprimer l'assiduité d'un département : `flask downgrade-assiduites-module -d DEPT -a`
- Pour supprimer les justificatifs d'un département : `flask downgrade-assiduites-module -d DEPT -j`
!!! note "Voir aussi"
- [Le module assiduités](Assiduites.md)
- [Mise à jour vers ScoDoc 9.6 / Debian 12](UpgradeToDeb12Sco96.md)
- [FAQ](FAQ.md)
- [Contacts](Contact.md)

View File

@ -0,0 +1,170 @@
<!-- markdownlint-disable MD024 -->
# Document expérimental sur les données du module Assiduité de ScoDoc
Dans ce document je (Matthias Hartmann) détaillerais plusieurs méthodes pour enregistrer les données du module Assiduité et les utiliser. Je mettrai à jour ce document et je l'utiliserai lors de l'implémentation du cahier des charges.
> Pour la suite du document je nomme `plage` l'objet représentant une absence/présence sur une période donnée.
Dans les diagrammes:
> - les noms précédés par `?` sont des valeurs optionnelles.
> - les noms précédés par `#` sont des clés externes.
> - les noms précédés par `$` sont des clés primaires.
___
> dev note *(11/10/22)*: Les types des données ne sont pas forcément les bons, je n'ai pas encore regardé comment était organisée la BDD de ScoDoc
## Représentation d'une assiduité et d'un justificatif
> voir l'API ScoDoc -> [ScoDoc9 API](ScoDoc9API.md#api-assiduite)
## Représentation des données (Version 4)
```mermaid
classDiagram
class assiduites{
$assiduiteid : Integer
#etuid : Integer
date_debut : DateTime
date_fin : DateTime,
etat : String
#module?: Integer
}
class justificatifs{
$justifid : Integer
#etuid : Integer
date_debut : DateTime
date_fin : DateTime
fichier? : Integer
raison? : String
#etat : Integer DEFAULT=0
}
class etat_justificatif{
$etat_id : Integer
desc : String
}
justificatifs --> etat_justificatif
```
### Explications de la représentation
> - Dans cette version, les objets en base de données suivent la représentation fait en json (dans l'API)
> - Le fichier justificatif est toujours stocker sur le serveur et en base il est stocker sous la forme d'un identifiant unique.
> - le champs `etat` de la table `justificatif` est une clé étrangère vers la table `etat_justificatif` qui contient les différents états (attente, validé, modifié, en cours . . . ), Cette table permettra aux utilisateurs d'ajouter eux même des états en fonction de leurs besoins. (deux états seront obligatoires : 0[Non Validé] 1[Validé] mais leurs noms pourront être changés.)
## Représentation des données (Version 3)
```mermaid
classDiagram
class plage{
plage_id : Integer
date_debut : DateTime
date_fin : DateTime
#etuid : Integer
type : String
? #module_id : Integer
? #enseignant_id : Integer
}
class justificatif{
$#etuid : Integer
$date_debut : DateTime
$date_fin : DateTime
attachement : String
#etat : Integer DEFAULT=0
}
class etat_justificatif{
$etat_id : Integer
desc : String
}
justificatif --> etat_justificatif
```
### Explications de la représentation
> - Dans cette représentation, une plage est complètement dissociée d'une formation / département. Elle repose uniquement sur un étudiant en particulier. On peut néanmoins spécifier l'enseignant et le module concerné par l'absence dans le but de produire des statistiques.
> - Du coté des justificatifs, on a désormais un attribut `etat` plutôt qu'un booléen. Cet attribut est une clé étrangère lié à la table `etat_justificatif`. Cela permet alors d'avoir plusieurs états (Validé, Refusé, En Attente, Incomplet...) l'état `0` étant `Pas encore étudié` par exemple.
### Problèmes de la représentation
> - On utilise une nouvelle table pour stocker les différents états. A moins que cette table ne puisse être modifiée par les administrateurs de ScoDoc (ajouter des états pour des cas précis par IUT), on créer une table pour enregistrer des données statiques.
### Améliorations potentielles
> - A la place d'une table dans la BDD, on pourrait directement hard coder les états de justificatifs. Les états seront plus simple à accéder mais on perd l'aspect modification au cas par cas.
## Représentation des données (Version 2)
```mermaid
classDiagram
class plage{
id_plage : Integer
date_debut : DateTime
date_fin : DateTime
#id_dept : Integer
#formsemestre_id : Integer
#etuid : Integer
type : String
? #id_module : Integer
? #id_enseignant : Integer
}
class justificatif{
$#etuid : Integer
$date_debut : DateTime
$date_fin : DateTime
attachement : String
valide : bool DEFAULT=False
}
```
### Problèmes liés à la représentation
> - L'export de la base de donnée avec les justificatif devient plus complexe (car on doit aller chercher les fichiers du dossier justificatifs)
> - Même problème que la version 1 pour les requêtes
## Représentation des données ( Version 1)
```mermaid
classDiagram
class plage{
id_plage : Integer
date_debut : DateTime
date_fin : DateTime
#id_dept : Integer
#formsemestre_id : Integer
#etuid : Integer
type : String
? #id_module : Integer
? #id_enseignant : Integer
}
class justificatif{
#$id_plage : Integer
attachement : Blob
valide : bool DEFAULT=False
}
```
### Problèmes liés à la représentation
> - Quasiment l'ensemble des données sont stockées dans un même tuple\
> __Conséquence__ : chaque requête utilisant les données sera longue et lourde pour le gestionnaire de BDD
> - Le stockage sour la forme de blob est très lourd pour la bdd ( cf : [Benchmark des différentes méthode de stockage de fichier binaire sur progresql](https://www.cybertec-postgresql.com/en/binary-data-performance-in-postgresql/) )
> - Un justificatif doit être donné pour chaque absence (par exemple un arrêt maladie de plusieurs jours est présent dans la base autant de fois que l'étudiant a été absence à un cours )
### Avantages liés à la représentation
> - Peu ou pas de jointure à faire
> - Ensemble des données facilement accessibles
> - Une absence (`plage: type=absence`) est justifiée si un justificatif (`justificatifs : idPlage={idAbsence}`) est présent dans la base. Une absence peut être justifiée(par un étudiant par exemple) mais pas forcément validé par le corps enseignant / administratif. (`justificatifs : valide=Faux`)
> - l'objet justificatif permet de stocker un fichier / un texte servant de justification (`justificatifs : attachement={Blob}`). L'utilisation d'un __Blob__ permet de stocker virtuellement n'import quel type de fichier dans la bdd.
### Améliorations potentielles
> - Stocker les fichiers justificatifs dans un dossier sur le serveur plutôt que dans la base de donnée. On aurait alors une sauvegarde uniquement d'une chaîne de caractères (le chemin du fichier / la justification textuelle) au lieu de __Blob__ prenant beaucoup de place et étant lourds à traiter.\
> __Le problème est qu'on perd la facilité d'accès et les vérifications opérées automatiquement par le gestionnaire de base de donnée.__
> - Définir une durée de validité pour chaque justificatif au lieu de lier le justificatif à une plage. (et donc lier un justificatif à un étudiant)\
> __Le problème est qu'on perd de la simplicité de selection (utilisation de l'id de la plage dans un cas et utilisation de 2 *datetime* dans un autre) Mais au moins on a pas besoin d'entrer plusieurs fois un même justificatif.__

View File

@ -0,0 +1,119 @@
<!-- markdownlint-disable MD024 -->
# Gestions des fichiers justificatifs pour le module Assiduité
Le fonctionnement de l'importation / lecture des fichiers justificatifs est légèrement plus complexe que l'utilisation de l'API seule. Voici les différentes informations à savoir pour correctement utiliser les fichiers justificatifs.
Afin de bien comprendre les différentes informations, merci de lire d'abord la documentation de l'API Assiduité : [Documentation Assiduité](ScoDoc9API.md#api-assiduite)
## Importer un fichier
L'importation d'un fichier pour un justificatif se fait en deux temps :
* Créer un nouvel objet justificatif à l'aide de l'API
* Envoyer le fichier sur le serveur ScoDoc
### Envoyer le fichier sur le serveur ScoDoc
Dans un premier temps il faut créer un objet justificatif à l'aide de l'API.
Dans un second temps il faut envoyer le fichier sur le serveur à l'aide d'une requête `POST`.
#### Exemple en Python
##### Script d'envoi du justificatif
> `token` est le même token que pour le reste de l'API
```py
data = {
"etat": "attente",
"date_debut": "2022-10-27T08:00",
"date_fin": "2022-10-27T12:00",
}
# la route de l'api est : /justificatif/<etudid:int>/create
r = requests.post(API_URL + "/justificatif/123/create", json=data, headers=token)
print(r.json)
```
##### Réponse
```json
{
"justif_id" : 424242
}
```
##### Script d'envoi du fichier
> `token` est le même token que pour le reste de l'API
```py
with open('exemple.txt', 'rb') as f:
# la route pour importer est : api/justificatif/<justif_id:int>/import
r = requests.post(API_URL + "/justificatif/424242/import", files={"exemple.txt": f}, headers=token)
print(r.json)
```
##### Réponse
```json
{
"filename" : "exemple.txt"
}
```
Veillez à bien noter le nom de fichier renvoyé car c'est le nom coté "server", il sera à utiliser lors que vous souhaitez récupérer le fichier
ou lorsque vous voudrez le supprimer
## Télécharger un fichier
Pour télécharger un fichier de justificatif rien de plus simple
### Une simple requête POST
* **Méthode:** POST
* **Permission: `ScoView`**
* **Paramètres:**
* `justif_id`
* `filename`
* **Routes:** `/justificatif/<justif_id:int>/export/<filename>`
* **Exemple d'utilisation:** `/api/justificatif/424242/export/exemple.txt`
* **Résultat:** télécharge directement le fichier
## Supprimer un fichier
Pour supprimer un fichier il suffit d'envoyer une requête post sur le justificatif, avec un json correct
### Script de suppression du fichier
> `token` est le même token que pour le reste de l'API
```py
# la route pour supprimer est : api/justificatif/<justif_id:int>/remove
d = {
"remove": "list",
"filenames": [
"exemple.txt"
]
}
# ou
d = {
"remove": "al",
}
r = requests.post(API_URL + "/justificatif/424242/remove", data=d, headers=token)
print(r.json)
```
#### Réponse
```json
{
"response" : "removed"
}
```

View File

@ -1,3 +1,4 @@
<!-- markdownlint-disable MD041 MD040 MD033 MD051 -->
# API pour ScoDoc 9 # API pour ScoDoc 9
L'API ScoDoc permet à des applications tierces d'interroger ScoDoc. Elle offre L'API ScoDoc permet à des applications tierces d'interroger ScoDoc. Elle offre
@ -18,13 +19,13 @@ L'API fournit des données JSON, sauf exception (bulletins PDF par exemple).
Les objets ScoDoc manipulables sont identifiés par des id numériques. Les objets ScoDoc manipulables sont identifiés par des id numériques.
- etudid: étudiant - `etudid` : étudiant
- formation_id: un programme de formation (page "programmes"); - `formation_id` : un programme de formation (page "programmes");
- ue_id: une UE dans un programme; - `ue_id` : une UE dans un programme;
- matiere_id: une matière dans un programme; - `matiere_id` : une matière dans un programme;
- module_id: un module dans un programme; - `module_id` : un module dans un programme;
- moduleimpl_id: un module réalisé dans un semestre; - `moduleimpl_id` : un module réalisé dans un semestre;
- formsemestre_id: un "semestre" de formation. - `formsemestre_id` : un "semestre" de formation.
(pour plus de précisions, voir le [guide développeurs](GuideDeveloppeurs.md)) (pour plus de précisions, voir le [guide développeurs](GuideDeveloppeurs.md))
@ -77,7 +78,7 @@ flask user-password lecteur_api
Si vous êtes intéressé par le développement, voir 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 section sur les tests unitaires de l'API](TestsScoDoc.md#tests-de-lapi-scodoc9);
- [la documentation développeurs](GuideDeveloppeurs.md)] et sur les [vues de l'API](DevInternals.md#vues-de-lapi-et-permissions). - [la documentation développeurs](GuideDeveloppeurs.md) et sur les [vues de l'API](DevInternals.md#vues-de-lapi-et-permissions).
!!! note !!! note
@ -159,7 +160,7 @@ donnée ci-dessous dans [Référence](#reference).
#### Authentification #### Authentification
Lors de votre authentification (*connexion avec login et mdp*) à Scodoc, il Lors de votre authentification (*connexion avec login et mot de passe*) à Scodoc, il
vous sera attribué un jeton (token jwt *généré automatiquement*) vous permettant vous sera attribué un jeton (token jwt *généré automatiquement*) vous permettant
d'utiliser l'api suivant les droits correspondant à votre session. d'utiliser l'api suivant les droits correspondant à votre session.
@ -206,8 +207,8 @@ par le serveur ScoDoc.
## Règles générales ## Règles générales
* une route s'écrit comme une suite de noms et d'identifiants; * une route s'écrit comme une suite de noms et d'identifiants;
* les noms token, departement, formation, formsemestre, groupe, etudiant, * les noms token, département, formation, formsemestre, groupe, etudiant,
bulletin, absence, logo, programme, évaluation, resultat, decision désignent bulletin, absence, logo, programme, évaluation, résultat, décision désignent
des types d'objets; des types d'objets;
* les noms (verbes ou groupes verbaux): set_etudiant, remove_etudiant, query, * les noms (verbes ou groupes verbaux): set_etudiant, remove_etudiant, query,
create, delete, edit, order sont des actions; create, delete, edit, order sont des actions;
@ -248,6 +249,21 @@ Ce tableau est trié selon le type des informations renvoyées:
| Retour | Remarque | Méthode | Navigation | Permission | | Retour | Remarque | Méthode | Navigation | Permission |
|:------------------------|:----------------------------------------|---------|---------------------------------------------------------------------------|---------------------| |:------------------------|:----------------------------------------|---------|---------------------------------------------------------------------------|---------------------|
| assiduite | une assiduité | GET | [assiduité](#assiduite) | ScoView |
| assiduite**`*`** | liste d'assiduités d'un étudiant | GET | [assiduités](#assiduites) | ScoView |
| assiduite**`*`** | liste d'assiduités d'un formsemestre | GET | [assiduités-formsemestre](#assiduites-formsemestre) | ScoView |
| assiduite**`#`** | liste d'id d'assiduités justifiées par un justificatif | GET | [justificatif-justifies](#justificatif-justifies) | ScoView |
| assiduite:CREATE | création d'assiduité | POST | [assiduite-create](#assiduite-create) | ScoAssiduiteChange |
| assiduite:EDIT | édition d'assiduité | POST | [assiduite-edit](#assiduite-edit) | ScoAssiduiteChange |
| assiduite:DELETE | suppression d'assiduité | POST | [assiduite-delete](#assiduite-delete) | ScoAssiduiteChange |
| justificatif | un justificatif | GET | [justificatif](#justificatif) | ScoView |
| justificatif**`*`** | liste de justificatif d'un étudiant | GET | [justificatifs](#justificatifs) | ScoView |
| justificatif:CREATE | création de justificatif | POST | [justificatif-create](#justificatif-create) | ScoJustifChange |
| justificatif:EDIT | édition de justificatif | POST | [justificatif-edit](#justificatif-edit) | ScoJustifChange |
| justificatif:DELETE | suppression de justificatif | POST | [justificatif-delete](#justificatif-delete) | ScoJustifChange |
| justificatif:IMPORT | importation de fichier justificatif | POST | [justificatif-import](#justificatif-import) | ScoJustifChange |
| justificatif:EXPORT | exportation de fichier justificatif | POST | [justificatif-export](#justificatif-export) | ScoJustifChange |
| justificatif:REMOVE | suppression de fichier justificatif | POST | [justificatif-remove](#justificatif-remove) | ScoJustifChange |
| departement**`*`** | tous les depts | GET | [departements](#departements) | | | departement**`*`** | tous les depts | GET | [departements](#departements) | |
| departement**`#`** | tous les ids des depts | GET | [departements-ids](#departements-ids) | ScoView | | departement**`#`** | tous les ids des depts | GET | [departements-ids](#departements-ids) | ScoView |
| departement | recherche par id | GET | [departement](#departement) | ScoView | | departement | recherche par id | GET | [departement](#departement) | ScoView |
@ -322,12 +338,11 @@ Ce tableau est trié selon le type des informations renvoyées:
Pour uniformiser les résultats des exemples, ceux sont soumis à quelques post-traitements non réalisés par l'API. Il n'est par exemple pas garanti que les clés des objets json sont triées: Pour uniformiser les résultats des exemples, ceux sont soumis à quelques post-traitements non réalisés par l'API. Il n'est par exemple pas garanti que les clés des objets json sont triées:
* les clés sont triées - les clés sont triées
* les listes de plus de 2 éléments sont tronquées à 2 éléments, la fin de la liste étant représentée par la notation en json '...' - les listes de plus de 2 éléments sont tronquées à 2 éléments, la fin de la liste étant représentée par la notation en json '...'
* les dates (au format ISO) sont systématiquement remplacées par une date fixe (la date de modification d'un mot de passe peut évidement être différente de sa date de création) - les dates (au format ISO) sont systématiquement remplacées par une date fixe (la date de modification d'un mot de passe peut évidement être différente de sa date de création)
### **API Départements**
### **API Départements**
#### Structure Département #### Structure Département
@ -342,76 +357,76 @@ Pour uniformiser les résultats des exemples, ceux sont soumis à quelques post-
#### **departements** #### **departements**
* **Méthode:** GET - **Méthode:** GET
* **Routes:** `/departements` - **Routes:** `/departements`
* **Exemple d'utilisation:** `/api/departements` - **Exemple d'utilisation:** `/api/departements`
* **Résultat:** Liste de tous les départements (visibles ou non). - **Résultat:** Liste de tous les départements (visibles ou non).
* **Exemple de résultat:** [departements.json](samples/sample_departements.json.md) - **Exemple de résultat:** [departements.json](samples/sample_departements.json.md)
#### **departements-ids** #### **departements-ids**
* **Méthode:** GET - **Méthode:** GET
* **Permission: `ScoView`** - **Permission: `ScoView`**
* **Routes:** `/departements_ids` - **Routes:** `/departements_ids`
* **Résultat:** Liste des id départements (visibles ou non). - **Résultat:** Liste des id départements (visibles ou non).
* **Exemple de résultat:** - **Exemple de résultat:**
* **Exemple de résultat:** [departements-ids.json](samples/sample_departements-ids.json.md) - **Exemple de résultat:** [departements-ids.json](samples/sample_departements-ids.json.md)
#### **departement** #### **departement**
* **Méthode:** GET - **Méthode:** GET
* **Permission: `ScoView`** - **Permission: `ScoView`**
* **Routes:** - **Routes:**
* `/departement/id/<int:dept_id>` - `/departement/id/<int:dept_id>`
* `/departement/<string:dept>` - `/departement/<string:dept>`
* **Résultat:** Un département - **Résultat:** Un département
* **Exemple de résultat:** [departement.json](samples/sample_departement.json.md) - **Exemple de résultat:** [departement.json](samples/sample_departement.json.md)
#### **`departement-create`** #### **`departement-create`**
* **Méthode: POST** - **Méthode: POST**
* **Permission: `ScoSuperAdmin`** - **Permission: `ScoSuperAdmin`**
* **Paramètres:** aucun - **Paramètres:** aucun
* **Data:** `{ "acronym": str, "visible":bool }` - **Data:** `{ "acronym": str, "visible":bool }`
* **Routes:** `/departement/create` - **Routes:** `/departement/create`
* **Exemple d'utilisation:** `/departement/create` - **Exemple d'utilisation:** `/departement/create`
>`{ "acronym": "QLIO", "visible": true }` >`{ "acronym": "QLIO", "visible": true }`
* **Résultat:** Crée un nouveau département. L'acronyme du département (RT, - **Résultat:** Crée un nouveau département. L'acronyme du département (RT,
GEII, ...) doit être unique (il est d'usage de le mettre en majuscules, mais GEII, ...) doit être unique (il est d'usage de le mettre en majuscules, mais
ce n'est pas obligatoire). Le paramètre optionnel `visible`indique si le ce n'est pas obligatoire). Le paramètre optionnel `visible`indique si le
département est affiché sur la page d'accueil de ScoDoc. Notez qu'un département est affiché sur la page d'accueil de ScoDoc. Notez qu'un
département "invisible" peut quand même être utilisé si l'on connait son département "invisible" peut quand même être utilisé si l'on connait son
adresse (URL). Renvoie le département créé. adresse (URL). Renvoie le département créé.
* **Exemple de résultat:** [departements-create.json](samples/sample_departement-create.json.md) - **Exemple de résultat:** [departements-create.json](samples/sample_departement-create.json.md)
#### **`departement-edit`** #### **`departement-edit`**
* **Méthode: POST** - **Méthode: POST**
* **Permission: `ScoSuperAdmin`** - **Permission: `ScoSuperAdmin`**
* **Paramètres:** `dept_acronym` - **Paramètres:** `dept_acronym`
* **Data:** `{ "visible":bool }` - **Data:** `{ "visible":bool }`
* **Routes:** `/departement/<string:dept_acronym>/edit` - **Routes:** `/departement/<string:dept_acronym>/edit`
* **Exemple d'utilisation:** `/departement/edit` - **Exemple d'utilisation:** `/departement/edit`
>`{ "visible": false }` >`{ "visible": false }`
* **Résultat:** Modifie un département. Seul le champs `visible` peut être - **Résultat:** Modifie un département. Seul le champs `visible` peut être
modifié. L'acronyme ne peut pas être changé car il peut être mentionné dans de modifié. L'acronyme ne peut pas être changé car il peut être mentionné dans de
nombreux objets et documents, y compris à l'extérieur de ScoDoc. nombreux objets et documents, y compris à l'extérieur de ScoDoc.
* **Exemple de résultat:** [departements-edit.json](samples/sample_departement-edit.json.md) - **Exemple de résultat:** [departements-edit.json](samples/sample_departement-edit.json.md)
#### **`departement-delete`** #### **`departement-delete`**
* **Méthode: POST** - **Méthode: POST**
* **Permission: `ScoSuperAdmin`** - **Permission: `ScoSuperAdmin`**
* **Paramètres:** `dept_acronym` - **Paramètres:** `dept_acronym`
* **Routes:** `/departement/<string:dept_acronym>/delete` - **Routes:** `/departement/<string:dept_acronym>/delete`
* **Exemple d'utilisation:** `/departement/delete/EARTH` - **Exemple d'utilisation:** `/departement/delete/EARTH`
* **Résultat:** supprime définitivement un département. *Toutes les données sont effacées* - **Résultat:** supprime définitivement un département. *Toutes les données sont effacées*
(étudiants, formations, ...). (étudiants, formations, ...).
* **Exemple de résultat:** [departements-delete.json](samples/sample_departement-delete.json.md) - **Exemple de résultat:** [departements-delete.json](samples/sample_departement-delete.json.md)
### **API Etudiant** ### **API Etudiant**
@ -597,6 +612,7 @@ Pour uniformiser les résultats des exemples, ceux sont soumis à quelques post-
| _version_ | int | | | _version_ | int | |
#### **`formations`** #### **`formations`**
* **Méthode:** GET * **Méthode:** GET
* **Permission: `ScoView`** * **Permission: `ScoView`**
* **Routes:** `/formations` * **Routes:** `/formations`
@ -1101,7 +1117,7 @@ d'un autre).
* **Permission: `ScoUsersView`** * **Permission: `ScoUsersView`**
* **Routes:** * **Routes:**
* `/users/query?departement=dept_acronym&active=1&starts_with=<str:nom>` * `/users/query?departement=dept_acronym&active=1&starts_with=<str:nom>`
* **Résultat:** Liste d'utilisateurs, filtrés par département, statut, début de * **Résultat:** Liste d'utilisateurs, filtrés par département, statut, début de
nom (paramètres tous optionnels). Seuls les utilisateurs que l'on a la nom (paramètres tous optionnels). Seuls les utilisateurs que l'on a la
@ -1141,6 +1157,7 @@ d'un autre).
L'opération peut être rejetée si le mot de passe ne satisfait pas les conditions requises (trop simple par exemple), avec le retour suivant: L'opération peut être rejetée si le mot de passe ne satisfait pas les conditions requises (trop simple par exemple), avec le retour suivant:
> ```json > ```json
>
{ {
"error": "Bad Request", "error": "Bad Request",
"status": 400, "status": 400,
@ -1177,7 +1194,7 @@ d'un autre).
logiciel. Voir [ConfigPermissions](ConfigPermissions.md). logiciel. Voir [ConfigPermissions](ConfigPermissions.md).
* **Exemple de résultat:** [permissions.json](samples/sample_permissions.json.md) * **Exemple de résultat:** [permissions.json](samples/sample_permissions.json.md)
### ** API Bulletin, Évaluations, Notes** ### **API Bulletin, Évaluations, Notes**
Attention, les bulletins ne sont publiés sur l'API que si l'option "*publier le Attention, les bulletins ne sont publiés sur l'API que si l'option "*publier le
bulletin sur le portail étudiant*" est cochée dans le semestre concerné. bulletin sur le portail étudiant*" est cochée dans le semestre concerné.
@ -1197,10 +1214,9 @@ indiquer les matières. Par défaut (version `long`), il est structuré en `UEs
version est `short_mat`ou `long_mat`, il sera structuré en version est `short_mat`ou `long_mat`, il sera structuré en
`UEs / matieres / modules`. `UEs / matieres / modules`.
#### **etudiant-formsemestre-bulletin** #### **etudiant-formsemestre-bulletin**
Récapitulatif par étudiant (état, groupe(s), moyennes d'UEs et de modules Récapitulatif par étudiant (état, groupe(s), moyennes d'UEs et de modules)
pour un formsemestre spécifié par son id. pour un formsemestre spécifié par son id.
Par défaut les valeurs numériques sont formatées en chaînes. Si format=raw, valeurs numériques Par défaut les valeurs numériques sont formatées en chaînes. Si format=raw, valeurs numériques
mais pas JSON compliant à cause des `NaN`. mais pas JSON compliant à cause des `NaN`.
@ -1250,9 +1266,9 @@ mais pas JSON compliant à cause des `NaN`.
* **Exemple d'utilisation:** `/ScoDoc/api/formsemestre/1/programme` * **Exemple d'utilisation:** `/ScoDoc/api/formsemestre/1/programme`
* **Résultat:** Retourne la structure 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, * **`ues`**: liste des UEs
* **`ressources`**: liste des ressources (BUT), * **`ressources`**: liste des ressources (BUT)
* **`saes`**: liste des saes (BUT), * **`saes`**: liste des SAÉs (BUT)
* **`modules`**: liste des modules classiques (DUT ou sport/culture) * **`modules`**: liste des modules classiques (DUT ou sport/culture)
* **`malus`**: listes des modules de type bonus/malus. * **`malus`**: listes des modules de type bonus/malus.
@ -1268,7 +1284,7 @@ mais pas JSON compliant à cause des `NaN`.
* **Exemple d'utilisation:** `/api/formsemestre/1/resultats` * **Exemple d'utilisation:** `/api/formsemestre/1/resultats`
* **Résultat:** [formsemestre-resultats.json](samples/sample_formsemestre-resultats.json.md) * **Résultat:** [formsemestre-resultats.json](samples/sample_formsemestre-resultats.json.md)
Récapitulatif par étudiant (état, groupe(s), moyennes d'UEs et de modules Récapitulatif par étudiant (état, groupe(s), moyennes d'UEs et de modules)
pour un formsemestre spécifié par son id. pour un formsemestre spécifié par son id.
Par défaut les valeurs numériques sont formatées en chaînes. Si format=raw, Par défaut les valeurs numériques sont formatées en chaînes. Si format=raw,
valeurs numériques mais pas JSON compliant à cause des `NaN`. valeurs numériques mais pas JSON compliant à cause des `NaN`.
@ -1377,7 +1393,7 @@ valeurs numériques mais pas JSON compliant à cause des `NaN`.
* **Paramètres :** Aucun * **Paramètres :** Aucun
* **Route:** `/logo/<string:nom>` * **Route:** `/logo/<string:nom>`
* **Exemple d'utilisation :** `/ScoDoc/api/logo/header` * **Exemple d'utilisation :** `/ScoDoc/api/logo/header`
* **Résultat :** l'image (format png ou jpg. le format retourné dépend du format sous lequel l'image a été initialement enregistrée) * **Résultat :** l'image (format png ou jpg; le format retourné dépend du format sous lequel l'image a été initialement enregistrée)
* **Exemple de résultat:** [logo.json](samples/sample_logo.json.md) * **Exemple de résultat:** [logo.json](samples/sample_logo.json.md)
#### **`departement-logos`** #### **`departement-logos`**
@ -1408,12 +1424,502 @@ valeurs numériques mais pas JSON compliant à cause des `NaN`.
* `/departement/id/<int:departement_id>/logo/<string:nom>` * `/departement/id/<int:departement_id>/logo/<string:nom>`
* **Exemple d'utilisation:** * **Exemple d'utilisation:**
* `/ScoDoc/api/departement/MMI/logo/header` * `/ScoDoc/api/departement/MMI/logo/header`
* `/ScoDoc/api/departement/id/3/logo/header` * `/ScoDoc/api/departement/id/3/logo/header`
* **Résultat :** l'image (format png ou jpg) * **Résultat :** l'image (format png ou jpg)
* **Exemple de résultat:** [departement-logo.json](samples/sample_departement-logo.json.md) * **Exemple de résultat:** [departement-logo.json](samples/sample_departement-logo.json.md)
### **API Assiduités**
Cette API est disponible à partir de ScoDoc 9.6 et remplace les absences.
<!-- TODO: faire les samples -->
#### Structure Assiduité
| attribut | type | commentaire |
| :-------------- | :------------- | :--------------------------------------------------------------- |
| *assiduite_id* | int | identifiant unique |
| *etudid* | int | identifiant unique de l'étudiant concerné par l'assiduité |
| *moduleimpl_id* | int ou null | identifiant unique du module concerné par l'assiduité si indiqué |
| *date_debut* | string | date ISO du début de la période d'assiduité |
| *date_fin* | string | date ISO de la fin de la période d'assiduité |
| *etat* | string | état de l'assiduité (présent, absent, retard) |
| *desc* | string ou null | description de l'assiduité |
| *user_id* | int ou null | utilisateur ayant créé l'assiduité |
| *est_just* | boolean | l'assiduité est-elle justifiée |
| *entry_date* | string | la date d'entrée de l'assiduité |
> Rappel du format de date ISO : yyyy-mm-jjTHH:MM:SS
> Vous pouvez aussi spécifier le temps UTC en ajoutant '+HH:MM' à la fin
#### **assiduite**
* **Méthode:** GET
* **Permission: `ScoView`**
* **Paramètres:** `assiduite_id`
* **Routes:** `/assiduite/<int:assiduite_id>`
* **Exemple d'utilisation:** `/api/assiduite/1`
* **Résultat:** Retourne un objet assiduité ou une erreur si l'id n'est pas connu
* **Exemple de résultat:** [assiduite.json](samples/sample_assiduite.json.md)
#### **assiduites[-query]**
* **Méthode:** GET
* **Permission: `ScoView`**
* **Paramètres:** `etudid`
* **Query string:**
* `etat` ('present','retard','absent)
* `moduleimpl_id` (X : id du moduleimpl concerné)
* `date_debut` (X : date format iso)
* `date_fin` (X : date format iso)
* `formsemestre_id` (X : id du formsemestre)
* `est_just` (v,t,f,vrai,faux,true,false)
* `user_id` (X : id de l'utilisateur)
* **Routes:**
* `/assiduites/<int:etudid>`
* `/assiduites/<int:etudid>/query?`
* **Exemple d'utilisation:**
* `/api/assiduites/1`
* `/api/assiduites/1/query?etat=retard`
* `/api/assiduites/1/query?moduleimpl_id=1`
* **Résultat:** Liste de toutes les objets assiduité qui correspondent aux critères sélectionnés
* **Exemple de résultat:** [assiduites.json](samples/sample_assiduites.json.md)
#### **assiduites-count[-query]**
* **Méthode:** GET
* **Permission: `ScoView`**
* **Paramètres:** `etudid`
* **Query string:**
* `etat` ('present','retard','absent)
* `moduleimpl_id` (X : id du moduleimpl concerné)
* `date_debut` (X : date format ISO)
* `date_fin` (X : date format ISO)
* `formsemestre_id` (X : id du formsemestre)
* `est_just` (v,t,f,vrai,faux,true,false)
* `user_id` (X : id de l'utilisateur)
* `metric` ('compte', 'demi', 'journee', 'heure')
* **Routes:**
* `/assiduites/<int:etudid>/count`
* `/assiduites/<int:etudid>/count/query?`
* **Exemple d'utilisation:**
* `/api/assiduites/1`
* `/api/assiduites/1/count/query?etat=retard`
* `/api/assiduites/1/count/query?moduleimpl_id=1`
* `/api/assiduites/1/count/query?etat=present,retard&metric=compte,heure`
* **Résultat:** les métriques obtenu à partir des assiduitées correspondant aux critères sélectionnés
* **Exemple de résultat:** [assiduites-count.json](samples/sample_assiduites_count.json.md)
#### **assiduites-formsemestre[-query]**
* **Méthode:** GET
* **Permission: `ScoView`**
* **Paramètres:** `etudid`
* **Query string:**
* `etat` ('present','retard','absent)
* `moduleimpl_id` (X : id du moduleimpl concerné)
* `date_debut` (X : date format ISO)
* `date_fin` (X : date format ISO)
* `est_just` (v,t,f,vrai,faux,true,false)
* `user_id` (X : id de l'utilisateur)
* **Routes:**
* `/assiduites/formsemestre/<int:formsemestre_id>`
* `/assiduites/formsemestre/<int:formsemestre_id>/query?`
* **Exemple d'utilisation:**
* `/api/assiduites/formsemestre/1`
* `/api/assiduites/formsemestre/1/query?etat=retard`
* `/api/assiduites/formsemestre/1/query?moduleimpl=1`
* **Résultat:** Liste de toutes les objets assiduité des étudiants du formsemestre qui correspondent aux critères sélectionnés
* **Exemple de résultat:** [assiduites_formsemestre.json](samples/sample_assiduites_formsemestre.json.md)
#### **assiduites-formsemestre-count[-query]**
* **Méthode:** GET
* **Permission: `ScoView`**
* **Paramètres:** `etudid`
* **Query string:**
* `etat` ('present','retard','absent)
* `moduleimpl_id` (X : id du moduleimpl concerné)
* `date_debut` (X : date format ISO)
* `date_fin` (X : date format ISO)
* `est_just` (v,t,f,vrai,faux,true,false)
* `user_id` (X : id de l'utilisateur)
* **Routes:**
* `/assiduites/formsemestre/<int:formsemestre_id>/count`
* `/assiduites/formsemestre/<int:formsemestre_id>/count/query?`
* **Exemple d'utilisation:**
* `/api/assiduites/formsemestre/1/count`
* `/api/assiduites/formsemestre/1/count/query?etat=retard`
* `/api/assiduites/formsemestre/1/count/query?moduleimpl=1&metric=demi,journee`
* **Résultat:** les métriques obtenu à partir des assiduités de tous les étudiants du formsemestre correspondant aux critères sélectionnés
* **Exemple de résultat:** [assiduites_formsemestre-count.json](samples/sample_assiduites_formsemestre_count.json.md)
#### **assiduites-group[-query]**
* **Méthode:** GET
* **Permission: `ScoView`**
* **Query string:**
* `etudids` **Obligatoire** (liste des etudids sous la forme `x,y,z,...`)
* `etat` ('present','retard','absent)
* `moduleimpl_id` (X : id du moduleimpl concerné)
* `date_debut` (X : date format ISO)
* `date_fin` (X : date format ISO)
* `est_just` (v,t,f,vrai,faux,true,false)
* `user_id` (X : id de l'utilisateur)
* **Routes:**
* `/assiduites/group/query?etudids=`
* **Exemple d'utilisation:**
* `/assiduites/group/query?etudids=1,2,3`
* `/assiduites/group/query?etudids=1,2,3&etat=retard`
* `/assiduites/group/query?etudids=1,2,3&moduleimpl=1`
* **Résultat:**
```json
{
etudid1 : [{assiduité...}],
etudid2 : [{assiduité...}],
etudid3 : [{assiduité...}],
}
```
#### **assiduites-create**
* **Méthode:** POST
* **Permission: `ScoAssiduiteChange`**
* **Data:**
```json
[
{
"etudid":<int>,
"date_debut": <string>,
"date_fin": <string>,
"etat": <string>,
"moduleimpl_id"?: <int>,
"desc"?:<string>,
},
...
]
```
* **Routes:**
* `/assiduites/create`
* **Exemple d'utilisation:** `/api/assiduites/create`
> `[{date_debut: "2022-10-27T08:00",date_fin: "2022-10-27T10:00",etat: "absent",etudid:1}]`
* **Résultat:** Retourne un objet en deux parties (errors et success) contenant le retour de chaque objet donné dans la requête POST.
#### **assiduite-create**
* **Méthode:** POST
* **Permission: `ScoAssiduiteChange`**
* **Paramètres:** `etudid`
* **Data:**
```json
[
{
"date_debut": <string>,
"date_fin": <string>,
"etat": <string>,
"moduleimpl_id"?: <int>,
"desc"?:<string>
},
...
]
```
* **Routes:**
* `/assiduite/<int:etudid>/create`
* **Exemple d'utilisation:** `/api/assiduite/1/create`
> `[{date_debut: "2022-10-27T08:00",date_fin: "2022-10-27T10:00",etat: "absent"}]`
* **Résultat:** Retourne un objet en deux parties (errors et success) contenant le retour de chaque objet donné dans la requête POST.
* **Exemple de résultat:** [assiduite_create.json](samples/sample_assiduite_create.json.md)
#### **assiduite-edit**
* **Méthode:** POST
* **Permission: `ScoAssiduiteChange`**
* **Paramètres:** `assiduite_id`
* **Data:**
```json
{
"etat": <string>,
"moduleimpl_id": <int>,
"desc" : <string>,
}
```
* **Routes:** `/assiduite/<int:assiduite_id>/edit`
* **Exemple d'utilisation:** `/api/assiduite/1/edit`
> `{etat: "absent"}`
* **Résultat:** Modifie l'assiduité désignée. Renvoie une erreur si la
modification rend incompatible la plage de l'assiduité par rapport aux autres
assiduités du même étudiant.
* **Exemple de résultat:** [assiduite_edit.json](samples/sample_assiduite_edit.json.md)
#### **assiduites-edit**
* **Méthode:** POST
* **Permission: `ScoAssiduiteChange`**
* **Data:**
```json
[
{
"etudid":<int>
"etat"?: <string>,
"moduleimpl_id"?: <int>
"desc"?:<string>
},
...
]
```
* **Routes:**
* `/assiduites/edit`
* **Exemple d'utilisation:** `/api/assiduites/edit`
> `[{etat: "absent",assiduite_id:1},{etat: "retard",moduleimpl_id:12,assiduite_id:2}]`
* **Résultat:** Retourne un objet en deux parties (errors et success) contenant le retour de chaque objet donné dans la requête POST.
#### **assiduite-delete**
* **Méthode:** POST
* **Permission: `ScoAssiduiteChange`**
* **Data:**
```json
[
<int:assiduite_id>,
...
]
```
* **Routes:**
* `/assiduite/delete`
* **Exemple d'utilisation:** `/api/assiduite/delete`
> `[2,3,5,7]`
* **Résultat:** Retourne un objet en deux parties (errors et success) contenant le retour de chaque objet donné dans la requête POST.
* **Exemple de résultat:** [assiduite_delete.json](samples/sample_assiduite_delete.json.md)
#### Structure Justificatif
| attribut | type | commentaire |
| :----------- | :------------- | :------------------------------------------------------------ |
| *justif_id* | int | identifiant unique |
| *etudid* | int | identifiant unique de l'étudiant concerné par le justificatif |
| *date_debut* | string | date ISO du début de la période du justificatif |
| *date_fin* | string | date ISO de la fin de la période du justificatif |
| *etat* | string | état du justificatif ( attente, valide, non_valide, modifie) |
| *raison* | string ou null | explication du justificatif si présente |
| *fichier* | string | identifiant de l'archivage des fichiers |
| *entry_date* | string | date ISO de l'entrée du justificatif |
#### **justificatif**
* **Méthode:** GET
* **Permission: `ScoView`**
* **Paramètres:** `justif_id`
* **Routes:** `/justificatif/<int:justif_id>`
* **Exemple d'utilisation:** `/api/justificatif/1`
* **Résultat:** Retourne un objet justificatif ou une erreur si l'id n'est pas connu
* **Exemple de résultat:** [justificatif.json](samples/sample_justificatif.json.md)
#### **justificatifs[-query]**
* **Méthode:** GET
* **Permission: `ScoView`**
* **Paramètres:** `etudid`
* **Query string:**
* `etat` ( attente, valide, non_valide, modifie)
* `date_debut` (X : date format ISO)
* `date_fin` (X : date format ISO)
* **Routes:**
* `/justificatifs/<int:etudid>`
* `/justificatifs/<int:etudid>/query?etat=VALIDE`
* **Exemple d'utilisation:**
* `/api/justificatifs/1`
* `/api/justificatifs/1/query?etat=modifie`
* `/api/justificatifs/1/query?date_debut=2022-10-27T08:00`
* **Résultat:** Liste de toutes les objets justificatifs qui correspondent aux critères sélectionnés
* **Exemple de résultat:** [justificatifs.json](samples/sample_justificatifs.json.md)
#### **justificatif-create**
* **Méthode:** POST
* **Permission: `ScoJustifChange`**
* **Paramètres:** `etudid`
* **Data:**
```json
[
{
"etat": <string>,
"date_debut": <string>,
"date_fin": <string>,
"raison"?: <string>,
},
...
]
```
> Un fichier justificatif peut être importé dans scodoc après avoir créer l'objet justificatif voir [importer un justificatif](FichiersJustificatifs.md#importer-un-fichier)
* **Routes:** `/justificatif/<int:etudid>/create`
* **Exemple d'utilisation:** `/api/justificatif/1/create`
```json
[
{
"etat": "attente",
"date_debut": "2022-10-27T08:00",
"date_fin": "2022-10-27T12:00",
"raison": "Opération médicale",
}
]
```
* **Résultat:** Retourne un objet en deux parties (errors et success) contenant
le retour de chaque objet donné dans la requête POST.
* **Exemple de résultat:** [justificatif-create.json](samples/sample_justificatif_create.json.md)
#### **justificatif-edit**
* **Méthode:** POST
* **Permission: `ScoJustifChange`**
* **Paramètres:** `justif_id`
* **Data:**
```json
{
"etat": <string>,
"raison": <string>,
"date_debut": <string>,
"date_fin": <string>,
}
```
* **Routes:** `/justificatif/<int:justif_id>/edit`
* **Exemple d'utilisation:** `/api/justificatif/1/edit`
> `{etat: "valide"}`
* **Résultat:** Modifie le justificatif désigné.
* **Exemple de résultat:** [justificatif-edit.json](samples/sample_justificatif_edit.json.md)
#### **justificatif-delete**
* **Méthode:** POST
* **Permission: `ScoJustifChange`**
* **Paramètres:** `etudid`
* **Data:**
```json
[
<int:justif_id>,
...
]
```
* **Routes:** `/justificatif/delete`
* **Exemple d'utilisation:** `/api/justificatif/delete`
```json
[
2,3,5,7
]
```
* **Résultat:** Retourne un objet en deux partie (errors et success) contenant le retour de chaque objet donné dans la requête POST.
* **Exemple de résultat:** [justificatif-delete.json](samples/sample_justificatif_delete.json.md)
#### **justificatif-import**
* **Méthode:** POST
* **Permission: `ScoJustifChange`**
* **Paramètres:** `justif_id`
> Procédure d'importation de fichier : [importer un justificatif](FichiersJustificatifs.md#importer-un-fichier)
* **Routes:** `/justificatif/<int:justif_id>/import`
* **Résultat:** Le nom du fichier archivé (nom coté serveur)
* **Exemple de résultat:** [justificatif-import.json](samples/sample_justificatif_import.json.md)
#### **justificatif-export**
* **Méthode:** POST
* **Permission: `ScoJustifChange`**
* **Paramètres:**
* `justif_id`
* `filename`
> Procédure de téléchargement de fichier : [télécharger un justificatif](FichiersJustificatifs.md#télécharger-un-fichier)
* **Routes:** `/justificatif/<int:justif_id>/export/<str:filename>`
* **Résultat:** le fichier (téléchargement direct / renvoie octets)
* **Exemple de résultat:** [justificatif-export.json](samples/sample_justificatif_export.json.md)
#### **justificatif-remove**
* **Méthode:** POST
* **Permission: `ScoJustifChange`**
* **Paramètres:** `justif_id`
> Procédure de suppression de fichier : [supprimer un justificatif](FichiersJustificatifs.md#supprimer-un-fichier)
* **Routes:** `/justificatif/<int:justif_id>/remove`
* **Résultat:** `{response:"removed"}` ou une erreur
* **Exemple de résultat:** [justificatif-remove.json](samples/sample_justificatif_remove.json.md)
#### **justificatif-list**
* **Méthode:** GET
* **Permission: `ScoView` / `ScoJustifView`**
* Si `ScoView` : retourne uniquement les fichiers fourni par le même utilisateur
* Si `ScoJustifView` : retourne tous les fichiers
* **Paramètres:** `justif_id`
* **Routes:** `/justificatif/<int:justif_id>/list`
* **Exemple d'utilisation:** `/api/justificatif/1/list`
* **Résultat:**
```json
{
"filenames" : [
<str>,
...
],
"total": <int>
}
```
* Le total indique le nombre total de fichiers (visibles ou non)
* **Exemple de résultat:** [justificatif-list.json](samples/sample_justificatif_list.json.md)
#### **justificatif-justifies**
* **Méthode:** GET
* **Permission: `ScoView`**
* **Paramètres:** `justif_id`
* **Routes:** `/justificatif/<int:justif_id>/justifies`
* **Exemple d'utilisation:** `/api/justificatif/1/justifies`
* **Résultat:** Retourne la liste des assiduite_id qui sont justifiés par le justificatif ou une erreur si l'id n'est pas connu
* **Exemple de résultat:** [justificatif-justifies.json](samples/sample_justificatif_justifies.json.md)
--------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------
### En savoir plus ### En savoir plus

View File

@ -157,6 +157,9 @@ source venv/bin/activate
flask migrate-abs-to-assiduites flask migrate-abs-to-assiduites
``` ```
Pour plus de détails et paramétrages (plages horaires, ...), voir
[la documentation sur la migration des absences](AssiduitesMigration.md).
Le traitement est assez long et peut prendre plusieurs dizaines de minutes, Le traitement est assez long et peut prendre plusieurs dizaines de minutes,
suivant le nombre d'absences et la vitesse de votre serveur. suivant le nombre d'absences et la vitesse de votre serveur.

View File

@ -0,0 +1,16 @@
### assiduite
#### GET /assiduite/1
```json
{
"assiduite_id": 1,
"date_debut": "2022-08-20T12:00:00.000000+02:00",
"date_fin": "2022-08-20T12:00:00.000000+02:00",
"desc": null,
"entry_date": "2022-08-20T12:00:00.000000+02:00",
"etat": "PRESENT",
"etudid": 1,
"moduleimpl_id": 8
}
```

View File

@ -0,0 +1,18 @@
### assiduite_create
#### POST /assiduite/1/create
> `Content-Type: application/json`
>
> `[{"date_debut": "2022-10-27T08:00","date_fin": "2022-10-27T10:00","etat": "absent"}]`
```json
{
"errors": {},
"success": {
"0": {
"assiduite_id": 60
}
}
}
```

View File

@ -0,0 +1,23 @@
### assiduite_delete
#### POST /assiduite/delete
> `Content-Type: application/json`
>
> `[2,2,3]`
```json
{
"errors": {
"1": "Assiduite non existante"
},
"success": {
"0": {
"OK": true
},
"2": {
"OK": true
}
}
}
```

View File

@ -0,0 +1,35 @@
### assiduite_edit
#### POST /assiduite/1/edit
> `Content-Type: application/json`
>
> `{"etat": "retard","moduleimpl_id":3}`
```json
{
"OK": true
}
```
#### POST /assiduite/1/edit
> `Content-Type: application/json`
>
> `{"etat":"absent"}`
```json
{
"OK": true
}
```
#### POST /assiduite/1/edit
> `Content-Type: application/json`
>
> `{"moduleimpl_id":2}`
```json
{
"OK": true
}
```

View File

@ -0,0 +1,63 @@
### assiduites
#### GET /assiduites/1
```json
[
{
"assiduite_id": 1,
"date_debut": "2022-08-20T12:00:00.000000+02:00",
"date_fin": "2022-08-20T12:00:00.000000+02:00",
"desc": null,
"entry_date": "2022-08-20T12:00:00.000000+02:00",
"etat": "PRESENT",
"etudid": 1,
"moduleimpl_id": 8
},
{
"assiduite_id": 2,
"date_debut": "2022-08-20T12:00:00.000000+02:00",
"date_fin": "2022-08-20T12:00:00.000000+02:00",
"desc": null,
"entry_date": "2022-08-20T12:00:00.000000+02:00",
"etat": "RETARD",
"etudid": 1,
"moduleimpl_id": 13
},
"..."
]
```
#### GET /assiduites/1/query?etat=retard
```json
[
{
"assiduite_id": 2,
"date_debut": "2022-08-20T12:00:00.000000+02:00",
"date_fin": "2022-08-20T12:00:00.000000+02:00",
"desc": null,
"entry_date": "2022-08-20T12:00:00.000000+02:00",
"etat": "RETARD",
"etudid": 1,
"moduleimpl_id": 13
},
{
"assiduite_id": 3,
"date_debut": "2022-08-20T12:00:00.000000+02:00",
"date_fin": "2022-08-20T12:00:00.000000+02:00",
"desc": null,
"entry_date": "2022-08-20T12:00:00.000000+02:00",
"etat": "RETARD",
"etudid": 1,
"moduleimpl_id": 14
},
"..."
]
```
#### GET /assiduites/1/query?moduleimpl_id=1
```json
[
"..."
]
```

View File

@ -0,0 +1,30 @@
### assiduites_count
#### GET /assiduites/1/count
```json
{
"compte": 4,
"demi": 3,
"heure": 6.0,
"journee": 4
}
```
#### GET /assiduites/1/count/query?etat=present,retard&metric=compte,heure
```json
{
"compte": 4,
"heure": 6.0
}
```
#### GET /assiduites/1/count/query?etat=retard
```json
{
"compte": 3,
"demi": 3,
"heure": 6.0,
"journee": 3
}
```

View File

@ -0,0 +1,23 @@
### assiduites_formsemestre
#### GET /assiduites/formsemestre/1
```json
[
"..."
]
```
#### GET /assiduites/formsemestre/1/query?etat=retard
```json
[
"..."
]
```
#### GET /assiduites/formsemestre/1/query?moduleimpl_id=1
```json
[
"..."
]
```

View File

@ -0,0 +1,30 @@
### assiduites_formsemestre_count
#### GET /assiduites/formsemestre/1/count
```json
{
"compte": 0,
"demi": 0,
"heure": 0.0,
"journee": 0
}
```
#### GET /assiduites/formsemestre/1/count/query?etat=present,retard&metric=compte,heure
```json
{
"compte": 0,
"heure": 0.0
}
```
#### GET /assiduites/formsemestre/1/count/query?etat=retard
```json
{
"compte": 0,
"demi": 0,
"heure": 0.0,
"journee": 0
}
```

View File

@ -0,0 +1,16 @@
### justificatif
#### GET /justificatif/1
```json
{
"date_debut": "2022-08-20T12:00:00.000000+02:00",
"date_fin": "2022-08-20T12:00:00.000000+02:00",
"entry_date": "2022-08-20T12:00:00.000000+02:00",
"etat": "VALIDE",
"etudid": 1,
"fichier": null,
"justif_id": 1,
"raison": "raison"
}
```

View File

@ -0,0 +1,18 @@
### justificatif_create
#### POST /justificatif/1/create
> `Content-Type: application/json`
>
> `[{"date_debut": "2022-10-27T08:00","date_fin": "2022-10-27T10:00","etat": "attente"}]`
```json
{
"errors": {},
"success": {
"0": {
"justif_id": 12
}
}
}
```

View File

@ -0,0 +1,23 @@
### justificatif_delete
#### POST /justificatif/delete
> `Content-Type: application/json`
>
> `[2,2,3]`
```json
{
"errors": {
"1": "Justificatif non existant"
},
"success": {
"0": {
"OK": true
},
"2": {
"OK": true
}
}
}
```

View File

@ -0,0 +1,24 @@
### justificatif_edit
#### POST /justificatif/1/edit
> `Content-Type: application/json`
>
> `{"etat":"valide"}`
```json
{
"OK": true
}
```
#### POST /justificatif/1/edit
> `Content-Type: application/json`
>
> `{"raison":"MEDIC"}`
```json
{
"OK": true
}
```

View File

@ -0,0 +1,26 @@
### justificatifs
#### GET /justificatifs/1
```json
[
{
"date_debut": "2022-08-20T12:00:00.000000+02:00",
"date_fin": "2022-08-20T12:00:00.000000+02:00",
"entry_date": "2022-08-20T12:00:00.000000+02:00",
"etat": "VALIDE",
"etudid": 1,
"fichier": null,
"justif_id": 1,
"raison": "raison"
},
"..."
]
```
#### GET /justificatifs/1/query?etat=attente
```json
[
"..."
]
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB