doc/devmanual_fr/sect_definition_schema.txt
changeset 0 b97547f5f1fa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/devmanual_fr/sect_definition_schema.txt	Wed Nov 05 15:52:50 2008 +0100
@@ -0,0 +1,348 @@
+.. -*- coding: utf-8 -*-
+
+Définition d'un type d'entité
+-----------------------------
+
+Un type d'entité est définit par une classe python héritant de `EntityType`. Le
+nom de la classe correspond au nom du type. Ensuite le corps de la classe
+contient la description des attributs et des relations pour ce type d'entité,
+par exemple ::
+
+  class Personne(EntityType):
+    """une personne avec les propriétés et relations nécessaires à mon
+    application"""
+
+    nom = String(required=True, fulltextindexed=True)
+    prenom = String(required=True, fulltextindexed=True)
+    civilite = String(vocabulary=('M', 'Mme', 'Mlle'))
+    date_naiss = Date()
+    travaille_pour = SubjectRelation('Company', cardinality='?*')
+
+* le nom de l'attribut python correspond au nom de l'attribut ou de la relation
+  dans cubicweb.
+
+* tout les types de bases sont disponibles nativement : `String`, `Int`, `Float`,
+  `Boolean`, `Date`, `Datetime`, `Time`, `Byte`.
+
+* Chaque type d'entité a au moins les méta-relations suivantes :
+
+  - `eid` (`Int`)
+  
+  - `creation_date` (`Datetime`)
+  
+  - `modification_date` (`Datetime`)
+  
+  - `created_by` (`EUser`) (quel utilisateur a créé l'entité)
+  
+  - `owned_by` (`EUser`) (à qui appartient l'entité, par défaut le
+     créateur mais pas forcément et il peut exister plusieurs propriétaires)
+     
+  - `is` (`EEType`)
+
+  
+* il est également possible de définir des relations dont le type d'entité est
+  l'objet en utilisant `ObjectRelation` plutôt que `SubjectRelation`
+
+* le premier argument de `SubjectRelation` et `ObjectRelation` donne
+  respectivement le type d'entité objet /sujet de la relation. Cela
+  peut être : 
+
+  * une chaine de caractères correspondant à un type d'entité
+
+  * un tuple de chaines de caractères correspondant à plusieurs types d'entité
+
+  * les chaînes de caractères spéciales suivantes :
+
+    - "**" : tout les types d'entité
+    - "*" : tout les types d'entité non méta
+    - "@" : tout les types d'entité méta mais non "système" (i.e. servant à la
+      description du schema en base)
+
+* il est possible d'utiliser l'attribut possible `meta` pour marquer un type
+  d'entité comme étant "méta" (i.e. servant à décrire / classifier d'autre
+  entités) 
+
+* propriétés optionnelles des attributs et relations : 
+
+  - `description` : chaine de caractères décrivant un attribut ou une
+    relation. Par défaut cette chaine sera utilisée dans le formulaire de saisie
+    de l'entité, elle est donc destinée à aider l'utilisateur final et doit être
+    marquée par la fonction `_` pour être correctement internationalisée.
+
+  - `constraints` : liste de contraintes devant être respecté par la relation
+    (c.f. `Contraintes`_)
+
+  - `cardinality` : chaine de 2 caractères spécifiant la cardinalité de la
+    relation. Le premier caractère donne la cardinalité de la relation sur le
+    sujet, le 2eme sur l'objet. Quand une relation possède plusieurs sujets ou
+    objets possibles, la cardinalité s'applique sur l'ensemble et non un à un (et
+    doit donc à priori être cohérente...). Les valeurs possibles sont inspirées
+    des expressions régulières :
+
+    * `1`: 1..1
+    * `?`: 0..1
+    * `+`: 1..n
+    * `*`: 0..n
+
+  - `meta` : booléen indiquant que la relation est une méta relation (faux par
+    défaut)
+
+* propriétés optionnelles des attributs : 
+
+  - `required` : booléen indiquant si l'attribut est obligatoire (faux par
+    défaut)
+
+  - `unique` : booléen indiquant si la valeur de l'attribut doit être unique
+    parmi toutes les entités de ce type (faux par défaut)
+
+  - `indexed` : booléen indiquant si un index doit être créé dans la base de
+    données sur cette attribut (faux par défaut). C'est utile uniquement si vous
+    savez que vous allez faire de nombreuses recherche sur la valeur de cet
+    attribut. 
+
+  - `default` : valeur par défaut de l'attribut. A noter que dans le cas des
+    types date, les chaines de caractères correspondant aux mots-clés RQL
+    `TODAY` et `NOW` sont utilisables.
+
+  - `vocabulary` : spécifie statiquement les valeurs possibles d'un attribut
+
+* propriétés optionnelles des attributs de type `String` : 
+
+  - `fulltextindexed` : booléen indiquant si l'attribut participe à l'index plein
+    texte (faux par défaut) (*valable également sur le type `Byte`*)
+
+  - `internationalizable` : booléen indiquant si la valeur de cet attribut est
+    internationalisable (faux par défaut) 
+
+  - `maxsize` : entier donnant la taille maximum de la chaine (pas de limite par
+    défaut)  
+
+* propriétés optionnelles des relations : 
+
+  - `composite` : chaîne indiquant que le sujet (composite == 'subject') est
+    composé de ou des objets de la relation. Pour le cas opposé (l'objet est
+    composé de ou des sujets de la relation, il suffit de mettre 'object' comme
+    valeur. La composition implique que quand la relation est supprimé (et donc
+    aussi quand le composite est supprimé), le ou les composés le sont
+    également. 
+
+Contraintes
+```````````
+Par défaut les types de contraintes suivant sont disponibles :
+
+* `SizeConstraint` : permet de spécifier une taille minimale et/ou maximale sur
+  les chaines de caractères (cas générique de `maxsize`)
+
+* `BoundConstraint` : permet de spécifier une valeur minimale et/ou maximale sur
+  les types numériques
+
+* `UniqueConstraint` : identique à "unique=True"
+
+* `StaticVocabularyConstraint` : identique à "vocabulary=(...)"
+
+* `RQLConstraint` : permet de spécifier une requête RQL devant être satisfaite
+  par le sujet et/ou l'objet de la relation. Dans cette requête les variables `S`
+  et `O` sont préféfinies respectivement comme l'entité sujet et objet de la
+  relation
+
+* `RQLVocabularyConstraint` : similaire à la précédente, mais exprimant une
+  contrainte "faible", i.e. servant uniquement à limiter les valeurs apparaissant
+  dans la liste déroulantes du formulaire d'édition, mais n'empêchant pas une
+  autre entité d'être séléctionnée
+
+
+Définition d'un type de relation
+--------------------------------
+
+Un type de relation est définit par une classe python héritant de `RelationType`. Le
+nom de la classe correspond au nom du type. Ensuite le corps de la classe
+contient la description des propriétés de ce type de relation, ainsi
+qu'éventuellement une chaine pour le sujet et une autre pour l'objet permettant
+de créer des définitions de relations associées (auquel cas il est possibles de
+donner sur la classe les propriétés de définition de relation explicitées
+ci-dessus), par exemple ::
+
+  class verrouille_par(RelationType):
+    """relation sur toutes les entités applicatives indiquant que celles-ci sont vérouillées
+    inlined = True
+    cardinality = '?*'
+    subject = '*'
+    object = 'EUser'
+
+En plus des permissions, les propriétés propres aux types de relation (et donc
+partagés par toutes les définitions de relation de ce type) sont :
+
+* `inlined` : booléen contrôlant l'optimisation physique consistant à stocker la
+  relation dans la table de l'entité sujet au lieu de créer une table spécifique
+  à la relation. Cela se limite donc aux relations dont la cardinalité
+  sujet->relation->objet vaut 0..1 ('?') ou 1..1 ('1')
+
+* `symetric` : booléen indiquant que la relation est symétrique. i.e.
+  `X relation Y` implique `Y relation X`
+
+Dans le cas de définitions de relations simultanée, `sujet` et `object` peuvent
+tout deux valoir la même chose que décrite pour le 1er argument de
+`SubjectRelation` et `ObjectRelation`.
+
+A partir du moment où une relation n'est ni mise en ligne, ni symétrique, et
+ne nécessite pas de permissions particulières, sa définition (en utilisant
+`SubjectRelation` ou `ObjectRelation`) est suffisante.
+
+
+Définition des permissions
+--------------------------
+
+La définition des permissions se fait à l'aide de l'attribut `permissions` des
+types d'entité ou de relation. Celui-ci est un dictionnaire dont les clés sont
+les types d'accès (action), et les valeurs les groupes ou expressions autorisées. 
+
+Pour un type d'entité, les actions possibles sont `read`, `add`, `update` et
+`delete`.
+
+Pour un type de relation, les actions possibles sont `read`, `add`, et `delete`.
+
+Pour chaque type d'accès, un tuple indique le nom des groupes autorisés et/ou
+une ou plusieurs expressions RQL devant être vérifiées pour obtenir
+l'accès. L'accès est donné à partir du moment où l'utilisateur fait parti d'un
+des groupes requis ou dès qu'une expression RQL est vérifiée.
+
+Les groupes standards sont :
+
+* `guests`
+
+* `users`
+
+* `managers`
+
+* `owners` : groupe virtuel correspondant au propriétaire d'une entité. Celui-ci
+  ne peut être utilisé que pour les actions `update` et `delete` d'un type
+  d'entité. 
+
+Il est également possible d'utiliser des groupes spécifiques devant être pour
+cela créés dans le precreate de l'application (`migration/precreate.py`).
+
+Utilisation d'expression RQL sur les droits en écriture
+```````````````````````````````````````````````````````
+Il est possible de définir des expressions RQL donnant des droits de
+modification (`add`, `delete`, `update`) sur les types d'entité et de relation.
+
+Expression RQL pour les permissions sur un type d'entité :
+
+* il faut utiliser la classe `ERQLExpression`
+
+* l'expression utilisée correspond à la clause WHERE d'une requête RQL
+
+* dans cette expression, les variables X et U sont des références prédéfinies
+  respectivement sur l'entité courante (sur laquelle l'action est vérifiée) et
+  sur l'utilisateur ayant effectué la requête
+
+* il est possible d'utiliser dans cette expression les relations spéciales
+  "has_<ACTION>_permission" dont le sujet est l'utilisateur et l'objet une
+  variable quelquonque, signifiant ainsi que l'utilisateur doit avoir la
+  permission d'effectuer l'action <ACTION> sur la ou les entités liées cette
+  variable
+
+Pour les expressions RQL sur un type de relation, les principes sont les mêmes
+avec les différences suivantes :
+
+* il faut utiliser la classe `RRQLExpression` dans le cas d'une relation non
+  finale
+
+* dans cette expression, les variables S, O et U sont des références
+  prédéfinies respectivement sur le sujet et l'objet de la relation
+  courante (sur laquelle l'action est vérifiée) et sur l'utilisateur
+  ayant effectué la requête
+
+* On peut aussi définir des droits sur les attributs d'une entité (relation non
+  finale), sachant les points suivants :
+
+  - pour définir des expressions rql, il faut utiliser la classe `ERQLExpression`
+    dans laquelle X représentera l'entité auquel appartient l'attribut
+
+  - les permissions 'add' et 'delete' sont équivalentes. En pratique seul
+    'add'/'read' son pris en considération
+
+
+En plus de cela, le type d'entité `EPermission` de la librairie standard permet
+de construire des modèles de sécurités très complexes et dynamiques. Le schéma
+de ce type d'entité est le suivant : ::
+
+
+    class EPermission(MetaEntityType):
+	"""entity type that may be used to construct some advanced security configuration
+	"""
+	name = String(required=True, indexed=True, internationalizable=True, maxsize=100)
+	require_group = SubjectRelation('EGroup', cardinality='+*',
+					description=_('groups to which the permission is granted'))
+	require_state = SubjectRelation('State',
+				    description=_("entity'state in which the permission is applyable"))
+	# can be used on any entity
+	require_permission = ObjectRelation('**', cardinality='*1', composite='subject',
+					    description=_("link a permission to the entity. This "
+							  "permission should be used in the security "
+							  "definition of the entity's type to be useful."))
+
+
+Exemple de configuration extrait de *jpl* ::
+
+    ...
+
+    class Version(EntityType):
+	"""a version is defining the content of a particular project's release"""
+
+	permissions = {'read':   ('managers', 'users', 'guests',),
+		       'update': ('managers', 'logilab', 'owners',),
+		       'delete': ('managers', ),
+		       'add':    ('managers', 'logilab',
+				  ERQLExpression('X version_of PROJ, U in_group G,'
+						 'PROJ require_permission P, P name "add_version",'
+						 'P require_group G'),)}
+
+    ...
+
+    class version_of(RelationType):
+	"""link a version to its project. A version is necessarily linked to one and only one project.
+	"""
+	permissions = {'read':   ('managers', 'users', 'guests',),
+		       'delete': ('managers', ),
+		       'add':    ('managers', 'logilab',
+				  RRQLExpression('O require_permission P, P name "add_version",'
+						 'U in_group G, P require_group G'),)
+		       }
+	inlined = True
+
+Cette configuration suppose indique qu'une entité `EPermission` de nom
+"add_version" peut-être associée à un projet et donner le droit de créer des
+versions sur ce projet à des groupes spécifiques. Il est important de noter les
+points suivants :
+
+* dans ce cas il faut protéger à la fois le type d'entité "Version" et la
+  relation liant une version à un projet ("version_of")
+
+* du fait de la généricité du type d'entité `EPermission`, il faut effectuer
+  l'unification avec les groupes et / ou les états le cas échéant dans
+  l'expression ("U in_group G, P require_group G" dans l'exemple ci-dessus)
+
+
+Utilisation d'expression RQL sur les droits en lecture
+``````````````````````````````````````````````````````
+Les principes sont les mêmes mais avec les restrictions suivantes :
+
+* on ne peut de `RRQLExpression` sur les types de relation en lecture
+
+* les relations spéciales "has_<ACTION>_permission" ne sont pas utilisables
+
+
+Note sur l'utilisation d'expression RQL sur la permission 'add'
+```````````````````````````````````````````````````````````````
+L'utilisation d'expression RQL sur l'ajout d'entité ou de relation pose
+potentiellement un problème pour l'interface utilisateur car si l'expression
+utilise l'entité ou la relation à créer, on est pas capable de vérifier les
+droits avant d'avoir effectué l'ajout (noter que cela n'est pas un problème coté
+serveur rql car la vérification des droits est effectuée après l'ajout
+effectif). Dans ce cas les méthodes de vérification des droits (check_perm,
+has_perm) peuvent inidquer qu'un utilisateur n'a pas le droit d'ajout alors
+qu'il pourrait effectivement l'obtenir. Pour palier à ce soucis il est en général
+nécessaire dans tel cas d'utiliser une action reflétant les droits du schéma
+mais permettant de faire la vérification correctement afin qu'elle apparaisse
+bien le cas échéant.