Skip to content

Commit

Permalink
Storage: Implement predefined acl
Browse files Browse the repository at this point in the history
  • Loading branch information
chemelnucfin committed Jan 26, 2018
1 parent 7714d0c commit 295eb03
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 7 deletions.
25 changes: 20 additions & 5 deletions storage/google/cloud/storage/blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -872,7 +872,8 @@ def _do_upload(self, client, stream, content_type, size, num_retries):
return response.json()

def upload_from_file(self, file_obj, rewind=False, size=None,
content_type=None, num_retries=None, client=None):
content_type=None, num_retries=None, client=None,
predefined_acl=None):
"""Upload the contents of this blob from a file-like object.
The content type of the upload will be determined in order
Expand Down Expand Up @@ -930,6 +931,9 @@ def upload_from_file(self, file_obj, rewind=False, size=None,
:param client: (Optional) The client to use. If not passed, falls back
to the ``client`` stored on the blob's bucket.
:type predefined_acl: str
:param predefined_acl: (Optional) predefined access control list
:raises: :class:`~google.cloud.exceptions.GoogleCloudError`
if the upload response returns an error status.
Expand All @@ -945,10 +949,13 @@ def upload_from_file(self, file_obj, rewind=False, size=None,
created_json = self._do_upload(
client, file_obj, content_type, size, num_retries)
self._set_properties(created_json)
if predefined_acl is not None:
self.acl.save_predefined(predefined_acl)
except resumable_media.InvalidResponse as exc:
_raise_from_invalid_response(exc)

def upload_from_filename(self, filename, content_type=None, client=None):
def upload_from_filename(self, filename, content_type=None, client=None,
predefined_acl=None):
"""Upload this blob's contents from the content of a named file.
The content type of the upload will be determined in order
Expand Down Expand Up @@ -982,16 +989,20 @@ def upload_from_filename(self, filename, content_type=None, client=None):
:type client: :class:`~google.cloud.storage.client.Client`
:param client: (Optional) The client to use. If not passed, falls back
to the ``client`` stored on the blob's bucket.
:type predefined_acl: str
:param predefined_acl: (Optional) predefined access control list
"""
content_type = self._get_content_type(content_type, filename=filename)

with open(filename, 'rb') as file_obj:
total_bytes = os.fstat(file_obj.fileno()).st_size
self.upload_from_file(
file_obj, content_type=content_type, client=client,
size=total_bytes)
size=total_bytes, predefined_acl=predefined_acl)

def upload_from_string(self, data, content_type='text/plain', client=None):
def upload_from_string(self, data, content_type='text/plain', client=None,
predefined_acl=None):
"""Upload contents of this blob from the provided string.
.. note::
Expand Down Expand Up @@ -1020,12 +1031,16 @@ def upload_from_string(self, data, content_type='text/plain', client=None):
``NoneType``
:param client: Optional. The client to use. If not passed, falls back
to the ``client`` stored on the blob's bucket.
:type predefined_acl: str
:param predefined_acl: (Optional) predefined access control list
"""
data = _to_bytes(data, encoding='utf-8')
string_buffer = BytesIO(data)
self.upload_from_file(
file_obj=string_buffer, size=len(data),
content_type=content_type, client=client)
content_type=content_type, client=client,
predefined_acl=predefined_acl)

def create_resumable_upload_session(
self,
Expand Down
23 changes: 23 additions & 0 deletions storage/tests/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,29 @@ def test_blob_acl_w_user_project(self):
acl.save()
self.assertFalse(acl.has_entity('allUsers'))

def test_upload_blob_acl(self):
control = self.bucket.blob('logo')
control_data = self.FILES['logo']

blob = self.bucket.blob('SmallFile')
file_data = self.FILES['simple']

try:
control.upload_from_filename(control_data['path'])
blob.upload_from_filename(file_data['path'],
predefined_acl='publicRead')
finally:
self.case_blobs_to_delete.append(blob)
self.case_blobs_to_delete.append(control)

control_acl = control.acl
self.assertNotIn('READER', control_acl.all().get_roles())
acl = blob.acl
self.assertIn('READER', acl.all().get_roles())
acl.all().revoke_read()
self.assertSequenceEqual(acl.all().get_roles(), set([]))
self.assertEqual(control_acl.all().get_roles(), acl.all().get_roles())

def test_write_metadata(self):
filename = self.FILES['logo']['path']
blob_name = os.path.basename(filename)
Expand Down
7 changes: 5 additions & 2 deletions storage/tests/unit/test_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -1252,9 +1252,10 @@ def test__do_upload_with_retry(self):

def _upload_from_file_helper(self, side_effect=None, **kwargs):
from google.cloud._helpers import UTC
from google.cloud.storage.acl import ACL

blob = self._make_one('blob-name', bucket=None)

blob._acl = mock.create_autospec(ACL)
# Mock low-level upload helper on blob (it is tested elsewhere).
created_json = {'updated': '2017-01-01T09:09:09.081Z'}
blob._do_upload = mock.Mock(return_value=created_json, spec=[])
Expand All @@ -1268,9 +1269,11 @@ def _upload_from_file_helper(self, side_effect=None, **kwargs):
stream.seek(2) # Not at zero.
content_type = u'font/woff'
client = mock.sentinel.client
predefined_acl = 'private'

ret_val = blob.upload_from_file(
stream, size=len(data), content_type=content_type,
client=client, **kwargs)
client=client, predefined_acl=predefined_acl, **kwargs)

# Check the response and side-effects.
self.assertIsNone(ret_val)
Expand Down

0 comments on commit 295eb03

Please sign in to comment.