Exemple #1
0
class AuthProvider(object):

    _sql_get_login = ptah.QueryFreezer(
        lambda: ptah.get_session().query(User)\
            .filter(User.login==sqla.sql.bindparam('login')))

    _sql_search = ptah.QueryFreezer(
        lambda: ptah.get_session().query(User) \
            .filter(sqla.sql.or_(
                User.name.contains(sqla.sql.bindparam('term')),
                User.email.contains(sqla.sql.bindparam('term'))))\
            .order_by(sqla.sql.asc('name')))

    def authenticate(self, creds):
        login, password = creds['login'], creds['password']

        user = self._sql_get_login.first(login=login)
        if user is not None:
            if ptah.pwd_tool.check(user.password, password):
                return user

    def get_principal_bylogin(self, login):
        return self._sql_get_login.first(login=login)

    def add(self, user):
        """ Add user to crowd application. """
        Session = ptah.get_session()
        Session.add(user)
        Session.flush()

        return user

    def get_user_bylogin(self, login):
        """ Given a login string return a user """
        return self._sql_get_login.first(login=login)
Exemple #2
0
class User(ptah.get_base()):
    """Default user
    
    ``name``: User name.

    ``email``: User email.

    ``properties``: User properties.
    """

    __tablename__ = 'users'

    id = sqla.Column(sqla.Integer, primary_key=True)
    token = sqla.Column(sqla.String(255), index=True)
    source = sqla.Column(sqla.String(18))
    name = sqla.Column(sqla.Unicode(255))
    email = sqla.Column(sqla.Unicode(255), unique=True)
    joined = sqla.Column(sqla.DateTime())
    properties = sqla.Column(ptah.JsonDictType(), default={})

    def __init__(self, **kw):
        self.joined = datetime.utcnow()
        self.properties = {}

        super(User, self).__init__(**kw)

    def __str__(self):
        return self.name

    def __name__(self):
        return str(self.id)

    def __repr__(self):
        return '%s<%s:%s>' % (self.__class__.__name__, self.name, self.__uri__)

    _sql_get_id = ptah.QueryFreezer(
        lambda: ptah.get_session().query(User)\
            .filter(User.id==sqla.sql.bindparam('id')))

    @classmethod
    def get_byid(cls, id):
        return cls._sql_get_id.first(id=id)

    _sql_get_token = ptah.QueryFreezer(
        lambda: ptah.get_session().query(User)\
            .filter(User.token==sqla.sql.bindparam('token')))

    @classmethod
    def get_bytoken(cls, token):
        return cls._sql_get_token.first(token=token)
Exemple #3
0
    def test_freezer_all(self):
        import ptah

        class Test(ptah.get_base()):
            __tablename__ = 'test13'

            id = sqla.Column('id', sqla.Integer, primary_key=True)
            name = sqla.Column(sqla.Unicode())

        Session = ptah.get_session()
        ptah.get_base().metadata.create_all()
        transaction.commit()

        sql_get = ptah.QueryFreezer(lambda: Session.query(Test).filter(
            Test.name == sqla.sql.bindparam('name')))

        self.assertIsNone(sql_get.first(name='test'))

        rec = Test()
        rec.name = 'test'
        Session.add(rec)
        Session.flush()

        rec = sql_get.all(name='test')
        self.assertEqual(rec[0].name, 'test')
Exemple #4
0
class CrowdGroup(ptah.get_base()):
    """Crowd group

    ``title``: Group title.

    ``description``: Group description.

    ``users``: Users list.

    """

    __tablename__ = 'ptahcrowd_groups'

    id = sqla.Column(sqla.Integer, primary_key=True)
    title = sqla.Column(sqla.Unicode(255))
    description = sqla.Column(sqla.UnicodeText, default=text_type(''),
                              info = {'missing': '', 'field_type': 'textarea',
                                      'default': '', 'required': False})

    _sql_get_id = ptah.QueryFreezer(
        lambda: ptah.get_session().query(CrowdGroup)\
            .filter(CrowdGroup.id==sqla.sql.bindparam('id')))

    @classmethod
    def get_byid(cls, id):
        return cls._sql_get_id.first(id=id)

    def __str__(self):
        return self.title
