diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 4ec1563fc..1b7b6dba3 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -4,7 +4,7 @@ on: [push] jobs: gulp: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest strategy: matrix: node-version: [14.15.x] diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 30cb3b650..fcebed035 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11' ] + python-version: [ '3.8', '3.9', '3.10', '3.11' ] requirements-file: [ django-2.2.txt, django-3.0.txt, @@ -19,12 +19,6 @@ jobs: django-4.2.txt, ] exclude: - - python-version: 3.7 - requirements-file: django-4.0.txt - - python-version: 3.7 - requirements-file: django-4.1.txt - - python-version: 3.7 - requirements-file: django-4.2.txt - python-version: 3.9 requirements-file: django-2.2.txt - python-version: 3.10 @@ -40,7 +34,7 @@ jobs: - python-version: 3.11 requirements-file: django-3.1.txt os: [ - ubuntu-20.04, + ubuntu-latest, ] steps: @@ -50,7 +44,7 @@ jobs: with: python-version: ${{ matrix.python-version }} - name: library prerequisites - run: sudo apt-get install python-dev libpq-dev libmagic1 gcc libxml2-dev libxslt1-dev libjpeg62 libopenjp2-7 -y + run: sudo apt-get install python-dev-is-python3 libpq-dev libmagic1 gcc libxml2-dev libxslt1-dev libjpeg62 libopenjp2-7 -y - name: Install extra dependencies run: pip install lxml if: matrix.python-version == '3.10' diff --git a/.readthedocs.yaml b/.readthedocs.yaml index e6f30f627..1db2e5343 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -7,7 +7,7 @@ version: 2 # Set the version of Python and other tools you might need build: - os: ubuntu-20.04 + os: ubuntu-latest tools: python: "3.9" # You can also specify other tool versions: diff --git a/filer/admin/clipboardadmin.py b/filer/admin/clipboardadmin.py index 9c2d23bb3..6572c1434 100644 --- a/filer/admin/clipboardadmin.py +++ b/filer/admin/clipboardadmin.py @@ -1,7 +1,8 @@ -from django.contrib import admin +from django.contrib import admin, messages from django.forms.models import modelform_factory from django.http import JsonResponse from django.urls import path +from django.utils.translation import gettext_lazy as _ from django.views.decorators.csrf import csrf_exempt from .. import settings as filer_settings @@ -11,8 +12,9 @@ from . import views -NO_FOLDER_ERROR = "Can't find folder to upload. Please refresh and try again" -NO_PERMISSIONS_FOR_FOLDER = ( +NO_PERMISSIONS = _("You do not have permission to upload files.") +NO_FOLDER_ERROR = _("Can't find folder to upload. Please refresh and try again") +NO_PERMISSIONS_FOR_FOLDER = _( "Can't use this folder, Permission Denied. Please select another folder." ) @@ -68,17 +70,24 @@ def ajax_upload(request, folder_id=None): """ Receives an upload from the uploader. Receives only one file at a time. """ + + if not request.user.has_perm("filer.add_file"): + messages.error(request, NO_PERMISSIONS) + return JsonResponse({'error': NO_PERMISSIONS}) + if folder_id: try: # Get folder folder = Folder.objects.get(pk=folder_id) except Folder.DoesNotExist: + messages.error(request, NO_FOLDER_ERROR) return JsonResponse({'error': NO_FOLDER_ERROR}) else: folder = Folder.objects.filter(pk=request.session.get('filer_last_folder_id', 0)).first() # check permissions if folder and not folder.has_add_children_permission(request): + messages.error(request, NO_PERMISSIONS_FOR_FOLDER) return JsonResponse({'error': NO_PERMISSIONS_FOR_FOLDER}) if len(request.FILES) == 1: diff --git a/filer/admin/folderadmin.py b/filer/admin/folderadmin.py index 08dfba06a..2d80574ed 100644 --- a/filer/admin/folderadmin.py +++ b/filer/admin/folderadmin.py @@ -233,6 +233,8 @@ def get_urls(self): # custom views def directory_listing(self, request, folder_id=None, viewtype=None): + if not request.user.has_perm("filer.can_use_directory_listing"): + raise PermissionDenied() clipboard = tools.get_user_clipboard(request.user) if viewtype == 'images_with_missing_data': folder = ImagesWithMissingData() diff --git a/filer/models/filemodels.py b/filer/models/filemodels.py index 61f5c7516..f188c707f 100644 --- a/filer/models/filemodels.py +++ b/filer/models/filemodels.py @@ -300,13 +300,13 @@ def __lt__(self, other): return self.label.lower() < other.label.lower() def has_edit_permission(self, request): - return self.has_generic_permission(request, 'edit') + return request.user.has_perm("filer.change_file") and self.has_generic_permission(request, 'edit') def has_read_permission(self, request): return self.has_generic_permission(request, 'read') def has_add_children_permission(self, request): - return self.has_generic_permission(request, 'add_children') + return request.user.has_perm("filer.add_file") and self.has_generic_permission(request, 'add_children') def has_generic_permission(self, request, permission_type): """ diff --git a/filer/models/foldermodels.py b/filer/models/foldermodels.py index d89a69b62..904b23498 100644 --- a/filer/models/foldermodels.py +++ b/filer/models/foldermodels.py @@ -200,13 +200,13 @@ def quoted_logical_path(self): return urlquote(self.pretty_logical_path) def has_edit_permission(self, request): - return self.has_generic_permission(request, 'edit') + return request.user.has_perm("filer.change_folder") and self.has_generic_permission(request, 'edit') def has_read_permission(self, request): return self.has_generic_permission(request, 'read') def has_add_children_permission(self, request): - return self.has_generic_permission(request, 'add_children') + return request.user.has_perm("filer.change_folder") and self.has_generic_permission(request, 'add_children') def has_generic_permission(self, request, permission_type): """ diff --git a/tests/requirements/django-2.2.txt b/tests/requirements/django-2.2.txt index b11817dee..67429a151 100644 --- a/tests/requirements/django-2.2.txt +++ b/tests/requirements/django-2.2.txt @@ -3,3 +3,4 @@ django>=2.2,<3.0 django_polymorphic>=2.0,<2.1 django-app-helper +easy-thumbnails[svg]<2.10 diff --git a/tests/requirements/django-3.0.txt b/tests/requirements/django-3.0.txt index 7acd7b8cd..9888afb33 100644 --- a/tests/requirements/django-3.0.txt +++ b/tests/requirements/django-3.0.txt @@ -3,3 +3,4 @@ django>=3.0,<3.1 django_polymorphic>=2.1,<2.2 django-app-helper +easy-thumbnails[svg]<2.10 diff --git a/tests/requirements/django-3.1.txt b/tests/requirements/django-3.1.txt index a02465ea6..6ccb0621d 100644 --- a/tests/requirements/django-3.1.txt +++ b/tests/requirements/django-3.1.txt @@ -3,3 +3,4 @@ django>=3.1,<3.2 django_polymorphic>=2,<3.1 django-app-helper +easy-thumbnails[svg]<2.10 diff --git a/tests/requirements/django-3.2.txt b/tests/requirements/django-3.2.txt index 52ee4482d..e51c93320 100644 --- a/tests/requirements/django-3.2.txt +++ b/tests/requirements/django-3.2.txt @@ -3,3 +3,4 @@ django>=3.2,<4 django_polymorphic>=2,<3.1 django-app-helper +easy-thumbnails[svg]<2.10 diff --git a/tests/requirements/django-4.0.txt b/tests/requirements/django-4.0.txt index 1a782168a..e942141dd 100644 --- a/tests/requirements/django-4.0.txt +++ b/tests/requirements/django-4.0.txt @@ -3,3 +3,4 @@ django>=4.0,<4.1 django_polymorphic>=3.1 https://github.com/jrief/django-app-helper/archive/refs/heads/develop.zip +easy-thumbnails[svg]<2.10 diff --git a/tests/requirements/django-4.1.txt b/tests/requirements/django-4.1.txt index e47bf45d9..33eea6114 100644 --- a/tests/requirements/django-4.1.txt +++ b/tests/requirements/django-4.1.txt @@ -3,3 +3,4 @@ django>=4.1,<4.2 django_polymorphic>=3.1 https://github.com/jrief/django-app-helper/archive/refs/heads/develop.zip +easy-thumbnails[svg]<2.10 diff --git a/tests/test_admin.py b/tests/test_admin.py index 00f601b9f..29aeb5030 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -6,7 +6,9 @@ from django.contrib import admin from django.contrib.admin import helpers from django.contrib.auth import get_user_model +from django.contrib.auth.models import Permission from django.forms.models import model_to_dict as model_to_dict_django +from django.http import HttpRequest, HttpResponseForbidden from django.test import TestCase from django.urls import reverse @@ -223,14 +225,16 @@ def tearDown(self): def test_filer_upload_file(self, extra_headers={}): self.assertEqual(Image.objects.count(), 0) folder = Folder.objects.create(name='foo') - file_obj = django.core.files.File(open(self.filename, 'rb')) - url = reverse('admin:filer-ajax_upload', kwargs={'folder_id': folder.pk}) - post_data = { - 'Filename': self.image_name, - 'Filedata': file_obj, - 'jsessionid': self.client.session.session_key - } - response = self.client.post(url, post_data, **extra_headers) # noqa + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + url = reverse('admin:filer-ajax_upload', kwargs={'folder_id': folder.pk}) + post_data = { + 'Filename': self.image_name, + 'Filedata': file_obj, + 'jsessionid': self.client.session.session_key + } + self.client.post(url, post_data, **extra_headers) + self.assertEqual(Image.objects.count(), 1) self.assertEqual(Image.objects.all()[0].original_filename, self.image_name) @@ -244,14 +248,16 @@ def test_filer_upload_video(self, extra_headers={}): )): self.assertEqual(Video.objects.count(), 0) folder = Folder.objects.create(name='foo') - file_obj = django.core.files.File(open(self.video_filename, 'rb')) - url = reverse('admin:filer-ajax_upload', kwargs={'folder_id': folder.pk}) - post_data = { - 'Filename': self.video_name, - 'Filedata': file_obj, - 'jsessionid': self.client.session.session_key - } - response = self.client.post(url, post_data, **extra_headers) # noqa + with open(self.video_filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + url = reverse('admin:filer-ajax_upload', kwargs={'folder_id': folder.pk}) + post_data = { + 'Filename': self.video_name, + 'Filedata': file_obj, + 'jsessionid': self.client.session.session_key + } + self.client.post(url, post_data, **extra_headers) + self.assertEqual(Video.objects.count(), 1) self.assertEqual(Video.objects.all()[0].original_filename, self.video_name) @@ -264,62 +270,67 @@ def test_filer_upload_extimage(self, extra_headers={}): )): self.assertEqual(ExtImage.objects.count(), 0) folder = Folder.objects.create(name='foo') - file_obj = django.core.files.File(open(self.filename, 'rb')) - url = reverse('admin:filer-ajax_upload', kwargs={'folder_id': folder.pk}) + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + url = reverse('admin:filer-ajax_upload', kwargs={'folder_id': folder.pk}) + post_data = { + 'Filename': self.image_name, + 'Filedata': file_obj, + 'jsessionid': self.client.session.session_key + } + self.client.post(url, post_data, **extra_headers) + + self.assertEqual(ExtImage.objects.count(), 1) + self.assertEqual(ExtImage.objects.all()[0].original_filename, self.image_name) + + def test_filer_upload_file_no_folder(self, extra_headers={}): + self.assertEqual(Image.objects.count(), 0) + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + url = reverse('admin:filer-ajax_upload') post_data = { 'Filename': self.image_name, 'Filedata': file_obj, 'jsessionid': self.client.session.session_key } response = self.client.post(url, post_data, **extra_headers) # noqa - self.assertEqual(ExtImage.objects.count(), 1) - self.assertEqual(ExtImage.objects.all()[0].original_filename, self.image_name) - - def test_filer_upload_file_no_folder(self, extra_headers={}): - self.assertEqual(Image.objects.count(), 0) - file_obj = django.core.files.File(open(self.filename, 'rb')) - url = reverse('admin:filer-ajax_upload') - post_data = { - 'Filename': self.image_name, - 'Filedata': file_obj, - 'jsessionid': self.client.session.session_key - } - response = self.client.post(url, post_data, **extra_headers) # noqa - self.assertEqual(Image.objects.count(), 1) - stored_image = Image.objects.first() - self.assertEqual(stored_image.original_filename, self.image_name) - self.assertEqual(stored_image.mime_type, 'image/jpeg') + self.assertEqual(Image.objects.count(), 1) + stored_image = Image.objects.first() + self.assertEqual(stored_image.original_filename, self.image_name) + self.assertEqual(stored_image.mime_type, 'image/jpeg') def test_filer_upload_binary_data(self, extra_headers={}): self.assertEqual(File.objects.count(), 0) - file_obj = django.core.files.File(open(self.binary_filename, 'rb')) - url = reverse('admin:filer-ajax_upload') - post_data = { - 'Filename': self.binary_name, - 'Filedata': file_obj, - 'jsessionid': self.client.session.session_key - } - response = self.client.post(url, post_data, **extra_headers) # noqa - self.assertEqual(Image.objects.count(), 0) - self.assertEqual(File.objects.count(), 1) - stored_file = File.objects.first() - self.assertEqual(stored_file.original_filename, self.binary_name) - self.assertEqual(stored_file.mime_type, 'application/octet-stream') + with open(self.binary_filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + url = reverse('admin:filer-ajax_upload') + post_data = { + 'Filename': self.binary_name, + 'Filedata': file_obj, + 'jsessionid': self.client.session.session_key + } + self.client.post(url, post_data, **extra_headers) + self.assertEqual(Image.objects.count(), 0) + self.assertEqual(File.objects.count(), 1) + stored_file = File.objects.first() + self.assertEqual(stored_file.original_filename, self.binary_name) + self.assertEqual(stored_file.mime_type, 'application/octet-stream') def test_filer_ajax_upload_file(self): self.assertEqual(Image.objects.count(), 0) folder = Folder.objects.create(name='foo') - file_obj = django.core.files.File(open(self.filename, 'rb')) - url = reverse( - 'admin:filer-ajax_upload', - kwargs={'folder_id': folder.pk} - ) + '?filename=%s' % self.image_name - response = self.client.post( # noqa - url, - data=file_obj.read(), - content_type='image/jpeg', - **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} - ) + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + url = reverse( + 'admin:filer-ajax_upload', + kwargs={'folder_id': folder.pk} + ) + '?filename=%s' % self.image_name + response = self.client.post( # noqa + url, + data=file_obj.read(), + content_type='image/jpeg', + **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} + ) self.assertEqual(Image.objects.count(), 1) stored_image = Image.objects.first() self.assertEqual(stored_image.original_filename, self.image_name) @@ -328,17 +339,18 @@ def test_filer_ajax_upload_file(self): def test_filer_ajax_upload_file_using_content_type(self): self.assertEqual(Image.objects.count(), 0) folder = Folder.objects.create(name='foo') - file_obj = django.core.files.File(open(self.binary_filename, 'rb')) - url = reverse( - 'admin:filer-ajax_upload', - kwargs={'folder_id': folder.pk} - ) + '?filename=renamed.pdf' - response = self.client.post( # noqa - url, - data=file_obj.read(), - content_type='application/pdf', - **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} - ) + with open(self.binary_filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + url = reverse( + 'admin:filer-ajax_upload', + kwargs={'folder_id': folder.pk} + ) + '?filename=renamed.pdf' + self.client.post( + url, + data=file_obj.read(), + content_type='application/pdf', + **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} + ) self.assertEqual(Image.objects.count(), 0) self.assertEqual(File.objects.count(), 1) stored_file = File.objects.first() @@ -347,16 +359,17 @@ def test_filer_ajax_upload_file_using_content_type(self): def test_filer_ajax_upload_file_no_folder(self): self.assertEqual(Image.objects.count(), 0) - file_obj = django.core.files.File(open(self.filename, 'rb')) - url = reverse( - 'admin:filer-ajax_upload' - ) + '?filename=%s' % self.image_name - response = self.client.post( # noqa - url, - data=file_obj.read(), - content_type='image/jpeg', - **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} - ) + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + url = reverse( + 'admin:filer-ajax_upload' + ) + '?filename=%s' % self.image_name + self.client.post( + url, + data=file_obj.read(), + content_type='image/jpeg', + **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} + ) self.assertEqual(Image.objects.count(), 1) stored_image = Image.objects.first() self.assertEqual(stored_image.original_filename, self.image_name) @@ -365,15 +378,16 @@ def test_filer_ajax_upload_file_no_folder(self): def test_filer_upload_file_error(self, extra_headers={}): self.assertEqual(Image.objects.count(), 0) folder = Folder.objects.create(name='foo') - file_obj = django.core.files.File(open(self.filename, 'rb')) - url = reverse('admin:filer-ajax_upload', - kwargs={'folder_id': folder.pk + 1}) - post_data = { - 'Filename': self.image_name, - 'Filedata': file_obj, - 'jsessionid': self.client.session.session_key - } - response = self.client.post(url, post_data, **extra_headers) + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + url = reverse('admin:filer-ajax_upload', + kwargs={'folder_id': folder.pk + 1}) + post_data = { + 'Filename': self.image_name, + 'Filedata': file_obj, + 'jsessionid': self.client.session.session_key + } + response = self.client.post(url, post_data, **extra_headers) from filer.admin.clipboardadmin import NO_FOLDER_ERROR self.assertContains(response, NO_FOLDER_ERROR) self.assertEqual(Image.objects.count(), 0) @@ -381,18 +395,19 @@ def test_filer_upload_file_error(self, extra_headers={}): def test_filer_ajax_upload_file_error(self): self.assertEqual(Image.objects.count(), 0) folder = Folder.objects.create(name='foo') - file_obj = django.core.files.File(open(self.filename, 'rb')) - url = reverse( - 'admin:filer-ajax_upload', - kwargs={ - 'folder_id': folder.pk + 1} - ) + '?filename={0}'.format(self.image_name) - response = self.client.post( - url, - data=file_obj.read(), - content_type='application/octet-stream', - **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} - ) + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + url = reverse( + 'admin:filer-ajax_upload', + kwargs={ + 'folder_id': folder.pk + 1} + ) + '?filename={0}'.format(self.image_name) + response = self.client.post( + url, + data=file_obj.read(), + content_type='application/octet-stream', + **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} + ) from filer.admin.clipboardadmin import NO_FOLDER_ERROR self.assertContains(response, NO_FOLDER_ERROR) self.assertEqual(Image.objects.count(), 0) @@ -403,35 +418,38 @@ def test_filer_upload_permissions_error(self, extra_headers={}): username='joe_new', password='x', email='joe@mata.com') staff_user.is_staff = True staff_user.save() + staff_user.user_permissions.add(*Permission.objects.filter(codename="add_file")) self.client.login(username='joe_new', password='x') self.assertEqual(Image.objects.count(), 0) folder = Folder.objects.create(name='foo') - file_obj = django.core.files.File(open(self.filename, 'rb')) - - with SettingsOverride(filer_settings, FILER_ENABLE_PERMISSIONS=True): - - # give permissions over BAR - FolderPermission.objects.create( - folder=folder, - user=staff_user, - type=FolderPermission.THIS, - can_edit=FolderPermission.DENY, - can_read=FolderPermission.ALLOW, - can_add_children=FolderPermission.DENY) - url = reverse('admin:filer-ajax_upload', - kwargs={'folder_id': folder.pk}) - post_data = { - 'Filename': self.image_name, - 'Filedata': file_obj, - 'jsessionid': self.client.session.session_key - } - response = self.client.post(url, post_data, **extra_headers) + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + + with SettingsOverride(filer_settings, FILER_ENABLE_PERMISSIONS=True): + + # give permissions over BAR + FolderPermission.objects.create( + folder=folder, + user=staff_user, + type=FolderPermission.THIS, + can_edit=FolderPermission.DENY, + can_read=FolderPermission.ALLOW, + can_add_children=FolderPermission.DENY) + url = reverse('admin:filer-ajax_upload', + kwargs={'folder_id': folder.pk}) + post_data = { + 'Filename': self.image_name, + 'Filedata': file_obj, + 'jsessionid': self.client.session.session_key + } + response = self.client.post(url, post_data, **extra_headers) from filer.admin.clipboardadmin import NO_PERMISSIONS_FOR_FOLDER self.assertContains(response, NO_PERMISSIONS_FOR_FOLDER) self.assertEqual(Image.objects.count(), 0) - def test_filer_ajax_upload_permissions_error(self, extra_headers={}): + def test_filer_ajax_upload_without_permissions_error(self, extra_headers={}): + """User without add_file permission cannot upload""" self.client.logout() staff_user = User.objects.create_user( username='joe_new', password='x', email='joe@mata.com') @@ -440,18 +458,9 @@ def test_filer_ajax_upload_permissions_error(self, extra_headers={}): self.client.login(username='joe_new', password='x') self.assertEqual(Image.objects.count(), 0) folder = Folder.objects.create(name='foo') - file_obj = django.core.files.File(open(self.filename, 'rb')) - - with SettingsOverride(filer_settings, FILER_ENABLE_PERMISSIONS=True): + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh) - # give permissions over BAR - FolderPermission.objects.create( - folder=folder, - user=staff_user, - type=FolderPermission.THIS, - can_edit=FolderPermission.DENY, - can_read=FolderPermission.ALLOW, - can_add_children=FolderPermission.DENY) url = reverse( 'admin:filer-ajax_upload', kwargs={ @@ -463,6 +472,73 @@ def test_filer_ajax_upload_permissions_error(self, extra_headers={}): content_type='application/octet-stream', **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} ) + + from filer.admin.clipboardadmin import NO_PERMISSIONS + + self.assertContains(response, NO_PERMISSIONS) + self.assertEqual(Image.objects.count(), 0) + + def test_filer_add_file_permissions(self, extra_headers={}): + """Add_file permissions reflect in has_... methods of File and Folder classes""" + self.client.logout() + staff_user = User.objects.create_user( + username='joe_new', password='x', email='joe@mata.com') + staff_user.is_staff = True + staff_user.save() + self.client.login(username='joe_new', password='x') + self.assertEqual(Image.objects.count(), 0) + folder = Folder.objects.create(name='foo') + + file_data = django.core.files.base.ContentFile('some data') + file_data.name = self.filename + file = File.objects.create( + owner=self.superuser, + original_filename=self.filename, + file=file_data, + folder=folder + ) + file.save() + request = HttpRequest() + setattr(request, "user", staff_user) + + self.assertEqual(folder.has_add_children_permission(request), False) + self.assertEqual(file.has_add_children_permission(request), False) + + def test_filer_ajax_upload_permissions_error(self, extra_headers={}): + self.client.logout() + staff_user = User.objects.create_user( + username='joe_new', password='x', email='joe@mata.com') + staff_user.is_staff = True + staff_user.save() + staff_user.user_permissions.add(*Permission.objects.filter(codename="add_file")) + self.client.login(username='joe_new', password='x') + self.assertEqual(Image.objects.count(), 0) + folder = Folder.objects.create(name='foo') + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh) + + with SettingsOverride(filer_settings, FILER_ENABLE_PERMISSIONS=True): + + # give permissions over BAR + FolderPermission.objects.create( + folder=folder, + user=staff_user, + type=FolderPermission.THIS, + can_edit=FolderPermission.DENY, + can_read=FolderPermission.ALLOW, + can_add_children=FolderPermission.DENY) + url = reverse( + 'admin:filer-ajax_upload', + kwargs={ + 'folder_id': folder.pk} + ) + '?filename={0}'.format(self.image_name) + response = self.client.post( + url, + data=file_obj.read(), + content_type='application/octet-stream', + **{'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'} + ) + from filer.admin.clipboardadmin import NO_PERMISSIONS_FOR_FOLDER self.assertContains(response, NO_PERMISSIONS_FOR_FOLDER) self.assertEqual(Image.objects.count(), 0) @@ -471,9 +547,10 @@ def test_templatetag_file_icon_url(self): filename = os.path.join(settings.FILE_UPLOAD_TEMP_DIR, 'invalid.svg') with open(filename, 'wb') as fh: fh.write(b'') - file_obj = django.core.files.File(open(filename, 'rb'), name=filename) - image_obj = Image.objects.create(owner=self.superuser, original_filename=self.image_name, file=file_obj, mime_type='image/svg+xml') - image_obj.save() + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh, name=filename) + image_obj = Image.objects.create(owner=self.superuser, original_filename=self.image_name, file=file_obj, mime_type='image/svg+xml') + image_obj.save() url = file_icon_url(image_obj) self.assertEqual(url, '/static/filer/icons/file\\u002Dunknown.svg') @@ -517,9 +594,10 @@ def create_src_and_dst_folders(self): def create_image(self, folder, filename=None): filename = filename or 'test_image.jpg' - file_obj = django.core.files.File(open(self.filename, 'rb'), name=filename) - image_obj = Image.objects.create(owner=self.superuser, original_filename=self.image_name, file=file_obj, folder=folder, mime_type='image/jpeg') - image_obj.save() + with open(self.filename, 'rb') as fh: + file_obj = django.core.files.File(fh, name=filename) + image_obj = Image.objects.create(owner=self.superuser, original_filename=self.image_name, file=file_obj, folder=folder, mime_type='image/jpeg') + image_obj.save() return image_obj def create_file(self, folder, filename=None): @@ -869,6 +947,8 @@ def setUp(self): username='joe', password='x', email='joe@mata.com') self.staff_user.is_staff = True self.staff_user.save() + perms = Permission.objects.filter(codename__in=["view_folder", "add_file", "add_folder", "can_use_directory_listing"]) + self.staff_user.user_permissions.add(*perms) self.parent = Folder.objects.create(name='bar', parent=None, owner=superuser) self.foo_folder = Folder.objects.create(name='foo', parent=self.parent, owner=self.staff_user) @@ -882,6 +962,18 @@ def setUp(self): file=file_data, folder=self.parent) self.client.login(username='joe', password='x') + def test_with_without_permissions(self): + staff_user_wo_permissions = User.objects.create_user( + username='joemata', password='x', email='joe@mata.com') + staff_user_wo_permissions.is_staff = True + staff_user_wo_permissions.save() + self.client.login(username='joemata', password='x') + with SettingsOverride(filer_settings, FILER_ENABLE_PERMISSIONS=False): + response = self.client.get( + reverse('admin:filer-directory_listing', + kwargs={'folder_id': self.parent.id})) + self.assertIsInstance(response, HttpResponseForbidden) + def test_with_permissions_disabled(self): with SettingsOverride(filer_settings, FILER_ENABLE_PERMISSIONS=False): response = self.client.get( diff --git a/tests/test_dump.py b/tests/test_dump.py index 9121ef184..d8295ddfd 100644 --- a/tests/test_dump.py +++ b/tests/test_dump.py @@ -35,17 +35,19 @@ def tearDown(self): pass def create_filer_image(self, folder=None): - file_obj = DjangoFile(open(self.filename, 'rb'), name=self.image_name) - image = Image.objects.create(owner=self.superuser, - original_filename=self.image_name, - file=file_obj, folder=folder) + with open(self.filename, 'rb') as file: + file_obj = DjangoFile(file, name=self.image_name) + image = Image.objects.create(owner=self.superuser, + original_filename=self.image_name, + file=file_obj, folder=folder) return image def create_filer_file(self, folder=None): - file_obj = DjangoFile(open(self.filename, 'rb'), name=self.image_name) - fileobj = File.objects.create(owner=self.superuser, - original_filename=self.image_name, - file=file_obj, folder=folder) + with open(self.filename, 'rb') as file: + file_obj = DjangoFile(file, name=self.image_name) + fileobj = File.objects.create(owner=self.superuser, + original_filename=self.image_name, + file=file_obj, folder=folder) return fileobj def test_dump_data_base(self): diff --git a/tests/test_permissions.py b/tests/test_permissions.py index 23e7d93bc..1dacb2a38 100644 --- a/tests/test_permissions.py +++ b/tests/test_permissions.py @@ -1,7 +1,7 @@ import os from django.conf import settings -from django.contrib.auth.models import Group +from django.contrib.auth.models import Group, Permission from django.core.files import File as DjangoFile from django.test.testcases import TestCase @@ -33,8 +33,11 @@ def setUp(self): self.owner = User.objects.create(username='owner') + perms = Permission.objects.filter(codename="change_folder") self.test_user1 = User.objects.create(username='test1', password='secret') self.test_user2 = User.objects.create(username='test2', password='secret') + self.test_user1.user_permissions.add(*perms) + self.test_user2.user_permissions.add(*perms) self.group1 = Group.objects.create(name='name1') self.group2 = Group.objects.create(name='name2') diff --git a/tests/test_tools.py b/tests/test_tools.py index 2b548597a..914aabd4c 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -35,6 +35,7 @@ def setUp(self): self.folder = Folder.objects.create(name='test_folder') def tearDown(self): + self.file.close() self.client.logout() os.remove(self.filename) for img in Image.objects.all(): diff --git a/tox.ini b/tox.ini index 1d868b739..159ba6974 100644 --- a/tox.ini +++ b/tox.ini @@ -4,12 +4,12 @@ envlist = isort docs frontend - py{36,37,38}-dj{22}-swap - py{36,37,38}-dj{22}-noswap - py{36,37,38,39}-dj{30,31}-swap - py{36,37,38,39}-dj{30,31}-noswap - py{36,37,38,39,310}-dj32-swap - py{36,37,38,39,310}-dj32-noswap + py{38}-dj{22}-swap + py{38}-dj{22}-noswap + py{38,39}-dj{30,31}-swap + py{38,39}-dj{30,31}-noswap + py{38,39,310}-dj32-swap + py{38,39,310}-dj32-noswap py{38,39,310,311}-dj{40,41,42}-{swap,noswap} [gh-actions]