"""USE_SQLITE=true python manage.py test drive.test_empty_trash""" import tempfile from pathlib import Path from uuid import uuid4 from django.contrib.auth import get_user_model from django.test import TestCase, override_settings from django.utils import timezone from rest_framework.test import APIClient from .models import DriveItem, SpaceGrant from .spaces import ensure_private_space, ensure_space from .storage_layout import disk_path class EmptyTrashTests(TestCase): def setUp(self): temp = tempfile.TemporaryDirectory() self.addCleanup(temp.cleanup) root = Path(temp.name) config = override_settings(DRIVE_STORAGE_ROOT=root, FILE_UPLOAD_TEMP_DIR=str(root / '.tmp')) config.enable() self.addCleanup(config.disable) self.admin = get_user_model().objects.create_superuser('admin-trash', 'admin@example.org', 'pass') self.other = get_user_model().objects.create_user('private-owner', password='pass') self.shared = ensure_space(self.admin) SpaceGrant.objects.create(user=self.other, space=self.shared, permissions=['view', 'download']) self.private = ensure_private_space(self.other) self.client = APIClient() self.client.force_authenticate(self.admin) def file(self, space, owner, filename, relative_location): location = '/'.join(p for p in (space.relative_path, relative_location) if p) path = disk_path(location) path.parent.mkdir(parents=True, exist_ok=True) path.write_bytes(filename.encode()) record = DriveItem.objects.create( space=space, owner=owner, name=filename, mime_type='text/plain', storage_key=str(uuid4()), storage_location=location, size=len(filename), trashed_at=timezone.now(), ) return record, path def test_empty_trash_removes_accessible_files_but_not_other_private_files(self): item1, path1 = self.file(self.shared, self.admin, 'duplicata.txt', '.gooddrive-trash/id1/duplicata.txt') item2, path2 = self.file(self.shared, self.admin, 'duplicata.txt', '.gooddrive-trash/id2/duplicata.txt') secret, secret_path = self.file(self.private, self.other, 'prive.txt', '.gooddrive-trash/private/prive.txt') with self.captureOnCommitCallbacks(execute=True): response = self.client.delete('/api/drive/trash/') self.assertEqual(response.status_code, 200, response.data) self.assertEqual(response.data['deleted'], 2) self.assertFalse(DriveItem.objects.filter(pk=item1.pk).exists()) self.assertFalse(DriveItem.objects.filter(pk=item2.pk).exists()) self.assertTrue(DriveItem.objects.filter(pk=secret.pk).exists()) self.assertFalse(path1.exists()) self.assertFalse(path2.exists()) self.assertTrue(secret_path.exists()) def test_empty_trash_requires_authentication(self): self.client.force_authenticate(user=None) response = self.client.delete('/api/drive/trash/') self.assertEqual(response.status_code, 401) def test_empty_trash_never_deletes_active_files(self): active, path = self.file(self.shared, self.admin, 'actif.txt', 'actif.txt') DriveItem.objects.filter(pk=active.pk).update(trashed_at=None) response = self.client.delete('/api/drive/trash/') self.assertEqual(response.status_code, 200) self.assertEqual(response.data['deleted'], 0) self.assertTrue(path.exists()) self.assertTrue(DriveItem.objects.filter(pk=active.pk).exists()) def test_reader_cannot_empty_trash(self): reader = get_user_model().objects.create_user('reader', password='pass') SpaceGrant.objects.create(user=reader, space=self.shared, permissions=['view', 'download']) item, path = self.file(self.shared, self.admin, 'lecture.txt', '.gooddrive-trash/reader/lecture.txt') self.client.force_authenticate(reader) response = self.client.delete('/api/drive/trash/') self.assertEqual(response.status_code, 200, response.data) self.assertEqual(response.data['deleted'], 0) self.assertEqual(response.data['skipped'], 1) self.assertTrue(path.exists()) self.assertTrue(DriveItem.objects.filter(pk=item.pk).exists())