Option to show only shared containers/objects in listings.
authorAntony Chazapis <chazapis@gmail.com>
Tue, 19 Jul 2011 16:07:09 +0000 (19:07 +0300)
committerAntony Chazapis <chazapis@gmail.com>
Tue, 19 Jul 2011 16:07:09 +0000 (19:07 +0300)
Refs #765

docs/source/devguide.rst
pithos/api/functions.py
pithos/backends/base.py
pithos/backends/simple.py

index 854ebfb..a083222 100644 (file)
@@ -30,6 +30,7 @@ Revision                   Description
 \                          Create object using a standard HTML form.
 \                          Purge container/object history.
 \                          List other accounts that share objects with a user.
+\                          List shared containers/objects.
 0.4 (July 01, 2011)        Object permissions and account groups.
 \                          Control versioning behavior and container quotas with container policy directives.
 \                          Support updating/deleting individual metadata with ``POST``.
@@ -206,6 +207,7 @@ Request Parameter Name  Value
 limit                   The amount of results requested (default is 10000)
 marker                  Return containers with name lexicographically after marker
 format                  Optional extended reply type (can be ``json`` or ``xml``)
+shared                  Show only shared containers (no value parameter)
 until                   Optional timestamp
 ======================  =========================
 
@@ -343,6 +345,7 @@ delimiter               Return objects up to the delimiter (discussion follows)
 path                    Assume ``prefix=path`` and ``delimiter=/``
 format                  Optional extended reply type (can be ``json`` or ``xml``)
 meta                    Return objects having the specified meta keys (can be a comma separated list)
+shared                  Show only shared objects (no value parameter)
 until                   Optional timestamp
 ======================  ===================================
 
@@ -883,7 +886,8 @@ List of differences from the OOS API:
 * Headers ``X-Container-Block-*`` at the container level, exposing the underlying storage characteristics.
 * All metadata replies, at all levels, include latest modification information.
 * At all levels, a ``GET`` request may use ``If-Modified-Since`` and ``If-Unmodified-Since`` headers.
-* Container/object lists include all associated metadata if the reply is of type json/xml. Some names are kept to their OOS API equivalents for compatibility. 
+* Container/object lists include all associated metadata if the reply is of type json/xml. Some names are kept to their OOS API equivalents for compatibility.
+* Option to include only shared containers/objects in listings.
 * Object metadata allowed, in addition to ``X-Object-Meta-*``: ``Content-Encoding``, ``Content-Disposition``, ``X-Object-Manifest``. These are all replaced with every update operation, except if using the ``update`` parameter (in which case individual keys can also be deleted). Deleting meta by providing empty values also works when copying/moving an object.
 * Multi-range object ``GET`` support as outlined in RFC2616.
 * Object hashmap retrieval through ``GET`` and the ``format`` parameter.
index abad451..6fe2593 100644 (file)
@@ -198,7 +198,7 @@ def account_update(request, v_account):
     meta, groups = get_account_headers(request)
     replace = True
     if 'update' in request.GET:
-        replace = False    
+        replace = False
     if groups:
         try:
             backend.update_account_groups(request.user, v_account, groups, replace)
@@ -237,8 +237,12 @@ def container_list(request, v_account):
     if not limit:
         limit = 10000
     
+    shared = False
+    if 'shared' in request.GET:
+        shared = True
+    
     try:
-        containers = backend.list_containers(request.user, v_account, marker, limit, until)
+        containers = backend.list_containers(request.user, v_account, marker, limit, shared, until)
     except NotAllowedError:
         raise Unauthorized('Access denied')
     except NameError:
@@ -426,8 +430,12 @@ def object_list(request, v_account, v_container):
     else:
         keys = []
     
+    shared = False
+    if 'shared' in request.GET:
+        shared = True
+    
     try:
-        objects = backend.list_objects(request.user, v_account, v_container, prefix, delimiter, marker, limit, virtual, keys, until)
+        objects = backend.list_objects(request.user, v_account, v_container, prefix, delimiter, marker, limit, virtual, keys, shared, until)
     except NotAllowedError:
         raise Unauthorized('Access denied')
     except NameError:
