diff --git a/konova/forms.py b/konova/forms.py index 95cf5902..359b78bc 100644 --- a/konova/forms.py +++ b/konova/forms.py @@ -354,7 +354,7 @@ class NewDocumentForm(BaseModalForm): file = forms.FileField( label=_("File"), label_suffix=_(""), - help_text=_("Must be smaller than 15 Mb"), + help_text=_("Allowed formats: pdf, jpg, png. Max size 15 MB."), widget=forms.FileInput( attrs={ "class": "form-control-file", @@ -391,6 +391,28 @@ class NewDocumentForm(BaseModalForm): if not self.document_model: raise NotImplementedError("Unsupported document type for {}".format(self.instance.__class__)) + def is_valid(self): + super_valid = super().is_valid() + + _file = self.cleaned_data.get("file", None) + + mime_type_valid = self.document_model.is_mime_type_valid(_file) + if not mime_type_valid: + self.add_error( + "file", + _("Unsupported file type") + ) + + file_size_valid = self.document_model.is_file_size_valid(_file) + if not file_size_valid: + self.add_error( + "file", + _("File too large") + ) + + file_valid = mime_type_valid and file_size_valid + return super_valid and file_valid + def save(self): with transaction.atomic(): action = UserActionLogEntry.get_created_action(self.user) diff --git a/konova/models/document.py b/konova/models/document.py index 11b6c06d..72b124d3 100644 --- a/konova/models/document.py +++ b/konova/models/document.py @@ -5,6 +5,7 @@ Contact: michel.peltriaux@sgdnord.rlp.de Created on: 15.11.21 """ +import mimetypes import os from django.db import models @@ -62,6 +63,15 @@ class AbstractDocument(BaseResource): file = models.FileField() comment = models.TextField() + _valid_mime_types = { + mimetypes.types_map[".pdf"], + mimetypes.types_map[".jpg"], + mimetypes.types_map[".jpeg"], + mimetypes.types_map[".png"], + } + # _maximum_file_size in MB + _maximum_file_size = 15 + class Meta: abstract = True @@ -82,3 +92,12 @@ class AbstractDocument(BaseResource): pass super().delete(using=using, keep_parents=keep_parents) + @classmethod + def is_mime_type_valid(cls, _file: str): + mime_type = _file.content_type + return mime_type in cls._valid_mime_types + + @classmethod + def is_file_size_valid(cls, _file): + max_size = cls._maximum_file_size * pow(1000, 2) + return _file.size <= max_size diff --git a/konova/tests/test_documents.py b/konova/tests/test_documents.py new file mode 100644 index 00000000..e1f800e0 --- /dev/null +++ b/konova/tests/test_documents.py @@ -0,0 +1,73 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 09.12.21 + +""" +import mimetypes + +from django.core.files.uploadedfile import InMemoryUploadedFile + +from konova.models import AbstractDocument +from konova.tests.test_views import BaseTestCase + + +class TestCaseDocuments(BaseTestCase): + """ + Tests for the Documents functionalities + """ + + @classmethod + def setUpTestData(cls): + """ Creates a test file in memory for using in further tests + + Returns: + + """ + super().setUpTestData() + cls.max_file_size = AbstractDocument._maximum_file_size * pow(1000, 2) + cls.test_file = InMemoryUploadedFile( + charset="utf-8", + name="test_file", + size=cls.max_file_size, + file=None, + content_type=None, + field_name=None + ) + + def test_allowed_mime_types(self): + """ Unit test for mime type validity checker + + Checks that only as acceptable configured mime types of an AbstractDocument object will pass the + validity check. + + Returns: + + """ + accepted_mime_types = [] + for file_ending, mime_type in mimetypes.types_map.items(): + self.test_file.content_type = mime_type + valid = AbstractDocument.is_mime_type_valid(self.test_file) + if valid: + accepted_mime_types.append(mime_type) + accepted_mime_types = set(accepted_mime_types) + + self.assertEqual(accepted_mime_types, AbstractDocument._valid_mime_types) + + def test_max_file_size(self): + """ Unit test for maximum file size validity checker + + Returns: + + """ + # Test for exact maximum size + self.assertTrue(AbstractDocument.is_file_size_valid(self.test_file)) + + # Test for lower than maximum size + self.test_file.size = self.max_file_size - 1 + self.assertTrue(AbstractDocument.is_file_size_valid(self.test_file)) + + # Test for larger than maximum size + self.test_file.size = self.max_file_size + 1 + self.assertFalse(AbstractDocument.is_file_size_valid(self.test_file)) diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index d5e0cf26..bea21be2 100644 Binary files a/locale/de/LC_MESSAGES/django.mo and b/locale/de/LC_MESSAGES/django.mo differ diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 83f193bb..b194437a 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -19,7 +19,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-11-17 14:27+0100\n" +"POT-Creation-Date: 2021-12-09 12:36+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -1311,7 +1311,7 @@ msgstr "Datum des Widerspruchs" msgid "Document" msgstr "Dokument" -#: intervention/forms/modalForms.py:140 konova/forms.py:357 +#: intervention/forms/modalForms.py:140 msgid "Must be smaller than 15 Mb" msgstr "Muss kleiner als 15 Mb sein" @@ -1333,7 +1333,7 @@ msgstr "Kompensationen und Zahlungen geprüft" msgid "Run check" msgstr "Prüfung vornehmen" -#: intervention/forms/modalForms.py:196 konova/forms.py:429 +#: intervention/forms/modalForms.py:196 konova/forms.py:451 msgid "" "I, {} {}, confirm that all necessary control steps have been performed by " "myself." @@ -1559,27 +1559,39 @@ msgstr "Wann wurde diese Datei erstellt oder das Foto aufgenommen?" msgid "File" msgstr "Datei" -#: konova/forms.py:397 +#: konova/forms.py:357 +msgid "Allowed formats: pdf, jpg, png. Max size 15 MB." +msgstr "Formate: pdf, jpg, png. Maximal 15 MB." + +#: konova/forms.py:403 +msgid "Unsupported file type" +msgstr "Dateiformat nicht unterstützt" + +#: konova/forms.py:410 +msgid "File too large" +msgstr "Datei zu groß" + +#: konova/forms.py:419 msgid "Added document" msgstr "Dokument hinzugefügt" -#: konova/forms.py:420 +#: konova/forms.py:442 msgid "Confirm record" msgstr "Verzeichnen bestätigen" -#: konova/forms.py:428 +#: konova/forms.py:450 msgid "Record data" msgstr "Daten verzeichnen" -#: konova/forms.py:435 +#: konova/forms.py:457 msgid "Confirm unrecord" msgstr "Entzeichnen bestätigen" -#: konova/forms.py:436 +#: konova/forms.py:458 msgid "Unrecord data" msgstr "Daten entzeichnen" -#: konova/forms.py:437 +#: konova/forms.py:459 msgid "I, {} {}, confirm that this data must be unrecorded." msgstr "" "Ich, {} {}, bestätige, dass diese Daten wieder entzeichnet werden müssen." @@ -3182,6 +3194,9 @@ msgstr "" msgid "A fontawesome icon field" msgstr "" +#~ msgid "No file given!" +#~ msgstr "Keine Datei angegeben!" + #~ msgid "Added payment" #~ msgstr "Zahlung hinzufügen"