Exemple #1
0
class SQLFolderItems(SQLGatewayBase):
    """SQL folder items gateway"""

    __implements__ = SQLGatewayBase.__implements__

    schema = RowSequenceSchema()
    schema.add('key', 'string', 1)
    schema.add('oid', 'string')
    schema.add('classification', 'classification')
    table_name = 'folder_items'
    table_schema = RowSequenceSchema()
    table_schema.add('name', 'string', 1)
    table_schema.add('child_oid', 'int', 0)

    def load(self, event):
        table = self.get_table(event)
        rows = table.select(self.column_names, oid=event.oid)
        res = []
        h = []
        for name, child_oid in rows:
            s = str(child_oid)
            classification = event.classify(s)
            res.append((name, s, classification))
            h.append((name, long(child_oid)))
        h.sort()
        return res, tuple(h)

    def store(self, event, state):
        table = self.get_table(event)
        rows = [(name, long(child_oid)) for (name, child_oid, cls) in state]
        rows.sort()
        # Note that set_many() requires the child_oid column to match
        # its database type.
        table.set_many(event.oid, ('name', ), ('child_oid', ), rows)
        return tuple(rows)
Exemple #2
0
class SQLProperties(SQLGatewayBase):
    """SQL properties gateway
    """

    __implements__ = SQLGatewayBase.__implements__

    schema = RowSequenceSchema()
    schema.add('id', 'string', 1)
    schema.add('type', 'string')
    schema.add('data', 'string')
    table_name = 'properties'
    table_schema = RowSequenceSchema()
    table_schema.add('id', 'string', 1)
    table_schema.add('type', 'string', 0)
    table_schema.add('data', 'blob', 0)

    def load(self, event):
        table = self.get_table(event)
        rows = table.select(self.column_names, oid=event.oid)
        rows.sort()
        return rows, tuple(rows)

    def store(self, event, state):
        table = self.get_table(event)
        rows = [(id, t, data) for id, t, data in state]
        table.set_many(event.oid, ('id', ), ('type', 'data'), rows)
        state = list(state)
        state.sort()
        return tuple(state)
Exemple #3
0
 def __init__(self, conn_name='db'):
     self.conn_name = conn_name
     if self.table_schema is None:
         if self.schema is not None:
             self.table_schema = self.schema
         else:
             self.table_schema = RowSequenceSchema()
     self.column_names = [f.name for f in self.table_schema.get_columns()]
Exemple #4
0
 def init(self, event):
     conn = self.get_connection(event)
     for table_name, columns in self.table_defs.items():
         table_schema = RowSequenceSchema()
         for args in columns:
             table_schema.add(*args)
         table = conn.define_table(table_name, table_schema)
         if not conn.exists(table_name, 'table'):
             table.create()
         elif event.clear_all:
             table.delete_rows()
Exemple #5
0
 def init(self, event):
     conn = self.get_connection(event)
     for table_name, columns in self.table_defs.items():
         table_schema = RowSequenceSchema()
         for args in columns:
             table_schema.add(*args)
         table = conn.define_table(table_name, table_schema)
         if not conn.exists(table_name, 'table'):
             table.create()
         elif event.clear_all:
             table.delete_rows()
Exemple #6
0
class SQLGatewayBase:
    """SQL gateway base class"""

    __implements__ = IGateway, IDatabaseInitializer

    # override these in subclasses
    table_name = None
    schema = None
    table_schema = None
    oid_columns = [ColumnSchema('oid', 'int', 1)]

    def __init__(self, conn_name='db'):
        self.conn_name = conn_name
        if self.table_schema is None:
            if self.schema is not None:
                self.table_schema = self.schema
            else:
                self.table_schema = RowSequenceSchema()
        self.column_names = [f.name for f in self.table_schema.get_columns()]

    def get_connection(self, event):
        return event.connections[self.conn_name]

    def get_table(self, event):
        c = event.connections[self.conn_name]
        return c.get_table(self.table_name)

    def create(self, event):
        self.get_table(event).create()

    def init(self, event):
        conn = self.get_connection(event)
        assert IRDBMSConnection.isImplementedBy(conn)
        all = RowSequenceSchema(
            self.oid_columns + self.table_schema.get_columns())
        table = conn.define_table(self.table_name, all)
        if conn.exists(self.table_name, 'table'):
            if IDatabaseInitEvent.isImplementedBy(event) and event.clear_all:
                table.delete_rows()
        else:
            table.create()

    def load(self, event):
        raise NotImplementedError, "abstract method"

    def store(self, event, obj):
        raise NotImplementedError, "abstract method"

    def get_sources(self, event):
        return None
Exemple #7
0
class SQLSecurityAttributes(SQLGatewayBase):
    """SQL security attribute storage"""

    __implements__ = SQLGatewayBase.__implements__

    schema = RowSequenceSchema()
    schema.add('declaration_type', 'string')
    schema.add('role', 'string')
    schema.add('permission', 'string')
    schema.add('username', 'string')

    table_name = 'security'
    oid_columns = [ColumnSchema('oid', 'int', 0)]  # Don't create a primary key

    def load(self, event):
        table = self.get_table(event)
        items = table.select(self.column_names, oid=event.oid)
        items.sort()
        return items, tuple(items)

    def store(self, event, state):
        table = self.get_table(event)
        table.set_many(event.oid, (), self.column_names, state)
        state = list(state)
        state.sort()
        return tuple(state)