Exemple #5
0
def register_type_impl(config,
                       cls,
                       tinfo,
                       name,
                       fieldset=None,
                       fieldNames=None,
                       **kw):

    # generate schema
    fieldset = kw.get('fieldset')
    if fieldset is None:
        kw['fieldset'] = ptah.generate_fieldset(cls,
                                                fieldNames=fieldNames,
                                                namesFilter=names_filter)
        log.info("Generating fieldset for %s content type.", cls)

    if 'global_allow' not in kw and not issubclass(cls, Content):
        kw['global_allow'] = False

    tinfo.__dict__.update(kw)

    tinfo.cls = cls

    config.get_cfg_storage(TYPES_DIR_ID)[tinfo.__uri__] = tinfo

    # sql query for content resolver
    cls.__uri_sql_get__ = ptah.QueryFreezer(
        lambda: ptah.get_session().query(cls) \
            .filter(cls.__uri__ == sqla.sql.bindparam('uri')))

    # build cms actions
    build_class_actions(cls)
Exemple #6
0
    def test_freezer_one(self):
        import ptah

        class Test(ptah.get_base()):
            __tablename__ = 'test10'

            id = sqla.Column('id', sqla.Integer, primary_key=True)
            name = sqla.Column(sqla.Unicode())

        Session = ptah.get_session()
        ptah.get_base().metadata.create_all()
        transaction.commit()

        sql_get = ptah.QueryFreezer(lambda: Session.query(Test).filter(
            Test.name == sqla.sql.bindparam('name')))

        self.assertRaises(sqla.orm.exc.NoResultFound, sql_get.one, name='test')

        rec = Test()
        rec.name = 'test'
        Session.add(rec)
        Session.flush()

        rec = sql_get.one(name='test')
        self.assertEqual(rec.name, 'test')

        rec = Test()
        rec.name = 'test'
        Session.add(rec)
        Session.flush()

        self.assertRaises(sqla.orm.exc.MultipleResultsFound,
                          sql_get.one,
                          name='test')
Exemple #7
0
class CrowdAuthProvider(object):

    _sql_get_username = ptah.QueryFreezer(
        lambda: ptah.get_session().query(CrowdUser)\
            .filter(CrowdUser.username==sqla.sql.bindparam('username')))

    _sql_get_email = ptah.QueryFreezer(
        lambda: ptah.get_session().query(CrowdUser)\
            .filter(CrowdUser.email==sqla.sql.bindparam('email')))

    _sql_search = ptah.QueryFreezer(
        lambda: ptah.get_session().query(CrowdUser) \
            .filter(sqla.sql.or_(
                CrowdUser.username.contains(sqla.sql.bindparam('term')),
                CrowdUser.email.contains(sqla.sql.bindparam('term'))))\
            .order_by(sqla.sql.asc('fullname')))

    def authenticate(self, creds):
        login, password = creds['login'], creds['password']

        user = self.get_principal_bylogin(login=login)

        if user is not None:
            if ptah.pwd_tool.check(user.password, password):
                return user

    def get_principal_bylogin(self, login):
        user = self._sql_get_username.first(username=login)
        if not user:
            user = self._sql_get_email.first(email=login)
        return user

    @classmethod
    def search(cls, term):
        for user in cls._sql_search.all(term = '%%%s%%'%term):
            yield user

    def add(self, user):
        """ Add user to crowd application. """
        Session = ptah.get_session()
        Session.add(user)
        Session.flush()

        return user
Exemple #8
0
class BlobStorage(object):
    """ simple blob storage """

    _sql_get = ptah.QueryFreezer(lambda: ptah.get_session().query(Blob).filter(
        Blob.__uri__ == sqla.sql.bindparam('uri')))

    _sql_get_by_parent = ptah.QueryFreezer(lambda: ptah.get_session().query(
        Blob).filter(Blob.__parent_uri__ == sqla.sql.bindparam('parent')))

    def create(self, parent=None):
        blob = Blob(__parent__=parent)
        Session = ptah.get_session()
        Session.add(blob)
        Session.flush()

        return blob

    def add(self, data, parent=None, **metadata):
        blob = self.create(parent)

        data.seek(0)

        blob.data = data.read()
        blob.updateMetadata(**metadata)

        data.seek(0, os.SEEK_END)
        blob.size = data.tell()

        return blob

    def get(self, uri):
        """SQL Blob resolver"""
        return self._sql_get.first(uri=uri)

    def getByParent(self, parent):
        return self._sql_get_by_parent.first(parent=parent)

    def replace(self, uri, data, **metadata):  # pragma: no cover
        pass

    def remove(self, uri):  # pragma: no cover
        pass
