Skip to content

Commit

Permalink
Use ACL-specific endpoints where feasible for buckets.
Browse files Browse the repository at this point in the history
- Refactor lazy-handling of 'acl' and 'default_object_acl' using properties.

- Fetch 'ac' and 'defaultObjectAcl' via GET to specific endpoints.

- Continue to update 'acl' and 'defaultObjectAcl' via PATCH to the object's
  resource (we can't do incremental updates to ACEs).

Fixes #163.
  • Loading branch information
tseaver committed Nov 1, 2014
1 parent b524729 commit 6fe5372
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 131 deletions.
87 changes: 64 additions & 23 deletions gcloud/storage/bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,27 @@ class Bucket(object):
:type name: string
:param name: The name of the bucket.
"""
# ACL rules are lazily retrieved.
_acl = _default_object_acl = None

def __init__(self, connection=None, name=None, metadata=None):
self.connection = connection
self.name = name
self.metadata = metadata

# ACL rules are lazily retrieved.
self.acl = None
self.default_object_acl = None
@property
def acl(self):
"""Create our ACL on demand."""
if self._acl is None:
self._acl = BucketACL(self)
return self._acl

@property
def default_object_acl(self):
"""Create our defaultObjectACL on demand."""
if self._default_object_acl is None:
self._default_object_acl = DefaultObjectACL(self)
return self._default_object_acl

@classmethod
def from_dict(cls, bucket_dict, connection=None):
Expand Down Expand Up @@ -431,11 +443,15 @@ def reload_acl(self):
:rtype: :class:`Bucket`
:returns: The current bucket.
"""
self.acl = BucketACL(bucket=self)
self.acl.clear()

for entry in self.get_metadata('acl', []):
entity = self.acl.entity_from_dict(entry)
self.acl.add_entity(entity)
url_path = '%s/acl' % self.path
found = self.connection.api_request(method='GET', path=url_path)
for entry in found['items']:
self.acl.add_entity(self.acl.entity_from_dict(entry))

# Even if we fetch no entries, the ACL is still loaded.
self.acl.loaded = True

return self

Expand All @@ -445,7 +461,7 @@ def get_acl(self):
:rtype: :class:`gcloud.storage.acl.BucketACL`
:returns: An ACL object for the current bucket.
"""
if not self.acl:
if not self.acl.loaded:
self.reload_acl()
return self.acl

Expand Down Expand Up @@ -487,12 +503,17 @@ def save_acl(self, acl=None):
# both evaluate to False, but mean very different things.
if acl is None:
acl = self.acl
dirty = acl.loaded
else:
dirty = True

if acl is None:
return self
if dirty:
result = self.connection.api_request(
method='PATCH', path=self.path, data={'acl': list(acl)})
self.acl.clear()
for entry in result['acl']:
self.acl.entity(self.acl.entity_from_dict(entry))

self.patch_metadata({'acl': list(acl)})
self.reload_acl()
return self

def clear_acl(self):
Expand Down Expand Up @@ -522,19 +543,28 @@ def clear_acl(self):
At this point all the custom rules you created have been removed.
"""
return self.save_acl(acl=[])
self.connection.api_request(
method='PATCH', path=self.path, data={'acl': []})
self.acl.clear()
self.acl.loaded = True
return self

def reload_default_object_acl(self):
"""Reload the Default Object ACL rules for this bucket.
:rtype: :class:`Bucket`
:returns: The current bucket.
"""
self.default_object_acl = DefaultObjectACL(bucket=self)
doa = self.default_object_acl
doa.clear()

url_path = '%s/defaultObjectAcl' % self.path
found = self.connection.api_request(method='GET', path=url_path)
for entry in found['items']:
doa.add_entity(doa.entity_from_dict(entry))

for entry in self.get_metadata('defaultObjectAcl', []):
entity = self.default_object_acl.entity_from_dict(entry)
self.default_object_acl.add_entity(entity)
# Even if we fetch no entries, the ACL is still loaded.
doa.loaded = True

return self

Expand All @@ -547,7 +577,7 @@ def get_default_object_acl(self):
:rtype: :class:`gcloud.storage.acl.DefaultObjectACL`
:returns: A DefaultObjectACL object for this bucket.
"""
if not self.default_object_acl:
if not self.default_object_acl.loaded:
self.reload_default_object_acl()
return self.default_object_acl

Expand All @@ -562,18 +592,29 @@ def save_default_object_acl(self, acl=None):
"""
if acl is None:
acl = self.default_object_acl
dirty = acl.loaded
else:
dirty = True

if acl is None:
return self
if dirty:
result = self.connection.api_request(
method='PATCH', path=self.path,
data={'defaultObjectAcl': list(acl)})
doa = self.default_object_acl
doa.clear()
for entry in result['defaultObjectAcl']:
doa.entity(doa.entity_from_dict(entry))

self.patch_metadata({'defaultObjectAcl': list(acl)})
self.reload_default_object_acl()
return self

def clear_default_object_acl(self):
"""Remove the Default Object ACL from this bucket."""

return self.save_default_object_acl(acl=[])
self.connection.api_request(
method='PATCH', path=self.path, data={'defaultObjectAcl': []})
self.default_object_acl.clear()
self.default_object_acl.loaded = True
return self

def make_public(self, recursive=False, future=False):
"""Make a bucket public.
Expand Down
Loading

0 comments on commit 6fe5372

Please sign in to comment.