diff -r 49075f57cf2c -r aa09e20dd8c0 doc/book/en/B0012-schema-definition.en.txt --- a/doc/book/en/B0012-schema-definition.en.txt Tue May 05 17:18:49 2009 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,430 +0,0 @@ -.. -*- coding: utf-8 -*- - -Entity type definition ----------------------- - -An entity type is defined by a Python class which inherits from `EntityType`. -The class definition contains the description of attributes and relations -for the defined entity type. -The class name corresponds to the entity type name. It is exepected to be -defined in the module ``mycube.schema``. - - -For example :: - - class Person(EntityType): - """A person with the properties and the relations necessary for my - application""" - - last_name = String(required=True, fulltextindexed=True) - first_name = String(required=True, fulltextindexed=True) - title = String(vocabulary=('Mr', 'Mrs', 'Miss')) - date_of_birth = Date() - works_for = SubjectRelation('Company', cardinality='?*') - - -The entity described above defines three attributes of type String, -last_name, first_name and title, an attribute of type Date for the date of -birth and a relation that connects a `Person` to another entity of type -`Company` through the semantic `works_for` (:ref:`relations`). - -The name of the Python attribute corresponds to the name of the attribute -or the relation in `CubicWeb` application. - -Built-in types for attributes -````````````````````````````` - -All `CubicWeb` built-in types are available : `String`, `Int`, `Float`, -`Decimal`, `Boolean`, `Date`, `Datetime`, `Time`, `Interval`, `Byte` -and `Password`. -They are implicitely imported (as well as the special the function "_" -for translation :ref:`internationalisation`). - -An attribute is defined in the schema as follows:: - - attr_name = attr_type(properties*) - -where `attr_type` is one of the type listed above and `properties` is -a list of properties the attribute will comply to (see :ref:`properties` -for more details). - - -Meta-data -````````` - -Each entity type has at least the following meta-relations : - - - `eid` (`Int`): provides the unique numeric identifier of an entity - - - `creation_date` (`Datetime`): date on which the entity has been created - - - `modification_date` (`Datetime`: date on which the entity has been last modified - - - `created_by` (`EUser`): which user created the entity - - - `owned_by` (`EUser`): to whom the entity belongs; by default the - creator but not necessary, and it could have multiple owners - - - `is` (`EEType`): of which type the entity is - -.. _relations: - -Relation definition -``````````````````` - -There are two types of relation you can use to define an entity type: -`ObjectRelation` or `SubjectRelation`. -The first argument of `SubjectRelation` or `ObjectRelation` gives respectively -the object/subject entity type of the relation. This could be : - - * a string corresponding to an entity type - - * a tuple of string corresponding to multiple entity types - - * special string such as follows : - - - "**" : all types of entities - - "*" : all types of non-meta entities - - "@" : all types of meta entities but not system entities (e.g. used for - the basic schema description) - -.. it is possible to use the attribute `meta` to flag an entity type as a `meta` - (e.g. used to describe/categorize other entities) - -.. _properties: - -Optionnal properties -```````````````````` - -Follows the list of properties that are available for defining -attribute and relation of a new entity type. - -* Optional properties for attributes and relations : - - - `description` : a string describing an attribute or a relation. By default - this string will be used in the editing form of the entity, which means - that it is supposed to help the end-user and should be flagged by the - function `_` to be properly internationalized. - - - `constraints` : a list of conditions/constraints that the relation has to - satisfy (c.f. `Contraints`_) - - - `cardinality` : a two character string which specify the cardinality of the - relation. The first character defines the cardinality of the relation on - the subject, and the second on the object. When a relation can have - multiple subjects or objects, the cardinality applies to all, - not on a one-to-one basis (so it must be consistent...). The possible - values are inspired from regular expression syntax : - - * `1`: 1..1 - * `?`: 0..1 - * `+`: 1..n - * `*`: 0..n - - - `meta` : boolean indicating that the relation is a meta-relation (false by - default) - -* Optional properties for attributes : - - - `required` : boolean indicating if the attribute is required (false by default) - - - `unique` : boolean indicating if the value of the attribute has to be unique - or not within all entities of the same type (false by default) - - - `indexed` : boolean indicating if an index needs to be created for this - attribute in the database (false by default). This is useful only if - you know that you will have to run numerous searches on the value of this - attribute. - - - `default` : default value of the attribute. In case of date types, the values - which could be used correspond to the RQL keywords `TODAY` and `NOW`. - - - `vocabulary` : specify static possible values of an attribute - -* Optional properties of type `String` : - - - `fulltextindexed` : boolean indicating if the attribute is part of - the full text index (false by default) (*applicable on the type `Byte` - as well*) - - - `internationalizable` : boolean indicating if the value of the attribute - is internationalizable (false by default) - - - `maxsize` : integer providing the maximum size of the string (no limit by default) - -* Optional properties for relations : - - - `composite` : string indicating that the subject (composite == 'subject') - is composed of the objects of the relations. For the opposite case (when - the object is composed of the subjects of the relation), we just set - 'object' as value. The composition implies that when the relation - is deleted (so when the composite is deleted), the composed are also deleted. - -Constraints -``````````` -By default, the available constraint types are : - -* `SizeConstraint` : allows to specify a minimum and/or maximum size on - string (generic case of `maxsize`) - -* `BoundConstraint` : allows to specify a minimum and/or maximum value on - numeric types - -* `UniqueConstraint` : identical to "unique=True" - -* `StaticVocabularyConstraint` : identical to "vocabulary=(...)" - -* `RQLConstraint` : allows to specify a RQL query that has to be satisfied - by the subject and/or the object of the relation. In this query the variables - `S` and `O` are reserved for the entities subject and object of the - relation. - -* `RQLVocabularyConstraint` : similar to the previous type of constraint except - that it does not express a "strong" constraint, which means it is only used to - restrict the values listed in the drop-down menu of editing form, but it does - not prevent another entity to be selected. - - -Definition of relations ------------------------ - -XXX add note about defining relation type / definition - -A relation is defined by a Python class heriting `RelationType`. The name -of the class corresponds to the name of the type. The class then contains -a description of the properties of this type of relation, and could as well -contain a string for the subject and a string for the object. This allows to create -new definition of associated relations, (so that the class can have the -definition properties from the relation) for example :: - - class locked_by(RelationType): - """relation on all entities indicating that they are locked""" - inlined = True - cardinality = '?*' - subject = '*' - object = 'EUser' - -In addition to the permissions, the properties of the relation types -(shared also by all definition of relation of this type) are : - - -* `inlined` : boolean handling the physical optimization for archiving - the relation in the subject entity table, instead of creating a specific - table for the relation. This applies to the relation when the cardinality - of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) - -* `symmetric` : boolean indicating that the relation is symmetrical, which - means `X relation Y` implies `Y relation X` - -In the case of simultaneous relations definitions, `subject` and `object` -can both be equal to the value of the first argument of `SubjectRelation` -and `ObjectRelation`. - -When a relation is not inlined and not symmetrical, and it does not require -specific permissions, its definition (by using `SubjectRelation` and -`ObjectRelation`) is all we need. - -.. _security: - -The security model ------------------- - -The security model of `cubicWeb` is based on `Access Control List`. -The main principles are: - -* users and groups of users -* a user belongs to at least one group of user -* permissions (read, update, create, delete) -* permissions are assigned to groups (and not to users) - -For `CubicWeb` in particular: - -* we associate rights at the enttities/relations schema level -* for each entity, we distinguish four kind of permissions: read, - add, update and delete -* for each relation, we distinguish three king of permissions: read, - add and delete (we can not modify a relation) -* the basic groups are: Administrators, Users and Guests -* by default, users belongs to the group Users -* there is a virtual group called `Owners users` to which we - can associate only deletion and update permissions -* we can not add users to the `Owners users` group, they are - implicetely added to it according to the context of the objects - they own -* the permissions of this group are only be checked on update/deletion - actions if all the other groups the user belongs does not provide - those permissions - - -Permissions definition -`````````````````````` - -Setting permissions is done with the attribute `permissions` of entities and -relation types. It defines a dictionary where the keys are the access types -(action), and the values are the authorized groups or expressions. - -For an entity type, the possible actions are `read`, `add`, `update` and -`delete`. - -For a relation type, the possible actions are `read`, `add`, and `delete`. - -For each access type, a tuple indicates the name of the authorized groups and/or -one or multiple RQL expressions to satisfy to grant access. The access is -provided once the user is in the listed groups or one of the RQL condition is -satisfied. - -The standard groups are : - -* `guests` - -* `users` - -* `managers` - -* `owners` : virtual group corresponding to the entity's owner. - This can only be used for the actions `update` and `delete` of an entity - type. - -It is also possible to use specific groups if they are defined in the precreate -of the cube (``migration/precreate.py``). - - -Use of RQL expression for writing rights -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -It is possible to define RQL expression to provide update permission -(`add`, `delete` and `update`) on relation and entity types. - -RQL expression for entity type permission : - -* you have to use the class `ERQLExpression` - -* the used expression corresponds to the WHERE statement of an RQL query - -* in this expression, the variables X and U are pre-defined references - respectively on the current entity (on which the action is verified) and - on the user who send the request - -* it is possible to use, in this expression, a special relation - "has__permission" where the subject is the user and the - object is a any variable, meaning that the user needs to have - permission to execute the action on the entities related - to this variable - -For RQL expressions on a relation type, the principles are the same except -for the following : - -* you have to use the class `RQLExpression` in the case of a non-final relation - -* in the expression, the variables S, O and U are pre-defined references - to respectively the subject and the object of the current relation (on - which the action is being verified) and the user who executed the query - -* we can also defined rights on attributes of an entity (non-final relation), - knowing that : - - - to defines RQL expression, we have to use the class `ERQLExpression` - in which X represents the entity the attribute belongs to - - - the permissions `add` and `delete` are equivalent. Only `add`/`read` - are actually taken in consideration. - -In addition to that the entity type `EPermission` from the standard library -allow to build very complex and dynamic security architecture. The schema of -this entity type is as follow : :: - - 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.")) - - -Example of configuration :: - - - ... - - 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 - -This configuration indicates that an entity `EPermission` named -"add_version" can be associated to a project and provides rights to create -new versions on this project to specific groups. It is important to notice that : - -* in such case, we have to protect both the entity type "Version" and the relation - associating a version to a project ("version_of") - -* because of the genricity of the entity type `EPermission`, we have to execute - a unification with the groups and/or the states if necessary in the expression - ("U in_group G, P require_group G" in the above example) - -Use of RQL expression for reading rights -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The principles are the same but with the following restrictions : - -* we can not use `RRQLExpression` on relation types for reading - -* special relations "has__permission" can not be used - - -Note on the use of RQL expression for `add` permission -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Potentially, the use of an RQL expression to add an entity or a relation -can cause problems for the user interface, because if the expression uses -the entity or the relation to create, then we are not able to verify the -permissions before we actually add the entity (please note that this is -not a problem for the RQL server at all, because the permissions checks are -done after the creation). In such case, the permission check methods -(check_perm, has_perm) can indicate that the user is not allowed to create -this entity but can obtain the permission. -To compensate this problem, it is usually necessary, for such case, -to use an action that reflects the schema permissions but which enables -to check properly the permissions so that it would show up if necessary. - - -Updating your application with your new schema -`````````````````````````````````````````````` - -If you modified your schema, the update is not automatic; indeed, this is -in general not a good idea. -Instead, you call a shell on your application, which is a -an interactive python shell, with an appropriate -cubicweb environment :: - - cubicweb-ctl shell myinstance - -and type :: - - add_entity_type('Person') - -And restart your application!