\ 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``.
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
====================== =========================
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
====================== ===================================
* 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.
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)
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:
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:
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:
"""
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
"""
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:
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
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)
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
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:
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)
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()]