doc/book/en/B0012-schema-definition.en.txt
changeset 292 2d9e83c34b23
parent 229 767ff7f5d5a7
child 301 e47150482ac1
equal deleted inserted replaced
291:87c8d96f6173 292:2d9e83c34b23
       
     1 .. -*- coding: utf-8 -*-
       
     2 
       
     3 Entity type definition
       
     4 ----------------------
       
     5 
       
     6 An entity type is defined by a Python class which inherits `EntityType`. The
       
     7 class name correponds to the type name. Then the content of the class contains
       
     8 the description of attributes and relations for the defined entity type,
       
     9 for example ::
       
    10 
       
    11   class Personne(EntityType):
       
    12     """A person with the properties and the relations necessarry for my
       
    13     application"""
       
    14 
       
    15     last_name = String(required=True, fulltextindexed=True)
       
    16     first_name = String(required=True, fulltextindexed=True)
       
    17     title = String(vocabulary=('M', 'Mme', 'Mlle'))
       
    18     date_of_birth = Date()
       
    19     works_for = SubjectRelation('Company', cardinality='?*')
       
    20 
       
    21 * the name of the Python attribute corresponds to the name of the attribute
       
    22   or the relation in `CubicWeb` application.
       
    23 
       
    24 * all built-in types are available : `String`, `Int`, `Float`,
       
    25   `Boolean`, `Date`, `Datetime`, `Time`, `Byte`.
       
    26 
       
    27 * each entity type has at least the following meta-relations :
       
    28 
       
    29   - `eid` (`Int`)
       
    30   
       
    31   - `creation_date` (`Datetime`)
       
    32   
       
    33   - `modification_date` (`Datetime`)
       
    34   
       
    35   - `created_by` (`EUser`) (which user created the entity)
       
    36   
       
    37   - `owned_by` (`EUser`) (who does the entity belongs to, by default the 
       
    38      creator but not necessarry and it could have multiple owners)
       
    39      
       
    40   - `is` (`EEType`)
       
    41 
       
    42   
       
    43 * it is also possible to define relations of type object by using `ObjectRelation`
       
    44   instead of `SubjectRelation`
       
    45 
       
    46 * the first argument of `SubjectRelation` and `ObjectRelation` gives respectively
       
    47   the object/subject entity type of the relation. This could be :  
       
    48 
       
    49   * a string corresponding to an entity type
       
    50 
       
    51   * a tuple of string correponding to multiple entities types
       
    52 
       
    53   * special string such as follows :
       
    54 
       
    55     - "**" : all types of entities
       
    56     - "*" : all types of non-meta entities 
       
    57     - "@" : all types of meta entities but not system entities (e.g. used for
       
    58       the basic schema description)
       
    59 
       
    60 * it is possible to use the attribute `meta` to flag an entity type as a `meta`
       
    61   (e.g. used to describe/categorize other entities)
       
    62 
       
    63 * optional properties for attributes and relations : 
       
    64 
       
    65   - `description` : string describing an attribute or a relation. By default
       
    66     this string will be used in the editing form of the entity, which means
       
    67     that it is supposed to help the end-user and should be flagged by the
       
    68     function `_` to be properly internationalized.
       
    69 
       
    70   - `constraints` : list of conditions/constraints that the relation needs to
       
    71     satisfy (c.f. `Contraints`_)
       
    72 
       
    73   - `cardinality` : two characters string which specify the cardinality of the
       
    74     relation. The first character defines the cardinality of the relation on
       
    75     the subject, the second on the object of the relation. When a relation
       
    76     has multiple possible subjects or objects, the cardinality applies to all
       
    77     and not on a one to one basis (so it must be consistent...). The possible
       
    78     values are inspired from regular expressions syntax :
       
    79 
       
    80     * `1`: 1..1
       
    81     * `?`: 0..1
       
    82     * `+`: 1..n
       
    83     * `*`: 0..n
       
    84 
       
    85   - `meta` : boolean indicating that the relation is a meta-relation (false by
       
    86     default)
       
    87 
       
    88 * optionnal properties for attributes : 
       
    89 
       
    90   - `required` : boolean indicating if the attribute is required (false by default)
       
    91 
       
    92   - `unique` : boolean indicating if the value of the attribute has to be unique
       
    93     or not within all entities of the same type (false by default)
       
    94 
       
    95   - `indexed` : boolean indicating if an index needs to be created for this 
       
    96     attribute in the database (false by default). This is usefull only if
       
    97     you know that you will have to run numerous searches on the value of this
       
    98     attribute.
       
    99 
       
   100   - `default` : default value of the attribute. In case of date types, the values
       
   101     which could be used correpond to the RQL keywords `TODAY` and `NOW`.
       
   102   
       
   103   - `vocabulary` : specify static possible values of an attribute
       
   104 
       
   105 * optionnal properties of type `String` : 
       
   106 
       
   107   - `fulltextindexed` : boolean indicating if the attribute is part of
       
   108     the full text index (false by default) (*applicable on the type `Byte`
       
   109     as well*)
       
   110 
       
   111   - `internationalizable` : boolean indicating if the value of the attribute
       
   112     is internationalizable (false by default)
       
   113 
       
   114   - `maxsize` : integer providing the maximum size of the string (no limit by default)
       
   115 
       
   116 * optionnal properties for relations : 
       
   117 
       
   118   - `composite` : string indicating that the subject (composite == 'subject')
       
   119     is composed of the objects of the relations. For the opposite case (when
       
   120     the object is composed of the subjects of the relation), we just need
       
   121     to set 'object' as the value. The composition implies that when the relation
       
   122     is deleted (so when the composite is deleted), the composed are also deleted.
       
   123 
       
   124 Contraints
       
   125 ``````````
       
   126 By default, the available constraints types are :
       
   127 
       
   128 * `SizeConstraint` : allows to specify a minimum and/or maximum size on
       
   129   string (generic case of `maxsize`)
       
   130 
       
   131 * `BoundConstraint` : allows to specify a minimum and/or maximum value on 
       
   132   numeric types
       
   133 
       
   134 * `UniqueConstraint` : identical to "unique=True"
       
   135 
       
   136 * `StaticVocabularyConstraint` : identical to "vocabulary=(...)"
       
   137 
       
   138 * `RQLConstraint` : allows to specify a RQL query that needs to be satisfied
       
   139   by the subject and/or the object of the relation. In this query the variables
       
   140   `S` and `O` are reserved for the entities subject and object of the 
       
   141   relation.
       
   142 
       
   143 * `RQLVocabularyConstraint` : similar to the previous type of constraint except
       
   144   that it does not express a "strong" constraint, which means it is only used to
       
   145   restrict the values listed in the drop-down menu of editing form, but it does
       
   146   not prevent another entity to be selected
       
   147 
       
   148 
       
   149 Relation definition
       
   150 -------------------
       
   151 
       
   152 XXX add note about defining relation type / definition
       
   153 
       
   154 A relation is defined by a Python class heriting `RelationType`. The name
       
   155 of the class corresponds to the name of the type. The class then contains
       
   156 a description of the properties of this type of relation, and could as well 
       
   157 contains a string for the subject and a string for the object. This allows to create
       
   158 new definition of associated relations, (so that the class can have the 
       
   159 definition properties from the relation) for example ::
       
   160 
       
   161   class locked_by(RelationType):
       
   162     """relation on all entities indicating that they are locked"""
       
   163     inlined = True
       
   164     cardinality = '?*'
       
   165     subject = '*'
       
   166     object = 'EUser'
       
   167 
       
   168 In addition to the permissions, the properties of the relation types
       
   169 (shared also by all definition of relation of this type) are :
       
   170 
       
   171 
       
   172 * `inlined` : boolean handling the physical optimization for archiving
       
   173   the relation in the subject entity table, instead of creating a specific
       
   174   table for the relation. This applies to the relation when the cardinality
       
   175   of subject->relation->object is 0..1 (`?`) or 1..1 (`1`)
       
   176 
       
   177 * `symetric` : boolean indication that the relation is symetrical, which
       
   178   means `X relation Y` implies `Y relation X`
       
   179 
       
   180 In the case of simultaneous relations definitions, `subject` and `object`
       
   181 can both be equal to the value of the first argument of `SubjectRelation`
       
   182 and `ObjectRelation`.
       
   183 
       
   184 When a relation is not inlined and not symetrical, and it does not require
       
   185 specific permissions, its definition (by using `SubjectRelation` and
       
   186 `ObjectRelation`) is all we need.
       
   187 
       
   188 
       
   189 The security model
       
   190 ------------------
       
   191 
       
   192 The security model of `cubicWeb` is based on `Access Control List`. 
       
   193 The main principles are:
       
   194 
       
   195 * users and groups of users
       
   196 * a user belongs to at least one group of user
       
   197 * permissions (read, update, create, delete)
       
   198 * permissions are assigned to groups (and not to users)
       
   199 
       
   200 For `CubicWeb` in particular:
       
   201 
       
   202 * we associate rights at the enttities/relations schema level
       
   203 * for each entity, we distinguish four kind of permissions: read,
       
   204   add, update and delete
       
   205 * for each relation, we distinguish three king of permissions: read,
       
   206   add and delete (we can not modify a relation)
       
   207 * the basic groups are: Administrators, Users and Guests
       
   208 * by default, users belongs to the group Users
       
   209 * there is a virtual group called `Owners users` to which we
       
   210   can associate only deletion and update permissions
       
   211 * we can not add users to the `Owners users` group, they are
       
   212   implicetely added to it according to the context of the objects
       
   213   they own
       
   214 * the permissions of this group are only be checked on update/deletion
       
   215   actions if all the other groups the user belongs does not provide
       
   216   those permissions
       
   217 
       
   218   
       
   219 Permissions definition
       
   220 ``````````````````````
       
   221 
       
   222 Define permissions is set through to the attribute `permissions` of entities and
       
   223 relations types. It defines a dictionnary where the keys are the access types
       
   224 (action), and the values are the authorized groups or expressions.
       
   225 
       
   226 For an entity type, the possible actions are `read`, `add`, `update` and
       
   227 `delete`.
       
   228 
       
   229 For a relation type, the possible actions are `read`, `add`, and `delete`.
       
   230 
       
   231 For each access type, a tuple indicates the name of the authorized groups and/or
       
   232 one or multiple RQL expressions to satisfy to grant access. The access is
       
   233 provided once the user is in the listed groups or one of the RQL condition is
       
   234 satisfied.
       
   235 
       
   236 The standard groups are :
       
   237 
       
   238 * `guests`
       
   239 
       
   240 * `users`
       
   241 
       
   242 * `managers`
       
   243 
       
   244 * `owners` : virtual group corresponding to the entity's owner.
       
   245   This can only be used for the actions `update` and `delete` of an entity
       
   246   type.
       
   247 
       
   248 It is also possible to use specific groups if they are defined in the precreate 
       
   249 of the cube (``migration/precreate.py``).
       
   250 
       
   251 
       
   252 Use of RQL expression for writing rights
       
   253 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   254 It is possible to define RQL expression to provide update permission 
       
   255 (`add`, `delete` and `update`) on relation and entity types.
       
   256 
       
   257 RQL expression for entity type permission :
       
   258 
       
   259 * you have to use the class `ERQLExpression`
       
   260 
       
   261 * the used expression corresponds to the WHERE statement of an RQL query
       
   262 
       
   263 * in this expression, the variables X and U are pre-defined references
       
   264   respectively on the current entity (on which the action is verified) and
       
   265   on the user who send the request
       
   266 
       
   267 * it is possible to use, in this expression, a special relation 
       
   268   "has_<ACTION>_permission" where the subject is the user and the 
       
   269   object is a any variable, meaning that the user needs to have
       
   270   permission to execute the action <ACTION> on the entities related
       
   271   to this variable 
       
   272 
       
   273 For RQL expressions on a relation type, the principles are the same except 
       
   274 for the following :
       
   275 
       
   276 * you have to use the class `RQLExpression` in the case of a non-final relation
       
   277 
       
   278 * in the expression, the variables S, O and U are pre-defined references
       
   279   to respectively the subject and the object of the current relation (on
       
   280   which the action is being verified) and the user who executed the query
       
   281 
       
   282 * we can also defined rights on attributes of an entity (non-final relation),
       
   283   knowing that : 
       
   284 
       
   285   - to defines RQL expression, we have to use the class `ERQLExpression`
       
   286     in which X represents the entity the attribute belongs to
       
   287 
       
   288   - the permissions `add` and `delete` are equivalent. Only `add`/`read`
       
   289     are actually taken in consideration.
       
   290 
       
   291 In addition to that the entity type `EPermission` from the standard library
       
   292 allow to build very complex and dynamic security architecture. The schema of
       
   293 this entity type is as follow : ::
       
   294 
       
   295     class EPermission(MetaEntityType):
       
   296 	"""entity type that may be used to construct some advanced security configuration
       
   297 	"""
       
   298 	name = String(required=True, indexed=True, internationalizable=True, maxsize=100)
       
   299 	require_group = SubjectRelation('EGroup', cardinality='+*',
       
   300 					description=_('groups to which the permission is granted'))
       
   301 	require_state = SubjectRelation('State',
       
   302 				    description=_("entity'state in which the permission is applyable"))
       
   303 	# can be used on any entity
       
   304 	require_permission = ObjectRelation('**', cardinality='*1', composite='subject',
       
   305 					    description=_("link a permission to the entity. This "
       
   306 							  "permission should be used in the security "
       
   307 							  "definition of the entity's type to be useful."))
       
   308 
       
   309 
       
   310 Example of configuration ::
       
   311 
       
   312 
       
   313     ...
       
   314 
       
   315     class Version(EntityType):
       
   316 	"""a version is defining the content of a particular project's release"""
       
   317 
       
   318 	permissions = {'read':   ('managers', 'users', 'guests',),
       
   319 		       'update': ('managers', 'logilab', 'owners',),
       
   320 		       'delete': ('managers', ),
       
   321 		       'add':    ('managers', 'logilab',
       
   322 				  ERQLExpression('X version_of PROJ, U in_group G,'
       
   323 						 'PROJ require_permission P, P name "add_version",'
       
   324 						 'P require_group G'),)}
       
   325 
       
   326     ...
       
   327 
       
   328     class version_of(RelationType):
       
   329 	"""link a version to its project. A version is necessarily linked to one and only one project.
       
   330 	"""
       
   331 	permissions = {'read':   ('managers', 'users', 'guests',),
       
   332 		       'delete': ('managers', ),
       
   333 		       'add':    ('managers', 'logilab',
       
   334 				  RRQLExpression('O require_permission P, P name "add_version",'
       
   335 						 'U in_group G, P require_group G'),)
       
   336 		       }
       
   337 	inlined = True
       
   338 
       
   339 This configuration indicates that an entity `EPermission` named
       
   340 "add_version" can be associated to a project and provides rights to create
       
   341 new versions on this project to specific groups. It is important to notice that :
       
   342 
       
   343 * in such case, we have to protect both the entity type "Version" and the relation
       
   344   associating a version to a project ("version_of")
       
   345 
       
   346 * because of the genricity of the entity type `EPermission`, we have to execute
       
   347   a unification with the groups and/or the states if necessary in the expression
       
   348   ("U in_group G, P require_group G" in the above example)
       
   349 
       
   350 Use of RQL expression for reading rights
       
   351 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   352 
       
   353 The principles are the same but with the following restrictions :
       
   354 
       
   355 * we can not use `RRQLExpression` on relation types for reading
       
   356 
       
   357 * special relations "has_<ACTION>_permission" can not be used
       
   358 
       
   359 
       
   360 Note on the use of RQL expression for `add` permission
       
   361 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   362 Potentially, the use of an RQL expression to add an entity or a relation
       
   363 can cause problems for the user interface, because if the expression uses
       
   364 the entity or the relation to create, then we are not able to verify the 
       
   365 permissions before we actually add the entity (please note that this is
       
   366 not a problem for the RQL server at all, because the permissions checks are
       
   367 done after the creation). In such case, the permission check methods 
       
   368 (check_perm, has_perm) can indicate that the user is not allowed to create 
       
   369 this entity but can obtain the permission. 
       
   370 To compensate this problem, it is usually necessary, for such case,
       
   371 to use an action that reflects the schema permissions but which enables
       
   372 to check properly the permissions so that it would show up if necessary.
       
   373 
       
   374 
       
   375 Updating your application with your new schema
       
   376 ``````````````````````````````````````````````
       
   377 
       
   378 You have to get a shell on your application ::
       
   379 
       
   380    cubicweb-ctl shell moninstance
       
   381 
       
   382 and type ::
       
   383 
       
   384    add_entity_type('Personne')
       
   385 
       
   386 And restart your application!