Exemple #8
0
class SQLObjectData(SQLGatewayBase):
    """SQL object data gateway"""

    __implements__ = SQLGatewayBase.__implements__

    schema = ColumnSchema('data', 'string')
    table_name = 'object_data'
    table_schema = RowSequenceSchema()
    table_schema.add('data', 'blob', 0)

    def load(self, event):
        table = self.get_table(event)
        firstcol = self.column_names[:1]
        items = table.select(firstcol, oid=event.oid)
        if items:
            state = str(items[0][0])
        else:
            state = ''
        return state, state

    def store(self, event, state):
        conn = self.get_connection(event)
        table = self.get_table(event)
        firstcol = self.column_names[:1]
        data = (state, )
        table.set_one(event.oid, firstcol, data, event.is_new)
        return state
Exemple #9
0
 def init(self, event):
     conn = self.get_connection(event)
     all = RowSequenceSchema(self.oid_columns +
                             self.table_schema.get_columns())
     table = conn.define_table(self.table_name, all)
     if not conn.exists(self.table_name, 'table'):
         table.create()
Exemple #10
0
class SQLClassification(SQLGatewayBase):

    __implements__ = SQLGatewayBase.__implements__

    schema = ColumnSchema('classification', 'classification')
    table_name = 'classification'
    table_schema = RowSequenceSchema()
    table_schema.add('class_name', 'string', 0)
    table_schema.add('mapper_name', 'string', 0)

    def load(self, event):
        table = self.get_table(event)
        rows = table.select(self.column_names, oid=event.oid)
        classification = {}
        if rows:
            rec = rows[0]
            if rec[0]:
                classification['class_name'] = rec[0]
            if rec[1]:
                classification['mapper_name'] = rec[1]
        else:
            raise KeyError(event.oid)
        return classification, rec

    def store(self, event, classification):
        conn = self.get_connection(event)
        table = self.get_table(event)
        row = (classification.get('class_name',
                                  ''), classification.get('mapper_name', ''))
        try:
            table.set_one(event.oid, self.column_names, row, event.is_new)
        except conn.module.DatabaseError:
            raise OIDConflictError(event.oid)
        return row
Exemple #11
0
class SQLItemId(SQLGatewayBase):
    """SQL item ID gateway.

    Piggybacks SQLFolderItems for init and store.
    Makes the assumption that the item is stored in only one place.
    """

    __implements__ = SQLGatewayBase.__implements__

    schema = ColumnSchema('id', 'string')
    table_name = 'folder_items'
    table_schema = RowSequenceSchema()
    table_schema.add('child_oid', 'int', 1)
    table_schema.add('name', 'string', 0)

    def init(self, event):
        pass

    def load(self, event):
        table = self.get_table(event)
        rows = table.select(('name', ), child_oid=event.oid)
        if len(rows) >= 1:
            name = rows[0][0]  # Accept only the first result
        else:
            name = None
        # Disable conflict checking by returning None as the hash value.
        return name, None

    def store(self, event, state):
        return None
Exemple #12
0
class SQLModTime(SQLGatewayBase):
    """SQL object mod time gateway"""

    __implements__ = SQLGatewayBase.__implements__

    schema = ColumnSchema('mtime', 'int')  # second
    table_name = 'mtime'
    table_schema = RowSequenceSchema()
    table_schema.add('mtime', 'long', 0)

    def load(self, event):
        table = self.get_table(event)
        items = table.select(self.column_names, oid=event.oid)
        if items:
            state = long(items[0][0])
        else:
            state = 0L
        return state, state

    def store(self, event, state):
        state = long(state)
        table = self.get_table(event)
        data = (state, )
        table.set_one(event.oid, self.column_names, data, event.is_new)
        return state
Exemple #13
0
class SQLRemainder(SQLObjectData):
    """SQL remainder pickle gateway"""

    __implements__ = SQLGatewayBase.__implements__

    table_name = 'remainder'
    table_schema = RowSequenceSchema()
    table_schema.add('pickle', 'blob', 0)
Exemple #14
0
class ZSQLMethodPropertiesSerializer:
    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.add('id', 'string', 1)
    schema.add('type', 'string')
    schema.add('data', 'string')

    attributes = {
        'title': str,
        'connection_id': str,
        'max_rows_': int,
        'max_cache_': int,
        'cache_time': int, 
        'class_name_': str, 
        'class_file_': str,
        'zclass': str, # XXX, what's that 
        'allow_simple_one_argument_traversal': int,
        'connection_hook': str, 
    }

    def can_serialize(self, obj):
        return isinstance(obj, SQL)

    def serialize(self, event):
        obj = event.obj
        assert isinstance(obj, SQL)
        res = []
        for attribute, factory in self.attributes.items():
            if not hasattr(obj, attribute):
                continue
            value = getattr(obj, attribute)
            t = factory.__name__
            if value is None:
                if factory in (int, long):
                    value = 0
                else: 
                    value = ''
            value = str(value)
            event.serialized(attribute, value, 1)
            res.append((attribute, t, value))
        event.ignore('_col') 
        return res 

    def deserialize(self, event, state):
        obj = event.obj
        assert isinstance(obj, SQL)
        for attribute, t, value in state:
            factory = self.attributes.get(attribute)
            if factory is None:
                continue
            value = factory(value)
            setattr(obj, attribute, value)
            event.deserialized(attribute, value)
        if not hasattr(obj, 'connection_id'):
            obj.connection_id = ''
