doc/book/en/04-02-schema-definition.en.txt
changeset 93 9c919a47e140
child 101 c9138325b89f
equal deleted inserted replaced
92:30f19b976857 93:9c919a47e140
       
     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.