From 1993fea93fb334b86fc80c28cc86f0e781834748 Mon Sep 17 00:00:00 2001 From: Antony Chazapis Date: Mon, 4 Jul 2011 15:47:01 +0300 Subject: [PATCH] Return the conflicting path in the reply, when refusing to change permissions because of a conflict. Refs #449 --- docs/source/devguide.rst | 3 +++ pithos/api/functions.py | 19 ++++++++----------- pithos/api/util.py | 7 ++++--- pithos/backends/simple.py | 12 +++++++----- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/docs/source/devguide.rst b/docs/source/devguide.rst index 8f99ba4..0f89ca5 100644 --- a/docs/source/devguide.rst +++ b/docs/source/devguide.rst @@ -596,6 +596,7 @@ The ``X-Object-Sharing`` header may include either a ``read=...`` comma-separate Return Code Description =========================== ============================== 201 (Created) The object has been created +409 (Conflict) The object can not be created from the provided hashmap, or there are conflicting permissions (a list of missing hashes, or a conflicting sharing path will be included in the reply - in JSON format) 411 (Length Required) Missing ``Content-Length`` or ``Content-Type`` in the request 422 (Unprocessable Entity) The MD5 checksum of the data written to the storage system does not match the (optionally) supplied ETag value =========================== ============================== @@ -626,6 +627,7 @@ No reply content/headers. Return Code Description =========================== ============================== 201 (Created) The object has been created +409 (Conflict) There are conflicting permissions (a conflicting sharing path will be included in the reply - in JSON format) =========================== ============================== @@ -692,6 +694,7 @@ Return Code Description =========================== ============================== 202 (Accepted) The request has been accepted (not a data update) 204 (No Content) The request succeeded (data updated) +409 (Conflict) There are conflicting permissions (a conflicting sharing path will be included in the reply - in JSON format) 411 (Length Required) Missing ``Content-Length`` in the request 416 (Range Not Satisfiable) The supplied range is invalid =========================== ============================== diff --git a/pithos/api/functions.py b/pithos/api/functions.py index 461c33e..509982f 100644 --- a/pithos/api/functions.py +++ b/pithos/api/functions.py @@ -650,21 +650,18 @@ def object_write(request, v_account, v_container, v_object): if etag and parse_etags(etag)[0].lower() != meta['hash']: raise UnprocessableEntity('Object ETag does not match') - payload = '' - code = 201 try: backend.update_object_hashmap(request.user, v_account, v_container, v_object, size, hashmap, meta, True, permissions) except NotAllowedError: raise Unauthorized('Access denied') except IndexError, e: - payload = json.dumps(e.data) - code = 409 + raise Conflict(json.dumps(e.data)) except NameError: raise ItemNotFound('Container does not exist') except ValueError: raise BadRequest('Invalid sharing header') - except AttributeError: - raise Conflict('Sharing already set above or below this path in the hierarchy') + except AttributeError, e: + raise Conflict(json.dumps(e.data)) if public is not None: try: backend.update_object_public(request.user, v_account, v_container, v_object, public) @@ -673,7 +670,7 @@ def object_write(request, v_account, v_container, v_object): except NameError: raise ItemNotFound('Object does not exist') - response = HttpResponse(content=payload, status=code) + response = HttpResponse(status=201) response['ETag'] = meta['hash'] return response @@ -754,8 +751,8 @@ def object_update(request, v_account, v_container, v_object): raise ItemNotFound('Object does not exist') except ValueError: raise BadRequest('Invalid sharing header') - except AttributeError: - raise Conflict('Sharing already set above or below this path in the hierarchy') + except AttributeError, e: + raise Conflict(json.dumps(e.data)) if public is not None: try: backend.update_object_public(request.user, v_account, v_container, v_object, public) @@ -827,8 +824,8 @@ def object_update(request, v_account, v_container, v_object): raise ItemNotFound('Container does not exist') except ValueError: raise BadRequest('Invalid sharing header') - except AttributeError: - raise Conflict('Sharing already set above or below this path in the hierarchy') + except AttributeError, e: + raise Conflict(json.dumps(e.data)) if public is not None: try: backend.update_object_public(request.user, v_account, v_container, v_object, public) diff --git a/pithos/api/util.py b/pithos/api/util.py index 342242e..430cac5 100644 --- a/pithos/api/util.py +++ b/pithos/api/util.py @@ -39,6 +39,7 @@ from binascii import hexlify from django.conf import settings from django.http import HttpResponse +from django.utils import simplejson as json from django.utils.http import http_date, parse_etags from pithos.api.compat import parse_http_date_safe, parse_http_date @@ -258,8 +259,8 @@ def copy_or_move_object(request, v_account, src_container, src_name, dest_contai raise ItemNotFound('Container or object does not exist') except ValueError: raise BadRequest('Invalid sharing header') - except AttributeError: - raise Conflict('Sharing already set above or below this path in the hierarchy') + except AttributeError, e: + raise Conflict(json.dumps(e.data)) if public is not None: try: backend.update_object_public(request.user, v_account, v_container, v_object, public) @@ -666,7 +667,7 @@ def update_response_headers(request, response): def render_fault(request, fault): if settings.DEBUG or settings.TEST: fault.details = format_exc(fault) - + request.serialization = 'text' data = '\n'.join((fault.message, fault.details)) + '\n' response = HttpResponse(data, status=fault.code) diff --git a/pithos/backends/simple.py b/pithos/backends/simple.py index 137e8ab..45e9c3f 100644 --- a/pithos/backends/simple.py +++ b/pithos/backends/simple.py @@ -458,6 +458,8 @@ class SimpleBackend(BaseBackend): self._put_version(path, user, 0, 1) sql = 'delete from permissions where name = ?' self.con.execute(sql, (path,)) + sql = 'delete from public where name = ?' + self.con.execute(sql, (path,)) self.con.commit() def list_versions(self, user, account, container, name): @@ -694,9 +696,11 @@ class SimpleBackend(BaseBackend): sql = '''select name from permissions where name != ? and (name like ? or ? like name || ?)''' c = self.con.execute(sql, (path, path + '%', path, '%')) - rows = c.fetchall() - if rows: - raise AttributeError('Permissions already set') + row = c.fetchone() + if row: + ae = AttributeError() + ae.data = row[0] + raise ae # Format given permissions. if len(permissions) == 0: @@ -803,6 +807,4 @@ class SimpleBackend(BaseBackend): self.con.execute(sql, (path,)) sql = '''delete from versions where name = ?''' self.con.execute(sql, (path,)) - sql = '''delete from permissions where name like ?''' - self.con.execute(sql, (path + '%',)) # Redundant. self.con.commit() -- 1.7.10.4