Exemple #15
0
 def init(self, event):
     conn = self.get_connection(event)
     assert IRDBMSConnection.isImplementedBy(conn)
     all = RowSequenceSchema(
         self.oid_columns + self.table_schema.get_columns())
     table = conn.define_table(self.table_name, all)
     if conn.exists(self.table_name, 'table'):
         if IDatabaseInitEvent.isImplementedBy(event) and event.clear_all:
             table.delete_rows()
     else:
         table.create()
Exemple #16
0
    def get_schema_for_class(self, module_name, class_name):
        """Returns the class-defined property schema.

        This Zope2-ism should be made pluggable later on.
        """
        d = {}
        m = __import__(module_name, d, d, ('__doc__', ))
        klass = getattr(m, class_name)
        schema = RowSequenceSchema()
        props = getattr(klass, '_properties', ())
        if not props:
            return None
        for p in props:
            if not safe_property_types.has_key(p['type']):
                # Don't store this property in its own column.
                # It is of a type that's hard to convert faithfully.
                continue
            prop_name = p['id']
            if prop_name == 'oid':
                name = '_oid'
            else:
                name = prop_name
            schema.add(name, p['type'], 0)
        return schema
Exemple #17
0
    def get_schema_for_class(self, module_name, class_name):
        """Returns the class-defined property schema.

        This Zope2-ism should be made pluggable later on.
        """
        d = {}
        m = __import__(module_name, d, d, ('__doc__',))
        klass = getattr(m, class_name)
        schema = RowSequenceSchema()
        props = getattr(klass, '_properties', ())
        if not props:
            return None
        for p in props:
            if not safe_property_types.has_key(p['type']):
                # Don't store this property in its own column.
                # It is of a type that's hard to convert faithfully.
                continue
            prop_name = p['id']
            if prop_name == 'oid':
                name = '_oid'
            else:
                name = prop_name
            schema.add(name, p['type'], 0)
        return schema
Exemple #18
0
class BTreeFolder2Items:
    """BTreeFolder2 items (de)serializer
    """
    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.add('key', 'string', 1)
    schema.add('oid', 'string')
    schema.add('classification', 'classification')

    def can_serialize(self, obj):
        return hasattr(obj, '_tree')

    def serialize(self, event):
        obj = event.obj
        assert self.can_serialize(obj)
        state = []
        event.ignore('_objects')
        d = obj._tree
        event.ignore(('_tree', '_mt_index', '_count'))
        for id in obj.objectIds():
            base = d[id]
            oid = event.obj_db.identify(base)
            if oid is None:
                oid = event.obj_db.new_oid()
            event.referenced(id, base, True, oid)
            # No need to pass classification.
            state.append((id, oid, None))
        # The structure that makes up the BTree (the root node and
        # the buckets) are unmanaged.  Tell the event about them.
        event.upos.extend(find_unmanaged(obj._tree, obj._tree.values()))
        return state

    def deserialize(self, event, state):
        obj = event.obj
        if hasattr(obj, '_initBTrees'):
            # Version 1.0.1+ of BTreeFolder2
            obj._initBTrees()
        else:
            # Crufty workaround for older versions
            obj.__init__(obj.id)
        assert self.can_serialize(obj)
        for (id, oid, classification) in state:
            subob = event.resolve(id, oid, classification)
            obj._setOb(id, subob)
        # The tree and the buckets are unmanaged.
        event.upos.extend(find_unmanaged(obj._tree, obj._tree.values()))
Exemple #19
0
class FSDirectoryItems(FSGatewayBase):
    """Read/write objects in a filesystem directory."""

    __implements__ = IGateway

    schema = RowSequenceSchema()
    schema.add('key', 'string', 1)
    schema.add('oid', 'string')
    schema.add('classification', 'classification')

    def load(self, event):
        c = self.get_connection(event)
        if c.read_node_type(event.oid) != 'd':
            raise LoadError("Not a directory")
        data = list(c.read_directory(event.oid))
        data.sort()
        # Assign OIDs to previously existing subobjects.
        assigned = {}
        for objname, child_oid in data:
            if child_oid is None:
                child_oid = event.conf.oid_gen.new_oid(event)
                assigned[objname] = child_oid
        if assigned:
            # Saw existing objects.  Tell the connection what their OIDs are.
            c.assign_existing(event.oid, assigned.items())
        # Return the results.
        res = []
        hash_value = []
        for objname, child_oid in data:
            if child_oid is None:
                child_oid = assigned[objname]
            classification = event.classify(child_oid)
            # Return info about each subobject.
            res.append((objname, child_oid, classification))
            hash_value.append((objname, child_oid))
        return res, tuple(hash_value)

    def store(self, event, state):
        c = self.get_connection(event)
        c.write_node_type(event.oid, 'd')
        data = []
        for objname, child_oid, classification in state:
            data.append((objname, child_oid))
        data.sort()
        c.write_directory(event.oid, data)
        return tuple(data)
