Repository: jschneier/django-storages

Issue:
GoogleCloud Storage not respecting ACL setting when using default_storage class Django
When using default_storage class to write a file to google bucket, it is created as projectPrivate even if the acl setting is publicRead.


Discussion:
@mj8894 How can you reproduce this? It does not happen for me. I have several projects in production using this setup.
Hi Scott,

Try Using this piece of code:

`file_to_write = default_storage.open(file_path, 'w')
 file_to_write.write('some content here')
 file_to_write.close()
`
Note:
1.  Make sure there isn't any existing file with file_path


I can confirm this happens. The culprit is here:

https://github.com/jschneier/django-storages/blob/44fe7698ece8bdf125d5529194e5277952bc6193/storages/backends/gcloud.py#L78

You can see how when the file is saved the `upload_from_file` method gets called without the default acl parameter. 

See in contrast to how it works in the save method:

https://github.com/jschneier/django-storages/blob/44fe7698ece8bdf125d5529194e5277952bc6193/storages/backends/gcloud.py#L180


Resolving patch:
diff --git a/storages/backends/gcloud.py b/storages/backends/gcloud.py
--- a/storages/backends/gcloud.py
+++ b/storages/backends/gcloud.py
@@ -74,8 +74,9 @@ def write(self, content):
     def close(self):
         if self._file is not None:
             if self._is_dirty:
-                self.blob.upload_from_file(self.file, rewind=True,
-                                           content_type=self.mime_type)
+                self.blob.upload_from_file(
+                    self.file, rewind=True, content_type=self.mime_type,
+                    predefined_acl=self._storage.default_acl)
             self._file.close()
             self._file = None
 
@@ -173,14 +174,9 @@ def _save(self, name, content):
         encoded_name = self._encode_name(name)
         file = GoogleCloudFile(encoded_name, 'rw', self)
         file.blob.cache_control = self.cache_control
-        if self.default_acl:
-            file.blob.upload_from_file(
-                content, rewind=True, size=content.size,
-                content_type=file.mime_type, predefined_acl=self.default_acl)
-        else:
-            file.blob.upload_from_file(
-                content, rewind=True, size=content.size,
-                content_type=file.mime_type)
+        file.blob.upload_from_file(
+            content, rewind=True, size=content.size,
+            content_type=file.mime_type, predefined_acl=self.default_acl)
         return cleaned_name
 
     def delete(self, name):


Test patch:
diff --git a/tests/test_gcloud.py b/tests/test_gcloud.py
--- a/tests/test_gcloud.py
+++ b/tests/test_gcloud.py
@@ -83,6 +83,7 @@ def test_open_write(self, MockBlob):
         # Simulate the file not existing before the write
         self.storage._bucket = mock.MagicMock()
         self.storage._bucket.get_blob.return_value = None
+        self.storage.default_acl = 'projectPrivate'
 
         f = self.storage.open(self.filename, 'wb')
         MockBlob.assert_called_with(self.filename, self.storage._bucket)
@@ -94,7 +95,8 @@ def test_open_write(self, MockBlob):
 
         MockBlob().upload_from_file.assert_called_with(
             tmpfile, rewind=True,
-            content_type=mimetypes.guess_type(self.filename)[0])
+            content_type=mimetypes.guess_type(self.filename)[0],
+            predefined_acl='projectPrivate')
 
     def test_save(self):
         data = 'This is some test content.'
@@ -104,7 +106,8 @@ def test_save(self):
 
         self.storage._client.bucket.assert_called_with(self.bucket_name)
         self.storage._bucket.get_blob().upload_from_file.assert_called_with(
-            content, rewind=True, size=len(data), content_type=mimetypes.guess_type(self.filename)[0])
+            content, rewind=True, size=len(data), content_type=mimetypes.guess_type(self.filename)[0],
+            predefined_acl=None)
 
     def test_save2(self):
         data = 'This is some test ủⓝï℅ⅆℇ content.'
@@ -115,7 +118,8 @@ def test_save2(self):
 
         self.storage._client.bucket.assert_called_with(self.bucket_name)
         self.storage._bucket.get_blob().upload_from_file.assert_called_with(
-            content, rewind=True, size=len(data), content_type=mimetypes.guess_type(filename)[0])
+            content, rewind=True, size=len(data), content_type=mimetypes.guess_type(filename)[0],
+            predefined_acl=None)
 
     def test_save_with_default_acl(self):
         data = 'This is some test ủⓝï℅ⅆℇ content.'