8000 Fix #324: Move ACL back-end manipulations from bucket / key to acl objects by tseaver · Pull Request #326 · googleapis/google-cloud-python · GitHub
[go: up one dir, main page]

Skip to content

Fix #324: Move ACL back-end manipulations from bucket / key to acl objects #326

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 3, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 158 additions & 15 deletions gcloud/storage/acl.py
10000
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,6 @@ class ACL(object):
def __init__(self):
self.entities = {}

def clear(self):
"""Remove all entities from the ACL."""
self.entities.clear()

def reset(self):
"""Remove all entities from the ACL, and clear the ``loaded`` flag."""
self.entities.clear()
Expand Down Expand Up @@ -338,17 +334,35 @@ def get_entities(self):
"""
return self.entities.values()

def save(self):
def reload(self):
"""Reload the ACL data from Cloud Storage.

:rtype: :class:`ACL`
:returns: The current ACL.
"""
raise NotImplementedError

def save(self, acl=None):
"""A method to be overridden by subclasses.

:type acl: :class:`gcloud.storage.acl.ACL`, or a compatible list.
:param acl: The ACL object to save. If left blank, this will save
current entries.

:raises: NotImplementedError
"""
raise NotImplementedError

def clear(self):
"""Remove all entities from the ACL."""
raise NotImplementedError


class BucketACL(ACL):
"""An ACL specifically for a bucket."""

_URL_PATH_ELEM = 'acl'

def __init__(self, bucket):
"""
:type bucket: :class:`gcloud.storage.bucket.Bucket`
Expand All @@ -357,19 +371,101 @@ def __init__(self, bucket):
super(BucketACL, self).__init__()
self.bucket = bucket

def save(self):
"""Save this ACL for the current bucket."""
def reload(self):
"""Reload the ACL data from Cloud Storage.

:rtype: :class:`gcloud.storage.acl.BucketACL`
:returns: The current ACL.
"""
self.entities.clear()

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

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

return self

def save(self, acl=None):
"""Save this ACL for the current bucket.

If called without arguments, this will save the entries
currently stored on this ACL::

return self.bucket.save_acl(acl=self)
>>> acl.save()

You can also provide a specific ACL to save instead of the one
currently set on the Bucket object::

>>> acl.save(acl=my_other_acl)

You can use this to set access controls to be consistent from
one bucket to another::

>>> bucket1 = connection.get_bucket(bucket1_name)
>>> bucket2 = connection.get_bucket(bucket2_name)
>>> bucket2.acl.save(bucket1.get_acl())

:type acl: :class:`gcloud.storage.acl.ACL`, or a compatible list.
:param acl: The ACL object to save. If left blank, this will save
current entries.

:rtype: :class:`gcloud.storage.acl.BucketACL`
:returns: The current ACL.
"""
if acl is None:
acl = self
save_to_backend = acl.loaded
else:
save_to_backend = True

if save_to_backend:
result = self.bucket.connection.api_request(
method='PATCH', path=self.bucket.path,
data={self._URL_PATH_ELEM: list(acl)},
query_params={'projection': 'full'})
self.entities.clear()
for entry in result[self._URL_PATH_ELEM]:
self.add_entity(self.entity_from_dict(entry))
self.loaded = True

return self

def clear(self):
"""Remove all ACL entries.

Note that this won't actually remove *ALL* the rules, but it
will remove all the non-default rules. In short, you'll still
have access to a bucket that you created even after you clear
ACL rules with this method.

For example, imagine that you granted access to this bucket to a
bunch of coworkers::

>>> acl.user('coworker1@example.org').grant_read()
>>> acl.user('coworker2@example.org').grant_read()
>>> acl.save()

Now they work in another part of the company and you want to
'start fresh' on who has access::

>>> acl.clear()

At this point all the custom rules you created have been removed.

:rtype: :class:`gcloud.storage.acl.BucketACL`
:returns: The current ACL.
"""
return self.save([])


class DefaultObjectACL(BucketACL):
"""A class representing the default object ACL for a bucket."""

def save(self):
"""Save this ACL as the default object ACL for the current bucket."""

return self.bucket.save_default_object_acl(acl=self)
_URL_PATH_ELEM = 'defaultObjectAcl'


class ObjectACL(ACL):
Expand All @@ -383,7 +479,54 @@ def __init__(self, key):
super(ObjectACL, self).__init__()
self.key = key

def save(self):
"""Save this ACL for the current key."""
def reload(self):
"""Reload the ACL data from Cloud Storage.

:rtype: :class:`ObjectACL`
:returns: The current ACL.
"""
self.entities.clear()

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

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

return self

def save(self, acl=None):
"""Save the ACL data for this key.

:type acl: :class:`gcloud.storage.acl.ACL`
:param acl: The ACL object to save. If left blank, this will
save the entries set locally on the ACL.
"""
if acl is None:
acl = self
save_to_backend = acl.loaded
else:
save_to_backend = True

if save_to_backend:
result = self.key.connection.api_request(
method='PATCH', path=self.key.path, data={'acl': list(acl)},
query_params={'projection': 'full'})
self.entities.clear()
for entry in result['acl']:
self.add_entity(self.entity_from_dict(entry))
self.loaded = True

return self

def clear(self):
"""Remove all ACL rules from the key.

Note that this won't actually remove *ALL* the rules, but it
will remove all the non-default rules. In short, you'll still
have access to a key that you created even after you clear ACL
rules with this method.
"""
return self.save([])
Loading
0