Exemple #20
0
class UserFolderSerializer:
    """Serializer for a user folder.

    This version lets the application keep a list of all users in RAM.
    """

    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.add('id', 'string', 1)
    schema.add('password', 'string')
    schema.add('roles', 'string:list')
    schema.add('domains', 'string:list')

    def can_serialize(self, obj):
        return isinstance(obj, UserFolder)

    def serialize(self, event):
        obj = event.obj
        assert isinstance(obj, UserFolder), repr(obj)
        state = []
        event.ignore('data')
        for id, user in obj.data.items():
            assert isinstance(user, User), repr(user)
            assert len(user.__dict__.keys()) == 4, user.__dict__.keys()
            r = list(user.roles)
            r.sort()
            d = list(user.domains)
            d.sort()
            state.append((id, user.__, tuple(r), tuple(d)))
            event.serialized(id, user, 0)
        event.upos.append(obj.data)
        event.upos.extend(obj.data.values())
        return state

    def deserialize(self, event, state):
        obj = event.obj
        assert isinstance(obj, UserFolder)
        obj.data = PersistentMapping()
        for id, password, roles, domains in state:
            user = User(id, password, roles, domains)
            obj.data[id] = user
            event.deserialized(id, user)
        event.upos.append(obj.data)
        event.upos.extend(obj.data.values())
Exemple #21
0
class FolderItems:
    """Zope 2 folder items (de)serializer
    """
    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.add('key', 'string', 1)
    schema.add('oid', 'string')
    schema.add('classification', 'classification')

    def can_serialize(self, obj):
        return isinstance(obj, ObjectManager)

    def serialize(self, event):
        obj = event.obj
        assert isinstance(obj, ObjectManager), repr(obj)
        state = []
        event.ignore('_objects')
        d = obj.__dict__
        for id in obj.objectIds():
            if d.has_key(id):
                base = d[id]
            else:
                # Fall back to _getOb.
                base = aq_base(obj._getOb(id))
            oid = event.obj_db.identify(base)
            if oid is None:
                oid = event.obj_db.new_oid()
            event.referenced(id, base, True, oid)
            # No need to pass classification.
            state.append((id, oid, None))
        return state

    def deserialize(self, event, state):
        obj = event.obj
        assert isinstance(obj, ObjectManager), obj
        for (id, oid, classification) in state:
            subob = event.resolve(id, oid, classification)
            obj._setOb(id, subob)
            obj._objects += ({
                'id': id,
                'meta_type': subob.__class__.meta_type,
            }, )
Exemple #22
0
class FSProperties(FSGatewayBase):
    """Simple properties to filesystem properties annotation gateway.
    """

    __implements__ = IGateway

    schema = RowSequenceSchema()
    schema.add('id', 'string', 1)
    schema.add('type', 'string')
    schema.add('data', 'string')

    def __init__(self, annotation='properties', conn_name='fs'):
        self.annotation = str(annotation)
        FSGatewayBase.__init__(self, conn_name)

    def load(self, event):
        fs_conn = self.get_connection(event)
        text = fs_conn.read_annotation(event.oid, self.annotation, '')
        res = []
        if text:
            lines = text.split('\n')
            for line in lines:
                if '=' in line:
                    k, v = line.split('=', 1)
                    if ':' in k:
                        k, t = k.split(':', 1)
                    else:
                        t = 'string'
                    res.append((k, t, unescape_string(v)))
        res.sort()
        return res, tuple(res)

    def store(self, event, state):
        lines = []
        for k, t, v in state:
            lines.append('%s:%s=%s' % (k, t, escape_string(v)))
        lines.sort()
        text = '\n'.join(lines)
        fs_conn = self.get_connection(event)
        fs_conn.write_annotation(event.oid, self.annotation, text)
        state = list(state)
        state.sort()
        return tuple(state)