Exemple #9
0
    def __init__(self,
                 cls,
                 path='',
                 name='',
                 title='',
                 policy=ApplicationPolicy,
                 default_root=None,
                 parent_factory=None,
                 config=None):
        self.id = '-'.join(part for part in path.split('/') if part)
        self.path = path if path.endswith('/') else '%s/' % path
        self.name = name
        self.title = title

        self.default_root = default_root
        if (self.path == '/') and default_root is None:
            self.default_root = True

        self.cls = cls
        self.type = cls.__type__
        self.policy = policy
        self.parent_factory = parent_factory

        discr = (APPFACTORY_ID, path)
        intr = ptah.config.Introspectable(APPFACTORY_ID, discr, name,
                                          APPFACTORY_ID)
        intr['id'] = self.id
        intr['factory'] = self

        if config is not None:
            ptah.config.get_cfg_storage(
                APPFACTORY_ID, registry=config.registry)[self.id] = self

        info = ptah.config.DirectiveInfo()
        info.attach(
            ptah.config.Action(
                lambda cfg: cfg.get_cfg_storage(APPFACTORY_ID)\
                    .update({self.id: self}),
                discriminator=discr, introspectables=(intr,))
            )

        self._sql_get_root = ptah.QueryFreezer(
            lambda: Session.query(cls)\
                .filter(sqla.sql.and_(
                    cls.__name_id__ == sqla.sql.bindparam('name'),
                    cls.__type_id__ == sqla.sql.bindparam('type'))))
Exemple #10
0
def register_sqla_type(config, cls, tinfo, name, **kw):
    base = ptah.get_base()
    if not issubclass(cls, base):
        return

    # generate schema
    fieldset = tinfo.fieldset

    if fieldset is None:
        fieldset = ptah.generate_fieldset(cls,
                                          fieldNames=kw.get('fieldNames'),
                                          namesFilter=kw.get('namesFilter'))
        log.info("Generating fieldset for %s content type.", cls)

    if fieldset is not None:
        tinfo.fieldset = fieldset

    if tinfo.add_method is None:
        tinfo.add_method = sqla_add_method

    # install __uri__ property
    if not hasattr(cls, '__uri__') or hasattr(cls, '__uri_reinstall__'):
        pname = None
        for cl in cls.__table__.columns:
            if cl.primary_key:
                pname = cl.name
                break

        l = len(tinfo.name) + 1
        cls.__uri_reinstall__ = True
        cls.__uri__ = UriProperty(tinfo.name, cl.name)

        cls.__uri_sql_get__ = ptah.QueryFreezer(
            lambda: ptah.get_session().query(cls) \
                .filter(getattr(cls, pname) == sqla.sql.bindparam('uri')))

        def resolver(uri):
            """Content resolver for %s type'""" % tinfo.name
            return cls.__uri_sql_get__.first(uri=uri[l:])

        storage = config.get_cfg_storage(ID_RESOLVER)
        if tinfo.name in storage:
            raise ConfigurationError('Resolver for "%s" already registered' %
                                     tinfo.name)
        storage[tinfo.name] = resolver
Exemple #11
0
class Theme(ptah.cms.Container):

    __tablename__ = 'ploud_themes'

    __type__ = ptah.cms.Type(
        'diazo-theme',
        'Theme',
        add='newtheme.html',
        fieldset=ThemeSchema,
        description='A diazo theme.',
        permission=permissions.AddTheme,
        global_allow=False,
        filter_content_types=True,
        allowed_content_types=('diazo-theme-file', ),
    )

    _sql_values = ptah.QueryFreezer(
        lambda: ptah.get_session().query(ThemeFile).filter(
            ThemeFile.__parent_uri__ == sqla.sql.bindparam('uri')))

    author = sqla.Column(sqla.Unicode)
    url = sqla.Column(sqla.Unicode)
    email = sqla.Column(sqla.Unicode)
    attribution = sqla.Column(sqla.Unicode)
    featured = sqla.Column(sqla.Boolean)
    status = sqla.Column(sqla.Unicode, default=text_type('private'))

    preview = sqla.Column(sqla.Unicode)
    thumbnail = sqla.Column(sqla.Unicode)

    def __init__(self, *args, **kw):
        super(Theme, self).__init__(*args, **kw)

        self.changeStatus('private')

    def changeStatus(self, status):
        self.status = status

        pmap = permissions.status[status]
        self.__acls__ = [pmap.id]

    @ptah.cms.action(permission=ptah.cms.ModifyContent)
    def update(self, **data):
        preview = data.pop('preview')

        for node in self.__type__.fieldset.fields():
            val = data.get(node.name, node.default)
            if val is not form.null:
                setattr(self, node.name, val)

        if preview:
            blob = ptah.resolve(self.preview)
            if blob is None:
                blob = ptah.cms.blob_storage.create(self)
                self.preview = blob.__uri__

            blob.write(preview['fp'].read())
            blob.updateMetadata(filename=preview['filename'],
                                mimetype=preview['mimetype'])

            generateThumbnail(self)

        get_current_registry().notify(ptah.events.ContentModifiedEvent(self))
