Fixed #21380 -- Added a way to set different permission for static directories.
Previously when collecting static files, the directories would receive permissions from the global umask. Now the default permission comes from FILE_UPLOAD_DIRECTORY_PERMISSIONS and there's an option to specify the permissions by subclassing any of the static files storage classes and setting the directory_permissions_mode parameter.
This commit is contained in:
parent
42ac138009
commit
7e2d61a972
|
@ -294,12 +294,6 @@ Type 'yes' to continue, or 'no' to cancel: """
|
|||
self.log("Pretending to copy '%s'" % source_path, level=1)
|
||||
else:
|
||||
self.log("Copying '%s'" % source_path, level=1)
|
||||
if self.local:
|
||||
full_path = self.storage.path(prefixed_path)
|
||||
try:
|
||||
os.makedirs(os.path.dirname(full_path))
|
||||
except OSError:
|
||||
pass
|
||||
with source_storage.open(path) as source_file:
|
||||
self.storage.save(prefixed_path, source_file)
|
||||
if not prefixed_path in self.copied_files:
|
||||
|
|
|
@ -149,7 +149,8 @@ class FileSystemStorage(Storage):
|
|||
Standard filesystem storage
|
||||
"""
|
||||
|
||||
def __init__(self, location=None, base_url=None, file_permissions_mode=None):
|
||||
def __init__(self, location=None, base_url=None, file_permissions_mode=None,
|
||||
directory_permissions_mode=None):
|
||||
if location is None:
|
||||
location = settings.MEDIA_ROOT
|
||||
self.base_location = location
|
||||
|
@ -161,6 +162,10 @@ class FileSystemStorage(Storage):
|
|||
file_permissions_mode if file_permissions_mode is not None
|
||||
else settings.FILE_UPLOAD_PERMISSIONS
|
||||
)
|
||||
self.directory_permissions_mode = (
|
||||
directory_permissions_mode if directory_permissions_mode is not None
|
||||
else settings.FILE_UPLOAD_DIRECTORY_PERMISSIONS
|
||||
)
|
||||
|
||||
def _open(self, name, mode='rb'):
|
||||
return File(open(self.path(name), mode))
|
||||
|
@ -175,12 +180,12 @@ class FileSystemStorage(Storage):
|
|||
directory = os.path.dirname(full_path)
|
||||
if not os.path.exists(directory):
|
||||
try:
|
||||
if settings.FILE_UPLOAD_DIRECTORY_PERMISSIONS is not None:
|
||||
if self.directory_permissions_mode is not None:
|
||||
# os.makedirs applies the global umask, so we reset it,
|
||||
# for consistency with FILE_UPLOAD_PERMISSIONS behavior.
|
||||
# for consistency with file_permissions_mode behavior.
|
||||
old_umask = os.umask(0)
|
||||
try:
|
||||
os.makedirs(directory, settings.FILE_UPLOAD_DIRECTORY_PERMISSIONS)
|
||||
os.makedirs(directory, self.directory_permissions_mode)
|
||||
finally:
|
||||
os.umask(old_umask)
|
||||
else:
|
||||
|
|
|
@ -60,16 +60,19 @@ by the :class:`~django.contrib.staticfiles.storage.CachedStaticFilesStorage`
|
|||
by default.
|
||||
|
||||
By default, collected files receive permissions from
|
||||
:setting:`FILE_UPLOAD_PERMISSIONS`. If you would like different permissions for
|
||||
these files, you can subclass either of the :ref:`static files storage
|
||||
classes <staticfiles-storages>` and specify the ``file_permissions_mode``
|
||||
parameter. For example::
|
||||
:setting:`FILE_UPLOAD_PERMISSIONS` and collected directories receive permissions
|
||||
from :setting:`FILE_UPLOAD_DIRECTORY_PERMISSIONS`. If you would like different
|
||||
permissions for these files and/or directories, you can subclass either of the
|
||||
:ref:`static files storage classes <staticfiles-storages>` and specify the
|
||||
``file_permissions_mode`` and/or ``directory_permissions_mode`` parameters,
|
||||
respectively. For example::
|
||||
|
||||
from django.contrib.staticfiles import storage
|
||||
|
||||
class MyStaticFilesStorage(storage.StaticFilesStorage):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['file_permissions_mode'] = 0o640
|
||||
kwargs['directory_permissions_mode'] = 0o760
|
||||
super(CustomStaticFilesStorage, self).__init__(*args, **kwargs)
|
||||
|
||||
Then set the :setting:`STATICFILES_STORAGE` setting to
|
||||
|
@ -77,9 +80,10 @@ Then set the :setting:`STATICFILES_STORAGE` setting to
|
|||
|
||||
.. versionadded:: 1.7
|
||||
|
||||
The ability to override ``file_permissions_mode`` is new in Django 1.7.
|
||||
Previously the file permissions always used
|
||||
:setting:`FILE_UPLOAD_PERMISSIONS`.
|
||||
The ability to override ``file_permissions_mode`` and
|
||||
``directory_permissions_mode`` is new in Django 1.7. Previously the file
|
||||
permissions always used :setting:`FILE_UPLOAD_PERMISSIONS` and the directory
|
||||
permissions always used :setting:`FILE_UPLOAD_DIRECTORY_PERMISSIONS`.
|
||||
|
||||
.. highlight:: console
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ Django provides two convenient ways to access the current storage class:
|
|||
The FileSystemStorage Class
|
||||
---------------------------
|
||||
|
||||
.. class:: FileSystemStorage([location=None, base_url=None, file_permissions_mode=None])
|
||||
.. class:: FileSystemStorage([location=None, base_url=None, file_permissions_mode=None, directory_permissions_mode=None])
|
||||
|
||||
The :class:`~django.core.files.storage.FileSystemStorage` class implements
|
||||
basic file storage on a local filesystem. It inherits from
|
||||
|
@ -46,6 +46,17 @@ The FileSystemStorage Class
|
|||
The ``file_permissions_mode`` attribute was added. Previously files
|
||||
always received :setting:`FILE_UPLOAD_PERMISSIONS` permissions.
|
||||
|
||||
.. attribute:: directory_permissions_mode
|
||||
|
||||
The file system permissions that the directory will receive when it is
|
||||
saved. Defaults to :setting:`FILE_UPLOAD_DIRECTORY_PERMISSIONS`.
|
||||
|
||||
.. versionadded:: 1.7
|
||||
|
||||
The ``directory_permissions_mode`` attribute was added. Previously
|
||||
directories always received
|
||||
:setting:`FILE_UPLOAD_DIRECTORY_PERMISSIONS` permissions.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``FileSystemStorage.delete()`` method will not raise
|
||||
|
|
|
@ -1135,9 +1135,15 @@ FILE_UPLOAD_DIRECTORY_PERMISSIONS
|
|||
|
||||
Default: ``None``
|
||||
|
||||
The numeric mode to apply to directories created in the process of
|
||||
uploading files. This value mirrors the functionality and caveats of
|
||||
the :setting:`FILE_UPLOAD_PERMISSIONS` setting.
|
||||
The numeric mode to apply to directories created in the process of uploading
|
||||
files.
|
||||
|
||||
This setting also determines the default permissions for collected static
|
||||
directories when using the :djadmin:`collectstatic` management command. See
|
||||
:djadmin:`collectstatic` for details on overriding it.
|
||||
|
||||
This value mirrors the functionality and caveats of the
|
||||
:setting:`FILE_UPLOAD_PERMISSIONS` setting.
|
||||
|
||||
.. setting:: FILE_UPLOAD_PERMISSIONS
|
||||
|
||||
|
@ -1157,7 +1163,7 @@ system's standard umask.
|
|||
|
||||
This setting also determines the default permissions for collected static files
|
||||
when using the :djadmin:`collectstatic` management command. See
|
||||
:djadmin:`collectstatic` for details on overridding it.
|
||||
:djadmin:`collectstatic` for details on overriding it.
|
||||
|
||||
.. warning::
|
||||
|
||||
|
|
|
@ -256,10 +256,11 @@ Minor features
|
|||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* The :ref:`static files storage classes <staticfiles-storages>` may be
|
||||
subclassed to override the permissions that collected static files receive by
|
||||
setting the
|
||||
subclassed to override the permissions that collected static files and
|
||||
directories receive by setting the
|
||||
:attr:`~django.core.files.storage.FileSystemStorage.file_permissions_mode`
|
||||
parameter. See :djadmin:`collectstatic` for example usage.
|
||||
and :attr:`~django.core.files.storage.FileSystemStorage.directory_permissions_mode`
|
||||
parameters. See :djadmin:`collectstatic` for example usage.
|
||||
|
||||
:mod:`django.contrib.syndication`
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -823,6 +823,7 @@ class CustomStaticFilesStorage(storage.StaticFilesStorage):
|
|||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['file_permissions_mode'] = 0o640
|
||||
kwargs['directory_permissions_mode'] = 0o740
|
||||
super(CustomStaticFilesStorage, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
|
@ -839,21 +840,49 @@ class TestStaticFilePermissions(BaseCollectionTestCase, StaticFilesTestCase):
|
|||
'link': False,
|
||||
'dry_run': False}
|
||||
|
||||
def setUp(self):
|
||||
self.umask = 0o027
|
||||
self.old_umask = os.umask(self.umask)
|
||||
super(TestStaticFilePermissions, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
os.umask(self.old_umask)
|
||||
super(TestStaticFilePermissions, self).tearDown()
|
||||
|
||||
# Don't run collectstatic command in this test class.
|
||||
def run_collectstatic(self, **kwargs):
|
||||
pass
|
||||
|
||||
@override_settings(FILE_UPLOAD_PERMISSIONS=0o655)
|
||||
@override_settings(FILE_UPLOAD_PERMISSIONS=0o655,
|
||||
FILE_UPLOAD_DIRECTORY_PERMISSIONS=0o765)
|
||||
def test_collect_static_files_permissions(self):
|
||||
collectstatic.Command().execute(**self.command_params)
|
||||
test_file = os.path.join(settings.STATIC_ROOT, "test.txt")
|
||||
test_dir = os.path.join(settings.STATIC_ROOT, "subdir")
|
||||
file_mode = os.stat(test_file)[0] & 0o777
|
||||
dir_mode = os.stat(test_dir)[0] & 0o777
|
||||
self.assertEqual(file_mode, 0o655)
|
||||
self.assertEqual(dir_mode, 0o765)
|
||||
|
||||
@override_settings(FILE_UPLOAD_PERMISSIONS=None,
|
||||
FILE_UPLOAD_DIRECTORY_PERMISSIONS=None)
|
||||
def test_collect_static_files_default_permissions(self):
|
||||
collectstatic.Command().execute(**self.command_params)
|
||||
test_file = os.path.join(settings.STATIC_ROOT, "test.txt")
|
||||
test_dir = os.path.join(settings.STATIC_ROOT, "subdir")
|
||||
file_mode = os.stat(test_file)[0] & 0o777
|
||||
self.assertEqual(file_mode, 0o655)
|
||||
dir_mode = os.stat(test_dir)[0] & 0o777
|
||||
self.assertEqual(file_mode, 0o666 & ~self.umask)
|
||||
self.assertEqual(dir_mode, 0o777 & ~self.umask)
|
||||
|
||||
@override_settings(FILE_UPLOAD_PERMISSIONS=0o655,
|
||||
FILE_UPLOAD_DIRECTORY_PERMISSIONS=0o765,
|
||||
STATICFILES_STORAGE='staticfiles_tests.tests.CustomStaticFilesStorage')
|
||||
def test_collect_static_files_subclass_of_static_storage(self):
|
||||
collectstatic.Command().execute(**self.command_params)
|
||||
test_file = os.path.join(settings.STATIC_ROOT, "test.txt")
|
||||
test_dir = os.path.join(settings.STATIC_ROOT, "subdir")
|
||||
file_mode = os.stat(test_file)[0] & 0o777
|
||||
dir_mode = os.stat(test_dir)[0] & 0o777
|
||||
self.assertEqual(file_mode, 0o640)
|
||||
self.assertEqual(dir_mode, 0o740)
|
||||
|
|
Loading…
Reference in New Issue