Exemple #23
0
class SecurityAttributes:
    """Zope 2 security attribute serializer."""

    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.add('declaration_type', 'string')
    schema.add('role', 'string')
    schema.add('permission', 'string')
    schema.add('username', 'string')

    def can_serialize(self, obj):
        return 1

    def serialize(self, event):
        res = []

        # Get security attributes from the instance only, not the class.
        # There's no need to serialize the class attributes.
        obj_d = event.obj.__dict__
        eo = obj_d.get('_owner')
        if eo is not None:
            event.ignore('_owner')
            path, username = eo
            if '/' in username:
                raise ValueError, '/ not allowed in user names'
            s = '%s/%s' % ('/'.join(path), username)
            res.append(('executable-owner', '', '', s))

        roles = obj_d.get('__ac_roles__')
        if roles is not None:
            event.ignore('__ac_roles__')
            roles = list(roles)
            roles.sort()
            class_roles = getattr(event.obj.__class__, '__ac_roles__', None)
            if class_roles:
                class_roles = list(class_roles)
                class_roles.sort()
            if roles != class_roles:
                for role in roles:
                    res.append(('define-role', role, '', ''))
            # else inherit roles from the class

        local_roles = obj_d.get('__ac_local_roles__')
        if local_roles is not None:
            event.ignore('__ac_local_roles__')
            for username, roles in local_roles.items():
                for role in roles:
                    res.append(('local-role', role, '', username))

        proxy_roles = obj_d.get('_proxy_roles')
        if proxy_roles is not None:
            event.ignore('_proxy_roles')
            for role in proxy_roles:
                res.append(('proxy-role', role, '', ''))

        p_dict = None
        for attr, value in obj_d.items():
            if attr.endswith('_Permission') and attr.startswith('_'):
                if p_dict is None:
                    p_dict = get_permission_dict()
                p = p_dict.get(attr)
                if p is not None:
                    event.ignore(attr)
                    for role in value:
                        res.append(('permission-role', role, p, ''))
                    # List means acquired, tuple means not acquired.
                    if isinstance(value, TupleType):
                        res.append(('permission-no-acquire', '', p, ''))

        return res

    def deserialize(self, event, state):
        local_roles = {}  # { username -> [role,] }
        defined_roles = []  # [role,]
        proxy_roles = []  # [role,]
        permission_roles = {}  # { permission -> [role,] }
        permission_acquired = {}  # { permission -> 0 or 1 }

        obj = event.obj
        for decl_type, role, permission, username in state:
            if decl_type == 'executable-owner':
                assert not role
                assert not permission
                #assert username
                pos = username.rfind('/')
                if pos < 0:
                    # Default to the root folder
                    ufolder = ['acl_users']
                    uname = username
                else:
                    ufolder = list(username[:pos].split('/'))
                    uname = username[pos + 1:]
                assert ufolder
                assert uname
                obj._owner = (ufolder, uname)

            elif decl_type == 'local-role':
                #assert role
                assert not permission
                #assert username
                r = local_roles.get(username)
                if r is None:
                    r = []
                    local_roles[username] = r
                r.append(role)

            elif decl_type == 'define-role':
                #assert role
                assert not permission
                assert not username
                defined_roles.append(role)

            elif decl_type == 'proxy-role':
                #assert role
                assert not permission
                assert not username
                proxy_roles.append(role)

            elif decl_type == 'permission-role':
                #assert role
                #assert permission
                assert not username
                r = permission_roles.get(permission)
                if r is None:
                    r = []
                    permission_roles[permission] = r
                r.append(role)
                if not permission_acquired.has_key(permission):
                    permission_acquired[permission] = 1

            elif decl_type == 'permission-no-acquire':
                assert not role
                #assert permission
                assert not username
                permission_acquired[permission] = 0

            else:
                raise ValueError, ('declaration_type %s unknown' %
                                   repr(decl_type))

        if local_roles:
            obj.__ac_local_roles__ = local_roles
        if defined_roles:
            defined_roles.sort()
            obj.__ac_roles__ = tuple(defined_roles)
        if proxy_roles:
            obj._proxy_roles = tuple(proxy_roles)

        for p, acquired in permission_acquired.items():
            roles = permission_roles.get(p, [])
            if not acquired:
                roles = tuple(roles)
            setattr(obj, pname(p), roles)
Exemple #24
0
class PersistentMappingSerializer:
    """(de)serializer of a persistent mapping that uses string keys.

    Serializes both references and second-class persistent objects.
    Because of this flexibility, the schema is a little complex.
    """
    __implements__ = ISerializer

    # This schema includes both a list of items that are references to
    # persistent objects and a pickle containing items that are not
    # references.
    schema1 = RowSequenceSchema()
    schema1.add('key', 'string', 1)
    schema1.add('oid', 'string')
    schema1.add('classification', 'classification')
    schema2 = ColumnSchema('data', 'string')
    schema = {'references': schema1, 'others': schema2}

    def can_serialize(self, obj):
        return isinstance(obj, PersistentMapping)

    def serialize(self, event):
        assert self.can_serialize(event.obj)
        refs = []
        others = {}
        for key, value in event.obj.items():
            if is_persistent(value):
                oid = event.obj_db.identify(value)
                if oid is None:
                    oid = event.obj_db.new_oid()
                event.referenced(key, value, False, oid)
                # No need to pass classification.
                refs.append((key, oid, None))
            else:
                event.serialized(key, value, False)
                others[key] = value
        event.ignore(('data', '_container'))
        if others:
            # Encode as a sorted list to preserve order.
            others_list = others.items()
            others_list.sort()
            s = encode_to_text(dumps(others_list, 1), others.keys())
        else:
            s = ''
        return {'references': refs, 'others': s}

    def deserialize(self, event, state):
        assert self.can_serialize(event.obj)
        data_dict = {}
        s = state['others']
        if s:
            s = decode_from_text(s)
            if s:
                data = loads(s)
                if hasattr(data, 'items'):
                    # Stored as a dictionary
                    data_list = data.items()
                    data_dict = data
                else:
                    # Stored as a sequence of tuples
                    data_list = data
                    for key, value in data:
                        data_dict[key] = value
                for key, value in data_list:
                    event.deserialized(key, value)
        for (key, oid, classification) in state['references']:
            value = event.resolve(key, oid, classification)
            data_dict[key] = value
        event.obj.__init__(data_dict)