Exemple #12
0
class BaseContent(Node):
    """ Base class for content objects. A content class should inherit from
    `Content` to participate in content hierarchy traversal.

    .. attribute:: __path__

       A string used by the :py:class:`ptah.cms.ContentTraverser` which is
       used for efficient resolution of URL structure to content models.
       This is internal implementation and manually editing it can break
       your hierarchy.

    .. attribute:: __name__

       This is the identifier in a container if you are using containment and
       hierarchies.

    .. attribute:: title

       Content title which is editable by end user.

    .. attribute:: description

       Content description which is editable by end user.

    .. attribute:: view

       A URI which can be resolved with :py:func:`ptah.resolve` function
       which represents the 'default' view for content. Akin to index.html
       or default.php in Apache.

    .. attribute:: created

       Content creation time which is set by
       :py:func:`ptah.cms.content.createdHandler` during object creation.

       :type: :py:class:`datetime.datetime`

    .. attribute:: modified

       Content modification time which is set by
       :py:func:`ptah.cms.content.modifiedHandler` during object modification.

       :type: :py:class:`datetime.datetime`

    .. attribute:: effective

       :type: :py:class:`datetime.datetime` or None

    .. attribute:: expires

       :type: :py:class:`datetime.datetime` or None

    .. attribute:: creators

       a :py:class:`ptah.JsonListType` which contains sequence of users.  Using
       principal URIs is a good idea.

    .. attribute:: subjects

       a :py:class:`ptah.JsonListType` which contains sequence of subjects.
       Holding a sequence of URIs could resolve to subject objects. Or you can
       use strings.

    .. attribute: publisher

       a Unicode string which should identify the publisher.

    .. attribute: contributors

       a :py:class:`ptah.JsonListType` which contains sequence of contributors.
       You could keep a sequence of principal URIs.
    """

    __tablename__ = 'ptah_content'

    __id__ = sqla.Column('id',
                         sqla.Integer,
                         sqla.ForeignKey('ptah_nodes.id'),
                         primary_key=True)
    __path__ = sqla.Column('path', sqla.Unicode, default=text_type(''))
    __name_id__ = sqla.Column('name', sqla.Unicode(255))

    title = sqla.Column(sqla.Unicode, default=text_type(''))
    description = sqla.Column(sqla.Unicode,
                              default=text_type(''),
                              info={
                                  'missing': '',
                                  'field_type': 'textarea'
                              })
    view = sqla.Column(sqla.Unicode, default=text_type(''))

    created = sqla.Column(sqla.DateTime)
    modified = sqla.Column(sqla.DateTime)
    effective = sqla.Column(sqla.DateTime)
    expires = sqla.Column(sqla.DateTime)

    creators = sqla.Column(ptah.JsonListType(), default=[])
    subjects = sqla.Column(ptah.JsonListType(), default=[])
    publisher = sqla.Column(sqla.Unicode, default=text_type(''))
    contributors = sqla.Column(ptah.JsonListType(), default=[])

    # sql queries
    _sql_get = ptah.QueryFreezer(lambda: Session.query(BaseContent).filter(
        BaseContent.__uri__ == sqla.sql.bindparam('uri')))

    _sql_get_in_parent = ptah.QueryFreezer(
        lambda: Session.query(BaseContent).filter(
            BaseContent.__name_id__ == sqla.sql.bindparam('key')).filter(
                BaseContent.__parent_uri__ == sqla.sql.bindparam('parent')))

    _sql_parent = ptah.QueryFreezer(lambda: Session.query(BaseContent).filter(
        BaseContent.__uri__ == sqla.sql.bindparam('parent')))

    def __init__(self, **kw):
        super(BaseContent, self).__init__(**kw)

        if self.__name__ and self.__parent__ is not None:
            self.__path__ = '%s%s/' % (self.__parent__.__path__, self.__name__)

    @hybrid_property
    def __name__(self):
        return self.__name_id__

    @__name__.setter
    def __name__(self, value):
        self.__name_id__ = value

    def __resource_url__(self, request, info):
        return '%s%s' % (request.root.__root_path__,
                         self.__path__[len(request.root.__path__):])

    @action(permission=DeleteContent)
    def delete(self):
        parent = self.__parent__
        if parent is None:
            parent = self.__parent_ref__

        if parent is None:
            raise Error("Can't find parent")

        del parent[self]

    @action(permission=ModifyContent)
    def update(self, **data):
        if self.__type__:
            tinfo = self.__type__

            for field in tinfo.fieldset.fields():
                val = data.get(field.name, field.default)
                if val is not ptah.form.null:
                    setattr(self, field.name, val)

            get_current_registry().notify(
                ptah.events.ContentModifiedEvent(self))

    def _extra_info(self, info):
        if self.__type__:
            fieldset = self.__type__.fieldset.bind()
            for field in fieldset.fields():
                val = getattr(self, field.name, field.default)
                info[field.name] = field.serialize(val)

        info['view'] = self.view
        info['created'] = self.created
        info['modified'] = self.modified
        info['effective'] = self.effective
        info['expires'] = self.expires

    def info(self):
        info = super(BaseContent, self).info()
        info['__name__'] = self.__name__
        info['__content__'] = True
        info['__container__'] = False
        self._extra_info(info)
        return info
