cubicweb/schemas/base.py
changeset 11057 0b59724cb3f2
parent 11033 63d860a14a17
child 11681 b23d58050076
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cubicweb/schemas/base.py	Sat Jan 16 13:48:51 2016 +0100
@@ -0,0 +1,383 @@
+# copyright 2003-2012 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"
+from cubicweb import _
+
+from yams.buildobjs import (EntityType, RelationType, RelationDefinition,
+                            SubjectRelation,
+                            String, TZDatetime, Datetime, Password, Interval,
+                            Boolean, UniqueConstraint)
+from cubicweb.schema import (
+    RQLConstraint, WorkflowableEntityType, ERQLExpression, RRQLExpression,
+    PUB_SYSTEM_ENTITY_PERMS, PUB_SYSTEM_REL_PERMS, PUB_SYSTEM_ATTR_PERMS,
+    RO_ATTR_PERMS)
+
+class CWUser(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 mysql
+    firstname = String(maxsize=64)
+    surname   = String(maxsize=64)
+    last_login_time = TZDatetime(description=_('last connection date'))
+    in_group = SubjectRelation('CWGroup', cardinality='+*',
+                               constraints=[RQLConstraint('NOT O name "owners"')],
+                               description=_('groups grant permissions to the user'))
+
+
+class EmailAddress(EntityType):
+    """an electronic mail address associated to a short alias"""
+    __permissions__ = {
+        # application that wishes public email, or use it for something else
+        # than users (eg Company, Person), should explicitly change permissions
+        'read':   ('managers', ERQLExpression('U use_email X')),
+        '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.'))
+
+class use_email(RelationType):
+    fulltext_container = 'subject'
+
+
+class use_email_relation(RelationDefinition):
+    """user's email account"""
+    name = "use_email"
+    __permissions__ = {
+        'read':   ('managers', 'users', 'guests',),
+        'add':    ('managers', RRQLExpression('U has_update_permission S'),),
+        'delete': ('managers', RRQLExpression('U has_update_permission S'),),
+        }
+    subject = "CWUser"
+    object = "EmailAddress"
+    cardinality = '*?'
+    composite = 'subject'
+
+
+class primary_email(RelationDefinition):
+    """the prefered email"""
+    __permissions__ = {
+        'read':   ('managers', 'users', 'guests',),
+        'add':    ('managers', RRQLExpression('U has_update_permission S'),),
+        'delete': ('managers', RRQLExpression('U has_update_permission S'),),
+        }
+    subject = "CWUser"
+    object = "EmailAddress"
+    cardinality = '??'
+    constraints= [RQLConstraint('S use_email O')]
+
+
+class prefered_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'),),
+        }
+
+class in_group(RelationType):
+    """core relation indicating a user's groups"""
+    __permissions__ = PUB_SYSTEM_REL_PERMS
+
+class owned_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 entities
+    cardinality = '**'
+    subject = '*'
+    object = 'CWUser'
+
+class created_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 entities
+    cardinality = '?*'
+    subject = '*'
+    object = 'CWUser'
+
+
+class creation_date(RelationType):
+    """creation time of an entity"""
+    __permissions__ = PUB_SYSTEM_ATTR_PERMS
+    cardinality = '11'
+    subject = '*'
+    object = 'TZDatetime'
+
+
+class modification_date(RelationType):
+    """latest modification time of an entity"""
+    __permissions__ = PUB_SYSTEM_ATTR_PERMS
+    cardinality = '11'
+    subject = '*'
+    object = 'TZDatetime'
+
+
+class cwuri(RelationType):
+    """internal entity uri"""
+    __permissions__ = RO_ATTR_PERMS
+    cardinality = '11'
+    subject = '*'
+    object = 'String'
+
+
+# XXX find a better relation name
+class for_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 = True
+    subject = 'CWProperty'
+    object = 'CWUser'
+    composite = 'object'
+    cardinality = '?*'
+
+
+class ExternalUri(EntityType):
+    """a URI representing an object in external data store"""
+    uri = String(required=True, unique=True, maxsize=256,
+                 description=_('the URI of the object'))
+
+
+class same_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 = '**'
+    symmetric = True
+    # NOTE: the 'object = ExternalUri' declaration will still be mandatory
+    #       in the cube's schema.
+    object = 'ExternalUri'
+
+
+class CWCache(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, maxsize=128,
+                  description=_('name of the cache'))
+    timestamp = TZDatetime(default='NOW')
+
+
+class CWSource(EntityType):
+    __permissions__ = {
+        'read':   ('managers', 'users', 'guests'),
+        'add':    ('managers',),
+        'update': ('managers',),
+        'delete': ('managers',),
+        }
+    name = String(required=True, unique=True, maxsize=128,
+                  description=_('name of the source'))
+    type = String(required=True, maxsize=20, description=_('type of the source'))
+    config = String(description=_('source\'s configuration. One key=value per '
+                                  'line, authorized keys depending on the '
+                                  'source\'s type'),
+                    __permissions__={
+                        'read':   ('managers',),
+                        'add':    ('managers',),
+                        'update': ('managers',),
+                        })
+    # put this here and not in a subclass even if it's only for some sources
+    # since having subclasses on generic relation (cw_source) double the number
+    # of rdef in the schema, and make ms planning harder since queries solutions
+    # may changes when sources are specified
+    url = String(description=_('URLs from which content will be imported. You can put one url per line'))
+    parser = String(description=_('parser to use to extract entities from content retrieved at given URLs.'))
+    latest_retrieval = TZDatetime(description=_('latest synchronization time'))
+    in_synchronization = TZDatetime(description=_('start timestamp of the currently in synchronization, or NULL when no synchronization in progress.'))
+
+
+ENTITY_MANAGERS_PERMISSIONS = {
+    'read':   ('managers',),
+    'add':    ('managers',),
+    'update': ('managers',),
+    'delete': ('managers',),
+    }
+RELATION_MANAGERS_PERMISSIONS = {
+    'read':   ('managers',),
+    'add':    ('managers',),
+    'delete': ('managers',),
+    }
+
+
+class CWSourceHostConfig(EntityType):
+    __permissions__ = ENTITY_MANAGERS_PERMISSIONS
+    __unique_together__ = [('match_host', 'cw_host_config_of')]
+    match_host = String(required=True, maxsize=128,
+                        description=_('regexp matching host(s) to which this config applies'))
+    config = String(required=True,
+                    description=_('Source\'s configuration for a particular host. '
+                                  'One key=value per line, authorized keys '
+                                  'depending on the source\'s type, overriding '
+                                  'values defined on the source.'),
+                    __permissions__={
+                        'read':   ('managers',),
+                        'add':    ('managers',),
+                        'update': ('managers',),
+                        })
+
+
+class cw_host_config_of(RelationDefinition):
+    __permissions__ = RELATION_MANAGERS_PERMISSIONS
+    subject = 'CWSourceHostConfig'
+    object = 'CWSource'
+    cardinality = '1*'
+    composite = 'object'
+    inlined = True
+
+class cw_source(RelationDefinition):
+    __permissions__ = {
+        'read':   ('managers', 'users', 'guests'),
+        'add':    ('managers',),
+        'delete': ('managers',),
+        }
+    subject = '*'
+    object = 'CWSource'
+    cardinality = '1*'
+    composite = 'object'
+
+
+class CWDataImport(EntityType):
+    __permissions__ = ENTITY_MANAGERS_PERMISSIONS
+    start_timestamp = TZDatetime()
+    end_timestamp = TZDatetime()
+    log = String()
+    status = String(required=True, internationalizable=True, indexed=True,
+                    default='in progress',
+                    vocabulary=[_('in progress'), _('success'), _('failed')])
+
+class cw_import_of(RelationDefinition):
+    __permissions__ = RELATION_MANAGERS_PERMISSIONS
+    subject = 'CWDataImport'
+    object = 'CWSource'
+    cardinality = '1*'
+    composite = 'object'
+
+
+class CWSourceSchemaConfig(EntityType):
+    __permissions__ = ENTITY_MANAGERS_PERMISSIONS
+    cw_for_source = SubjectRelation(
+        'CWSource', inlined=True, cardinality='1*', composite='object',
+        __permissions__=RELATION_MANAGERS_PERMISSIONS)
+    options = String(description=_('allowed options depends on the source type'))
+
+
+class rtype_cw_schema(RelationDefinition):
+    __permissions__ = RELATION_MANAGERS_PERMISSIONS
+    name = 'cw_schema'
+    subject = 'CWSourceSchemaConfig'
+    object = ('CWEType', 'CWRType')
+    inlined = True
+    cardinality = '1*'
+    composite = 'object'
+    constraints = [RQLConstraint('NOT O final TRUE')]
+
+class rdef_cw_schema(RelationDefinition):
+    __permissions__ = RELATION_MANAGERS_PERMISSIONS
+    name = 'cw_schema'
+    subject = 'CWSourceSchemaConfig'
+    object = 'CWRelation'
+    inlined = True
+    cardinality = '1*'
+    composite = 'object'
+
+# "abtract" relation types, no definition in cubicweb itself ###################
+
+class identical_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'),),
+        }
+
+class see_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'),),
+        }