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