"""Run: USE_SQLITE=true python manage.py test drive.test_granular_permissions""" import tempfile import uuid from pathlib import Path from django.contrib.auth import get_user_model from django.test import TestCase, override_settings from django.core.files.uploadedfile import SimpleUploadedFile from rest_framework.test import APIClient from .models import DriveItem, DriveSpace, SpaceGrant, ItemGrant from .spaces import ensure_space, ensure_private_space from .quotas import quota_state, occupancy class GranularPermissionTests(TestCase): def setUp(self): tmp=tempfile.TemporaryDirectory() self.addCleanup(tmp.cleanup) self.dir=Path(tmp.name) settings=override_settings(DRIVE_STORAGE_ROOT=self.dir, FILE_UPLOAD_TEMP_DIR=str(self.dir/'.uploads')) settings.enable();self.addCleanup(settings.disable) User=get_user_model() self.admin=User.objects.create_superuser('test-admin','admin@localhost','ComplexPassword123!') self.member=User.objects.create_user('test-member',password='ComplexPassword123!') self.guest=User.objects.create_user('test-guest',password='ComplexPassword123!') self.root=ensure_space(self.admin) self.private=ensure_private_space(self.member) self.client=APIClient() self.client.force_authenticate(self.admin) def test_delegation_and_independent_rights(self): rights=['view','download','manage_access'] SpaceGrant.objects.create(user=self.member,space=self.root,permissions=rights,can_invite=True) self.client.force_authenticate(self.member) self.assertEqual(self.client.post('/api/drive/folders/',{'space':self.root.pk,'name':'NO'},format='json').status_code,403) created=self.client.post('/api/drive/invitations/',{ 'parent_space':self.root.pk,'permissions':['view','download']},format='json') self.assertEqual(created.status_code,201,created.data) escalation=self.client.post('/api/drive/invitations/',{ 'parent_space':self.root.pk,'permissions':['view','modify']},format='json') self.assertEqual(escalation.status_code,403) no_create=self.client.post('/api/drive/spaces/create/',{ 'parent_space':self.root.pk,'display_name':'Impossible','quota_bytes':None},format='json') self.assertEqual(no_create.status_code,403) self.client.force_authenticate(self.admin) grant=self.client.post('/api/drive/spaces/users/',{ 'parent_space':self.root.pk,'user_id':self.guest.pk, 'permissions':['view','add']},format='json',QUERY_STRING=f'parent_space={self.root.pk}') self.assertEqual(grant.status_code,201,grant.data) self.client.force_authenticate(self.guest) self.assertEqual(self.client.post('/api/drive/folders/',{'space':self.root.pk,'name':'OK'},format='json').status_code,201) self.assertEqual(self.client.post('/api/drive/invitations/',{'parent_space':self.root.pk},format='json').status_code,403) def test_granular_folder_share_and_anonymous_preview(self): folder=DriveItem.objects.create(owner=self.member,space=self.private,name='Photos',is_folder=True) image=DriveItem.objects.create(owner=self.member,space=self.private,parent=folder,name='photo.png', storage_key=str(uuid.uuid4()),storage_location=f'{self.private.relative_path}/Photos/photo.png',size=8,mime_type='image/png') filename=self.dir/image.storage_location filename.parent.mkdir(parents=True,exist_ok=True) filename.write_bytes(b'PNGDATA!') self.client.force_authenticate(self.member) share=self.client.post(f'/api/drive/items/{folder.pk}/shares/',{ 'user_id':self.guest.pk,'permissions':['view','download','add']},format='json') self.assertEqual(share.status_code,201,share.data) self.client.force_authenticate(self.guest) self.assertEqual(self.client.post('/api/drive/folders/',{ 'name':'Nouveau','parent':str(folder.pk),'space':self.private.pk},format='json').status_code,201) self.assertEqual(self.client.post(f'/api/drive/items/{image.pk}/trash/').status_code,403) self.client.force_authenticate(self.member) result=self.client.post(f'/api/drive/items/{image.pk}/public-links/',{},format='json') self.assertEqual(result.status_code,201,result.data) anonymous=APIClient() token=result.data['token'] inline=anonymous.get(f'/api/public/{token}/files/{image.pk}/?inline=1') self.assertEqual(inline.status_code,200) self.assertEqual(inline['Content-Type'],'image/png') self.assertEqual(b''.join(inline.streaming_content),b'PNGDATA!') partial=anonymous.get(f'/api/public/{token}/files/{image.pk}/?inline=1',HTTP_RANGE='bytes=0-2') self.assertEqual(partial.status_code,206) self.assertEqual(b''.join(partial.streaming_content),b'PNG') self.client.force_authenticate(self.member) self.assertEqual(self.client.patch(f'/api/drive/items/{folder.pk}/shares/{share.data["id"]}/permissions/',{ 'permissions':['view']},format='json').status_code,200) self.client.force_authenticate(self.guest) self.assertEqual(self.client.post('/api/drive/folders/',{ 'name':'Interdit','parent':str(folder.pk),'space':self.private.pk},format='json').status_code,403) self.assertEqual(self.client.post(f'/api/drive/items/{image.pk}/link/',{'inline':False},format='json').status_code,403) self.assertEqual(self.client.post(f'/api/drive/items/{image.pk}/link/',{'inline':True},format='json').status_code,200) def test_unreserved_child_quota_parent_usage_reduces_child_capacity(self): gib=1024**3 self.root.quota_bytes=50*gib self.root.save(update_fields=['quota_bytes']) self.client.force_authenticate(self.admin) res=self.client.post('/api/drive/spaces/create/',{ 'parent_space':self.root.pk,'display_name':'Sous espace','quota_bytes':30*gib},format='json') self.assertEqual(res.status_code,201,res.data) child=DriveSpace.objects.get(pk=res.data['id']) self.assertEqual(child.parent_id,self.root.pk) DriveItem.objects.create(space=self.root,owner=self.admin,name='parent.bin',size=20*gib, storage_key=str(uuid.uuid4()),storage_location='unused') self.assertEqual(quota_state(self.root)['used_bytes'],20*gib) self.assertEqual(quota_state(child)['used_bytes'],0) DriveItem.objects.filter(space=self.root).update(size=30*gib) self.assertEqual(quota_state(self.root)['used_bytes'],30*gib) self.assertEqual(quota_state(child)['used_bytes'],10*gib) self.assertEqual(quota_state(child)['available_bytes'],20*gib) DriveItem.objects.create(space=child,owner=self.admin,name='child.bin',size=10*gib, storage_key=str(uuid.uuid4()),storage_location='unused2') self.assertGreaterEqual(quota_state(self.root)['used_bytes'],10*gib) self.assertEqual(quota_state(self.root)['used_bytes'],40*gib) self.assertEqual(quota_state(child)['used_bytes'],20*gib) self.assertEqual(occupancy(child)[0],10*gib)