[entity] introduce a new 'adapters' registry
This changeset introduces the notion in adapters (as in Zope Component Architecture)
in a cubicweb way, eg using a specific registry of appobjects.
This allows nicer code structure, by avoid clutering entity classes and moving
code usually specific to a place of the ui (or something else) together with the
code that use the interface.
We don't use actual interface anymore, they are implied by adapters (which
may be abstract), whose reg id is an interface name.
Appobjects that used to 'implements(IFace)' should now be rewritten by:
* coding an IFaceAdapter(EntityAdapter) defining (implementing if desired)
the interface, usually with __regid__ = 'IFace'
* use "adaptable('IFace')" as selector instead
Also, the implements_adapter_compat decorator eases backward compatibility
with adapter's methods that may still be found on entities implementing
the interface.
Notice that unlike ZCA, we don't support automatic adapters chain (yagni?).
All interfaces defined in cubicweb have been turned into adapters, also
some new ones have been introduced to cleanup Entity / AnyEntity classes
namespace. At the end, the pluggable mixins mecanism should disappear in
favor of adapters as well.
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr## This file is part of CubicWeb.## CubicWeb is free software: you can redistribute it and/or modify it under the# terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## CubicWeb is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with CubicWeb. If not, see <http://www.gnu.org/licenses/>."""core CubicWeb schema, but not necessary at bootstrap time"""__docformat__="restructuredtext en"_=unicodefromyams.buildobjsimport(EntityType,RelationType,SubjectRelation,String,Datetime,Password)fromcubicweb.schemaimport(RQLConstraint,WorkflowableEntityType,ERQLExpression,RRQLExpression,PUB_SYSTEM_ENTITY_PERMS,PUB_SYSTEM_REL_PERMS,PUB_SYSTEM_ATTR_PERMS)classCWUser(WorkflowableEntityType):"""define a CubicWeb user"""__permissions__={'read':('managers','users',ERQLExpression('X identity U')),'add':('managers',),'delete':('managers',),'update':('managers',ERQLExpression('X identity U, NOT U in_group G, G name "guests"'),),}login=String(required=True,unique=True,maxsize=64,description=_('unique identifier used to connect to the application'))upassword=Password(required=True)# password is a reserved word for mysqlfirstname=String(maxsize=64)surname=String(maxsize=64)last_login_time=Datetime(description=_('last connection date'))# allowing an email to be the primary email of multiple entities is necessary for# test at least :-/primary_email=SubjectRelation('EmailAddress',cardinality='??',description=_('email address to use for notification'))use_email=SubjectRelation('EmailAddress',cardinality='*?',composite='subject')in_group=SubjectRelation('CWGroup',cardinality='+*',constraints=[RQLConstraint('NOT O name "owners"')],description=_('groups grant permissions to the user'))classEmailAddress(EntityType):"""an electronic mail address associated to a short alias"""__permissions__={'read':('managers','users','guests',),# XXX if P use_email X, U has_read_permission P'add':('managers','users',),'delete':('managers','owners',ERQLExpression('P use_email X, U has_update_permission P')),'update':('managers','owners',ERQLExpression('P use_email X, U has_update_permission P')),}alias=String(fulltextindexed=True,maxsize=56)address=String(required=True,fulltextindexed=True,indexed=True,unique=True,maxsize=128)prefered_form=SubjectRelation('EmailAddress',cardinality='?*',description=_('when multiple addresses are equivalent \(such as python-projects@logilab.org and python-projects@lists.logilab.org), set this \to indicate which is the preferred form.'))classuse_email(RelationType):""" """__permissions__={'read':('managers','users','guests',),'add':('managers',RRQLExpression('U has_update_permission S'),),'delete':('managers',RRQLExpression('U has_update_permission S'),),}fulltext_container='subject'classprimary_email(RelationType):"""the prefered email"""__permissions__=use_email.__permissions__classprefered_form(RelationType):__permissions__={'read':('managers','users','guests',),# XXX should have update __permissions__ on both subject and object,# though by doing this we will probably have no way to add# this relation in the web ui. The easiest way to acheive this# is probably to be able to have "U has_update_permission O" as# RQLConstraint of the relation definition, though this is not yet# possible'add':('managers',RRQLExpression('U has_update_permission S'),),'delete':('managers',RRQLExpression('U has_update_permission S'),),}classin_group(RelationType):"""core relation indicating a user's groups"""__permissions__=PUB_SYSTEM_REL_PERMSclassowned_by(RelationType):"""core relation indicating owners of an entity. This relation implicitly put the owner into the owners group for the entity """__permissions__={'read':('managers','users','guests'),'add':('managers',RRQLExpression('S owned_by U'),),'delete':('managers',RRQLExpression('S owned_by U'),),}# 0..n cardinality for entities created by internal session (no attached user)# and to support later deletion of a user which has created some entitiescardinality='**'subject='*'object='CWUser'classcreated_by(RelationType):"""core relation indicating the original creator of an entity"""__permissions__={'read':('managers','users','guests'),'add':('managers',),'delete':('managers',),}# 0..1 cardinality for entities created by internal session (no attached user)# and to support later deletion of a user which has created some entitiescardinality='?*'subject='*'object='CWUser'classcreation_date(RelationType):"""creation time of an entity"""__permissions__=PUB_SYSTEM_ATTR_PERMScardinality='11'subject='*'object='Datetime'classmodification_date(RelationType):"""latest modification time of an entity"""__permissions__=PUB_SYSTEM_ATTR_PERMScardinality='11'subject='*'object='Datetime'classcwuri(RelationType):"""internal entity uri"""__permissions__=PUB_SYSTEM_ATTR_PERMScardinality='11'subject='*'object='String'# XXX find a better relation nameclassfor_user(RelationType):"""link a property to the user which want this property customization. Unless you're a site manager, this relation will be handled automatically. """__permissions__={'read':('managers','users','guests'),'add':('managers',),'delete':('managers',),}inlined=Truesubject='CWProperty'object='CWUser'composite='object'cardinality='?*'classCWPermission(EntityType):"""entity type that may be used to construct some advanced security configuration """__permissions__=PUB_SYSTEM_ENTITY_PERMSname=String(required=True,indexed=True,internationalizable=True,maxsize=100,description=_('name or identifier of the permission'))label=String(required=True,internationalizable=True,maxsize=100,description=_('distinct label to distinguate between other permission entity of the same name'))require_group=SubjectRelation('CWGroup',description=_('groups to which the permission is granted'))# explicitly add X require_permission CWPermission for each entity that should have# configurable securityclassrequire_permission(RelationType):"""link a permission to the entity. This permission should be used in the security definition of the entity's type to be useful. """__permissions__=PUB_SYSTEM_REL_PERMSclassrequire_group(RelationType):"""used to grant a permission to a group"""__permissions__=PUB_SYSTEM_REL_PERMSclassExternalUri(EntityType):"""a URI representing an object in external data store"""uri=String(required=True,unique=True,maxsize=256,description=_('the URI of the object'))classsame_as(RelationType):"""generic relation to specify that an external entity represent the same object as a local one: http://www.w3.org/TR/owl-ref/#sameAs-def """#NOTE: You'll have to explicitly declare which entity types can have a#same_as relation__permissions__={'read':('managers','users','guests',),'add':('managers','users'),'delete':('managers','owners'),}cardinality='*1'symmetric=True# NOTE: the 'object = ExternalUri' declaration will still be mandatory# in the cube's schema.object='ExternalUri'classCWCache(EntityType):"""a simple cache entity characterized by a name and a validity date. The target application is responsible for updating timestamp when necessary to invalidate the cache (typically in hooks). Also, checkout the AppObject.get_cache() method. """# XXX only handle by hooks, shouldn't be readable/editable at all through# the ui and so no permissions should be granted, no?__permissions__={'read':('managers','users','guests'),'add':('managers',),'update':('managers','users',),# XXX'delete':('managers',),}name=String(required=True,unique=True,indexed=True,maxsize=128,description=_('name of the cache'))timestamp=Datetime(default='NOW')# "abtract" relation types, not used in cubicweb itselfclassidentical_to(RelationType):"""identical to"""symmetric=True__permissions__={'read':('managers','users','guests',),# XXX should have update __permissions__ on both subject and object,# though by doing this we will probably have no way to add# this relation in the web ui. The easiest way to acheive this# is probably to be able to have "U has_update_permission O" as# RQLConstraint of the relation definition, though this is not yet# possible'add':('managers',RRQLExpression('U has_update_permission S'),),'delete':('managers',RRQLExpression('U has_update_permission S'),),}classsee_also(RelationType):"""generic relation to link one entity to another"""symmetric=True__permissions__={'read':('managers','users','guests',),'add':('managers',RRQLExpression('U has_update_permission S'),),'delete':('managers',RRQLExpression('U has_update_permission S'),),}