DocScoDocPE/docs/Internals.md

95 lines
3.8 KiB
Markdown

# Code de ScoDoc 9
Quelques informations pour les développeurs.
- 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
est normalement intégré à votre éditeur (VSCode et PyCharm sont deux choix
judicieux).
- outre Python, les principaux composants logiciels sont:
- [Flask](https://flask-sqlalchemy.palletsprojects.com/en/2.x/): le
framework Web, dont on utilise notamment:
- l'ORM [SQLAlchemy](https://www.sqlalchemy.org/)
- les templates [Jinja2](https://jinja.palletsprojects.com/en/3.0.x/)
- [Postgresql](https://www.postgresql.org/)
- [Redis](https://redis.io/) cache persistant
- [NGINX](https://www.nginx.com/) serveur Web frontal
- [gunicorn](https://gunicorn.org/) WSGI HTTP server
- et bien sûr Linux (Debian 11 en 2021-2022) et systemd.
# 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
l'ORM SQLAlchemy (recommandé pour tout nouveau code).
Les modèles correspondant sont déclarés dans `/opt/scodoc/app/models/`.
Principales classes (les noms des classes Python sont en `CamelCase`).
- Étudiants (classe `Identite`): nom, codes INE/NIP, etc
- Formations: programmes pédagogiques, contenant
- Unités d'Enseignement (`UniteEns`);
- Matières et Modules (`Module`, avec son type standard, bonus, ressources
ou SAÉ).
- FormSemestre: instanciation d'une session de formation, avec un programme
pédagogique donné (Formation), les dates de début et fin, des étudiants
inscrits, des responsables, divers codes, et les ModuleImpl mis en œuvre.
- ModuleImpl: la mise en place d'un module pédagogique (le ModuleImpl est au
Module ce que le FormSemestre est à la Formation): lié à un module, avec un
enseignant responsable et des étudiants inscrits.
- Inscriptions: tables d'association avec codes et/ou état (démission,
défaillant): FormsemestreInscription ModuleImplInscription.
# Vues et décorateurs
Une vue ordinaire (Web) pourrait ressembler à cela. Noter la présence de
décorateurs:
- `@scodoc` récupère le département (présent dans l'URL) et initialise quelques
trucs, notamment `g.scodoc_dept` (l'acronyme du département courant) et
`g.scodoc_dept_id` (l'id du dépt. courant).
- `@permission_required`: permet de contrôler l'accès, en se basant sur les
permissions définies dans la classe `Permission`.
```
@bp.route("/un_exemple")
@scodoc
@permission_required(Permission.ScoChangeFormation)
def un_exemple():
# Récupérer le ou les arguments: exemple avec formation_id
formation_id = int(request.args["formation_id"])
# Charger le ou les objets utilies:
formation = models.Formation.query.get(
formation_id=formation_id
).first_or_404()
# Effectuer au besoin un traitement
resultat = ...
# Afficher le résultat
return render_template(
"exemple_template.html",
resultat=resultat, # par exemple
formation=formation,
... # etc
)
```
# 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.
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
faut donc invalider les objets quand on écrit des données susceptibles de les
modifier, et penser à le vider quand on modifie le code.
Par exemple:
```
git pull
flask clear-cache
```
La commande `redis-cli FLUSHALL` permet aussi de vider le cache sans avoir à
lancer flask (plus rapide).