1 .. -*- coding: utf-8 -*- |
|
2 |
|
3 Définition d'un type d'entité |
|
4 ----------------------------- |
|
5 |
|
6 Un type d'entité est définit par une classe python héritant de `EntityType`. Le |
|
7 nom de la classe correspond au nom du type. Ensuite le corps de la classe |
|
8 contient la description des attributs et des relations pour ce type d'entité, |
|
9 par exemple :: |
|
10 |
|
11 class Personne(EntityType): |
|
12 """une personne avec les propriétés et relations nécessaires à mon |
|
13 application""" |
|
14 |
|
15 nom = String(required=True, fulltextindexed=True) |
|
16 prenom = String(required=True, fulltextindexed=True) |
|
17 civilite = String(vocabulary=('M', 'Mme', 'Mlle')) |
|
18 date_naiss = Date() |
|
19 travaille_pour = SubjectRelation('Company', cardinality='?*') |
|
20 |
|
21 * le nom de l'attribut python correspond au nom de l'attribut ou de la relation |
|
22 dans cubicweb. |
|
23 |
|
24 * tout les types de bases sont disponibles nativement : `String`, `Int`, `Float`, |
|
25 `Boolean`, `Date`, `Datetime`, `Time`, `Byte`. |
|
26 |
|
27 * Chaque type d'entité a au moins les méta-relations suivantes : |
|
28 |
|
29 - `eid` (`Int`) |
|
30 |
|
31 - `creation_date` (`Datetime`) |
|
32 |
|
33 - `modification_date` (`Datetime`) |
|
34 |
|
35 - `created_by` (`EUser`) (quel utilisateur a créé l'entité) |
|
36 |
|
37 - `owned_by` (`EUser`) (à qui appartient l'entité, par défaut le |
|
38 créateur mais pas forcément et il peut exister plusieurs propriétaires) |
|
39 |
|
40 - `is` (`EEType`) |
|
41 |
|
42 |
|
43 * il est également possible de définir des relations dont le type d'entité est |
|
44 l'objet en utilisant `ObjectRelation` plutôt que `SubjectRelation` |
|
45 |
|
46 * le premier argument de `SubjectRelation` et `ObjectRelation` donne |
|
47 respectivement le type d'entité objet /sujet de la relation. Cela |
|
48 peut être : |
|
49 |
|
50 * une chaine de caractères correspondant à un type d'entité |
|
51 |
|
52 * un tuple de chaines de caractères correspondant à plusieurs types d'entité |
|
53 |
|
54 * les chaînes de caractères spéciales suivantes : |
|
55 |
|
56 - "**" : tout les types d'entité |
|
57 - "*" : tout les types d'entité non méta |
|
58 - "@" : tout les types d'entité méta mais non "système" (i.e. servant à la |
|
59 description du schema en base) |
|
60 |
|
61 * il est possible d'utiliser l'attribut possible `meta` pour marquer un type |
|
62 d'entité comme étant "méta" (i.e. servant à décrire / classifier d'autre |
|
63 entités) |
|
64 |
|
65 * propriétés optionnelles des attributs et relations : |
|
66 |
|
67 - `description` : chaine de caractères décrivant un attribut ou une |
|
68 relation. Par défaut cette chaine sera utilisée dans le formulaire de saisie |
|
69 de l'entité, elle est donc destinée à aider l'utilisateur final et doit être |
|
70 marquée par la fonction `_` pour être correctement internationalisée. |
|
71 |
|
72 - `constraints` : liste de contraintes devant être respecté par la relation |
|
73 (c.f. `Contraintes`_) |
|
74 |
|
75 - `cardinality` : chaine de 2 caractères spécifiant la cardinalité de la |
|
76 relation. Le premier caractère donne la cardinalité de la relation sur le |
|
77 sujet, le 2eme sur l'objet. Quand une relation possède plusieurs sujets ou |
|
78 objets possibles, la cardinalité s'applique sur l'ensemble et non un à un (et |
|
79 doit donc à priori être cohérente...). Les valeurs possibles sont inspirées |
|
80 des expressions régulières : |
|
81 |
|
82 * `1`: 1..1 |
|
83 * `?`: 0..1 |
|
84 * `+`: 1..n |
|
85 * `*`: 0..n |
|
86 |
|
87 - `meta` : booléen indiquant que la relation est une méta relation (faux par |
|
88 défaut) |
|
89 |
|
90 * propriétés optionnelles des attributs : |
|
91 |
|
92 - `required` : booléen indiquant si l'attribut est obligatoire (faux par |
|
93 défaut) |
|
94 |
|
95 - `unique` : booléen indiquant si la valeur de l'attribut doit être unique |
|
96 parmi toutes les entités de ce type (faux par défaut) |
|
97 |
|
98 - `indexed` : booléen indiquant si un index doit être créé dans la base de |
|
99 données sur cette attribut (faux par défaut). C'est utile uniquement si vous |
|
100 savez que vous allez faire de nombreuses recherche sur la valeur de cet |
|
101 attribut. |
|
102 |
|
103 - `default` : valeur par défaut de l'attribut. A noter que dans le cas des |
|
104 types date, les chaines de caractères correspondant aux mots-clés RQL |
|
105 `TODAY` et `NOW` sont utilisables. |
|
106 |
|
107 - `vocabulary` : spécifie statiquement les valeurs possibles d'un attribut |
|
108 |
|
109 * propriétés optionnelles des attributs de type `String` : |
|
110 |
|
111 - `fulltextindexed` : booléen indiquant si l'attribut participe à l'index plein |
|
112 texte (faux par défaut) (*valable également sur le type `Byte`*) |
|
113 |
|
114 - `internationalizable` : booléen indiquant si la valeur de cet attribut est |
|
115 internationalisable (faux par défaut) |
|
116 |
|
117 - `maxsize` : entier donnant la taille maximum de la chaine (pas de limite par |
|
118 défaut) |
|
119 |
|
120 * propriétés optionnelles des relations : |
|
121 |
|
122 - `composite` : chaîne indiquant que le sujet (composite == 'subject') est |
|
123 composé de ou des objets de la relation. Pour le cas opposé (l'objet est |
|
124 composé de ou des sujets de la relation, il suffit de mettre 'object' comme |
|
125 valeur. La composition implique que quand la relation est supprimé (et donc |
|
126 aussi quand le composite est supprimé), le ou les composés le sont |
|
127 également. |
|
128 |
|
129 Contraintes |
|
130 ``````````` |
|
131 Par défaut les types de contraintes suivant sont disponibles : |
|
132 |
|
133 * `SizeConstraint` : permet de spécifier une taille minimale et/ou maximale sur |
|
134 les chaines de caractères (cas générique de `maxsize`) |
|
135 |
|
136 * `BoundConstraint` : permet de spécifier une valeur minimale et/ou maximale sur |
|
137 les types numériques |
|
138 |
|
139 * `UniqueConstraint` : identique à "unique=True" |
|
140 |
|
141 * `StaticVocabularyConstraint` : identique à "vocabulary=(...)" |
|
142 |
|
143 * `RQLConstraint` : permet de spécifier une requête RQL devant être satisfaite |
|
144 par le sujet et/ou l'objet de la relation. Dans cette requête les variables `S` |
|
145 et `O` sont préféfinies respectivement comme l'entité sujet et objet de la |
|
146 relation |
|
147 |
|
148 * `RQLVocabularyConstraint` : similaire à la précédente, mais exprimant une |
|
149 contrainte "faible", i.e. servant uniquement à limiter les valeurs apparaissant |
|
150 dans la liste déroulantes du formulaire d'édition, mais n'empêchant pas une |
|
151 autre entité d'être séléctionnée |
|
152 |
|
153 |
|
154 Définition d'un type de relation |
|
155 -------------------------------- |
|
156 |
|
157 Un type de relation est définit par une classe python héritant de `RelationType`. Le |
|
158 nom de la classe correspond au nom du type. Ensuite le corps de la classe |
|
159 contient la description des propriétés de ce type de relation, ainsi |
|
160 qu'éventuellement une chaine pour le sujet et une autre pour l'objet permettant |
|
161 de créer des définitions de relations associées (auquel cas il est possibles de |
|
162 donner sur la classe les propriétés de définition de relation explicitées |
|
163 ci-dessus), par exemple :: |
|
164 |
|
165 class verrouille_par(RelationType): |
|
166 """relation sur toutes les entités applicatives indiquant que celles-ci sont vérouillées |
|
167 inlined = True |
|
168 cardinality = '?*' |
|
169 subject = '*' |
|
170 object = 'EUser' |
|
171 |
|
172 En plus des permissions, les propriétés propres aux types de relation (et donc |
|
173 partagés par toutes les définitions de relation de ce type) sont : |
|
174 |
|
175 * `inlined` : booléen contrôlant l'optimisation physique consistant à stocker la |
|
176 relation dans la table de l'entité sujet au lieu de créer une table spécifique |
|
177 à la relation. Cela se limite donc aux relations dont la cardinalité |
|
178 sujet->relation->objet vaut 0..1 ('?') ou 1..1 ('1') |
|
179 |
|
180 * `symetric` : booléen indiquant que la relation est symétrique. i.e. |
|
181 `X relation Y` implique `Y relation X` |
|
182 |
|
183 Dans le cas de définitions de relations simultanée, `sujet` et `object` peuvent |
|
184 tout deux valoir la même chose que décrite pour le 1er argument de |
|
185 `SubjectRelation` et `ObjectRelation`. |
|
186 |
|
187 A partir du moment où une relation n'est ni mise en ligne, ni symétrique, et |
|
188 ne nécessite pas de permissions particulières, sa définition (en utilisant |
|
189 `SubjectRelation` ou `ObjectRelation`) est suffisante. |
|
190 |
|
191 |
|
192 Définition des permissions |
|
193 -------------------------- |
|
194 |
|
195 La définition des permissions se fait à l'aide de l'attribut `permissions` des |
|
196 types d'entité ou de relation. Celui-ci est un dictionnaire dont les clés sont |
|
197 les types d'accès (action), et les valeurs les groupes ou expressions autorisées. |
|
198 |
|
199 Pour un type d'entité, les actions possibles sont `read`, `add`, `update` et |
|
200 `delete`. |
|
201 |
|
202 Pour un type de relation, les actions possibles sont `read`, `add`, et `delete`. |
|
203 |
|
204 Pour chaque type d'accès, un tuple indique le nom des groupes autorisés et/ou |
|
205 une ou plusieurs expressions RQL devant être vérifiées pour obtenir |
|
206 l'accès. L'accès est donné à partir du moment où l'utilisateur fait parti d'un |
|
207 des groupes requis ou dès qu'une expression RQL est vérifiée. |
|
208 |
|
209 Les groupes standards sont : |
|
210 |
|
211 * `guests` |
|
212 |
|
213 * `users` |
|
214 |
|
215 * `managers` |
|
216 |
|
217 * `owners` : groupe virtuel correspondant au propriétaire d'une entité. Celui-ci |
|
218 ne peut être utilisé que pour les actions `update` et `delete` d'un type |
|
219 d'entité. |
|
220 |
|
221 Il est également possible d'utiliser des groupes spécifiques devant être pour |
|
222 cela créés dans le precreate de l'application (`migration/precreate.py`). |
|
223 |
|
224 Utilisation d'expression RQL sur les droits en écriture |
|
225 ``````````````````````````````````````````````````````` |
|
226 Il est possible de définir des expressions RQL donnant des droits de |
|
227 modification (`add`, `delete`, `update`) sur les types d'entité et de relation. |
|
228 |
|
229 Expression RQL pour les permissions sur un type d'entité : |
|
230 |
|
231 * il faut utiliser la classe `ERQLExpression` |
|
232 |
|
233 * l'expression utilisée correspond à la clause WHERE d'une requête RQL |
|
234 |
|
235 * dans cette expression, les variables X et U sont des références prédéfinies |
|
236 respectivement sur l'entité courante (sur laquelle l'action est vérifiée) et |
|
237 sur l'utilisateur ayant effectué la requête |
|
238 |
|
239 * il est possible d'utiliser dans cette expression les relations spéciales |
|
240 "has_<ACTION>_permission" dont le sujet est l'utilisateur et l'objet une |
|
241 variable quelquonque, signifiant ainsi que l'utilisateur doit avoir la |
|
242 permission d'effectuer l'action <ACTION> sur la ou les entités liées cette |
|
243 variable |
|
244 |
|
245 Pour les expressions RQL sur un type de relation, les principes sont les mêmes |
|
246 avec les différences suivantes : |
|
247 |
|
248 * il faut utiliser la classe `RRQLExpression` dans le cas d'une relation non |
|
249 finale |
|
250 |
|
251 * dans cette expression, les variables S, O et U sont des références |
|
252 prédéfinies respectivement sur le sujet et l'objet de la relation |
|
253 courante (sur laquelle l'action est vérifiée) et sur l'utilisateur |
|
254 ayant effectué la requête |
|
255 |
|
256 * On peut aussi définir des droits sur les attributs d'une entité (relation non |
|
257 finale), sachant les points suivants : |
|
258 |
|
259 - pour définir des expressions rql, il faut utiliser la classe `ERQLExpression` |
|
260 dans laquelle X représentera l'entité auquel appartient l'attribut |
|
261 |
|
262 - les permissions 'add' et 'delete' sont équivalentes. En pratique seul |
|
263 'add'/'read' son pris en considération |
|
264 |
|
265 |
|
266 En plus de cela, le type d'entité `EPermission` de la librairie standard permet |
|
267 de construire des modèles de sécurités très complexes et dynamiques. Le schéma |
|
268 de ce type d'entité est le suivant : :: |
|
269 |
|
270 |
|
271 class EPermission(MetaEntityType): |
|
272 """entity type that may be used to construct some advanced security configuration |
|
273 """ |
|
274 name = String(required=True, indexed=True, internationalizable=True, maxsize=100) |
|
275 require_group = SubjectRelation('EGroup', cardinality='+*', |
|
276 description=_('groups to which the permission is granted')) |
|
277 require_state = SubjectRelation('State', |
|
278 description=_("entity'state in which the permission is applyable")) |
|
279 # can be used on any entity |
|
280 require_permission = ObjectRelation('**', cardinality='*1', composite='subject', |
|
281 description=_("link a permission to the entity. This " |
|
282 "permission should be used in the security " |
|
283 "definition of the entity's type to be useful.")) |
|
284 |
|
285 |
|
286 Exemple de configuration extrait de *jpl* :: |
|
287 |
|
288 ... |
|
289 |
|
290 class Version(EntityType): |
|
291 """a version is defining the content of a particular project's release""" |
|
292 |
|
293 permissions = {'read': ('managers', 'users', 'guests',), |
|
294 'update': ('managers', 'logilab', 'owners',), |
|
295 'delete': ('managers', ), |
|
296 'add': ('managers', 'logilab', |
|
297 ERQLExpression('X version_of PROJ, U in_group G,' |
|
298 'PROJ require_permission P, P name "add_version",' |
|
299 'P require_group G'),)} |
|
300 |
|
301 ... |
|
302 |
|
303 class version_of(RelationType): |
|
304 """link a version to its project. A version is necessarily linked to one and only one project. |
|
305 """ |
|
306 permissions = {'read': ('managers', 'users', 'guests',), |
|
307 'delete': ('managers', ), |
|
308 'add': ('managers', 'logilab', |
|
309 RRQLExpression('O require_permission P, P name "add_version",' |
|
310 'U in_group G, P require_group G'),) |
|
311 } |
|
312 inlined = True |
|
313 |
|
314 Cette configuration suppose indique qu'une entité `EPermission` de nom |
|
315 "add_version" peut-être associée à un projet et donner le droit de créer des |
|
316 versions sur ce projet à des groupes spécifiques. Il est important de noter les |
|
317 points suivants : |
|
318 |
|
319 * dans ce cas il faut protéger à la fois le type d'entité "Version" et la |
|
320 relation liant une version à un projet ("version_of") |
|
321 |
|
322 * du fait de la généricité du type d'entité `EPermission`, il faut effectuer |
|
323 l'unification avec les groupes et / ou les états le cas échéant dans |
|
324 l'expression ("U in_group G, P require_group G" dans l'exemple ci-dessus) |
|
325 |
|
326 |
|
327 Utilisation d'expression RQL sur les droits en lecture |
|
328 `````````````````````````````````````````````````````` |
|
329 Les principes sont les mêmes mais avec les restrictions suivantes : |
|
330 |
|
331 * on ne peut de `RRQLExpression` sur les types de relation en lecture |
|
332 |
|
333 * les relations spéciales "has_<ACTION>_permission" ne sont pas utilisables |
|
334 |
|
335 |
|
336 Note sur l'utilisation d'expression RQL sur la permission 'add' |
|
337 ``````````````````````````````````````````````````````````````` |
|
338 L'utilisation d'expression RQL sur l'ajout d'entité ou de relation pose |
|
339 potentiellement un problème pour l'interface utilisateur car si l'expression |
|
340 utilise l'entité ou la relation à créer, on est pas capable de vérifier les |
|
341 droits avant d'avoir effectué l'ajout (noter que cela n'est pas un problème coté |
|
342 serveur rql car la vérification des droits est effectuée après l'ajout |
|
343 effectif). Dans ce cas les méthodes de vérification des droits (check_perm, |
|
344 has_perm) peuvent inidquer qu'un utilisateur n'a pas le droit d'ajout alors |
|
345 qu'il pourrait effectivement l'obtenir. Pour palier à ce soucis il est en général |
|
346 nécessaire dans tel cas d'utiliser une action reflétant les droits du schéma |
|
347 mais permettant de faire la vérification correctement afin qu'elle apparaisse |
|
348 bien le cas échéant. |
|