273 lines
7.5 KiB
Markdown
273 lines
7.5 KiB
Markdown
# Conventions de codage pour ScoDoc
|
|
|
|
Le projet étant très ancien, le code est passé par différentes conventions et
|
|
frameworks. Le style de python et celui du _frontend_ web ont considérablement
|
|
évolués ces dernières décennies.
|
|
|
|
Pour les nouveaux codes, respecter les principes suivants:
|
|
|
|
- ScoDoc est avant tout une application serveur écrite en Python, qui offre des
|
|
services via une interface Web, une API, et accessoirement la ligne de
|
|
commande unix.
|
|
|
|
- Les pages Web générées doivent l'être en Python côté serveur. On peut utiliser
|
|
du JS pour les pages dynamiques complexes (eg éditeur de partition) mais
|
|
éviter d'utiliser du JS pour générer des éléments statiques: l'abus de JS
|
|
conduit à dupliquer du code (qui existe en général dans le serveur) et
|
|
augmente les coûts de maintenance.
|
|
|
|
## Conventions de codage
|
|
|
|
### Formatage du code
|
|
|
|
- l'usage de **[black](https://black.readthedocs.io/en/stable/)** est obligatoire
|
|
- l'usage de pylint et mypy est fortement recommandé
|
|
- Pour le code JS, indentation avec 2 espaces (sous VS Code, utiliser _Prettier_).
|
|
|
|
### Conventions standard Python
|
|
|
|
On se tient à la PEP8, c'est à dire en résumé:
|
|
`UneClasse`, `une_fonction`, `_une_fonction_privee`, `une_variable`, `UNE_CONSTANTE_GLOBALE`.
|
|
|
|
Les noms de fichiers sont en minuscules sans accents ni espaces, `comme_ceci.py`.
|
|
|
|
### Annotations de type (typehints)
|
|
|
|
On annote les paramètres et résultats des fonctions.
|
|
|
|
```py
|
|
def _upload_justificatif_files(
|
|
just: Justificatif, form: AjoutJustificatifEtudForm
|
|
) -> bool:
|
|
...
|
|
```
|
|
|
|
## Pages et templates
|
|
|
|
Les vues utilisent un template _Jinja2_, fichier avec extension j2.
|
|
|
|
On s'astreint, sauf cas particulier, à un nommage identique de la route, la vue et du template.
|
|
|
|
```py
|
|
@bp.route("/un_exemple")
|
|
def un_exemple(...):
|
|
...
|
|
return render_template(".../un_exemple.j2")
|
|
```
|
|
|
|
Le template aura typiquement avec la structure suivante:
|
|
|
|
```jinja
|
|
{% extends "sco_page.j2" %}
|
|
|
|
{% block app_content %}
|
|
<h1>Titre</h1>
|
|
{% endblock app_content %}
|
|
```
|
|
|
|
Pour les pages dans un semestre (avec barre menu etc.), on utilisera `<h2>` au
|
|
lieu de `<h1>`.
|
|
|
|
### Templates habituels
|
|
|
|
Les templates suivants sont les plus utilisés pour les pages:
|
|
|
|
- `base.j2` pages hors département (accueil, configuration, ...)
|
|
|
|
- `sco_page.j2` page standard dans un formsemestre: avec sidebar et barre de
|
|
menu du semestre. Le contenu de la variable `content` est placé comme HTML
|
|
brut (_safe_) dans la partie contenu. Passer `sco=ScoData(formsemestre=formsemestre)`
|
|
en argument au template.
|
|
|
|
- `sco_page_dept.j2` page dans un département (avec sidebar) mais sans formsemestre (pas de
|
|
barre de menu)
|
|
|
|
### Constantes définies dans les templates ScoDoc
|
|
|
|
Le `context_processor` `inject_sco_utils()` ajoute des objets pour accès à tous
|
|
les templates ScoDoc:
|
|
|
|
- `scu` : le module `sco_utils.py` (diverses fonctions utilitaires et variables
|
|
de config.)
|
|
- `sco` : des données sur le contexte, notamment les préférences, le
|
|
formsemestre et l'étudiant courants (resp. `sco.formsemestre` et `sco.etud`)
|
|
|
|
### Appel d'un template page
|
|
|
|
Pour mémoire, l'appel d'un template dans une vue se fait ainsi:
|
|
|
|
```py
|
|
render_template( "votre_template.j2",
|
|
title="Changer de référentiel de compétences",
|
|
autre_variable=...
|
|
)
|
|
```
|
|
|
|
### Passage des anciennes pages ScoDoc 7 aux templates Jinja
|
|
|
|
Les anciennes pages étaient générées en python selon la structure:
|
|
|
|
```py
|
|
html_sco_header.sco_header(
|
|
cssstyles=["css/....css"],
|
|
javascripts=[
|
|
"js/....js",
|
|
],
|
|
page_title="titre de la page",
|
|
)
|
|
... contenu ...
|
|
html_sco_header.sco_footer()
|
|
```
|
|
|
|
La migration la plus simple consiste à utilise `sco_page.j2`:
|
|
|
|
```py
|
|
render_template(
|
|
"sco_page.j2",
|
|
content=contenu,
|
|
title="titre de la page",
|
|
cssstyles=["..."],
|
|
javascripts=["..."],
|
|
)
|
|
```
|
|
|
|
Mais si on souhaite générer le contenu dans un template, cela prendra la forme:
|
|
|
|
```jinja-html
|
|
{% extends "sco_page.j2" %}
|
|
|
|
{% block title %}
|
|
...titre...
|
|
{% endblock title %}
|
|
|
|
{% block styles %}
|
|
{{ super() }}
|
|
<link rel="stylesheet" href="{{scu.STATIC_DIR}}/css/un_style_scodoc.css">
|
|
<style>
|
|
... styles locaux ...
|
|
</style>
|
|
{% endblock styles %}
|
|
|
|
{% block app_content %}
|
|
<div class="pageContent">
|
|
<h2>titre page</h2>
|
|
... contenu ...
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
{{ super() }}
|
|
<script src="{{scu.STATIC_DIR}}/js/un_script_scodoc.js"></script>
|
|
<script>
|
|
... script js local ...
|
|
</script>
|
|
{% endblock %}
|
|
```
|
|
|
|
### Classes css
|
|
|
|
`scodoc.css` (et à partir de 9.7, `scodoc97.css`) définissent quelques classes à usage général:
|
|
|
|
- `div.scobox`: boite (bords arrondis, fond uni) regroupant des éléments.
|
|
|
|
- `div.scobox-title` le titre de la boite
|
|
- `div.scobox-buttons` boutons en bas de boite.
|
|
|
|
- `p.help`, `div.help`: explications, aide.
|
|
- ...
|
|
|
|
## Accès à la base de donnée
|
|
|
|
Sauf exception (requêtes exotiques, problèmes de performance) à discuter, les
|
|
accès à la base se font à travers l'ORM _SQLAlchemy_. Les modèles sont définis
|
|
dans `app/models`, sauf les comptes utilisateurs qui sont dans
|
|
`/app/auth/models.py`.
|
|
|
|
Au moment de la définition de nouveaux modèles, éviter si possible les champs
|
|
_nullables_, penser à créer là où ce sera utile des index.
|
|
|
|
## Tableaux
|
|
|
|
ScoDoc génère beaucoup de tableaux, sauf exception destinés à l'affichage Web et à l'export xlsx.
|
|
|
|
On utilise la super-classe `Table` de `app/tables/table_builder.py`.
|
|
|
|
Le rendu HTML utilise _DataTables_.
|
|
|
|
## Dates et heures
|
|
|
|
ScoDoc, contrairement à de nombreuses applications, est centré sur les
|
|
_étudiants_ et les enseignements, qui sont censés opérer dans le fuseau horaire
|
|
du serveur. Cela signifie que, quelle que soit l'emplacement de l'utilisateur,
|
|
les heures affichées et saisies par ScoDoc seront données dans le fuseau horaire
|
|
du serveur.
|
|
|
|
L'API publie et reçoit des heures au format ISO avec fuseau horaire (_timezone_) et n'est pas
|
|
concernée par cette remarque.
|
|
|
|
## Sélection de groupes
|
|
|
|
De nombreuses pages ont besoin d'offrir un moyen de sélectionner un ou plusieurs
|
|
groupes d'étudiants, comme dans cet exemple:
|
|
|
|
![menu multiselect des groupes](screens/multiselect_groups.png)
|
|
|
|
La vue doit récupérer la liste des groupes sélectionnés ainsi:
|
|
|
|
```py
|
|
group_ids = request.args.getlist("group_ids")
|
|
```
|
|
|
|
ou s'il s'agit un `POST`:
|
|
|
|
```py
|
|
group_ids = request.form.getlist("group_ids")
|
|
```
|
|
|
|
On converti ensuite les arguments en entiers:
|
|
|
|
```py
|
|
try:
|
|
group_ids = [int(gid) for gid in group_ids]
|
|
except ValueError as exc:
|
|
raise ScoValueError("group_ids invalide") from exc
|
|
```
|
|
|
|
et on peut utiliser le code ancien `sco_groups_view`:
|
|
|
|
```py
|
|
groups_infos = sco_groups_view.DisplayedGroupsInfos(
|
|
group_ids,
|
|
formsemestre_id=formsemestre.id,
|
|
select_all_when_unspecified=True,
|
|
)
|
|
```
|
|
|
|
`groups_infos` est un objet qui permet de récupérer les informations et de générer le menu.
|
|
|
|
Par exemple:
|
|
|
|
```py
|
|
Choix des groupes :
|
|
{sco_groups_view.menu_groups_choice(groups_infos, submit_on_change=True)
|
|
if groups_infos else ''}
|
|
```
|
|
|
|
La fonction `form_groups_choice` génère un formulaire complet.
|
|
|
|
Autres attributs/méthodes utiles de `groups_infos`:
|
|
|
|
- `get_etudids():list[int]` : les ids des étudiants des groupes sélectionnés;
|
|
- `groups_titles:str` : titres des groupes;
|
|
- `groups_filename:str`: un (morceau de) nom de fichier pour ces groupes.
|
|
|
|
|
|
|
|
!!! note "Voir aussi"
|
|
|
|
- [Introduction au développement ScoDoc](DevInternals.md)
|
|
- [Guide développeurs](GuideDeveloppeurs.md)
|
|
- [API ScoDoc 9](ScoDoc9API.md)
|
|
- [Modélisation du BUT](ModelisationParcoursBUT.md)
|
|
- [Contacts](Contact.md)
|