goa/doc/devmanual_fr/sect_definition_schema.txt
author Julien Jehannet <Julien Jehannet <julien.jehannet@logilab.fr>>
Tue, 02 Mar 2010 21:48:36 +0100
branchstable
changeset 4783 6dc34d4cf892
parent 4467 0e73d299730a
permissions -rw-r--r--
[F] views: fix 2 unicode errors 1. You can now use valid unicode strings in ValidationError exception. Previously, if 'err' contains unicode, UnicodeDecodeError was raised by format_errors() >>> templstr = '<li>%s</li>\n' >>> e = ValidationError(None, {None: u'oué, une exception en unicode!'}) >>> templstr % e '<li>None (None): ou\xc3\xa9, une exception en unicode!</li>\n' >>> templstr = u'<li>%s</li>\n' >>> templstr % e u'<li>None (None): ou\xe9, une exception en unicode!</li>\n' 2. The message of an Exception can contains unicode. But it now properly managed by “informal” string representation. We can easily fix the problem by using the Exception.message attribute that still contains the original message. >>> a = AssertionError(u'séfdsdf') >>> a.message u's\xe9fdsdf' >>> str(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 1: ordinal not in range(128) >>> a = ValueError(u'fsdfsdéfsdfs') >>> str(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 6: ordinal not in range(128) >>> a ValueError(u'fsdfsd\xe9fsdfs',) >>> unicode(a) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 6: ordinal not in range(128) >>> a.message u'fsdfsd\xe9fsdfs'


Dfinition d'un type d'entit
-----------------------------

Un type d'entit est dfinit par une classe python hritant 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 proprits et relations ncessaires  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 mta-relations suivantes :
  - `eid` (`Int`)
  - `creation_date` (`Datetime`)
  - `modification_date` (`Datetime`)
  - `owned_by` (`CWUser`)
  - `is` (`CWEType`)

* il est galement possible de dfinir des relations dont le type d'entit est
  l'objet en utilisant `ObjectRelation` plutt 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 caractres correspondant  un type d'entit

  * un tuple de chaines de caractres correspondant  plusieurs types d'entit

  * les chanes de caractres spciales suivantes :

    - "**" : tout les types d'entit
    - "*" : tout les types d'entit non mta
    - "@" : tout les types d'entit mta mais non "systme" (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 "mta" (i.e. servant  dcrire / classifier d'autre
  entits) 

* proprits optionnelles des attributs et relations : 

  - `description` : chaine de caractres dcrivant un attribut ou une
    relation. Par dfaut cette chaine sera utilise dans le formulaire de saisie
    de l'entit, elle est donc destine  aider l'utilisateur final et doit tre
    marque par la fonction `_` pour tre correctement internationalise.

  - `constraints` : liste de contraintes devant tre respect par la relation
    (c.f. `Contraintes`_)

  - `cardinality` : chaine de 2 caractres spcifiant la cardinalit de la
    relation. Le premier caractre donne la cardinalit de la relation sur le
    sujet, le 2eme sur l'objet. Quand une relation possde plusieurs sujets ou
    objets possibles, la cardinalit s'applique sur l'ensemble et non un  un (et
    doit donc  priori tre cohrente...). Les valeurs possibles sont inspires
    des expressions rgulires :

    * `1`: 1..1
    * `?`: 0..1
    * `+`: 1..n
    * `*`: 0..n

  - `meta` : boolen indiquant que la relation est une mta relation (faux par
    dfaut)

* proprits optionnelles des attributs : 

  - `required` : boolen indiquant si l'attribut est obligatoire (faux par
    dfaut)

  - `unique` : boolen indiquant si la valeur de l'attribut doit tre unique
    parmi toutes les entits de ce type (faux par dfaut)

  - `indexed` : boolen indiquant si un index doit tre cr dans la base de
    donnes sur cette attribut (faux par dfaut). C'est utile uniquement si vous
    savez que vous allez faire de nombreuses recherche sur la valeur de cet
    attribut. 

  - `default` : valeur par dfaut de l'attribut. A noter que dans le cas des
    types date, les chaines de caractres correspondant aux mots-cls RQL
    `TODAY` et `NOW` sont utilisables.

  - `vocabulary` : spcifie statiquement les valeurs possibles d'un attribut

* proprits optionnelles des attributs de type `String` : 

  - `fulltextindexed` : boolen indiquant si l'attribut participe  l'index plein
    texte (faux par dfaut) (*valable galement sur le type `Byte`*)

  - `internationalizable` : boolen indiquant si la valeur de cet attribut est
    internationalisable (faux par dfaut) 

  - `maxsize` : entier donnant la taille maximum de la chaine (pas de limite par
    dfaut)  

* proprits optionnelles des relations : 

  - `composite` : chane 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 composs le sont
    galement. 


