From 563ce43ee9ffd35d68deaf54fc9daa06c5d71d56 Mon Sep 17 00:00:00 2001 From: Julien Cougnaud Date: Tue, 23 Apr 2024 18:26:07 +0200 Subject: [PATCH] All form document fields can have a default upload size limit --- README.md | 2 ++ osis_document/contrib/fields.py | 3 +-- osis_document/contrib/forms.py | 17 +++++++++++-- osis_document/locale/en/LC_MESSAGES/django.po | 4 ++++ .../locale/fr_BE/LC_MESSAGES/django.po | 4 ++++ osis_document/tests/test_fields.py | 6 ++--- osis_document/tests/test_forms.py | 24 +++++++++++++++++++ setup.py | 2 +- 8 files changed, 53 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 33471d4..c42aa6f 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,8 @@ OSIS_DOCUMENT_DOMAIN_LIST = [ OSIS_DOCUMENT_ALLOWED_EXTENSIONS = ['pdf', 'txt', 'docx', 'doc', 'odt', 'png', 'jpg'] # To enabled mimetype validation ENABLE_MIMETYPE_VALIDATION = True +# To define an upload size limit (in Bytes) (default: None) +OSIS_DOCUMENT_MAX_UPLOAD_SIZE = 52428800 ``` OSIS-Document is aimed at being run on multiple servers, so on your primary server, add it to your `urls.py` diff --git a/osis_document/contrib/fields.py b/osis_document/contrib/fields.py index dbcf1a6..a8adb40 100644 --- a/osis_document/contrib/fields.py +++ b/osis_document/contrib/fields.py @@ -23,9 +23,8 @@ # see http://www.gnu.org/licenses/. # # ############################################################################## -import uuid from os.path import dirname -from typing import Set, List, Union +from typing import List, Union from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.validators import ArrayMinLengthValidator diff --git a/osis_document/contrib/forms.py b/osis_document/contrib/forms.py index 3b467d0..5c6941a 100644 --- a/osis_document/contrib/forms.py +++ b/osis_document/contrib/forms.py @@ -25,6 +25,7 @@ # ############################################################################## from django import forms +from django.conf import settings from django.contrib.postgres.forms import SplitArrayField from django.utils.translation import gettext_lazy as _ @@ -68,11 +69,23 @@ class FileUploadField(SplitArrayField): 'max_files': _("Too many files uploaded"), 'min_files': _("Too few files uploaded"), 'invalid_token': _("Invalid token"), + 'item_invalid': _("Item %(nth)s in the array did not validate:"), } def __init__(self, **kwargs): self.mimetypes = kwargs.pop('mimetypes', None) - self.max_size = kwargs.pop('max_size', None) + + # Define an upload limit size based on the app settings and the field settings + absolute_upload_size_limit = getattr(settings, 'OSIS_DOCUMENT_MAX_UPLOAD_SIZE', None) + field_upload_size_limit = kwargs.pop('max_size', None) + + if field_upload_size_limit: + if absolute_upload_size_limit and field_upload_size_limit > absolute_upload_size_limit: + field_upload_size_limit = absolute_upload_size_limit + else: + field_upload_size_limit = absolute_upload_size_limit + + self.max_size = field_upload_size_limit self.max_files = kwargs.pop('max_files', None) self.min_files = kwargs.pop('min_files', None) self.upload_to = kwargs.pop('upload_to', None) @@ -152,7 +165,7 @@ def prepare_value(self, value): get_remote_token( v, write_token=True, - for_modified_upload=self.for_modified_upload + for_modified_upload=self.for_modified_upload, ) if is_uuid(v) else v diff --git a/osis_document/locale/en/LC_MESSAGES/django.po b/osis_document/locale/en/LC_MESSAGES/django.po index 3b55e8f..38f560b 100644 --- a/osis_document/locale/en/LC_MESSAGES/django.po +++ b/osis_document/locale/en/LC_MESSAGES/django.po @@ -116,6 +116,10 @@ msgstr "" msgid "Invalid upload UUID" msgstr "" +#, python-format +msgid "Item %(nth)s in the array did not validate:" +msgstr "" + msgid "MIME Type" msgstr "" diff --git a/osis_document/locale/fr_BE/LC_MESSAGES/django.po b/osis_document/locale/fr_BE/LC_MESSAGES/django.po index 101f5a6..9344e17 100644 --- a/osis_document/locale/fr_BE/LC_MESSAGES/django.po +++ b/osis_document/locale/fr_BE/LC_MESSAGES/django.po @@ -116,6 +116,10 @@ msgstr "Jeton invalide" msgid "Invalid upload UUID" msgstr "UUID de téléchargement non valide" +#, python-format +msgid "Item %(nth)s in the array did not validate:" +msgstr "L'élément n°%(nth)s du tableau n’est pas valide :" + msgid "MIME Type" msgstr "Type MIME" diff --git a/osis_document/tests/test_fields.py b/osis_document/tests/test_fields.py index fcae847..f33d264 100644 --- a/osis_document/tests/test_fields.py +++ b/osis_document/tests/test_fields.py @@ -145,7 +145,6 @@ def test_model_form_submit( self.assertEqual(len(document.documents), 0) @patch('osis_document.api.utils.get_remote_metadata') - @patch('osis_document.api.utils.get_several_remote_metadata') def test_model_form_confirms_remotely_with_correct_path( self, @@ -154,7 +153,7 @@ def test_model_form_confirms_remotely_with_correct_path( ): token = WriteTokenFactory() - get_remote_metadata.return_value = {"name": "test.jpg"} + get_remote_metadata.return_value = {"name": "test.jpg", "size": 1} get_several_remote_metadata.return_value = { str(token.token): get_remote_metadata.return_value } @@ -169,7 +168,6 @@ def test_model_form_confirms_remotely_with_correct_path( request_mock.assert_called_with(expected_url, json={'upload_to': 'path'}, headers={'X-Api-Key': 'very-secret'}) @patch('osis_document.api.utils.get_remote_metadata') - @patch('osis_document.api.utils.get_several_remote_metadata') def test_model_form_confirms_remotely_with_document_expiration_policy( self, @@ -178,7 +176,7 @@ def test_model_form_confirms_remotely_with_document_expiration_policy( ): token = WriteTokenFactory() - get_remote_metadata.return_value = {"name": "test.jpg"} + get_remote_metadata.return_value = {"name": "test.jpg", "size": 1} get_several_remote_metadata.return_value = { str(token.token): get_remote_metadata.return_value } diff --git a/osis_document/tests/test_forms.py b/osis_document/tests/test_forms.py index 26de1a7..4f6f410 100644 --- a/osis_document/tests/test_forms.py +++ b/osis_document/tests/test_forms.py @@ -215,6 +215,30 @@ class TestForm(forms.Form): error = TokenField.default_error_messages['size'] self.assertIn(str(error), form.errors['media'][0]) + # The max size is not defined in the settings + with override_settings(OSIS_DOCUMENT_MAX_UPLOAD_SIZE=None): + class TestForm(forms.Form): + media_with_limited_size = FileUploadField(max_size=2) + media_without_limited_size = FileUploadField() + + form = TestForm() + + self.assertEqual(form.fields['media_with_limited_size'].max_size, 2) + self.assertEqual(form.fields['media_without_limited_size'].max_size, None) + + # The max size is defined in the settings + with override_settings(OSIS_DOCUMENT_MAX_UPLOAD_SIZE=10): + class TestForm(forms.Form): + media_with_lower_limited_size = FileUploadField(max_size=2) + media_with_greater_limited_size = FileUploadField(max_size=15) + media_without_limited_size = FileUploadField() + + form = TestForm() + + self.assertEqual(form.fields['media_with_lower_limited_size'].max_size, 2) + self.assertEqual(form.fields['media_with_greater_limited_size'].max_size, 10) + self.assertEqual(form.fields['media_without_limited_size'].max_size, 10) + def test_check_mimetype(self): class TestForm(forms.Form): media = FileUploadField(mimetypes=('image/jpeg',)) diff --git a/setup.py b/setup.py index 411eb43..812e03f 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ setup( name='OSIS Document', - version='0.10.6', + version='0.10.7', description='Document management API and widget', url='http://github.com/uclouvain/osis-document', author='Université catholique de Louvain',