Exemple #13
0
class CrowdUser(ptah.get_base()):
    """Default crowd user

    ``fullname``: User full name.

    ``username``: User name.

    ``email``: User email.

    ``password``: User password.

    ``properties``: User properties.

    """

    __tablename__ = 'ptahcrowd_users'

    id = sqla.Column(sqla.Integer, primary_key=True)
    fullname = sqla.Column(sqla.Unicode(255), info={
        'title': const.FULLNAME_TITLE,
        'description': const.FULLNAME_DESCR,
        'required': False
    })
    username = sqla.Column(sqla.Unicode(255), unique=True, info={
        'title': const.USERNAME_TITLE,
        'description': const.USERNAME_DESCR,
        'preparer': lower,
        'validator': checkUsernameValidator,
    })
    email = sqla.Column(sqla.Unicode(255), unique=True, info={
        'title': const.EMAIL_TITLE,
        'description': const.EMAIL_DESCR,
        'preparer': lower,
        'validator': ptah.form.All(ptah.form.Email(), checkEmailValidator),
    })
    joined = sqla.Column(sqla.DateTime(), info={'skip': True})
    password = sqla.Column(sqla.Unicode(255), info={
        'title': const.PASSWORD_TITLE,
        'description': const.PASSWORD_DESCR,
        'validator': passwordValidator,
        'field_type': 'password'
    })
    validated = sqla.Column(sqla.Boolean(), default=False, info={
        'title': _('Validated'),
        'default': False,
    })
    suspended = sqla.Column(sqla.Boolean(), default=False, info={
        'title': _('Suspended'),
        'default': False,
    })
    properties = sqla.Column(ptah.JsonDictType(), default={})

    def __init__(self, **kw):
        self.joined = datetime.utcnow()
        self.properties = {}

        super(CrowdUser, self).__init__(**kw)

    def __str__(self):
        return self.name

    @property
    def __name__(self):
        return str(self.id)

    @property
    def name(self):
        return self.fullname or self.username

    def __repr__(self):
        return '%s<%s:%s:%s>'%(self.__class__.__name__, self.name,
            self.__type__.name, self.id)

    _sql_get_id = ptah.QueryFreezer(
        lambda: ptah.get_session().query(CrowdUser)\
            .filter(CrowdUser.id==sqla.sql.bindparam('id')))

    @classmethod
    def get_byid(cls, id):
        return cls._sql_get_id.first(id=id)
