Add function to list public paths.
authorAntony Chazapis <chazapis@gmail.com>
Thu, 16 Feb 2012 12:27:51 +0000 (14:27 +0200)
committerAntony Chazapis <chazapis@gmail.com>
Thu, 16 Feb 2012 12:27:51 +0000 (14:27 +0200)
pithos/api/functions.py
pithos/backends/base.py
pithos/backends/lib/sqlalchemy/public.py
pithos/backends/lib/sqlite/public.py
pithos/backends/modular.py

index 8c94921..3e9cd2c 100644 (file)
@@ -537,57 +537,23 @@ def object_list(request, v_account, v_container):
         objects = request.backend.list_object_meta(request.user_uniq, v_account,
                                     v_container, prefix, delimiter, marker,
                                     limit, virtual, 'pithos', keys, shared, until)
+        object_permissions = {}
+        object_public = {}
+        if until is None:
+            name_idx = len('/'.join((v_account, v_container, '')))
+            for x in request.backend.list_object_permissions(request.user_uniq,
+                                    v_account, v_container, prefix):
+                object = x[name_idx:]
+                object_permissions[object] = request.backend.get_object_permissions(
+                                    request.user_uniq, v_account, v_container, object)
+            for k, v in request.backend.list_object_public(request.user_uniq,
+                                    v_account, v_container, prefix).iteritems():
+                object_public[k[name_idx:]] = v
     except NotAllowedError:
         raise Forbidden('Not allowed')
     except NameError:
         raise ItemNotFound('Container does not exist')
     
-#     object_meta = []
-#     for x in objects:
-#         if x[1] is None:
-#             # Virtual objects/directories.
-#             object_meta.append({'subdir': x[0]})
-#         else:
-#             try:
-#                 meta = request.backend.get_object_meta(request.user_uniq, v_account,
-#                                                         v_container, x[0], 'pithos', x[1])
-#                 if until is None:
-#                     permissions = request.backend.get_object_permissions(
-#                                     request.user_uniq, v_account, v_container, x[0])
-#                     public = request.backend.get_object_public(request.user_uniq,
-#                                                 v_account, v_container, x[0])
-#                 else:
-#                     permissions = None
-#                     public = None
-#             except NotAllowedError:
-#                 raise Forbidden('Not allowed')
-#             except NameError:
-#                 pass
-#             else:
-#                 rename_meta_key(meta, 'hash', 'x_object_hash') # Will be replaced by checksum.
-#                 rename_meta_key(meta, 'checksum', 'hash')
-#                 rename_meta_key(meta, 'type', 'content_type')
-#                 rename_meta_key(meta, 'uuid', 'x_object_uuid')
-#                 rename_meta_key(meta, 'modified', 'last_modified')
-#                 rename_meta_key(meta, 'modified_by', 'x_object_modified_by')
-#                 rename_meta_key(meta, 'version', 'x_object_version')
-#                 rename_meta_key(meta, 'version_timestamp', 'x_object_version_timestamp')
-#                 m = dict([(k[14:], v) for k, v in meta.iteritems() if k.startswith('X-Object-Meta-')])
-#                 for k in m:
-#                     del(meta['X-Object-Meta-' + k])
-#                 if m:
-#                     meta['X-Object-Meta'] = printable_header_dict(m)
-#                 update_sharing_meta(request, permissions, v_account, v_container, x[0], meta)
-#                 update_public_meta(public, meta)
-#                 object_meta.append(printable_header_dict(meta))
-#     if request.serialization == 'xml':
-#         data = render_to_string('objects.xml', {'container': v_container, 'objects': object_meta})
-#     elif request.serialization  == 'json':
-#         data = json.dumps(object_meta, default=json_encode_decimal)
-#     response.status_code = 200
-#     response.content = data
-#     return response
-    
     object_meta = []
     for meta in objects:
         if len(meta) == 1:
@@ -605,6 +571,12 @@ def object_list(request, v_account, v_container):
             rename_meta_key(meta, 'modified_by', 'x_object_modified_by')
             rename_meta_key(meta, 'version', 'x_object_version')
             rename_meta_key(meta, 'version_timestamp', 'x_object_version_timestamp')
+            permissions = object_permissions.get(meta['name'], None)
+            if permissions:
+                update_sharing_meta(request, permissions, v_account, v_container, meta['name'], meta)
+            public = object_public.get(meta['name'], None)
+            if public:
+                update_public_meta(public, meta)
             object_meta.append(printable_header_dict(meta))
     if request.serialization == 'xml':
         data = render_to_string('objects.xml', {'container': v_container, 'objects': object_meta})