Exemple #25
0
class OFSProperties:
    """Serializer for OFS.PropertyManager properties."""

    __implements__ = ISerializer

    schema = RowSequenceSchema()
    schema.add('id', 'string', 1)
    schema.add('type', 'string')
    schema.add('data', 'string')

    def can_serialize(self, obj):
        return isinstance(obj, PropertyManager)

    def serialize(self, event):
        res = []
        obj = event.obj
        assert isinstance(obj, PropertyManager), repr(obj)
        assert obj._properties is obj._propertyMap()
        event.ignore('_properties')
        for p in obj._properties:
            name = p['id']
            t = p['type']
            event.ignore(name)
            data = obj.getProperty(name)
            if t == 'lines':
                v = '\n'.join(data)
            elif t == 'boolean':
                v = data and '1' or '0'
            elif string_repr_types.get(t):
                v = str(data)
            else:
                # Pickle the value and any extra info about the property.
                # Extra info is present in select and multi-select properties.
                d = p.copy()
                del d['id']
                del d['type']
                if d.has_key('mode'):
                    del d['mode']
                d['value'] = data
                v = dumps(d)
            res.append((name, t, v))
        return res

    def deserialize(self, event, state):
        obj = event.obj
        assert isinstance(obj, PropertyManager)
        assert obj._properties is obj._propertyMap()
        if not state:
            # No stored properties.  Revert the object to its
            # class-defined property schema.
            if obj.__dict__.has_key('_properties'):
                del obj._properties
            return

        old_props = obj.propdict()
        new_props = {}
        for id, t, v in state:
            p = old_props.get(id)
            if p is None:
                p = {'mode': 'wd'}
            else:
                p = p.copy()
            p['id'] = id
            p['type'] = t
            if v and not string_repr_types.get(t) and t != 'lines':
                # v is a pickle.
                # Check the pickle for extra property info.
                d = loads(v)
                if isinstance(d, DictType):
                    del d['value']
                    if d:
                        # The data is stored with extra property info.
                        p.update(d)
            new_props[id] = p

        if old_props != new_props:
            obj._properties = tuple(new_props.values())

        for id, t, v in state:
            if t == 'lines':
                data = v.split('\n')
            elif t == 'boolean':
                # match 0, [f]alse, [n]o
                if (not v or v == '0' or v[:1].lower() in 'fn'):
                    data = 0
                else:
                    data = 1
            elif string_repr_types.get(t):
                data = str(v)
            elif v:
                d = loads(v)
                if isinstance(d, DictType):
                    # The data is stored with extra property info.
                    data = d['value']
                else:
                    data = d
            else:
                # Fall back to a default.
                data = ''
            obj._updateProperty(id, data)
Exemple #26
0
class SQLUserList(SQLGatewayBase):
    """Stores and retrieves all users for a folder at once."""

    __implements__ = SQLGatewayBase.__implements__

    schema = RowSequenceSchema()
    schema.add('id', 'string', 1)
    schema.add('password', 'string')
    schema.add('roles', 'string:list')
    schema.add('domains', 'string:list')

    table_defs = {
        'users': [('oid', 'int', 1), ('id', 'string', 1),
                  ('password', 'string', 0)],
        'user_roles': [('oid', 'int', 0), ('id', 'string', 0),
                       ('role', 'string', 0)],
        'user_domains': [('oid', 'int', 0), ('id', 'string', 0),
                         ('domain', 'string', 0)],
    }

    def init(self, event):
        conn = self.get_connection(event)
        for table_name, columns in self.table_defs.items():
            table_schema = RowSequenceSchema()
            for args in columns:
                table_schema.add(*args)
            table = conn.define_table(table_name, table_schema)
            if not conn.exists(table_name, 'table'):
                table.create()
            elif event.clear_all:
                table.delete_rows()

    def load(self, event):
        conn = self.get_connection(event)
        rows = conn.get_table('users').select(('id', 'password'),
                                              oid=event.oid)
        data = {}
        for id, password in rows:
            data[id] = (password, [], [])
        rows = conn.get_table('user_roles').select(('id', 'role'),
                                                   oid=event.oid)
        for id, role in rows:
            row = data.get(id)
            if row is not None:
                row[1].append(role)
        rows = conn.get_table('user_domains').select(('id', 'domain'),
                                                     oid=event.oid)
        for id, domain in rows:
            row = data.get(id)
            if row is not None:
                row[2].append(domain)
        records = []
        for id, (password, roles, domains) in data.items():
            roles = list(roles)
            roles.sort()
            domains = list(domains)
            domains.sort()
            records.append((id, password, tuple(roles), tuple(domains)))
        records.sort()
        return records, tuple(records)

    def store(self, event, state):
        oid = event.oid
        conn = self.get_connection(event)
        rows = [(id, pw) for id, pw, roles, domains in state]
        conn.get_table('users').set_many(event.oid, (), (
            'id',
            'password',
        ), rows)
        roles_d = {}
        domains_d = {}
        for id, pw, roles, domains in state:
            for role in roles:
                roles_d[(id, role)] = 1
            for domain in domains:
                domains_d[(id, domain)] = 1
        conn.get_table('user_roles').set_many(event.oid, (), (
            'id',
            'role',
        ), roles_d.keys())
        conn.get_table('user_domains').set_many(event.oid, (), (
            'id',
            'domain',
        ), domains_d.keys())
        state = list(state)
        state.sort()
        return tuple(state)
