Revision 3436eeb0
b/pithos/api/functions.py | ||
---|---|---|
44 | 44 |
LengthRequired, PreconditionFailed, RangeNotSatisfiable, UnprocessableEntity) |
45 | 45 |
from pithos.api.util import (format_meta_key, printable_meta_dict, get_account_meta, |
46 | 46 |
put_account_meta, get_container_meta, put_container_meta, get_object_meta, put_object_meta, |
47 |
update_manifest_meta, validate_modification_preconditions, validate_matching_preconditions,
|
|
48 |
split_container_object_string, copy_or_move_object, get_int_parameter, get_content_length,
|
|
49 |
get_content_range, raw_input_socket, socket_read_iterator, object_data_response,
|
|
50 |
put_object_block, hashmap_hash, api_method) |
|
47 |
update_manifest_meta, format_permissions, validate_modification_preconditions,
|
|
48 |
validate_matching_preconditions, split_container_object_string, copy_or_move_object,
|
|
49 |
get_int_parameter, get_content_length, get_content_range, get_sharing, raw_input_socket,
|
|
50 |
socket_read_iterator, object_data_response, put_object_block, hashmap_hash, api_method)
|
|
51 | 51 |
from pithos.backends import backend |
52 | 52 |
|
53 | 53 |
|
... | ... | |
348 | 348 |
else: |
349 | 349 |
try: |
350 | 350 |
meta = backend.get_object_meta(request.user, v_account, v_container, x[0], x[1]) |
351 |
object_meta.append(printable_meta_dict(meta))
|
|
351 |
permissions = backend.get_object_permissions(request.user, v_account, v_container, x[0])
|
|
352 | 352 |
except NameError: |
353 | 353 |
pass |
354 |
if permissions: |
|
355 |
meta['X-Object-Sharing'] = format_permissions(permissions) |
|
356 |
object_meta.append(printable_meta_dict(meta)) |
|
354 | 357 |
if request.serialization == 'xml': |
355 | 358 |
data = render_to_string('objects.xml', {'container': v_container, 'objects': object_meta}) |
356 | 359 |
elif request.serialization == 'json': |
... | ... | |
370 | 373 |
version = get_int_parameter(request, 'version') |
371 | 374 |
try: |
372 | 375 |
meta = backend.get_object_meta(request.user, v_account, v_container, v_object, version) |
376 |
permissions = backend.get_object_permissions(request.user, v_account, v_container, v_object) |
|
373 | 377 |
except NameError: |
374 | 378 |
raise ItemNotFound('Object does not exist') |
375 | 379 |
except IndexError: |
376 | 380 |
raise ItemNotFound('Version does not exist') |
377 | 381 |
|
382 |
if permissions: |
|
383 |
meta['X-Object-Sharing'] = format_permissions(permissions) |
|
378 | 384 |
update_manifest_meta(request, v_account, meta) |
379 | 385 |
|
380 | 386 |
response = HttpResponse(status=200) |
... | ... | |
398 | 404 |
version_list = True |
399 | 405 |
try: |
400 | 406 |
meta = backend.get_object_meta(request.user, v_account, v_container, v_object, version) |
407 |
permissions = backend.get_object_permissions(request.user, v_account, v_container, v_object) |
|
401 | 408 |
except NameError: |
402 | 409 |
raise ItemNotFound('Object does not exist') |
403 | 410 |
except IndexError: |
404 | 411 |
raise ItemNotFound('Version does not exist') |
405 | 412 |
|
413 |
if permissions: |
|
414 |
meta['X-Object-Sharing'] = format_permissions(permissions) |
|
406 | 415 |
update_manifest_meta(request, v_account, meta) |
407 | 416 |
|
408 | 417 |
# Evaluate conditions. |
... | ... | |
485 | 494 |
# Error Response Codes: serviceUnavailable (503), |
486 | 495 |
# unprocessableEntity (422), |
487 | 496 |
# lengthRequired (411), |
497 |
# conflict (409), |
|
488 | 498 |
# itemNotFound (404), |
489 | 499 |
# unauthorized (401), |
490 | 500 |
# badRequest (400) |
... | ... | |
510 | 520 |
return HttpResponse(status=201) |
511 | 521 |
|
512 | 522 |
meta = get_object_meta(request) |
523 |
permissions = get_sharing(request) |
|
513 | 524 |
content_length = -1 |
514 | 525 |
if request.META.get('HTTP_TRANSFER_ENCODING') != 'chunked': |
515 | 526 |
content_length = get_content_length(request) |
... | ... | |
534 | 545 |
raise UnprocessableEntity('Object ETag does not match') |
535 | 546 |
|
536 | 547 |
try: |
537 |
backend.update_object_hashmap(request.user, v_account, v_container, v_object, size, hashmap, meta, True) |
|
548 |
backend.update_object_hashmap(request.user, v_account, v_container, v_object, size, hashmap, meta, True, permissions)
|
|
538 | 549 |
except NameError: |
539 | 550 |
raise ItemNotFound('Container does not exist') |
551 |
except ValueError: |
|
552 |
raise BadRequest('Invalid sharing header') |
|
553 |
except AttributeError: |
|
554 |
raise Conflict('Sharing already set above or below this path in the hierarchy') |
|
540 | 555 |
|
541 | 556 |
response = HttpResponse(status=201) |
542 | 557 |
response['ETag'] = meta['hash'] |
... | ... | |
582 | 597 |
def object_update(request, v_account, v_container, v_object): |
583 | 598 |
# Normal Response Codes: 202, 204 |
584 | 599 |
# Error Response Codes: serviceUnavailable (503), |
600 |
# conflict (409), |
|
585 | 601 |
# itemNotFound (404), |
586 | 602 |
# unauthorized (401), |
587 | 603 |
# badRequest (400) |
588 | 604 |
|
589 | 605 |
meta = get_object_meta(request) |
606 |
permissions = get_sharing(request) |
|
590 | 607 |
content_type = meta.get('Content-Type') |
591 | 608 |
if content_type: |
592 | 609 |
del(meta['Content-Type']) # Do not allow changing the Content-Type. |
... | ... | |
607 | 624 |
except NameError: |
608 | 625 |
raise ItemNotFound('Object does not exist') |
609 | 626 |
|
627 |
# Handle permission changes. |
|
628 |
if permissions: |
|
629 |
try: |
|
630 |
backend.update_object_permissions(request.user, v_account, v_container, v_object, permissions) |
|
631 |
except NameError: |
|
632 |
raise ItemNotFound('Object does not exist') |
|
633 |
except ValueError: |
|
634 |
raise BadRequest('Invalid sharing header') |
|
635 |
except AttributeError: |
|
636 |
raise Conflict('Sharing already set above or below this path in the hierarchy') |
|
637 |
|
|
638 |
# TODO: Merge above functions with updating the hashmap if there is data in the request. |
|
639 |
|
|
610 | 640 |
# A Content-Type or Content-Range header may indicate data updates. |
611 | 641 |
if content_type is None: |
612 | 642 |
return HttpResponse(status=202) |
... | ... | |
665 | 695 |
backend.update_object_hashmap(request.user, v_account, v_container, v_object, size, hashmap, meta, False) |
666 | 696 |
except NameError: |
667 | 697 |
raise ItemNotFound('Container does not exist') |
668 |
|
|
698 |
except ValueError: |
|
699 |
raise BadRequest('Invalid sharing header') |
|
700 |
except AttributeError: |
|
701 |
raise Conflict('Sharing already set above or below this path in the hierarchy') |
|
702 |
|
|
669 | 703 |
response = HttpResponse(status=204) |
670 | 704 |
response['ETag'] = meta['hash'] |
671 | 705 |
return response |
b/pithos/api/util.py | ||
---|---|---|
129 | 129 |
meta['Content-Disposition'] = request.META['HTTP_CONTENT_DISPOSITION'] |
130 | 130 |
if request.META.get('HTTP_X_OBJECT_MANIFEST'): |
131 | 131 |
meta['X-Object-Manifest'] = request.META['HTTP_X_OBJECT_MANIFEST'] |
132 |
if request.META.get('HTTP_X_OBJECT_PUBLIC'): |
|
133 |
meta['X-Object-Public'] = request.META['HTTP_X_OBJECT_PUBLIC'] |
|
134 | 132 |
return meta |
135 | 133 |
|
136 | 134 |
def put_object_meta(response, meta, public=False): |
... | ... | |
145 | 143 |
response['X-Object-Version-Timestamp'] = meta['version_timestamp'] |
146 | 144 |
for k in [x for x in meta.keys() if x.startswith('X-Object-Meta-')]: |
147 | 145 |
response[k.encode('utf-8')] = meta[k].encode('utf-8') |
148 |
for k in ('Content-Encoding', 'Content-Disposition', 'X-Object-Manifest', 'X-Object-Public'):
|
|
146 |
for k in ('Content-Encoding', 'Content-Disposition', 'X-Object-Manifest', 'X-Object-Sharing'):
|
|
149 | 147 |
if k in meta: |
150 | 148 |
response[k] = meta[k] |
151 | 149 |
else: |
... | ... | |
174 | 172 |
md5.update(hash) |
175 | 173 |
meta['hash'] = md5.hexdigest().lower() |
176 | 174 |
|
175 |
def format_permissions(permissions): |
|
176 |
ret = [] |
|
177 |
if 'public' in permissions: |
|
178 |
ret.append('public') |
|
179 |
if 'private' in permissions: |
|
180 |
ret.append('private') |
|
181 |
r = ','.join(permissions.get('read', [])) |
|
182 |
if r: |
|
183 |
ret.append('read=' + r) |
|
184 |
w = ','.join(permissions.get('write', [])) |
|
185 |
if w: |
|
186 |
ret.append('write=' + w) |
|
187 |
return '; '.join(ret) |
|
188 |
|
|
177 | 189 |
def validate_modification_preconditions(request, meta): |
178 | 190 |
"""Check that the modified timestamp conforms with the preconditions set.""" |
179 | 191 |
|
... | ... | |
221 | 233 |
"""Copy or move an object.""" |
222 | 234 |
|
223 | 235 |
meta = get_object_meta(request) |
236 |
permissions = get_sharing(request) |
|
224 | 237 |
# Keep previous values of 'Content-Type' (if a new one is absent) and 'hash'. |
225 | 238 |
try: |
226 | 239 |
src_meta = backend.get_object_meta(request.user, v_account, src_container, src_name) |
... | ... | |
234 | 247 |
|
235 | 248 |
try: |
236 | 249 |
if move: |
237 |
backend.move_object(request.user, v_account, src_container, src_name, dest_container, dest_name, meta, True) |
|
250 |
backend.move_object(request.user, v_account, src_container, src_name, dest_container, dest_name, meta, True, permissions)
|
|
238 | 251 |
else: |
239 | 252 |
src_version = request.META.get('HTTP_X_SOURCE_VERSION') |
240 |
backend.copy_object(request.user, v_account, src_container, src_name, dest_container, dest_name, meta, True, src_version) |
|
253 |
backend.copy_object(request.user, v_account, src_container, src_name, dest_container, dest_name, meta, True, permissions, src_version)
|
|
241 | 254 |
except NameError: |
242 | 255 |
raise ItemNotFound('Container or object does not exist') |
256 |
except ValueError: |
|
257 |
raise BadRequest('Invalid sharing header') |
|
258 |
except AttributeError: |
|
259 |
raise Conflict('Sharing already set above or below this path in the hierarchy') |
|
243 | 260 |
|
244 | 261 |
def get_int_parameter(request, name): |
245 | 262 |
p = request.GET.get(name) |
... | ... | |
341 | 358 |
length = upto - offset + 1 |
342 | 359 |
return (offset, length, total) |
343 | 360 |
|
361 |
def get_sharing(request): |
|
362 |
"""Parse an X-Object-Sharing header from the request. |
|
363 |
|
|
364 |
Raises BadRequest on error. |
|
365 |
""" |
|
366 |
|
|
367 |
permissions = request.META.get('HTTP_X_OBJECT_SHARING') |
|
368 |
if permissions is None or permissions == '': |
|
369 |
return None |
|
370 |
|
|
371 |
ret = {} |
|
372 |
for perm in (x.replace(' ','') for x in permissions.split(';')): |
|
373 |
if perm == 'public': |
|
374 |
ret['public'] = True |
|
375 |
continue |
|
376 |
elif perm == 'private': |
|
377 |
ret['private'] = True |
|
378 |
continue |
|
379 |
elif perm.startswith('read='): |
|
380 |
ret['read'] = [v.replace(' ','') for v in perm[5:].split(',')] |
|
381 |
if len(ret['read']) == 0: |
|
382 |
raise BadRequest('Bad X-Object-Sharing header value') |
|
383 |
elif perm.startswith('write='): |
|
384 |
ret['write'] = [v.replace(' ','') for v in perm[6:].split(',')] |
|
385 |
if len(ret['write']) == 0: |
|
386 |
raise BadRequest('Bad X-Object-Sharing header value') |
|
387 |
else: |
|
388 |
raise BadRequest('Bad X-Object-Sharing header value') |
|
389 |
return ret |
|
390 |
|
|
344 | 391 |
def raw_input_socket(request): |
345 | 392 |
"""Return the socket for reading the rest of the request.""" |
346 | 393 |
|
b/pithos/backends/base.py | ||
---|---|---|
182 | 182 |
""" |
183 | 183 |
return |
184 | 184 |
|
185 |
def get_object_permissions(self, user, account, container, name): |
|
186 |
"""Return a dictionary with the object permissions. |
|
187 |
|
|
188 |
The keys are: |
|
189 |
'public': The object is readable by all and available at a public URL |
|
190 |
'private': No permissions set |
|
191 |
'read': The object is readable by the users/groups in the list |
|
192 |
'write': The object is writable by the users/groups in the list |
|
193 |
|
|
194 |
Raises: |
|
195 |
NameError: Container/object does not exist |
|
196 |
""" |
|
197 |
return {} |
|
198 |
|
|
199 |
def update_object_permissions(self, user, account, container, name, permissions): |
|
200 |
"""Update the permissions associated with the object. |
|
201 |
|
|
202 |
Parameters: |
|
203 |
'permissions': Dictionary with permissions to update |
|
204 |
|
|
205 |
Raises: |
|
206 |
NameError: Container/object does not exist |
|
207 |
ValueError: Invalid users/groups in permissions |
|
208 |
AttributeError: Can not set permissions, as this object\ |
|
209 |
is already shared/private by another object higher\ |
|
210 |
in the hierarchy, or setting permissions here will\ |
|
211 |
invalidate other permissions deeper in the hierarchy |
|
212 |
""" |
|
213 |
return |
|
214 |
|
|
185 | 215 |
def get_object_hashmap(self, user, account, container, name, version=None): |
186 | 216 |
"""Return the object's size and a list with partial hashes. |
187 | 217 |
|
... | ... | |
191 | 221 |
""" |
192 | 222 |
return 0, [] |
193 | 223 |
|
194 |
def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False): |
|
224 |
def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False, permissions={}):
|
|
195 | 225 |
"""Create/update an object with the specified size and partial hashes. |
196 | 226 |
|
227 |
Parameters: |
|
228 |
'dest_meta': Dictionary with metadata to change |
|
229 |
'replace_meta': Replace metadata instead of update |
|
230 |
'permissions': Updated object permissions |
|
231 |
|
|
197 | 232 |
Raises: |
198 | 233 |
NameError: Container does not exist |
234 |
ValueError: Invalid users/groups in permissions |
|
235 |
AttributeError: Can not set permissions |
|
199 | 236 |
""" |
200 | 237 |
return |
201 | 238 |
|
202 |
def copy_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, src_version=None): |
|
239 |
def copy_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions={}, src_version=None):
|
|
203 | 240 |
"""Copy an object's data and metadata. |
204 | 241 |
|
205 | 242 |
Parameters: |
206 |
'dest_meta': Dictionary with metadata to changes from source to destination
|
|
243 |
'dest_meta': Dictionary with metadata to change from source to destination |
|
207 | 244 |
'replace_meta': Replace metadata instead of update |
208 |
'src_version': Copy from the version provided. |
|
245 |
'permissions': New object permissions |
|
246 |
'src_version': Copy from the version provided |
|
209 | 247 |
|
210 | 248 |
Raises: |
211 | 249 |
NameError: Container/object does not exist |
212 | 250 |
IndexError: Version does not exist |
251 |
ValueError: Invalid users/groups in permissions |
|
252 |
AttributeError: Can not set permissions |
|
213 | 253 |
""" |
214 | 254 |
return |
215 | 255 |
|
216 |
def move_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False): |
|
256 |
def move_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions={}):
|
|
217 | 257 |
"""Move an object's data and metadata. |
218 | 258 |
|
219 | 259 |
Parameters: |
220 |
'dest_meta': Dictionary with metadata to changes from source to destination
|
|
260 |
'dest_meta': Dictionary with metadata to change from source to destination |
|
221 | 261 |
'replace_meta': Replace metadata instead of update |
262 |
'permissions': New object permissions |
|
222 | 263 |
|
223 | 264 |
Raises: |
224 | 265 |
NameError: Container/object does not exist |
266 |
ValueError: Invalid users/groups in permissions |
|
267 |
AttributeError: Can not set permissions |
|
225 | 268 |
""" |
226 | 269 |
return |
227 | 270 |
|
b/pithos/backends/simple.py | ||
---|---|---|
79 | 79 |
sql = '''create table if not exists hashmaps ( |
80 | 80 |
version_id integer, pos integer, block_id text, primary key (version_id, pos))''' |
81 | 81 |
self.con.execute(sql) |
82 |
sql = '''create table if not exists permissions ( |
|
83 |
name text, read text, write text, primary key (name))''' |
|
84 |
self.con.execute(sql) |
|
82 | 85 |
self.con.commit() |
83 | 86 |
|
84 | 87 |
def delete_account(self, user, account): |
... | ... | |
227 | 230 |
path, version_id, mtime, size = self._get_objectinfo(account, container, name) |
228 | 231 |
self._put_metadata(path, meta, replace) |
229 | 232 |
|
233 |
def get_object_permissions(self, user, account, container, name): |
|
234 |
"""Return a dictionary with the object permissions.""" |
|
235 |
|
|
236 |
logger.debug("get_object_permissions: %s %s %s", account, container, name) |
|
237 |
path = self._get_objectinfo(account, container, name)[0] |
|
238 |
return self._get_permissions(path) |
|
239 |
|
|
240 |
def update_object_permissions(self, user, account, container, name, permissions): |
|
241 |
"""Update the permissions associated with the object.""" |
|
242 |
|
|
243 |
logger.debug("update_object_permissions: %s %s %s %s", account, container, name, permissions) |
|
244 |
path = self._get_objectinfo(account, container, name)[0] |
|
245 |
r, w = self._check_permissions(path, permissions) |
|
246 |
self._put_permissions(path, r, w) |
|
247 |
|
|
230 | 248 |
def get_object_hashmap(self, user, account, container, name, version=None): |
231 | 249 |
"""Return the object's size and a list with partial hashes.""" |
232 | 250 |
|
... | ... | |
237 | 255 |
hashmap = [x[0] for x in c.fetchall()] |
238 | 256 |
return size, hashmap |
239 | 257 |
|
240 |
def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False): |
|
258 |
def update_object_hashmap(self, user, account, container, name, size, hashmap, meta={}, replace_meta=False, permissions={}):
|
|
241 | 259 |
"""Create/update an object with the specified size and partial hashes.""" |
242 | 260 |
|
243 | 261 |
logger.debug("update_object_hashmap: %s %s %s %s %s", account, container, name, size, hashmap) |
244 | 262 |
path = self._get_containerinfo(account, container)[0] |
245 | 263 |
path = os.path.join(path, name) |
264 |
if permissions: |
|
265 |
r, w = self._check_permissions(path, permissions) |
|
246 | 266 |
src_version_id, dest_version_id = self._copy_version(path, path, not replace_meta, False) |
247 | 267 |
sql = 'update versions set size = ? where version_id = ?' |
248 | 268 |
self.con.execute(sql, (size, dest_version_id)) |
... | ... | |
253 | 273 |
for k, v in meta.iteritems(): |
254 | 274 |
sql = 'insert or replace into metadata (version_id, key, value) values (?, ?, ?)' |
255 | 275 |
self.con.execute(sql, (dest_version_id, k, v)) |
276 |
if permissions: |
|
277 |
sql = 'insert or replace into permissions (name, read, write) values (?, ?, ?)' |
|
278 |
self.con.execute(sql, (path, r, w)) |
|
256 | 279 |
self.con.commit() |
257 | 280 |
|
258 |
def copy_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, src_version=None): |
|
281 |
def copy_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions={}, src_version=None):
|
|
259 | 282 |
"""Copy an object's data and metadata.""" |
260 | 283 |
|
261 |
logger.debug("copy_object: %s %s %s %s %s %s %s %s", account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta, src_version)
|
|
284 |
logger.debug("copy_object: %s %s %s %s %s %s %s %s %s", account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta, permissions, src_version)
|
|
262 | 285 |
self._get_containerinfo(account, src_container) |
263 | 286 |
if src_version is None: |
264 | 287 |
src_path = self._get_objectinfo(account, src_container, src_name)[0] |
... | ... | |
266 | 289 |
src_path = os.path.join(account, src_container, src_name) |
267 | 290 |
dest_path = self._get_containerinfo(account, dest_container)[0] |
268 | 291 |
dest_path = os.path.join(dest_path, dest_name) |
292 |
if permissions: |
|
293 |
r, w = self._check_permissions(dest_path, permissions) |
|
269 | 294 |
src_version_id, dest_version_id = self._copy_version(src_path, dest_path, not replace_meta, True, src_version) |
270 | 295 |
for k, v in dest_meta.iteritems(): |
271 | 296 |
sql = 'insert or replace into metadata (version_id, key, value) values (?, ?, ?)' |
272 | 297 |
self.con.execute(sql, (dest_version_id, k, v)) |
298 |
if permissions: |
|
299 |
sql = 'insert or replace into permissions (name, read, write) values (?, ?, ?)' |
|
300 |
self.con.execute(sql, (dest_path, r, w)) |
|
273 | 301 |
self.con.commit() |
274 | 302 |
|
275 |
def move_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False): |
|
303 |
def move_object(self, user, account, src_container, src_name, dest_container, dest_name, dest_meta={}, replace_meta=False, permissions={}):
|
|
276 | 304 |
"""Move an object's data and metadata.""" |
277 | 305 |
|
278 |
logger.debug("move_object: %s %s %s %s %s %s %s", account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta)
|
|
279 |
self.copy_object(user, account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta, None) |
|
306 |
logger.debug("move_object: %s %s %s %s %s %s %s %s", account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta, permissions)
|
|
307 |
self.copy_object(user, account, src_container, src_name, dest_container, dest_name, dest_meta, replace_meta, permissions, None)
|
|
280 | 308 |
self.delete_object(user, account, src_container, src_name) |
281 | 309 |
|
282 | 310 |
def delete_object(self, user, account, container, name): |
... | ... | |
285 | 313 |
logger.debug("delete_object: %s %s %s", account, container, name) |
286 | 314 |
path, version_id, mtime, size = self._get_objectinfo(account, container, name) |
287 | 315 |
self._put_version(path, 0, 1) |
316 |
sql = 'delete from permissions where name = ?' |
|
317 |
self.con.execute(sql, (path,)) |
|
318 |
self.con.commit() |
|
288 | 319 |
|
289 | 320 |
def list_versions(self, user, account, container, name): |
290 | 321 |
"""Return a list of all (version, version_timestamp) tuples for an object.""" |
... | ... | |
449 | 480 |
self.con.execute(sql, (dest_version_id, k, v)) |
450 | 481 |
self.con.commit() |
451 | 482 |
|
483 |
def _can_read(self, user, path): |
|
484 |
return True |
|
485 |
|
|
486 |
def _can_write(self, user, path): |
|
487 |
return True |
|
488 |
|
|
489 |
def _check_permissions(self, path, permissions): |
|
490 |
# Check for existing permissions. |
|
491 |
sql = '''select name from permissions |
|
492 |
where name != ? and (name like ? or ? like name || ?)''' |
|
493 |
c = self.con.execute(sql, (path, path + '%', path, '%')) |
|
494 |
if c.fetchall() is not None: |
|
495 |
raise AttributeError('Permissions already set') |
|
496 |
|
|
497 |
# Format given permissions set. |
|
498 |
r = permissions.get('read', []) |
|
499 |
w = permissions.get('write', []) |
|
500 |
if True in [False or '*' in x or ',' in x for x in r]: |
|
501 |
raise ValueError('Bad characters in read permissions') |
|
502 |
if True in [False or '*' in x or ',' in x for x in w]: |
|
503 |
raise ValueError('Bad characters in write permissions') |
|
504 |
r = ','.join(r) |
|
505 |
w = ','.join(w) |
|
506 |
if 'public' in permissions: |
|
507 |
r = '*' |
|
508 |
if 'private' in permissions: |
|
509 |
r = '' |
|
510 |
w = '' |
|
511 |
return r, w |
|
512 |
|
|
513 |
def _get_permissions(self, path): |
|
514 |
sql = 'select read, write from permissions where name = ?' |
|
515 |
c = self.con.execute(sql, (path,)) |
|
516 |
row = c.fetchone() |
|
517 |
if not row: |
|
518 |
return {} |
|
519 |
|
|
520 |
r, w = row |
|
521 |
if r == '' and w == '': |
|
522 |
return {'private': True} |
|
523 |
ret = {} |
|
524 |
if w != '': |
|
525 |
ret['write'] = w.split(',') |
|
526 |
if r != '': |
|
527 |
if r == '*': |
|
528 |
ret['public'] = True |
|
529 |
else: |
|
530 |
ret['read'] = r.split(',') |
|
531 |
return ret |
|
532 |
|
|
533 |
def _put_permissions(self, path, r, w): |
|
534 |
sql = 'insert or replace into permissions (name, read, write) values (?, ?, ?)' |
|
535 |
self.con.execute(sql, (path, r, w)) |
|
536 |
self.con.commit() |
|
537 |
|
|
452 | 538 |
def _list_objects(self, path, prefix='', delimiter=None, marker=None, limit=10000, virtual=True, keys=[], until=None): |
453 | 539 |
cont_prefix = path + '/' |
454 | 540 |
if keys and len(keys) > 0: |
... | ... | |
502 | 588 |
self.con.execute(sql, (path,)) |
503 | 589 |
sql = '''delete from versions where name = ?''' |
504 | 590 |
self.con.execute(sql, (path,)) |
591 |
sql = '''delete from permissions where name like ?''' |
|
592 |
self.con.execute(sql, (path + '%',)) # Redundant. |
|
505 | 593 |
self.con.commit() |
b/pithos/public/functions.py | ||
---|---|---|
65 | 65 |
|
66 | 66 |
try: |
67 | 67 |
meta = backend.get_object_meta(request.user, v_account, v_container, v_object) |
68 |
permissions = backend.get_object_permissions(request.user, v_account, v_container, v_object) |
|
68 | 69 |
except NameError: |
69 | 70 |
raise ItemNotFound('Object does not exist') |
70 | 71 |
|
71 |
if 'X-Object-Public' not in meta:
|
|
72 |
if 'public' not in permissions:
|
|
72 | 73 |
raise ItemNotFound('Object does not exist') |
73 | 74 |
update_manifest_meta(request, v_account, meta) |
74 | 75 |
|
... | ... | |
89 | 90 |
|
90 | 91 |
try: |
91 | 92 |
meta = backend.get_object_meta(request.user, v_account, v_container, v_object) |
93 |
permissions = backend.get_object_permissions(request.user, v_account, v_container, v_object) |
|
92 | 94 |
except NameError: |
93 | 95 |
raise ItemNotFound('Object does not exist') |
94 | 96 |
|
95 |
if 'X-Object-Public' not in meta:
|
|
97 |
if 'public' not in permissions:
|
|
96 | 98 |
raise ItemNotFound('Object does not exist') |
97 | 99 |
update_manifest_meta(request, v_account, meta) |
98 | 100 |
|
Also available in: Unified diff