index 2f4119c..57a7eb8 100644 (file)
@@ -325,9 +325,26 @@ class BaseBackend(object):
         
         Same parameters with list_objects. Returned dicts have no user-defined
         metadata and, if until is not None, a None 'modified' timestamp.
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+            
+            NameError: Container does not exist
         """
         return []
     
+    def list_object_permissions(self, user, account, container, prefix=''):
+        """Return a list of paths that enforce permissions under a container.
+        
+        Raises:
+            NotAllowedError: Operation not permitted
+        """
+        return []
+    
+    def list_object_public(self, user, account, container, prefix=''):
+        """Return a dict mapping paths to public ids for objects that are public under a container."""
+        return {}
+    
     def get_object_meta(self, user, account, container, name, domain, version=None):
         """Return a dictionary with the object metadata for the domain.
         
index 3618961..e719480 100644 (file)
@@ -85,6 +85,15 @@ class Public(DBWorker):
             return row[0]
         return None
     
+    def public_list(self, prefix):
+        s = select([self.public.c.path, self.public.c.public_id])
+        s = s.where(self.xfeatures.c.path.like(self.escape_like(prefix) + '%', escape='\\'))
+        s = s.where(self.public.c.active == True)
+        r = self.conn.execute(s)
+        rows = r.fetchall()
+        r.close()
+        return rows
+    
     def public_path(self, public):
         s = select([self.public.c.path])
         s = s.where(and_(self.public.c.public_id == public,
index eec19b5..2d6e9cb 100644 (file)
@@ -66,6 +66,11 @@ class Public(DBWorker):
             return row[0]
         return None
     
+    def public_list(self, prefix):
+        q = "select path, public_id from public where path like ? escape '\\' and active = 1"
+        self.execute(q, (self.escape_like(prefix) + '%',))
+        return self.fetchall()
+    
     def public_path(self, public):
         q = "select path from public where public_id = ? and active = 1"
         self.execute(q, (public,))
index 5961ad0..ce78d3a 100644 (file)
@@ -423,21 +423,25 @@ class ModularBackend(BaseBackend):
         self._report_size_change(user, account, -size, {'action': 'container delete'})
     
     def _list_objects(self, user, account, container, prefix, delimiter, marker, limit, virtual, domain, keys, shared, until, size_range, all_props):
+        if user != account and until:
+            raise NotAllowedError
+        allowed = self._list_object_permissions(user, account, container, prefix, shared)
+        path, node = self._lookup_container(account, container)
+        allowed = self._get_formatted_paths(allowed)
+        return self._list_object_properties(node, path, prefix, delimiter, marker, limit, virtual, domain, keys, until, size_range, allowed, all_props)
+    
+    def _list_object_permissions(self, user, account, container, prefix, shared):
         allowed = []
         if user != account:
-            if until:
-                raise NotAllowedError
-            allowed = self.permissions.access_list_paths(user, '/'.join((account, container)))
+            allowed = self.permissions.access_list_paths(user, '/'.join((account, container, prefix)))
             if not allowed:
                 raise NotAllowedError
         else:
             if shared:
-                allowed = self.permissions.access_list_shared('/'.join((account, container)))
+                allowed = self.permissions.access_list_shared('/'.join((account, container, prefix)))
                 if not allowed:
                     return []
-        path, node = self._lookup_container(account, container)
-        allowed = self._get_formatted_paths(allowed)
-        return self._list_object_properties(node, path, prefix, delimiter, marker, limit, virtual, domain, keys, until, size_range, allowed, all_props)
+        return allowed
     
     @backend_method
     def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, domain=None, keys=[], shared=False, until=None, size_range=None):
@@ -470,6 +474,23 @@ class ModularBackend(BaseBackend):
         return objects
     
     @backend_method
+    def list_object_permissions(self, user, account, container, prefix=''):
+        """Return a list of paths that enforce permissions under a container."""
+        
+        logger.debug("list_object_permissions: %s %s %s", account, container, prefix)
+        return self._list_object_permissions(user, account, container, prefix, True)
+    
+    @backend_method
+    def list_object_public(self, user, account, container, prefix=''):
+        """Return a dict mapping paths to public ids for objects that are public under a container."""
+        
+        logger.debug("list_object_public: %s %s %s", account, container, prefix)
+        public = {}
+        for path, p in self.permissions.public_list('/'.join((account, container, prefix))):
+            public[path] = p + ULTIMATE_ANSWER
+        return public
+    
+    @backend_method
     def get_object_meta(self, user, account, container, name, domain, version=None):
         """Return a dictionary with the object metadata for the domain."""