@@ -901,7 +909,7 @@ def object_update(request, v_account, v_container, v_object):
         content_length = -1
         if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked':
             content_length = get_content_length(request)
-            
+        
         if length is None:
             length = content_length
         else:
index fd36289..1985d04 100644 (file)
@@ -111,12 +111,13 @@ class BaseBackend(object):
         """
         return
     
-    def list_containers(self, user, account, marker=None, limit=10000, until=None):
+    def list_containers(self, user, account, marker=None, limit=10000, shared=False, until=None):
         """Return a list of container names existing under an account.
         
         Parameters:
             'marker': Start list from the next item after 'marker'
             'limit': Number of containers to return
+            'shared': Only list containers with permissions set
         
         Raises:
             NotAllowedError: Operation not permitted
@@ -195,7 +196,7 @@ class BaseBackend(object):
         """
         return
     
-    def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], until=None):
+    def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], shared=False, until=None):
         """Return a list of object (name, version_id) tuples existing under a container.
         
         Parameters:
@@ -209,6 +210,7 @@ class BaseBackend(object):
                        If set, the result will include all names after 'prefix',\
                        up to and including the 'delimiter' if it is found
             'keys': Include objects that have meta with the keys in the list
+            'shared': Only list objects with permissions set
         
         Raises:
             NotAllowedError: Operation not permitted
index 7964893..c4c79b8 100644 (file)
@@ -238,7 +238,7 @@ class SimpleBackend(BaseBackend):
         self._del_groups(account)
     
     @backend_method
-    def list_containers(self, user, account, marker=None, limit=10000, until=None):
+    def list_containers(self, user, account, marker=None, limit=10000, shared=False, until=None):
         """Return a list of containers existing under an account."""
         
         logger.debug("list_containers: %s %s %s %s", account, marker, limit, until)
@@ -248,6 +248,11 @@ class SimpleBackend(BaseBackend):
             allowed = self._allowed_containers(user, account)
             start, limit = self._list_limits(allowed, marker, limit)
             return allowed[start:start + limit]
+        else:
+            if shared:
+                allowed = [x.split('/', 2)[1] for x in self._shared_paths(account)]
+                start, limit = self._list_limits(allowed, marker, limit)
+                return allowed[start:start + limit]
         return [x[0] for x in self._list_objects(account, '', '/', marker, limit, False, [], until)]
     
     @backend_method
@@ -369,10 +374,10 @@ class SimpleBackend(BaseBackend):
         self._copy_version(user, account, account, True, False) # New account version (for timestamp update).
     
     @backend_method
-    def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], until=None):
+    def list_objects(self, user, account, container, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], shared=False, until=None):
         """Return a list of objects existing under a container."""
         
-        logger.debug("list_objects: %s %s %s %s %s %s %s %s %s", account, container, prefix, delimiter, marker, limit, virtual, keys, until)
+        logger.debug("list_objects: %s %s %s %s %s %s %s %s %s %s", account, container, prefix, delimiter, marker, limit, virtual, keys, shared, until)
         allowed = []
         if user != account:
             if until:
@@ -380,6 +385,9 @@ class SimpleBackend(BaseBackend):
             allowed = self._allowed_paths(user, os.path.join(account, container))
             if not allowed:
                 raise NotAllowedError
+        else:
+            if shared:
+                allowed = self._shared_paths(os.path.join(account, container))
         path, version_id, mtime = self._get_containerinfo(account, container, until)
         return self._list_objects(path, prefix, delimiter, marker, limit, virtual, keys, until, allowed)
     
@@ -970,3 +978,8 @@ class SimpleBackend(BaseBackend):
         for path in self._allowed_paths(user, account):
             allow.add(path.split('/', 2)[1])
         return sorted(allow)
+    
+    def _shared_paths(self, prefix):
+        sql = 'select distinct name from permissions where name like ?'
+        c = self.con.execute(sql, (prefix + '/%',))
+        return [x[0] for x in c.fetchall()]