diff --git a/client/src/app/shared/components/media-upload-content/media-upload-content.component.html b/client/src/app/shared/components/media-upload-content/media-upload-content.component.html index d6bdae870..4cc4a808e 100644 --- a/client/src/app/shared/components/media-upload-content/media-upload-content.component.html +++ b/client/src/app/shared/components/media-upload-content/media-upload-content.component.html @@ -54,7 +54,10 @@ File information
- insert_drive_file {{ file.mediafile.type }} + + insert_drive_file + {{ getFiletype(file.mediafile) | translate }} + data_usage {{ getReadableSize(file.mediafile.size) }} diff --git a/client/src/app/shared/components/media-upload-content/media-upload-content.component.ts b/client/src/app/shared/components/media-upload-content/media-upload-content.component.ts index 94bf3ae62..9940d702e 100644 --- a/client/src/app/shared/components/media-upload-content/media-upload-content.component.ts +++ b/client/src/app/shared/components/media-upload-content/media-upload-content.component.ts @@ -158,14 +158,27 @@ export class MediaUploadContentComponent implements OnInit { } /** - * Converts a file size in bit into human readable format + * Returns the filetype from the file or a generic "File", if the type could + * not be determinated. * - * @param bits file size in bits + * @param file The file to get the type from. + */ + public getFiletype(file: File): string { + return file.type || 'File'; + } + + /** + * Converts a file size in byte into human readable format + * + * @param bytes file size in bytes * @returns a readable file size representation */ - public getReadableSize(bits: number): string { - const unitLevel = Math.floor(Math.log(bits) / Math.log(1024)); - const bytes = +(bits / Math.pow(1024, unitLevel)).toFixed(2); + public getReadableSize(bytes: number): string { + if (bytes === 0) { + return '0 B'; + } + const unitLevel = Math.floor(Math.log(bytes) / Math.log(1024)); + bytes = +(bytes / Math.pow(1024, unitLevel)).toFixed(2); return `${bytes} ${['B', 'kB', 'MB', 'GB', 'TB'][unitLevel]}`; } diff --git a/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.html b/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.html index 3e6118c42..921ba1860 100644 --- a/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.html +++ b/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.html @@ -111,7 +111,7 @@ {{ mediafile.filename }}
- {{ getDateFromTimestamp(mediafile.timestamp) }} · {{ mediafile.size }} + {{ getDateFromTimestamp(mediafile.timestamp) }} · {{ mediafile.filesize }}
diff --git a/openslides/mediafiles/models.py b/openslides/mediafiles/models.py index 53956a696..9898f5cb5 100644 --- a/openslides/mediafiles/models.py +++ b/openslides/mediafiles/models.py @@ -103,14 +103,27 @@ class Mediafile(RESTModelMixin, ListOfSpeakersMixin, models.Model): """ `unique_together` is not working with foreign keys with possible `null` values. So we do need to check this here. + + self.original_filename is not yet set, but if is_file is True, the actual + filename is self.mediafile.file """ + title_or_original_filename = models.Q(title=self.title) + if self.is_file: + title_or_original_filename = title_or_original_filename | models.Q( + original_filename=self.mediafile.name + ) + if ( - Mediafile.objects.exclude(pk=self.pk) - .filter(title=self.title, parent=self.parent) + Mediafile.objects.exclude( + pk=self.pk + ) # self.pk is None on creation, but this does not invalidate the exclude statement. + .filter(title_or_original_filename, parent=self.parent) .exists() ): raise ValidationError( - {"detail": "A mediafile with this title already exists in this folder."} + { + "detail": "A mediafile with this title or filename already exists in this folder." + } ) def __str__(self): diff --git a/tests/integration/mediafiles/test_viewset.py b/tests/integration/mediafiles/test_viewset.py index 4d5617745..1db7c1875 100644 --- a/tests/integration/mediafiles/test_viewset.py +++ b/tests/integration/mediafiles/test_viewset.py @@ -70,7 +70,35 @@ class TestCreation(TestCase): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertFalse(Mediafile.objects.exists()) - def test_mediafile_twice(self): + def test_no_extension(self): + file = SimpleUploadedFile("no_extension", b"some content.") + response = self.client.post( + reverse("mediafile-list"), + {"title": "test_title_vai8oDogohheideedie4", "mediafile": file}, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + mediafile = Mediafile.objects.get() + self.assertEqual(mediafile.title, "test_title_vai8oDogohheideedie4") + + def test_mediafile_twice_different_title(self): + file1 = SimpleUploadedFile("file.ext", b"some content.") + file2 = SimpleUploadedFile("file.ext", b"some content.") + response = self.client.post( + reverse("mediafile-list"), + {"title": "test_title_Zeicheipeequie3ohfid", "mediafile": file1}, + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + mediafile = Mediafile.objects.get() + self.assertEqual(mediafile.title, "test_title_Zeicheipeequie3ohfid") + + response = self.client.post( + reverse("mediafile-list"), + {"title": "test_title_aiChaetohs0quicee9eb", "mediafile": file2}, + ) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(Mediafile.objects.count(), 1) + + def test_directory_twice(self): title = "test_title_kFJq83fjmqo2babfqk3f" Mediafile.objects.create(is_directory=True, title=title) response = self.client.post(