@@ -166,6 +166,21 @@ class ACL(object):
166166 """Container class representing a list of access controls."""
167167
168168 _URL_PATH_ELEM = 'acl'
169+ _PREDEFINED_QUERY_PARAM = 'predefinedAcl'
170+
171+ _PREDEFINED_ACLS = frozenset ([
172+ 'private' ,
173+ 'project-private' ,
174+ 'public-read' ,
175+ 'public-read-write' ,
176+ 'authenticated-read' ,
177+ 'bucket-owner-read' ,
178+ 'bucket-owner-full-control' ,
179+ ])
180+ """See:
181+ https://cloud.google.com/storage/docs/access-control#predefined-acl
182+ """
183+
169184 loaded = False
170185
171186 # Subclasses must override to provide these attributes (typically,
@@ -385,6 +400,39 @@ def reload(self, client=None):
385400 for entry in found .get ('items' , ()):
386401 self .add_entity (self .entity_from_dict (entry ))
387402
403+ def _save (self , acl , predefined , client ):
404+ """Helper for :meth:`save` and :meth:`save_predefined`.
405+
406+ :type acl: :class:`gcloud.storage.acl.ACL`, or a compatible list.
407+ :param acl: The ACL object to save. If left blank, this will save
408+ current entries.
409+
410+ :type predefined: string or None
411+ :param predefined: An identifier for a predefined ACL. Must be one
412+ of the keys in :attr:`_PREDEFINED_ACLS`
413+ If passed, `acl` must be None.
414+
415+ :type client: :class:`gcloud.storage.client.Client` or ``NoneType``
416+ :param client: Optional. The client to use. If not passed, falls back
417+ to the ``client`` stored on the ACL's parent.
418+ """
419+ query_params = {'projection' : 'full' }
420+ if predefined is not None :
421+ acl = []
422+ query_params [self ._PREDEFINED_QUERY_PARAM ] = predefined
423+
424+ path = self .save_path
425+ client = self ._require_client (client )
426+ result = client .connection .api_request (
427+ method = 'PATCH' ,
428+ path = path ,
429+ data = {self ._URL_PATH_ELEM : list (acl )},
430+ query_params = query_params )
431+ self .entities .clear ()
432+ for entry in result .get (self ._URL_PATH_ELEM , ()):
433+ self .add_entity (self .entity_from_dict (entry ))
434+ self .loaded = True
435+
388436 def save (self , acl = None , client = None ):
389437 """Save this ACL for the current bucket.
390438
@@ -403,17 +451,24 @@ def save(self, acl=None, client=None):
403451 save_to_backend = True
404452
405453 if save_to_backend :
406- path = self .save_path
407- client = self ._require_client (client )
408- result = client .connection .api_request (
409- method = 'PATCH' ,
410- path = path ,
411- data = {self ._URL_PATH_ELEM : list (acl )},
412- query_params = {'projection' : 'full' })
413- self .entities .clear ()
414- for entry in result .get (self ._URL_PATH_ELEM , ()):
415- self .add_entity (self .entity_from_dict (entry ))
416- self .loaded = True
454+ self ._save (acl , None , client )
455+
456+ def save_predefined (self , predefined , client = None ):
457+ """Save this ACL for the current bucket using a predefined ACL.
458+
459+ :type predefined: string
460+ :param predefined: An identifier for a predefined ACL. Must be one
461+ of the keys in :attr:`_PREDEFINED_ACLS`
462+ If passed, `acl` must be None.
463+
464+ :type client: :class:`gcloud.storage.client.Client` or ``NoneType``
465+ :param client: Optional. The client to use. If not passed, falls back
466+ to the ``client`` stored on the ACL's parent.
467+ """
468+ if predefined not in self ._PREDEFINED_ACLS :
469+ raise ValueError ("Invalid predefined ACL: %s" % (predefined ,))
470+
471+ self ._save (None , predefined , client )
417472
418473 def clear (self , client = None ):
419474 """Remove all ACL entries.
@@ -461,6 +516,7 @@ class DefaultObjectACL(BucketACL):
461516 """A class representing the default object ACL for a bucket."""
462517
463518 _URL_PATH_ELEM = 'defaultObjectAcl'
519+ _PREDEFINED_QUERY_PARAM = 'predefinedDefaultObjectAcl'
464520
465521
466522class ObjectACL (ACL ):
0 commit comments