Exemple #27
0
class FSSecurityAttributes(FSGatewayBase):
    """Gateway for storing security attributes."""

    __implements__ = IGateway

    schema = RowSequenceSchema()
    schema.add('declaration_type', 'string')
    schema.add('role', 'string')
    schema.add('permission', 'string')
    schema.add('username', 'string')

    def __init__(self, annotation='security', conn_name='fs'):
        self.annotation = annotation
        FSGatewayBase.__init__(self, conn_name)

    def load(self, event):
        fs_conn = self.get_connection(event)
        text = fs_conn.read_annotation(event.oid, self.annotation, '')
        res = []
        if text:
            lines = text.split('\n')
            for line in lines:
                line = line.strip()
                if not line or line.startswith('#'):
                    continue
                params = string_to_params(line)
                if params:
                    decl_type = params[0][0]
                    row = [decl_type, '', '', '']
                    for k, v in params[1:]:
                        k = k.lower()
                        if '_' in k:
                            # temporary backward compatibility
                            k = k.split('_', 1)[0]
                        if k == 'role':
                            row[1] = v
                        elif k == 'permission':
                            row[2] = v
                        elif k == 'username':
                            row[3] = v
                        else:
                            raise ValueError(
                                "Could not read security declaration "
                                "%s for %s" % (repr(line), repr(event.oid)))
                    res.append(tuple(row))
        res.sort()
        return res, tuple(res)

    def store(self, event, state):
        lines = []
        for d, r, p, u in state:
            params = [(d, '')]
            if r:
                params.append(('role', r))
            if p:
                params.append(('permission', p))
            if u:
                params.append(('username', u))
            s = params_to_string(params)
            lines.append(s)
        if lines:
            lines.sort()
            text = '\n'.join(lines)
            fs_conn = self.get_connection(event)
            fs_conn.write_annotation(event.oid, self.annotation, text)
        state = list(state)
        state.sort()
        return tuple(state)
Exemple #28
0
class FSUserList(FSGatewayBase):
    """User list gateway, where the user list is stored in a flat file."""

    __implements__ = IGateway

    schema = RowSequenceSchema()
    schema.add('id', 'string', 1)
    schema.add('password', 'string')
    schema.add('roles', 'string:list')
    schema.add('domains', 'string:list')

    def load(self, event):
        c = self.get_connection(event)
        assert c.read_node_type(event.oid) == 'f'
        text = c.read_data(event.oid)
        res = []
        for line in text.split('\n'):
            L = line.strip()
            if not L.startswith('#') and ':' in L:
                id, password, rolelist, domainlist = L.split(':', 3)
                roles = self._split_list(rolelist)
                domains = self._split_list(domainlist)
                res.append((id, password, roles, domains))
        res.sort()
        return res, text

    def _split_list(self, s):
        return tuple([item.strip() for item in s.split(',') if item])

    def _join_list(self, items):
        for item in items:
            if item.strip() != item:
                raise MappingError(
                    "Leading and trailing whitespace are not allowed "
                    "in roles and domains")
            item = item.strip()
            if not item:
                raise MappingError("Empty role or domain not allowed")
            if ',' in item or ':' in item or '\n' in item:
                raise MappingError(
                    "Commas, colons, and newlines are not allowed "
                    "in roles and domains")
        return ','.join(items)

    def store(self, event, state):
        replace_lines = {}
        for id, password, roles, domains in state:
            if ':' in id or '\n' in id:
                raise MappingError('User IDs cannot have colons or newlines')
            if id.startswith('#'):
                raise MappingError('User IDs cannot start with #')
            if ':' in password or '\n' in password:
                raise MappingError('Passwords cannot have colons or newlines')
            rolelist = self._join_list(roles)
            domainlist = self._join_list(domains)
            to_write = '%s:%s:%s:%s' % (id, password, rolelist, domainlist)
            replace_lines[id] = to_write
        oid = event.oid
        fs_conn = self.get_connection(event)
        fs_conn.write_node_type(oid, 'f')
        # Read the existing text only to maintain the current order.
        text = fs_conn.read_data(oid, allow_missing=1)
        if text is None:
            text = ''
        new_lines = []
        # Replace / remove users
        for line in text.split('\n'):
            L = line.strip()
            if not L.startswith('#'):
                if ':' in L:
                    name, stuff = L.split(':', 1)
                    replace = replace_lines.get(name, '')
                    if replace and replace != L:
                        new_lines.append(replace)
                        del replace_lines[name]
                # else remove the line
            else:
                new_lines.append(line)
        # Append new users
        for line in replace_lines.values():
            new_lines.append(line)
        # Write it
        text = '\n'.join(new_lines)
        fs_conn.write_data(oid, text)
        serial = list(state)
        serial.sort()
        return text
