Merge branch 'next'
[pithos] / snf-pithos-backend / pithos / backends / modular.py
index c34d1e1..d1e3126 100644 (file)
@@ -324,17 +324,18 @@ class ModularBackend(BaseBackend):
             start, limit = self._list_limits(allowed, marker, limit)
             return allowed[start:start + limit]
         if shared or public:
-            allowed = []
+            allowed = set()
             if shared:
-                allowed.extend([x.split('/', 2)[1] for x in self.permissions.access_list_shared(account)])
+                allowed.update([x.split('/', 2)[1] for x in self.permissions.access_list_shared(account)])
             if public:
-                allowed.extend([x[0].split('/', 2)[1] for x in self.permissions.public_list(account)])
-            allowed = list(set(allowed))
-            allowed.sort()
+                allowed.update([x[0].split('/', 2)[1] for x in self.permissions.public_list(account)])
+            allowed = sorted(allowed)
             start, limit = self._list_limits(allowed, marker, limit)
             return allowed[start:start + limit]
         node = self.node.node_lookup(account)
-        return [x[0] for x in self._list_object_properties(node, account, '', '/', marker, limit, False, None, [], until)]
+        containers = [x[0] for x in self._list_object_properties(node, account, '', '/', marker, limit, False, None, [], until)]
+        start, limit = self._list_limits([x[0] for x in containers], marker, limit)
+        return containers[start:start + limit]
     
     @backend_method
     def list_container_meta(self, user, account, container, domain, until=None):
@@ -469,13 +470,45 @@ class ModularBackend(BaseBackend):
     def _list_objects(self, user, account, container, prefix, delimiter, marker, limit, virtual, domain, keys, shared, until, size_range, all_props, public):
         if user != account and until:
             raise NotAllowedError
+        if shared and public:
+            # get shared first
+            shared = self._list_object_permissions(user, account, container, prefix, shared=True, public=False)
+            objects = []
+            if shared:
+                path, node = self._lookup_container(account, container)
+                shared = self._get_formatted_paths(shared)
+                objects = self._list_object_properties(node, path, prefix, delimiter, marker, limit, virtual, domain, keys, until, size_range, shared, all_props)
+            
+            # get public
+            objects.extend(self._list_public_object_properties(user, account, container, prefix, all_props))
+            
+            objects.sort(key=lambda x: x[0])
+            start, limit = self._list_limits([x[0] for x in objects], marker, limit)
+            return objects[start:start + limit]
+        elif public:
+            objects = self._list_public_object_properties(user, account, container, prefix, all_props)
+            start, limit = self._list_limits([x[0] for x in objects], marker, limit)
+            return objects[start:start + limit]
+        
         allowed = self._list_object_permissions(user, account, container, prefix, shared, public)
-        if (shared or public) and not allowed:
+        if shared and 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)
+        objects = self._list_object_properties(node, path, prefix, delimiter, marker, limit, virtual, domain, keys, until, size_range, allowed, all_props)
+        start, limit = self._list_limits([x[0] for x in objects], marker, limit)
+        return objects[start:start + limit]
     
+    def _list_public_object_properties(self, user, account, container, prefix, all_props):
+        public = self._list_object_permissions(user, account, container, prefix, shared=False, public=True)
+        paths, nodes = self._lookup_objects(public)
+        path = '/'.join((account, container))
+        cont_prefix = path + '/'
+        paths = [x[len(cont_prefix):] for x in paths]
+        props = self.node.version_lookup_bulk(nodes, all_props=all_props)
+        objects = [(path,) + props for path, props in zip(paths, props)]
+        return objects
+        
     def _list_objects_no_limit(self, user, account, container, prefix, delimiter, virtual, domain, keys, shared, until, size_range, all_props, public):
         objects = []
         while True:
@@ -495,13 +528,12 @@ class ModularBackend(BaseBackend):
             if not allowed:
                 raise NotAllowedError
         else:
-            allowed = []
+            allowed = set()
             if shared:
-                allowed.extend(self.permissions.access_list_shared(path))
+                allowed.update(self.permissions.access_list_shared(path))
             if public:
-                allowed.extend([x[0] for x in self.permissions.public_list(path)])
-            allowed = list(set(allowed))
-            allowed.sort()
+                allowed.update([x[0] for x in self.permissions.public_list(path)])
+            allowed = sorted(allowed)
             if not allowed:
                 return []
         return allowed
@@ -746,7 +778,7 @@ class ModularBackend(BaseBackend):
         size = props[self.SIZE]
         is_copy = not is_move and (src_account, src_container, src_name) != (dest_account, dest_container, dest_name) # New uuid.
         dest_version_ids.append(self._update_object_hash(user, dest_account, dest_container, dest_name, size, type, hash, None, dest_domain, dest_meta, replace_meta, permissions, src_node=node, src_version_id=src_version_id, is_copy=is_copy))
-        if is_move:
+        if is_move and (src_account, src_container, src_name) != (dest_account, dest_container, dest_name):
                self._delete_object(user, src_account, src_container, src_name)
         
         if delimiter:
@@ -764,7 +796,7 @@ class ModularBackend(BaseBackend):
                 dest_prefix = dest_name + delimiter if not dest_name.endswith(delimiter) else dest_name
                 vdest_name = path.replace(prefix, dest_prefix, 1)
                 dest_version_ids.append(self._update_object_hash(user, dest_account, dest_container, vdest_name, size, vtype, hash, None, dest_domain, dest_meta, replace_meta, permissions, src_node=node, src_version_id=src_version_id, is_copy=is_copy))
-                if is_move:
+                if is_move and (src_account, src_container, src_name) != (dest_account, dest_container, dest_name):
                        self._delete_object(user, src_account, src_container, path)
         return dest_version_ids[0] if len(dest_version_ids) == 1 else dest_version_ids
     
@@ -944,6 +976,12 @@ class ModularBackend(BaseBackend):
             raise NameError('Object does not exist')
         return path, node
     
+    def _lookup_objects(self, paths):
+       nodes = self.node.node_lookup_bulk(paths)
+        if nodes is None:
+            raise NameError('Object does not exist')
+        return paths, nodes
+    
     def _get_properties(self, node, until=None):
         """Return properties until the timestamp given."""
         
@@ -1074,10 +1112,8 @@ class ModularBackend(BaseBackend):
         objects.extend([(p, None) for p in prefixes] if virtual else [])
         objects.sort(key=lambda x: x[0])
         objects = [(x[0][len(cont_prefix):],) + x[1:] for x in objects]
+        return objects
         
-        start, limit = self._list_limits([x[0] for x in objects], marker, limit)
-        return objects[start:start + limit]
-    
     # Reporting functions.
     
     def _report_size_change(self, user, account, size, details={}):