Skip to content

Commit

Permalink
Added support to ACLs on Keys and various other additions.
Browse files Browse the repository at this point in the history
  • Loading branch information
jgeewax committed Feb 6, 2014
1 parent 338f0f4 commit 214c67e
Show file tree
Hide file tree
Showing 3 changed files with 257 additions and 45 deletions.
55 changes: 44 additions & 11 deletions gcloud/storage/acl.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,20 +176,14 @@ def revoke_owner(self):
return self.revoke(ACL.Role.Owner)


def __init__(self, bucket):
"""
:type bucket: :class:`gcloud.storage.bucket.Bucket`
:param bucket: The bucket to which this ACL relates.
"""

self.bucket = bucket
def __init__(self):
self.entities = {}

def __iter__(self):
for entity in self.entities.itervalues():
for role in entity.get_roles():
if role:
yield {'entity': entity, 'role': role}
yield {'entity': str(entity), 'role': role}

def entity_from_dict(self, entity_dict):
"""Build an ACL.Entity object from a dictionary of data.
Expand Down Expand Up @@ -217,7 +211,7 @@ def entity_from_dict(self, entity_dict):
elif entity == 'allAuthenticatedUsers':
entity = self.all_authenticated()

if '-' in entity:
elif '-' in entity:
type, identifier = entity.split('-', 1)
entity = self.entity(type=type, identifier=identifier)

Expand Down Expand Up @@ -351,16 +345,55 @@ def get_entities(self):

return self.entities.values()

def save(self):
"""A method to be overridden by subclasses.
:raises: NotImplementedError
"""

raise NotImplementedError


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

def __init__(self, bucket):
"""
:type bucket: :class:`gcloud.storage.bucket.Bucket`
:param bucket: The bucket to which this ACL relates.
"""

super(BucketACL, self).__init__()
self.bucket = bucket

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

return self.bucket.save_acl(acl=self)


class DefaultObjectACL(ACL):
"""A subclass of ACL representing the default object ACL for a bucket."""
class DefaultObjectACL(BucketACL):
"""A subclass of BucketACL 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)


class ObjectACL(ACL):
"""An ACL specifically for a key."""

def __init__(self, key):
"""
:type key: :class:`gcloud.storage.key.Key`
:param key: The key that this ACL corresponds to.
"""

super(ObjectACL, self).__init__()
self.key = key

def save(self):
"""Save this ACL for the current key."""

return self.key.save_acl(acl=self)
42 changes: 34 additions & 8 deletions gcloud/storage/bucket.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from gcloud.storage import exceptions
from gcloud.storage.acl import ACL
from gcloud.storage.acl import BucketACL
from gcloud.storage.acl import DefaultObjectACL
from gcloud.storage.iterator import KeyIterator
from gcloud.storage.key import Key
Expand Down Expand Up @@ -247,8 +247,8 @@ def get_metadata(self, field=None, default=None):

if field:
return self.metadata.get(field, default)

return self.metadata
else:
return self.metadata

def patch_metadata(self, metadata):
"""Update particular fields of this bucket's metadata.
Expand Down Expand Up @@ -301,8 +301,7 @@ def reload_acl(self):
:returns: The current bucket.
"""

self.acl = ACL(bucket=self)
acl = self.get_metadata('acl')
self.acl = BucketACL(bucket=self)

for entry in self.get_metadata('acl', []):
entity = self.acl.entity_from_dict(entry)
Expand All @@ -312,9 +311,9 @@ def reload_acl(self):

def get_acl(self):
# TODO: This might be a VERY long list. Use the specific API endpoint.
"""Get ACL metadata as a :class:`gcloud.storage.acl.ACL` object.
"""Get ACL metadata as a :class:`gcloud.storage.acl.BucketACL` object.
:rtype: :class:`gcloud.storage.acl.ACL`
:rtype: :class:`gcloud.storage.acl.BucketACL`
:returns: An ACL object for the current bucket.
"""

Expand All @@ -331,7 +330,10 @@ def save_acl(self, acl=None):
set locally on the bucket.
"""

acl = acl or self.acl
# We do things in this weird way because [] and None
# both evaluate to False, but mean very different things.
if acl is None:
acl = self.acl

if acl is None:
return self
Expand Down Expand Up @@ -403,3 +405,27 @@ def clear_default_object_acl(self):
"""Remove the Default Object ACL from this bucket."""

return self.save_default_object_acl(acl=[])

def make_public(self, recursive=False, future=False):
"""Make a bucket public.
:type recursive: bool
:param recursive: If True, this will make all keys inside the bucket
public as well.
:type future: bool
:param future: If True, this will make all objects created in the future
public as well.
"""

self.get_acl().all().grant_read()
self.save_acl()

if future:
self.get_default_object_acl().all().grant_read()
self.save_default_object_acl()

if recursive:
for key in self:
key.get_acl().all().grant_read()
key.save_acl()
Loading

0 comments on commit 214c67e

Please sign in to comment.