cubicweb/schemas/bootstrap.py
author Denis Laxalde <denis.laxalde@logilab.fr>
Thu, 09 Mar 2017 16:36:33 +0100
changeset 12053 c3c9f2e1424c
parent 11767 432f87a63057
permissions -rw-r--r--
[pyramid] Add a "pyramid" instance configuration type In a new module 'cubicweb.pyramid.config' we define a "pyramid" instance configuration type. The noticeable feature of this configuration is that it manages a 'development.ini' file that gets installed in application home (along with `.conf` file). This file is templated and includes generated values for secrets of session and authtk tokens. This means that we can just call: pserve etc/cubicweb.d/<appname>/development.ini or gunicorn --paste etc/cubicweb.d/<appname>/development.ini -b :8080 just after instance creation to get a pyramid instance running without having to hack around a 'pyramid.ini' file. This patch drops 'development.ini' from skeleton and moves it in cubicweb/pyramid so that it gets installed at instance creation which is more appropriate than in cube creation. The new configuration class sets "cubicweb.bwcompat" setting to false so it is not intended to replace the "all-in-one" configuration type (which would require a bit more work). This configuration is close to the the 'repository' configuration type with just a couple of options from WebConfiguration that are needed for Pyramid (anonymous user/password plus some miscellaneous options that I'm not so sure are really needed). Note, in particular, that we do not pull CORS settings to be injected as a WSGI middleware like in wsgi_application_from_cwconfig() since I believe this should be left as an end-user responsibility and since this can be defined in a standard way in paste configuration. This configuration inherits from ServerConfiguration but registers the same appobjects as WebConfiguration. In cubicweb.web.request._CubicWebRequestBase, we guard against access to "uiprops" and "datadir_url" of the config because this new "pyramid" config does not have these (this does not make sense without bwcompat mode). At some point, we should either avoid using `cw_request`'s pyramid request attribute or make cubicweb's web request really independant of existing implementation and drop these assumptions.

# copyright 2003-2013 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 necessary for bootstrapping the actual instance's schema
"""


from cubicweb import _

from yams.buildobjs import (EntityType, RelationType, RelationDefinition, Bytes,
                            SubjectRelation, RichString, String, Boolean, Int)
from cubicweb.schema import (
    RQLConstraint,
    PUB_SYSTEM_ENTITY_PERMS, PUB_SYSTEM_REL_PERMS, PUB_SYSTEM_ATTR_PERMS
    )

# not restricted since as "is" is handled as other relations, guests need
# access to this
class CWEType(EntityType):
    """define an entity type, used to build the instance schema"""
    __permissions__ = PUB_SYSTEM_ENTITY_PERMS
    name = String(required=True, indexed=True, internationalizable=True,
                  unique=True, maxsize=64)
    description = RichString(internationalizable=True,
                             description=_('semantic description of this entity type'))
    # necessary to filter using RQL
    final = Boolean(default=False, description=_('automatic'))


class CWRType(EntityType):
    """define a relation type, used to build the instance schema"""
    __permissions__ = PUB_SYSTEM_ENTITY_PERMS
    name = String(required=True, indexed=True, internationalizable=True,
                  unique=True, maxsize=64)
    description = RichString(internationalizable=True,
                             description=_('semantic description of this relation type'))
    symmetric = Boolean(description=_('is this relation equivalent in both direction ?'))
    inlined = Boolean(description=_('is this relation physically inlined? you should know what you\'re doing if you are changing this!'))
    fulltext_container = String(description=_('if full text content of subject/object entity '
                                              'should be added to other side entity (the container).'),
                                vocabulary=('', _('subject'), _('object')),
                                maxsize=8, default=None)
    final = Boolean(description=_('automatic'))


class CWComputedRType(EntityType):
    """define a virtual relation type, used to build the instance schema"""
    __permissions__ = PUB_SYSTEM_ENTITY_PERMS
    name = String(required=True, indexed=True, internationalizable=True,
                  unique=True, maxsize=64)
    description = RichString(internationalizable=True,
                             description=_('semantic description of this relation type'))
    rule = String(required=True)


class CWAttribute(EntityType):
    """define a final relation: link a final relation type from a non final
    entity to a final entity type.

    used to build the instance schema
    """
    __permissions__ = PUB_SYSTEM_ENTITY_PERMS
    relation_type = SubjectRelation('CWRType', cardinality='1*',
                                    constraints=[RQLConstraint('O final TRUE')],
                                    composite='object')
    from_entity = SubjectRelation('CWEType', cardinality='1*',
                                  constraints=[RQLConstraint('O final FALSE')],
                                  composite='object')
    to_entity = SubjectRelation('CWEType', cardinality='1*',
                                constraints=[RQLConstraint('O final TRUE')],
                                composite='object')
    constrained_by = SubjectRelation('CWConstraint', cardinality='*1', composite='subject')

    cardinality = String(maxsize=2, internationalizable=True,
                         vocabulary=[_('?1'), _('11')],
                         description=_('subject/object cardinality'))
    ordernum = Int(description=('control subject entity\'s relations order'), default=0)

    formula = String(maxsize=2048)
    indexed = Boolean(description=_('create an index for quick search on this attribute'))
    fulltextindexed = Boolean(description=_('index this attribute\'s value in the plain text index'))
    internationalizable = Boolean(description=_('is this attribute\'s value translatable'))
    defaultval = Bytes(description=_('default value as gziped pickled python object'))
    extra_props = Bytes(description=_('additional type specific properties'))

    description = RichString(internationalizable=True,
                             description=_('semantic description of this attribute'))


CARDINALITY_VOCAB = [_('?*'), _('1*'), _('+*'), _('**'),
                     _('?+'), _('1+'), _('++'), _('*+'),
                     _('?1'), _('11'), _('+1'), _('*1'),
                     _('??'), _('1?'), _('+?'), _('*?')]

class CWRelation(EntityType):
    """define a non final relation: link a non final relation type from a non
    final entity to a non final entity type.

    used to build the instance schema
    """
    __permissions__ = PUB_SYSTEM_ENTITY_PERMS
    relation_type = SubjectRelation('CWRType', cardinality='1*',
                                    constraints=[RQLConstraint('O final FALSE')],
                                    composite='object')
    from_entity = SubjectRelation('CWEType', cardinality='1*',
                                  constraints=[RQLConstraint('O final FALSE')],
                                  composite='object')
    to_entity = SubjectRelation('CWEType', cardinality='1*',
                                constraints=[RQLConstraint('O final FALSE')],
                                composite='object')
    constrained_by = SubjectRelation('CWConstraint', cardinality='*1', composite='subject')

    cardinality = String(maxsize=2, internationalizable=True,
                         vocabulary=CARDINALITY_VOCAB,
                         description=_('subject/object cardinality'))
    ordernum = Int(description=_('control subject entity\'s relations order'),
                   default=0)
    composite = String(description=_('is the subject/object entity of the relation '
                                     'composed of the other ? This implies that when '
                                     'the composite is deleted, composants are also '
                                     'deleted.'),
                       vocabulary=('', _('subject'), _('object')),
                       maxsize=8, default=None)

    description = RichString(internationalizable=True,
                             description=_('semantic description of this relation'))


# not restricted since it has to be read when checking allowed transitions
class RQLExpression(EntityType):
    """define a rql expression used to define permissions"""
    __permissions__ = PUB_SYSTEM_ENTITY_PERMS
    exprtype = String(required=True, vocabulary=['ERQLExpression', 'RRQLExpression'])
    mainvars = String(maxsize=8,
                      description=_('name of the main variables which should be '
                                    'used in the selection if necessary (comma '
                                    'separated)'))
    expression = String(required=True,
                        description=_('restriction part of a rql query. '
                                      'For entity rql expression, X and U are '
                                      'predefined respectivly to the current object and to '
                                      'the request user. For relation rql expression, '
                                      'S, O and U are predefined respectivly to the current '
                                      'relation\'subject, object and to '
                                      'the request user. '))


class CWConstraint(EntityType):
    """define a schema constraint"""
    __permissions__ = PUB_SYSTEM_ENTITY_PERMS
    cstrtype = SubjectRelation('CWConstraintType', cardinality='1*')
    value = String(description=_('depends on the constraint type'))


class CWUniqueTogetherConstraint(EntityType):
    """defines a sql-level multicolumn unique index"""
    __permissions__ = PUB_SYSTEM_ENTITY_PERMS
    name = String(required=True, unique=True, maxsize=64)
    constraint_of = SubjectRelation('CWEType', cardinality='1*', composite='object',
                                    inlined=True)
    relations = SubjectRelation('CWRType', cardinality='+*',
                                constraints=[RQLConstraint(
           'S constraint_of ET, RDEF relation_type O, RDEF from_entity ET, '
           'O final TRUE OR (O final FALSE AND O inlined TRUE)')])


class CWConstraintType(EntityType):
    """define a schema constraint type"""
    __permissions__ = PUB_SYSTEM_ENTITY_PERMS
    name = String(required=True, indexed=True, internationalizable=True,
                  unique=True, maxsize=64)


# not restricted since it has to be read when checking allowed transitions
class CWGroup(EntityType):
    """define a CubicWeb users group"""
    __permissions__ = PUB_SYSTEM_ENTITY_PERMS
    name = String(required=True, indexed=True, internationalizable=True,
                  unique=True, maxsize=64)


class CWProperty(EntityType):
    """used for cubicweb configuration. Once a property has been created you
    can't change the key.
    """
    __permissions__ = {
        'read':   ('managers', 'users', 'guests'),
        'add':    ('managers', 'users',),
        'update': ('managers', 'owners',),
        'delete': ('managers', 'owners',),
        }
    # key is a reserved word for mysql
    pkey = String(required=True, internationalizable=True, maxsize=256,
                  description=_('defines what\'s the property is applied for. '
                                'You must select this first to be able to set '
                                'value'))
    value = String(internationalizable=True, maxsize=256)

class relation_type(RelationType):
    """link a relation definition to its relation type"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    inlined = True

class from_entity(RelationType):
    """link a relation definition to its subject entity type"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    inlined = True

class to_entity(RelationType):
    """link a relation definition to its object entity type"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    inlined = True

class constrained_by(RelationType):
    """constraints applying on this relation"""
    __permissions__ = PUB_SYSTEM_REL_PERMS

class cstrtype(RelationType):
    """constraint factory"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    inlined = True


class read_permission_cwgroup(RelationDefinition):
    """groups allowed to read entities/relations of this type"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    name = 'read_permission'
    subject = ('CWEType', 'CWAttribute', 'CWRelation', 'CWComputedRType')
    object = 'CWGroup'
    cardinality = '**'

class add_permission_cwgroup(RelationDefinition):
    """groups allowed to add entities/relations of this type"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    name = 'add_permission'
    subject = ('CWEType', 'CWRelation', 'CWAttribute')
    object = 'CWGroup'
    cardinality = '**'

class delete_permission_cwgroup(RelationDefinition):
    """groups allowed to delete entities/relations of this type"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    name = 'delete_permission'
    subject = ('CWEType', 'CWRelation')
    object = 'CWGroup'
    cardinality = '**'

class update_permission_cwgroup(RelationDefinition):
    """groups allowed to update entities/relations of this type"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    name = 'update_permission'
    subject = ('CWEType', 'CWAttribute')
    object = 'CWGroup'
    cardinality = '**'

class read_permission_rqlexpr(RelationDefinition):
    """rql expression allowing to read entities/relations of this type"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    name = 'read_permission'
    subject = ('CWEType', 'CWAttribute', 'CWRelation', 'CWComputedRType')
    object = 'RQLExpression'
    cardinality = '*?'
    composite = 'subject'

class add_permission_rqlexpr(RelationDefinition):
    """rql expression allowing to add entities/relations of this type"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    name = 'add_permission'
    subject = ('CWEType', 'CWRelation', 'CWAttribute')
    object = 'RQLExpression'
    cardinality = '*?'
    composite = 'subject'

class delete_permission_rqlexpr(RelationDefinition):
    """rql expression allowing to delete entities/relations of this type"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    name = 'delete_permission'
    subject = ('CWEType', 'CWRelation')
    object = 'RQLExpression'
    cardinality = '*?'
    composite = 'subject'

class update_permission_rqlexpr(RelationDefinition):
    """rql expression allowing to update entities/relations of this type"""
    __permissions__ = PUB_SYSTEM_REL_PERMS
    name = 'update_permission'
    subject = ('CWEType', 'CWAttribute')
    object = 'RQLExpression'
    cardinality = '*?'
    composite = 'subject'


class is_(RelationType):
    """core relation indicating the type of an entity
    """
    name = 'is'
    # don't explicitly set composite here, this is handled anyway
    #composite = 'object'
    __permissions__ = {
        'read':   ('managers', 'users', 'guests'),
        'add':    (),
        'delete': (),
        }
    cardinality = '1*'
    subject = '*'
    object = 'CWEType'

class is_instance_of(RelationType):
    """core relation indicating the types (including specialized types)
    of an entity
    """
    # don't explicitly set composite here, this is handled anyway
    #composite = 'object'
    __permissions__ = {
        'read':   ('managers', 'users', 'guests'),
        'add':    (),
        'delete': (),
        }
    cardinality = '+*'
    subject = '*'
    object = 'CWEType'

class specializes(RelationType):
    name = 'specializes'
    __permissions__ = {
        'read':   ('managers', 'users', 'guests'),
        'add':    ('managers',),
        'delete': ('managers',),
        }
    cardinality = '?*'
    subject = 'CWEType'
    object = 'CWEType'

def post_build_callback(schema):
    """set attributes permissions for schema/workflow entities"""
    from cubicweb.schema import SCHEMA_TYPES, WORKFLOW_TYPES, META_RTYPES
    wftypes = WORKFLOW_TYPES - set(('TrInfo',))
    for eschema in schema.entities():
        if eschema in SCHEMA_TYPES or eschema in wftypes:
            for rschema in eschema.subject_relations():
                if rschema.final and not rschema in META_RTYPES:
                    rdef = eschema.rdef(rschema)
                    rdef.permissions = PUB_SYSTEM_ATTR_PERMS