update docs

This commit is contained in:
imperosol 2024-11-30 22:47:47 +01:00
parent d657e3e258
commit a051e3cecc
2 changed files with 153 additions and 43 deletions

View File

@ -1,54 +1,157 @@
Il existe deux types de groupes sur le site AE :
## Un peu d'histoire
Par défaut, Django met à disposition un modèle `Group`,
lié par clef étrangère au modèle `User`.
Pour créer un système de gestion des groupes qui semblait plus
approprié aux développeurs initiaux, un nouveau
modèle [core.models.Group][]
a été crée, et la relation de clef étrangère a été modifiée
pour lier [core.models.User][] à ce dernier.
L'ancien modèle `Group` était implicitement
divisé en deux catégories :
- les *méta-groupes* : groupes liés aux clubs et créés à la volée.
Ces groupes n'étaient liés par clef étrangère à aucun utilisateur.
Ils étaient récupérés à partir de leur nom uniquement
et étaient plus une indirection pour désigner l'appartenance à un club
que des groupes à proprement parler.
- les *groupes réels* : groupes créés à la main
et souvent hardcodés dans la configuration.
Cependant, ce nouveau système s'éloignait trop du cadre de Django
et a fini par devenir une gêne.
La vérification des droits lors des opérations est devenue
une opération complexe et coûteuse en temps.
La gestion des groupes a donc été modifiée pour recoller un
peu plus au cadre de Django.
Toutefois, il n'a pas été tenté de revenir à 100%
sur l'architecture prônée par Django.
D'une part, cela représentait un risque pour le succès de l'application
de la migration sur la base de données de production.
D'autre part, si une autre architecture a été tentée au début,
ce n'était pas sans raison :
ce que nous voulons modéliser sur le site AE n'est pas
complètement modélisable avec ce qu'offre Django.
Il faut donc bien garder une surcouche au-dessus de l'authentification
de Django.
Tout le défi est de réussir à maintenir cette surcouche aussi fine
que possible sans limiter ce que nous voulons faire.
## Représentation en base de données
Le modèle [core.models.Group][] a donc été légèrement remanié
et la distinction entre groupes méta et groupes réels a été plus ou moins
supprimée.
La liaison de clef étrangère se fait toujours entre [core.models.User][]
et [core.models.Group][].
Cependant, il y a une subtilité.
Depuis le début, le modèle `Group` de django n'a jamais disparu.
En effet, lorsqu'un modèle hérite d'un modèle qui n'est pas
abstrait, Django garde les deux tables et les lie
par une clef étrangère unique de clef primaire à clef primaire
(pour plus de détail, lire
[la doc de django sur l'héritage de modèle](https://docs.djangoproject.com/fr/stable/topics/db/models/#model-inheritance))
L'organisation réelle de notre système de groupes
est donc la suivante :
<!-- J'ai utilisé un diagramme entité-relation
au lieu d'un diagramme de db, parce que Mermaid n'a que
le diagramme entité-relation. -->
```mermaid
---
title: Représentation des groupes
---
erDiagram
core_user }o..o{ core_group: core_user_groups
auth_group }o..o{ auth_permission: auth_group_permissions
core_group ||--|| auth_group: ""
core_user }o..o{ auth_permission :"core_user_user_permissions"
core_user {
int id PK
string username
string email
string first_name
etc etc
}
core_group {
int group_ptr_id PK,FK
string description
bool is_manually_manageable
}
auth_group {
int id PK
name string
}
auth_permission {
int id PK
string name
}
```
Cette organisation, rajoute une certaine complexité,
mais celle-ci est presque entièrement gérée par django,
ce qui fait que la gestion n'est pas tellement plus compliquée
du point de vue du développeur.
Chaque fois qu'un queryset implique notre `Group`
ou le `Group` de django, l'autre modèle est automatiquement
ajouté à la requête par jointure.
De cette façon, on peut manipuler l'un ou l'autre,
sans même se rendre que les tables sont dans des tables séparées.
Par exemple :
=== "python"
```python
from core.models import Group
Group.objects.all()
```
=== "SQL généré"
```sql
SELECT "auth_group"."id",
"auth_group"."name",
"core_group"."group_ptr_id",
"core_group"."is_manually_manageable",
"core_group"."description"
FROM "core_group"
INNER JOIN "auth_group" ON ("core_group"."group_ptr_id" = "auth_group"."id")
```
- l'un se base sur des groupes enregistrés en base de données pendant le développement,
c'est le système de groupes réels.
- L'autre est plus dynamique et comprend tous les groupes générés
pendant l'exécution et l'utilisation du programme.
Cela correspond généralement aux groupes liés aux clubs.
Ce sont les méta-groupes.
## La définition d'un groupe
Les deux types de groupes sont stockés dans la même table
en base de données, et ne sont différenciés que par un attribut `is_meta`.
Un groupe est constitué des informations suivantes :
### Les groupes réels
- son nom : `name`
- sa description : `description` (optionnelle)
- si on autorise sa gestion par les utilisateurs du site : `is_manually_manageable`
Pour plus différencier l'utilisation de ces deux types de groupe,
il a été créé une classe proxy
(c'est-à-dire qu'elle ne correspond pas à une vraie table en base de donnée)
qui encapsule leur utilisation.
`RealGroup` peut être utilisé pour créer des groupes réels dans le code
et pour faire une recherche sur ceux-ci
(dans le cadre d'une vérification de permissions par exemple).
Si un groupe est gérable manuellement, alors les administrateurs du site
auront le droit d'assigner des utilisateurs à ce groupe depuis l'interface dédiée.
### Les méta-groupes
S'il n'est pas gérable manuellement, on cache aux utilisateurs du site
la gestion des membres de ce groupe.
La gestion se fait alors uniquement "sous le capot",
de manière automatique lors de certains évènements.
Par exemple, lorsqu'un utilisateur rejoint un club,
il est automatiquement ajouté au groupe des membres
du club.
Lorsqu'il quitte le club, il est retiré du groupe.
Les méta-groupes, comme expliqué précédemment,
sont utilisés dans les contextes où il est nécessaire de créer un groupe dynamiquement.
Les objets `MetaGroup`, bien que dynamiques, doivent tout de même s'enregistrer
en base de données comme des vrais groupes afin de pouvoir être affectés
dans les permissions d'autres objets, comme un forum ou une page de wiki par exemple.
C'est principalement utilisé au travers des clubs,
qui génèrent automatiquement deux groupes à leur création :
## Les principaux groupes utilisés
- club-bureau : contient tous les membres d'un club **au dessus**
du grade défini dans `settings.SITH_MAXIMUM_FREE_ROLE`.
- club-membres : contient tous les membres d'un club
**en dessous** du grade défini dans `settings.SITH_MAXIMUM_FREE_ROLE`.
## Les groupes réels utilisés
Les groupes réels que l'on utilise dans le site sont les suivants :
Groupes gérés automatiquement par le site :
- `Public` : tous les utilisateurs du site
- `Subscribers` : tous les cotisants du site
- `Old subscribers` : tous les anciens cotisants
Groupes gérés par les administrateurs (à appliquer à la main sur un utilisateur) :
Les groupes les plus notables gérables par les administrateurs du site sont :
- `Root` : administrateur global du site
- `Accounting admin` : les administrateurs de la comptabilité
@ -62,3 +165,10 @@ Groupes gérés par les administrateurs (à appliquer à la main sur un utilisat
- `Banned to subscribe` : les utilisateurs interdits de cotisation
En plus de ces groupes, on peut noter :
- `Public` : tous les utilisateurs du site
- `Subscribers` : tous les cotisants du site
- `Old subscribers` : tous les anciens cotisants

View File

@ -4,7 +4,7 @@
Le fonctionnement de l'AE ne permet pas d'utiliser le système de permissions
intégré à Django tel quel. Lors de la conception du Sith, ce qui paraissait le
plus simple à l'époque était de concevoir un système maison afin de se calquer
sur ce que faisais l'ancien site.
sur ce que faisait l'ancien site.
### Protéger un modèle