Exemple #14
0
                                      'default': '', 'required': False})

    _sql_get_id = ptah.QueryFreezer(
        lambda: ptah.get_session().query(CrowdGroup)\
            .filter(CrowdGroup.id==sqla.sql.bindparam('id')))

    @classmethod
    def get_byid(cls, id):
        return cls._sql_get_id.first(id=id)

    def __str__(self):
        return self.title


_sql_group_search = ptah.QueryFreezer(
    lambda: ptah.get_session().query(CrowdGroup) \
    .filter(CrowdGroup.title.contains(sqla.sql.bindparam('term')))\
    .order_by(sqla.sql.asc('title')))

@ptah.principal_searcher('crowd-group')
def group_searcher(term):
    return _sql_group_search.all(term = '%%%s%%'%term)


@ptah.roles_provider('crowd')
def crowd_user_roles(context, uid, registry):
    """ crowd roles provider

    return user default roles and user group roles"""
    roles = set()

    props = getattr(ptah.resolve(uid), 'properties', None)
Exemple #15
0
    def __call__(self, request, queries=_path_queries):
        environ = request.environ
        context = root = self.root

        if root.__default_root__ and 'bfg.routes.route' in environ:
            return ResourceTreeTraverser(root)(request)

        path = '/%s/' % '/'.join(traversal_path(environ.get('PATH_INFO', '/')))

        vroot_tuple = ()

        l_path = len(root.__root_path__)

        # build paths for all parents in content hierarchy
        idx = 0
        paths = {}
        current = root.__path__
        for sec in path[l_path:].split('/'):
            if sec:
                current = '%s%s/' % (current, sec)
                paths[str(idx)] = current
                idx += 1

        if idx:
            if idx not in queries:
                bindparams = [sql.bindparam(str(p)) for p in range(idx)]

                queries[idx] = ptah.QueryFreezer(
                    lambda: ptah.get_session().query(BaseContent)\
                        .filter(BaseContent.__path__.in_(bindparams)))

            parents = sorted(queries[idx].all(**paths),
                             reverse=True,
                             key=lambda item: item.__path__)
        else:
            parents = []

        if parents:
            # set __parent__
            parents[-1].__parent__ = root
            for idx in range(len(parents) - 1):
                parents[idx].__parent__ = parents[idx + 1]

            context = parents[0]
            node = context.__path__[len(root.__path__):]
            leaf = path[l_path + len(node):].split('/')
            leaf, subpath = leaf[0], leaf[1:]

            return {
                'context': context,
                'view_name': leaf,
                'subpath': subpath,
                'traversed': traversal_path(node),
                'virtual_root': root,
                'virtual_root_path': vroot_tuple,
                'root': root
            }
        else:
            vpath_tuple = ()

            leaf = path[l_path:].split('/')
            leaf, subpath = leaf[0], leaf[1:]

            return {
                'context': context,
                'view_name': leaf,
                'subpath': subpath,
                'traversed': vpath_tuple,
                'virtual_root': root,
                'virtual_root_path': (),
                'root': root
            }
