1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-04-30 02:21:37 +00:00

Update Droits

Pierre-antoine Comby 2020-03-21 19:50:31 +01:00
parent 334ecfbd29
commit b9f287e344

@ -8,31 +8,37 @@ Ce Role est relié a la responsabilité/fonction de la personne dans un Club. Il
## Permission
Une permission est, intuitivement, une formule logique indiquant si un utilisateur a le droit d'intéragir avec un modèle ou non. Cela peut concerner uniquement un champ d'un modèle.
Une permission est un Model Django dont les principaux attributs sont:
* `model` : Le model sur lequel cette permission va s'appliquer
* `type` : Les différents types d'interaction sont : voir (`view`), modifier (`change`), ajouter (`add`) et supprimer (`delete`).
* `query` : Requete sur la cible, encodé en JSON, traduit en un Q object (cf [Query](#compilation-de-la-query)
* `field` : le champ cible qui pourra etre modifié. (tous les champs si vide)
Les différents types d'interaction sont : voir (`view`), modifier (`change`), ajouter (`add`) et supprimer (`delete`).
Pour savoir si un utilisateur a le droit sur un modèle ou non, la requête est compilée (voir ci-dessous) en un fitre de requête dans la base de données, un objet de la classe `Q` (En SQL l'objet Q s'interprete comme tout ce qui suit un `WHERE ...` Ils peuvent être combiné à l'aide d'opérateurs logiques. Plus d'information sur les Q object dans la [documentation officiel](https://docs.djangoproject.com/fr/2.2/topics/db/queries/#complex-lookups-with-q-objects) )
Pour savoir si un utilisateur a le droit sur un modèle ou non, la requête est compilée (voir ci-dessous) en un fitre de requête dans la base de données, un objet de la classe `Q`. Ensuite, il suffit d'appliquer ce filtre sur une requête à la base de données du modèle considéré, et voir si l'objet recherché est trouvé ou non.
Ce Q object sera donc utilisé pour savoir si l'instance que l'on veux modifier est concernée par notre permission.
Exception faite sur l'ajout d'objets : l'objet n'existant pas encore en base de données, il est ajouté puis supprimé à la volée, en prenant soin de désactiver les signaux.
## Compilation de la requête
## Compilation de la query
La requête est enregistrée sous un format JSON, puis est traduite en requête `Q` récursivement en appliquant certains paramètres (on note `about` la fonction de traduction) :
La query est enregistrée sous un format JSON, puis est traduite en requête `Q` récursivement en appliquant certains paramètres.
Le fonctionnemente de base des permission peux être décris avec les differents opérations :
* `[] | {} -> Q(pk=F("pk"))` Une liste ou un objet vide représente tous les objets
* `["AND", query, …] -> about(query) & … ` Conjonction de requêtes
* `["OR", query, …] -> about(query) | … ` Disjonction de requêtes
* `["NOT", query] -> ~about(query) ` Négation d'une requête
* `{key: value, …} -> Q(key=value, …) ` Liste de champs et de valeurs dans un objet Q
* `key` est une chaîne de caractères,représentant le nom du champ
* `value` peut être de plusieurs natures :
| opérations | JSON | Q object |
|----------------|---------------------------|---------------------------------|
| ALL | `[]` ou `{}` | `.objects.get(Q(pk=F("pk"))` |
| ET | `["AND", Q_1, Q_2, ... ]` | `.objects.get(Q_1 & Q_2 & ...)` |
| OU | `["OR", Q_1, Q_2, ...]` | `.objects.get(Q_1 \| Q_2 \| ...)` |
| NON | `["NOT", Q_1]` | `.objects.get(~Q_1)` |
| key == value | `{key: value}` | `.objects.get(Q(key = value))` |
De plus value peux être utilisé de différetentes manières:
* Un nombre, une chaîne de caractères, un booléen, `null` pour représenter des valeurs littérales
* Si c'est une liste, c'est interprété comme un paramètre
* Le premier argument de la liste représente le nom du paramètre. Ce peut être l'objet utilisateur `user`, l'objet club `club` ou des objets de classe (`Note`, ...).
* S'il y a des arguments suivants dans la liste, ils vont être interprétés comme des sous-attributs du paramètre initial.
* Si un argument est une liste, alors c'est interprété comme une fonction à appeler, dont les arguments sont donnés par les autres éléments de la liste. Si cette liste contient un dictionnaire, le dictionnaire est passé en argument à la fonction sous la forme de kwargs.
* Les exemples seront plus clairs.
* Si c'est un dictionnaire de la forme {"F": oper}, alors c'est interprété comme un objet `F`.
* Si `oper` est un littéral, il est interprété tel quel.
* Si `oper = ["ADD", oper1, oper2, …]`, le résultat est la somme des objets `F` calculés d'après le reste de la liste.
@ -41,40 +47,69 @@ La requête est enregistrée sous un format JSON, puis est traduite en requête
* Si `oper = ["F", name]`, le résultat est F(name).
* Dans les autres cas, `oper` est un paramètre calculé comme précédemment.
Vous n'avez rien compris ? Voilà des exemples:
## Exemples
Cette définition n'étant pas claire, voici quelques exemples facilitant la compréhension :
* Permission sur le model `User` avec comme query:
```js
{"is_superuser": true}
```
> si l'utilisateur cible est un super utilisateur.
```js
Modèle : User
Q(is_superuser=True) := {"is_superuser": true}
Permission accordée si l'utilisateur cible est un super utilisateur.
```
* sur le model `Note`:
```js
{"pk":
["user","note", "pk"]
}
```
> si l'identifiant de la note cible est l'identifiant de l'utilisateur dont on regarde la permission.
```js
Modèle : Note
Q(pk=user.note.pk) := {"pk": ["user", "note", "pk"]}
Permission accordée si l'identifiant de la note cible est l'identifiant de l'utilisateur dont on regarde la permission.
```
* sur le model `Transaction`:
```js
Modèle : Transaction
["AND", {"source": ["user", "note"]}, {"amount__lte": ["user", "note", "balance"]}]
Permission accordée si la source est la note de l'utilisateur et si le montant est inférieur à son solde.
```
```js
["AND",
{"source":
["user", "note"]},
{"amount__lte":
["user", "note", "balance"]}
]
```
> si la source est la note de l'utilisateur et si le montant est inférieur à son solde.
```js
Modèle : Alias
["OR", {"note__in": ["NoteUser", "objects", ["filter", {"user__membership__club__name": "Kfet"}], ["all"]]}, {"note__in": ["NoteClub", "objects", ["all"]]}]
Permission accordée si l'alias appartient à une note de club ou s'il appartient à la note d'un utilisateur membre du club Kfet.
```
* Sur le model `Alias`
```js
["OR",
{"note__in":
["NoteUser", "objects",[
"filter",{
"user__membership__club__name": "Kfet"
}],
["all"]
]},
{"note__in":
["NoteClub", "objects", ["all"]]
}
]
```
> si l'alias appartient à une note de club ou s'il appartient à la note d'un utilisateur membre du club Kfet.
* sur le model `Transaction`
```js
["AND",
{"destination": ["club", "note"]},
{"amount__lte":
{"F": [
"ADD",
["F", "source__balance"],
5000]
}
}
]
```
> si la destination est la note du club dont on est membre et si le montant est inférieur au solde de la source + 50 €, autrement dit le solde final est au-dessus de -50 €.
```js
Modèle : Transaction
["AND", {"destination": ["club", "note"]}, {"amount__lte": {"F": ["ADD", ["F", "source__balance"], 5000]}}]
Permission accordée si la destination est la note du club dont on est membre et si le montant est inférieur au solde de la source + 50 €, autrement dit le solde final est au-dessus de -50 €.
```
## Masques de permissions