Contraintes
```````````
Par dfaut les types de contraintes suivant sont disponibles :

* `SizeConstraint` : permet de spcifier une taille minimale et/ou maximale sur
  les chaines de caractres (cas gnrique de `maxsize`)

* `BoundConstraint` : permet de spcifier une valeur minimale et/ou maximale sur
  les types numriques

* `UniqueConstraint` : identique  "unique=True"

* `StaticVocabularyConstraint` : identique  "vocabulary=(...)"

* `RQLConstraint` : permet de spcifier une requte RQL devant tre satisfaite
  par le sujet et/ou l'objet de la relation. Dans cette requte les variables `S`
  et `O` sont prffinies respectivement comme l'entit sujet et objet de la
  relation

* `RQLVocabularyConstraint` : similaire  la prcdente, mais exprimant une
  contrainte "faible", i.e. servant uniquement  limiter les valeurs apparaissant
  dans la liste droulantes du formulaire d'dition, mais n'empchant pas une
  autre entit d'tre slctionne


Dfinition d'un type de relation
--------------------------------

Un type de relation est dfinit par une classe python hritant de `RelationType`. Le
nom de la classe correspond au nom du type. Ensuite le corps de la classe
contient la description des proprits de ce type de relation, ainsi
qu'ventuellement une chaine pour le sujet et une autre pour l'objet permettant
de crer des dfinitions de relations associes (auquel cas il est possibles de
donner sur la classe les proprits de dfinition de relation explicites
ci-dessus), par exemple ::

  class verrouille_par(RelationType):
    """relation sur toutes les entits applicatives indiquant que celles-ci sont vrouilles
    inlined = True
    cardinality = '?*'
    subject = '*'
    object = 'CWUser'

En plus des permissions, les proprits propres aux types de relation (et donc
partags par toutes les dfinitions de relation de ce type) sont :

* `inlined` : boolen contrlant l'optimisation physique consistant  stocker la
  relation dans la table de l'entit sujet au lieu de crer une table spcifique
   la relation. Cela se limite donc aux relations dont la cardinalit
  sujet->relation->objet vaut 0..1 ('?') ou 1..1 ('1')

* `symmetric` : boolen indiquant que la relation est symtrique, i.e. "X relation
   Y" implique "Y relation X"

Dans le cas de dfinitions de relations simultane, `sujet` et `object` peuvent
tout deux valoir la mme chose que dcrite pour le 1er argument de
`SubjectRelation` et `ObjectRelation`.

A partir du moment o une relation n'est ni mise en ligne, ni symtrique, et
ne ncessite pas de permissions particulires, sa dfinition (en utilisant
`SubjectRelation` ou `ObjectRelation`) est suffisante.


Dfinition des permissions
--------------------------

La dfinition des permissions se fait  l'aide de l'attribut `permissions` des
types d'entit ou de relation. Celui-ci est un dictionnaire dont les cls sont
les types d'accs (action), et les valeurs les groupes ou expressions autorises. 

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'accs, un tuple indique le nom des groupes autoriss et/ou
une ou plusieurs expressions RQL devant tre vrifies pour obtenir
l'accs. L'accs est donn  partir du moment o l'utilisateur fait parti d'un
des groupes requis ou ds qu'une expression RQL est vrifie.

Les groupes standards sont :

* `guests`

* `users`

* `managers`

* `owners` : groupe virtuel correspondant au propritaire 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 spcifiques devant tre pour
cela crs dans le precreate de l'application (`migration/precreate.py`).

Utilisation d'expression RQL sur les droits en criture
```````````````````````````````````````````````````````
Il est possible de dfinir 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 utilise correspond  la clause WHERE d'une requte RQL

* dans cette expression, les variables X et U sont des rfrences prdfinies
  respectivement sur l'entit courante (sur laquelle l'action est vrifie) et
  sur l'utilisateur ayant effectu la requte

* il est possible d'utiliser dans cette expression les relations spciales
  "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 entits lies cette
  variable

Pour les expressions RQL sur un type de relation, les principes sont les mmes
avec les diffrences 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 rfrences
  prdfinies respectivement sur le sujet et l'objet de la relation
  courante (sur laquelle l'action est vrifie) et sur l'utilisateur
  ayant effectu la requte

* On peut aussi dfinir des droits sur les attributs d'une entit (relation non
  finale), sachant les points suivants :

  - pour dfinir des expressions rql, il faut utiliser la classe `ERQLExpression`
    dans laquelle X reprsentera l'entit auquel appartient l'attribut

  - les permissions 'add' et 'delete' sont quivalentes. En pratique seul
    'add'/'read' son pris en considration


En plus de cela, le type d'entit `CWPermission` de la librairie standard permet
de construire des modles de scurits trs complexes et dynamiques. Le schma
de ce type d'entit est le suivant : ::


    class CWPermission(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('CWGroup', 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 `CWPermission` de nom
"add_version" peut-tre associe  un projet et donner le droit de crer des
versions sur ce projet  des groupes spcifiques. Il est important de noter les
points suivants :

* dans ce cas il faut protger  la fois le type d'entit "Version" et la
  relation liant une version  un projet ("version_of")

* du fait de la gnricit du type d'entit `CWPermission`, il faut effectuer
  l'unification avec les groupes et / ou les tats le cas chant 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 mmes mais avec les restrictions suivantes :

* on ne peut de `RRQLExpression` sur les types de relation en lecture

* les relations spciales "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 problme pour l'interface utilisateur car si l'expression
utilise l'entit ou la relation  crer, on est pas capable de vrifier les
droits avant d'avoir effectu l'ajout (noter que cela n'est pas un problme cot
serveur rql car la vrification des droits est effectue aprs l'ajout
effectif). Dans ce cas les mthodes de vrification 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 gnral
ncessaire dans tel cas d'utiliser une action refltant les droits du schma
mais permettant de faire la vrification correctement afin qu'elle apparaisse
bien le cas chant.