Exemple #29
0
class SQLMultiTableProperties(SQLGatewayBase):
    """Combines fixed and variable properties.
    """

    __implements__ = IGateway, IDatabaseInitializer

    schema = SQLProperties.schema

    table_name = 'property_tables'
    table_schema = RowSequenceSchema()
    table_schema.add('class_name', 'string', 1)
    table_schema.add('table_name', 'string', 0)
    oid_columns = []  # No OID column

    def __init__(self, conn_name='db'):
        self.var_props = SQLProperties(conn_name=conn_name)
        self.fixed_props = {}  # class name -> SQLFixedProperties instance
        SQLGatewayBase.__init__(self, conn_name)

    def get_sources(self, event):
        return None

    def init(self, event):
        conn = self.get_connection(event)
        table = conn.define_table(self.table_name, self.table_schema)
        if not conn.exists(self.table_name, 'table'):
            table.create()
        self.var_props.init(event)
        if event.clear_all:
            # Clear the fixed property tables.
            recs = table.select(('table_name', ))
            for (name, ) in recs:
                conn.clear_table(name)
            self.fixed_props = {}

    def get_schema_for_class(self, module_name, class_name):
        """Returns the class-defined property schema.

        This Zope2-ism should be made pluggable later on.
        """
        d = {}
        m = __import__(module_name, d, d, ('__doc__', ))
        klass = getattr(m, class_name)
        schema = RowSequenceSchema()
        props = getattr(klass, '_properties', ())
        if not props:
            return None
        for p in props:
            if not safe_property_types.has_key(p['type']):
                # Don't store this property in its own column.
                # It is of a type that's hard to convert faithfully.
                continue
            prop_name = p['id']
            if prop_name == 'oid':
                name = '_oid'
            else:
                name = prop_name
            schema.add(name, p['type'], 0)
        return schema

    def get_fixed_props(self, event):
        """Returns a SQLFixedProperties instance or None.
        """
        classification = event.classification
        if classification is None:
            return None
        cn = classification.get('class_name')
        if cn is None:
            return None
        if self.fixed_props.has_key(cn):
            return self.fixed_props[cn]  # May be None

        # Gather info about the class
        pos = cn.rfind('.')
        if pos < 0:
            raise ValueError, "Not a qualified class name: %s" % repr(cn)
        module_name = cn[:pos]
        class_name = cn[pos + 1:]
        schema = self.get_schema_for_class(module_name, class_name)
        if schema is None or not schema.get_columns():
            # No fixed properties exist for this class.
            self.fixed_props[cn] = None
            return None

        # Allocate a table name
        conn = self.get_connection(event)
        table = self.get_table(event)
        rows = table.select(('table_name', ), class_name=cn)
        if rows:
            table_name = rows[0][0]
        else:
            attempt = 0
            while 1:
                # Find an available table name.
                table_name = '%s_properties' % (class_name[:16])
                if attempt:
                    table_name += '_%02d' % attempt
                if not conn.exists(table_name, 'table'):
                    break
                attempt += 1
            table.insert(('class_name', 'table_name'), (cn, table_name))

        # Create the fixed properties and table
        fp = SQLFixedProperties(self.conn_name, table_name, schema)
        fp.init(event)
        # XXX If the transaction gets aborted, the table creation will
        # be undone, but self.fixed_props won't see the change.
        # Perhaps we need to reset self.fixed_props on abort.
        self.fixed_props[cn] = fp
        return fp

    def load(self, event):
        """Returns a combination of states from two tables."""
        var_state, var_hash = self.var_props.load(event)
        fp = self.get_fixed_props(event)
        if fp is None:
            return var_state, var_hash
        fixed_state, fixed_hash = fp.load(event)
        # Merge fixed_state and var_state, letting fixed_state
        # override var_state except when the value in fixed_state is
        # None.
        res = []
        placement = {}  # property name -> placement in results
        for rec in fixed_state:
            placement[rec[0]] = len(res)
            res.append(rec)
        for rec in var_state:
            index = placement.get(rec[0])
            if index is None:
                res.append(rec)
            elif res[index][2] is None:
                # override the fixed value, since it was None.
                res[index] = rec
        return res, (fixed_hash, var_hash)

    def store(self, event, state):
        """Stores state in two tables."""
        fp = self.get_fixed_props(event)
        if fp is None:
            return self.var_props.store(event, state)
        # Store the fixed state first and find out what got left over.
        leftover = {}
        state = list(state)
        state.sort()
        fixed_hash = fp.store(event, state, leftover=leftover)
        if leftover:
            var_state = []
            for prop_name, (typ, value) in leftover.items():
                var_state.append((prop_name, typ, value))
            var_hash = self.var_props.store(event, var_state)
        else:
            var_hash = ()
        return (fixed_hash, var_hash)