Exemple #16
0
class BaseContent(Node):
    """ Base class for content objects. A content class should inherit from
    `Content` to participate in content hierarchy traversal.

    .. attribute:: __path__

       A string used by the :py:class:`ptahcms.ContentTraverser` which is
       used for efficient resolution of URL structure to content models.
       This is internal implementation and manually editing it can break
       your hierarchy.

    .. attribute:: __name__

       This is the identifier in a container if you are using containment and
       hierarchies.

    .. attribute:: title

       Content title which is editable by end user.

    .. attribute:: description

       Content description which is editable by end user.

    .. attribute:: created

       Content creation time which is set by
       :py:func:`ptahcms.content.createdHandler` during object creation.

       :type: :py:class:`datetime.datetime`

    .. attribute:: modified

       Content modification time which is set by
       :py:func:`ptahcms.content.modifiedHandler` during object modification.

       :type: :py:class:`datetime.datetime`

    .. attribute:: effective

       :type: :py:class:`datetime.datetime` or None

    .. attribute:: expires

       :type: :py:class:`datetime.datetime` or None

    .. attribute:: lang

       Content language code. `en` is default value.

    """

    __tablename__ = 'ptahcms_contents'

    __id__ = sqla.Column('id', sqla.Integer,
                         sqla.ForeignKey('ptahcms_nodes.id'), primary_key=True)
    __path__ = sqla.Column('path', sqla.Unicode(1024),
                           default=text_type(''), index=True)
    __name_id__ = sqla.Column('name', sqla.Unicode(255), default=text_type(''))

    title = sqla.Column(sqla.Unicode(1024), default=text_type(''),
                        info={'title': _('Title')})
    description = sqla.Column(sqla.UnicodeText, default=text_type(''),
                              info = {'missing': '', 'field_type': 'textarea',
                                      'default': '', 'required': False,
                                      'title': _('Description')})

    public = sqla.Column(sqla.Boolean,
                         info={'required': False, 'missing': False,
                               'default': False, 'title': _('Public')})
    created = sqla.Column(sqla.DateTime)
    modified = sqla.Column(sqla.DateTime)
    effective = sqla.Column(sqla.DateTime)
    expires = sqla.Column(sqla.DateTime)
    lang = sqla.Column(sqla.String(12), default='en', info={'skip':True})

    __mapper_args__ = {'with_polymorphic': '*'}

    # sql queries
    _sql_get = ptah.QueryFreezer(
        lambda: ptah.get_session().query(BaseContent)
        .filter(BaseContent.__uri__ == sqla.sql.bindparam('uri')))

    _sql_get_in_parent = ptah.QueryFreezer(
        lambda: ptah.get_session().query(BaseContent)
            .filter(BaseContent.__name_id__ == sqla.sql.bindparam('key'))
            .filter(BaseContent.__parent_uri__ == sqla.sql.bindparam('parent')))

    _sql_parent = ptah.QueryFreezer(
        lambda: ptah.get_session().query(BaseContent)
            .filter(BaseContent.__uri__ == sqla.sql.bindparam('parent')))

    def __init__(self, **kw):
        super(BaseContent, self).__init__(**kw)

        if self.__name__ and self.__parent__ is not None:
            self.__path__ = '%s%s/'%(self.__parent__.__path__, self.__name__)

    @hybrid_property
    def __name__(self):
        return self.__name_id__

    @__name__.setter
    def __name__(self, value):
        self.__name_id__ = value

    def __resource_url__(self, request, info):
        return self.__path__

    @action(permission=DeleteContent)
    def delete(self):
        parent = self.__parent__
        if parent is None:
            parent = self.__parent_ref__

        if parent is None:
            raise Error("Can't find parent")

        del parent[self]

    @action(permission=ModifyContent)
    def update(self, **data):
        if self.__type__:
            tinfo = self.__type__

            for field in tinfo.fieldset.fields():
                val = data.get(field.name, field.default)
                if val is not form.null:
                    setattr(self, field.name, val)

            get_current_registry().notify(
                ptah.events.ContentModifiedEvent(self))

    @action(permission=RenameContent)
    def rename(self, name, **params):
        parent = self.__parent__
        if parent is None:
            parent = self.__parent_ref__

        if parent is None:
            raise Error("Can't find parent")

        if name != self.__name__:
            parent[name] = self

        return self

    def _extra_info(self, info):
        if self.__type__:
            fieldset = self.__type__.fieldset
            for field in fieldset.fields():
                val = getattr(self, field.name, field.default)
                info[field.name] = val

        info['created'] = self.created
        info['modified'] = self.modified
        info['effective'] = self.effective
        info['expires'] = self.expires

    def info(self):
        info = super(BaseContent, self).info()
        info['__name__'] = self.__name__
        info['__content__'] = True
        info['__container__'] = False
        self._extra_info(info)
        return info
