diff --git a/buildout.cfg b/buildout.cfg
index bb635cb..808636e 100644
--- a/buildout.cfg
+++ b/buildout.cfg
@@ -1,5 +1,10 @@
[buildout]
+
# use this extend one of the buildout configuration:
extends =
test_plone52.cfg
+
+[instance]
+eggs +=
+ redturtle.volto
diff --git a/collective/limitfilesizepanel/browser/configure.zcml b/collective/limitfilesizepanel/browser/configure.zcml
index a1b4a73..c098ede 100644
--- a/collective/limitfilesizepanel/browser/configure.zcml
+++ b/collective/limitfilesizepanel/browser/configure.zcml
@@ -3,37 +3,55 @@
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:plone="http://namespaces.plone.org/plone"
xmlns:zcml="http://namespaces.zope.org/zcml"
- i18n_domain="collective.limitfilesizepanel">
+ i18n_domain="collective.limitfilesizepanel"
+ >
-
+
-
+
-
+
+
+
+
+
diff --git a/collective/limitfilesizepanel/browser/folder_contents_upload.py b/collective/limitfilesizepanel/browser/folder_contents_upload.py
new file mode 100644
index 0000000..8974ad0
--- /dev/null
+++ b/collective/limitfilesizepanel/browser/folder_contents_upload.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+from plone import api
+from plone.app.content.browser.file import FileUploadView as BaseFileUploadView
+
+import mimetypes
+
+
+class FileUpload(BaseFileUploadView):
+ """
+ Add filetype validation for folder_contents massive upload view.
+ This view is a merge from collective.limitfilesizepanel and rer.hardening
+ customizations.
+ """
+
+ def __call__(self):
+ filedata = self.request.form.get("file", None)
+
+ if not filedata:
+ return super(FileUpload, self).__call__()
+
+ # limitfilesizepanel check
+ filename = filedata.filename
+ content_type = mimetypes.guess_type(filename)[0] or ""
+ ctr = api.portal.get_tool(name="content_type_registry")
+ portal_type = ctr.findTypeName(filename.lower(), content_type, "") or "File"
+
+ helper_view = api.content.get_view(
+ name="lfsp_helpers_view",
+ context=self.context,
+ request=self.context.REQUEST,
+ )
+
+ if helper_view.newDataOnly() and "/edit" in self.request.get(
+ "HTTP_REFERER"
+ ): # noqa
+ return super(FileUpload, self).__call__()
+ maxsize = helper_view.get_maxsize_tiny((portal_type,))
+ if not maxsize:
+ return super(FileUpload, self).__call__()
+
+ size_check = helper_view.check_size(maxsize=maxsize, uploadfile=filedata)
+ if size_check and not size_check.get("valid", False):
+ response = self.request.RESPONSE
+ response.setStatus(403)
+ return size_check.get("error", "")
+
+ return super(FileUpload, self).__call__()
diff --git a/collective/limitfilesizepanel/configure.zcml b/collective/limitfilesizepanel/configure.zcml
index d24b80b..346f835 100644
--- a/collective/limitfilesizepanel/configure.zcml
+++ b/collective/limitfilesizepanel/configure.zcml
@@ -1,50 +1,58 @@
+ xmlns:i18n="http://namespaces.zope.org/i18n"
+ xmlns:monkey="http://namespaces.plone.org/monkey"
+ xmlns:zcml="http://namespaces.zope.org/zcml"
+ i18n_domain="collective.limitfilesizepanel"
+ >
-
+
+ id="collective.limitfilesizepanel.LimitFileSizePanel"
+ title="collective.limitfilesizepanel: Manage limit file size settings"
+ />
+ id="collective.limitfilesizepanel.BypassLimitSize"
+ title="collective.limitfilesizepanel: Bypass limit size"
+ />
+
-
-
-
+
+
diff --git a/collective/limitfilesizepanel/tests/test_upload.py b/collective/limitfilesizepanel/tests/test_upload.py
new file mode 100644
index 0000000..cffca3d
--- /dev/null
+++ b/collective/limitfilesizepanel/tests/test_upload.py
@@ -0,0 +1,176 @@
+# -*- coding: utf-8 -*-
+from collective.limitfilesizepanel.interfaces import ILimitFileSizePanel
+from collective.limitfilesizepanel.testing import LIMITFILESIZEPANEL_FUNCTIONAL_TESTING
+from plone import api
+from plone.app.testing import setRoles
+from plone.app.testing import TEST_USER_ID
+from plone.registry.interfaces import IRegistry
+from zope.component import queryUtility
+from plone.namedfile.field import validate_image_field
+from plone.namedfile.field import validate_file_field
+from plone.namedfile.interfaces import INamedImageField
+from plone.namedfile.interfaces import INamedFileField
+from zope.interface import implementer
+from plone.namedfile.file import NamedImage
+from plone.namedfile.file import NamedFile
+from io import BytesIO
+from PIL import Image
+from transaction import commit
+from zope.interface.exceptions import Invalid
+
+import unittest
+import json
+
+
+@implementer(INamedImageField)
+class FakeImageField(object):
+ def __init__(self, name=""):
+ self.name = name
+
+ __name__ = "logo"
+
+ def getName(self):
+ return self.name
+
+
+@implementer(INamedFileField)
+class FakeFileField(object):
+ def __init__(self, name=""):
+ self.name = name
+
+ __name__ = "file"
+
+ def getName(self):
+ return self.name
+
+
+class TestValidation(unittest.TestCase):
+ layer = LIMITFILESIZEPANEL_FUNCTIONAL_TESTING
+
+ def setUp(self):
+ self.portal = self.layer["portal"]
+ self.request = self.layer["request"]
+
+ setRoles(self.portal, TEST_USER_ID, ["Manager"])
+ self.registry = queryUtility(IRegistry)
+
+ api.portal.set_registry_record(
+ "new_data_only",
+ False,
+ interface=ILimitFileSizePanel,
+ )
+
+ api.portal.set_registry_record(
+ "file_size",
+ 1,
+ interface=ILimitFileSizePanel,
+ )
+ api.portal.set_registry_record(
+ "image_size",
+ 1,
+ interface=ILimitFileSizePanel,
+ )
+
+ api.portal.set_registry_record(
+ "types_settings",
+ json.dumps(
+ [{"content_type": "News Item", "field_name": "image", "size": 2}]
+ ),
+ interface=ILimitFileSizePanel,
+ )
+ commit()
+
+ def generate_image(self, needed_size=1):
+ # Set the dimensions of the image
+ width = 1024
+ height = 1024
+ img_size = 1024 * 1024 * needed_size
+ # Create a new image with white background
+ image = Image.new("RGB", (width, height), (255, 255, 255))
+
+ # Save the image to an in-memory buffer as a JPEG file with maximum quality
+ buffer = BytesIO()
+ image.save(buffer, format="JPEG", quality=100)
+
+ # Get the size of the image buffer in bytes
+ size = buffer.tell()
+
+ # Ensure that the image buffer is exactly 1 MB
+ if size < img_size:
+ padding = b"\0" * (img_size - size)
+ buffer.write(padding)
+
+ return buffer
+
+ def test_validate_image_field(self):
+ # field is empty
+ field = FakeImageField()
+ field.context = self.portal
+
+ image = NamedImage()
+
+ # 1mb image is ok
+ image._setData(self.generate_image())
+ validate_image_field(field, image)
+
+ image._setData(self.generate_image(2))
+
+ with self.assertRaises(Invalid) as cm:
+ validate_image_field(field, image)
+
+ self.assertIn(
+ "Validation failed. Uploaded data is too large: 2.0MB (max 1.0MB)",
+ str(cm.exception),
+ )
+
+ def test_validate_file_field(self):
+ # field is empty
+ field = FakeFileField()
+ field.context = self.portal
+
+ example_file = NamedFile()
+ text = " " * (1024 * 1024)
+ example_file._setData(BytesIO(text.encode()))
+ # 1mb file is ok
+ validate_file_field(field, example_file)
+
+ text = " " * (1024 * 1024 * 2)
+ example_file._setData(BytesIO(text.encode()))
+
+ with self.assertRaises(Invalid) as cm:
+ validate_file_field(field, example_file)
+
+ self.assertIn(
+ "Validation failed. Uploaded data is too large: 2.0MB (max 1.0MB)",
+ str(cm.exception),
+ )
+
+ def test_validate_image_field_on_news(self):
+ news = api.content.create(
+ type="News Item",
+ id="news",
+ container=self.portal,
+ )
+
+ field = FakeImageField(name="image")
+ field.context = news
+ image = NamedImage()
+
+ # 1mb image is ok
+ image._setData(self.generate_image())
+ validate_image_field(field, image)
+
+ # 2mb image is ok
+ image._setData(self.generate_image(2))
+ validate_image_field(field, image)
+
+ # 3mb image is not ok
+ image._setData(self.generate_image(3))
+
+ with self.assertRaises(Invalid) as cm:
+ validate_image_field(field, image)
+
+ self.assertIn(
+ "Validation failed. Uploaded data is too large: 3.0MB (max 2.0MB)",
+ str(cm.exception),
+ )
diff --git a/collective/limitfilesizepanel/upgrades.zcml b/collective/limitfilesizepanel/upgrades.zcml
index f702ce1..0c2cf08 100644
--- a/collective/limitfilesizepanel/upgrades.zcml
+++ b/collective/limitfilesizepanel/upgrades.zcml
@@ -1,47 +1,48 @@
+ xmlns:i18n="http://namespaces.zope.org/i18n"
+ xmlns:zcml="http://namespaces.zope.org/zcml"
+ i18n_domain="collective.limitfilesizepanel"
+ >
+ title="Upgrade to collective.limitfilesizepanel to version 1.1"
+ description="Migrates collective.limitfilesizepanel to 1000"
+ profile="collective.limitfilesizepanel:default"
+ source="1.0"
+ destination="1000"
+ handler=".setuphandlers.migrateTo1000"
+ sortkey="1"
+ />
+ title="Upgrade to collective.limitfilesizepanel to version 1.3"
+ description="Migrates collective.limitfilesizepanel to 1100"
+ profile="collective.limitfilesizepanel:default"
+ source="11000"
+ destination="1100"
+ handler=".setuphandlers.migrateTo1100"
+ sortkey="2"
+ />
+ title="Upgrade to collective.limitfilesizepanel to version 1200"
+ description="Migrates collective.limitfilesizepanel to 1200"
+ profile="collective.limitfilesizepanel:default"
+ source="1100"
+ destination="1200"
+ handler=".setuphandlers.migrateTo1200"
+ sortkey="3"
+ />
+ title="Upgrade to collective.limitfilesizepanel to version 1300"
+ description="Migrates collective.limitfilesizepanel to 1300"
+ profile="collective.limitfilesizepanel:default"
+ source="1200"
+ destination="1300"
+ handler=".setuphandlers.migrateTo1300"
+ sortkey="4"
+ />