Exemple #17
0
class BaseContainer(BaseContent):
    """ Content container implementation. """

    _v_keys = None
    _v_keys_loaded = False
    _v_items = None

    _sql_keys = ptah.QueryFreezer(
        lambda: Session.query(BaseContent.__name_id__).filter(
            BaseContent.__parent_uri__ == sqla.sql.bindparam('uri')))

    _sql_values = ptah.QueryFreezer(lambda: Session.query(BaseContent).filter(
        BaseContent.__parent_uri__ == sqla.sql.bindparam('uri')))

    def keys(self):
        """Return an list of the keys in the container."""
        if self._v_keys_loaded:
            return self._v_keys
        else:
            if self._v_keys is None:
                self._v_keys = [
                    n for n, in self._sql_keys.all(uri=self.__uri__)
                ]

            self._v_keys_loaded = True
            return self._v_keys

    def get(self, key, default=None):
        """Get a value for a key

        The default is returned if there is no value for the key.
        """
        if self._v_items and key in self._v_items:
            return self._v_items[key]

        item = self._sql_get_in_parent.first(key=key, parent=self.__uri__)
        if item is not None:
            item.__parent__ = self
            if not self._v_items:
                self._v_items = {key: item}
            else:
                self._v_items[key] = item
        return item

    def values(self):
        """Return an list of the values in the container."""

        if self._v_keys_loaded and self._v_items:
            if len(self._v_items) == len(self._v_keys):
                return self._v_items.values()

        values = []
        old_items = self._v_items

        self._v_keys = keys = []
        self._v_items = items = {}

        for item in self._sql_values.all(uri=self.__uri__):
            item.__parent__ = self
            items[item.__name__] = item
            keys.append(item.__name__)
            values.append(item)

        if old_items:
            for name, item in old_items.items():
                if name not in items:
                    keys.append(name)
                    items[name] = item
                    values.append(item)

        return values

    def items(self):
        """Return the items of the container."""
        for item in self.values():
            yield item.__name__, item

    def __contains__(self, key):
        """Tell if a key exists in the mapping."""
        return key in self.keys()

    def __getitem__(self, key):
        """Get a value for a key

        A KeyError is raised if there is no value for the key.
        """
        if self._v_items and key in self._v_items:
            return self._v_items[key]

        try:
            item = self._sql_get_in_parent.one(key=key, parent=self.__uri__)
            item.__parent__ = self
            if not self._v_items:
                self._v_items = {key: item}
            else:
                self._v_items[key] = item

            return item
        except sqla.orm.exc.NoResultFound:
            raise KeyError(key)

    def __setitem__(self, key, item):
        """Set a new item in the container."""

        if not isinstance(item, BaseContent):
            raise ValueError("Content object is required")

        if item.__uri__ == self.__uri__:
            raise ValueError("Can't set to it self")

        parents = [p.__uri__ for p in load_parents(self)]
        if item.__uri__ in parents:
            raise TypeError("Can't itself to chidlren")

        if key in self.keys():
            raise KeyError(key)

        if item.__parent_uri__ is None:
            event = ptah.events.ContentAddedEvent(item)
        else:
            event = ptah.events.ContentMovedEvent(item)

        item.__name__ = key
        item.__parent__ = self
        item.__parent_uri__ = self.__uri__
        item.__path__ = '%s%s/' % (self.__path__, key)

        if item not in Session:
            Session.add(item)

        # temporary keys
        if not self._v_items:
            self._v_items = {key: item}
        else:
            self._v_items[key] = item

        if key not in self._v_keys:
            self._v_keys.append(key)

        # recursevly update children paths
        def update_path(container):
            path = container.__path__
            for item in container.values():
                item.__path__ = '%s%s/' % (path, item.__name__)

                if isinstance(item, BaseContainer):
                    update_path(item)

        if isinstance(item, BaseContainer):
            update_path(item)

        get_current_registry().notify(event)

    def __delitem__(self, item, flush=True):
        """Delete a value from the container using the key."""

        if isinstance(item, string_types):
            item = self[item]

        if item.__parent_uri__ == self.__uri__:
            if isinstance(item, BaseContainer):
                for key in item.keys():
                    item.__delitem__(key, False)

            get_current_registry().notify(
                ptah.events.ContentDeletingEvent(item))

            name = item.__name__
            if self._v_keys:
                self._v_keys.remove(name)
            if self._v_items and name in self._v_items:
                del self._v_items[name]

            if item in Session:
                try:
                    Session.delete(item)
                    if flush:
                        Session.flush()
                except:
                    pass

            return

        raise KeyError(item)

    @action
    def create(self, tname, name, **params):
        tinfo = ptah.resolve(tname)
        if tinfo is None:
            raise NotFound('Type information is not found')

        tinfo.check_context(self)

        if '/' in name:
            raise Error("Names cannot contain '/'")

        if name.startswith(' '):
            raise Error("Names cannot starts with ' '")

        if name in self:
            raise Error("Name already in use.")

        self[name] = tinfo.create()
        content = self[name]
        content.update(**params)

        return content

    @action(permission=DeleteContent)
    def batchdelete(self, uris):
        """Batch delete"""
        raise NotImplements()  # pragma: no cover

    def info(self):
        info = super(BaseContainer, self).info()
        info['__container__'] = True
        return info