Merge pull request #1017 from NightJar/new/5/set-max-upload-size-via-config

This commit is contained in:
Michal Kleiner 2022-10-28 14:41:21 +13:00 committed by GitHub
commit a356b0f8ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 138 additions and 7 deletions

View File

@ -56,6 +56,16 @@ class UserDefinedFormController extends PageController
private static string $file_upload_stage = Versioned::DRAFT;
/**
* Size that an uploaded file must not excede for it to be attached to an email
* Follows PHP "shorthand bytes" definition rules.
* @see self::parseByteSizeString()
*
* @var int
* @config
*/
private static $maximum_email_attachment_size = '1M';
protected function init()
{
parent::init();
@ -215,6 +225,42 @@ JS
}
}
/**
* Returns the maximum size uploaded files can be before they're excluded from CMS configured recipient emails
*
* @return int size in megabytes
*/
public function getMaximumAllowedEmailAttachmentSize()
{
return $this->parseByteSizeString($this->config()->get('maximum_email_attachment_size'));
}
/**
* Convert file sizes with a single character for unit size to true byte count.
* Just as with php.ini and e.g. 128M -> 1024 * 1024 * 128 bytes.
* @see https://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
*
* @param string $byteSize
* @return int bytes
*/
protected function parseByteSizeString($byteSize)
{
// kilo, mega, giga
$validUnits = 'kmg';
$valid = preg_match("/^(?<number>\d+)((?<unit>[$validUnits])b?)?$/i", $byteSize, $matches);
if (!$valid) {
throw new \InvalidArgumentException(
"Expected a positive integer followed optionally by K, M, or G. Found '$byteSize' instead"
);
}
$power = 0;
// prepend b for bytes to $validUnits to give correct mapping of ordinal position to exponent
if (isset($matches['unit'])) {
$power = stripos("b$validUnits", $matches['unit']);
}
return intval($matches['number']) * pow(1024, $power);
}
/**
* Process the form that is submitted through the site
*
@ -268,7 +314,7 @@ JS
if (!$field->getFolderExists()) {
$field->createProtectedFolder();
}
$file = Versioned::withVersionedMode(function () use ($field, $form) {
$stage = Injector::inst()->get(self::class)->config()->get('file_upload_stage');
Versioned::set_stage($stage);
@ -308,8 +354,8 @@ JS
// write file to form field
$submittedField->UploadedFileID = $file->ID;
// attach a file only if lower than 1MB
if ($file->getAbsoluteSize() < 1024 * 1024 * 1) {
// attach a file to recipient email only if lower than configured size
if ($file->getAbsoluteSize() <= $this->getMaximumAllowedEmailAttachmentSize()) {
$attachments[] = $file;
}
}

View File

@ -24,6 +24,7 @@ use SilverStripe\UserForms\Model\EditableFormField\EditableTextField;
use SilverStripe\UserForms\Model\Recipient\EmailRecipient;
use SilverStripe\UserForms\Model\Submission\SubmittedFormField;
use SilverStripe\UserForms\Model\UserDefinedForm;
use SilverStripe\UserForms\Tests\Control\fixtures\SizeStringTestableController;
use SilverStripe\Versioned\Versioned;
use SilverStripe\View\ArrayData;
use SilverStripe\View\SSViewer;
@ -47,7 +48,9 @@ class UserDefinedFormControllerTest extends FunctionalTest
// Set backend and base url
TestAssetStore::activate('AssetStoreTest');
Config::modify()->merge(SSViewer::class, 'themes', ['simple', '$default']);
$config = Config::modify();
$config->set(UserDefinedFormController::class, 'maximum_email_attachment_size', "1M");
$config->merge(SSViewer::class, 'themes', ['simple', '$default']);
}
protected function tearDown(): void
@ -273,7 +276,8 @@ class UserDefinedFormControllerTest extends FunctionalTest
$actions = $controller->Form()->getFormActions();
$expected = new FieldList(new FormAction('process', 'Custom Button'));
$expected->push(FormAction::create('clearForm', 'Clear')->setAttribute('type', 'reset'));
$clearAction = new FormAction('clearForm', 'Clear');
$expected->push($clearAction->setAttribute('type', 'reset'));
$expected->setForm($controller->Form());
$this->assertEquals($actions, $expected);
@ -404,7 +408,7 @@ class UserDefinedFormControllerTest extends FunctionalTest
Config::modify()->set(Upload_Validator::class, 'use_is_uploaded_file', false);
$userForm = $this->setupFormFrontend('upload-form');
$controller = UserDefinedFormController::create($userForm);
$controller = new UserDefinedFormController($userForm);
$field = $this->objFromFixture(EditableFileField::class, 'file-field-1');
$path = realpath(__DIR__ . '/fixtures/testfile.jpg');
@ -440,7 +444,7 @@ class UserDefinedFormControllerTest extends FunctionalTest
Config::modify()->set(Upload_Validator::class, 'use_is_uploaded_file', false);
$userForm = $this->setupFormFrontend('upload-form');
$controller = UserDefinedFormController::create($userForm);
$controller = new UserDefinedFormController($userForm);
$field = $this->objFromFixture(EditableFileField::class, 'file-field-1');
$path = realpath(__DIR__ . '/fixtures/testfile.jpg');
@ -511,4 +515,71 @@ class UserDefinedFormControllerTest extends FunctionalTest
$this->assertEquals(1, $fileDraftCount);
$this->assertEquals(0, $fileLiveCount);
}
public function testEmailAttachmentMaximumSizeCanBeConfigured()
{
$udfController = new UserDefinedFormController();
$config = Config::modify();
$config->set(UserDefinedFormController::class, 'maximum_email_attachment_size', '1M');
$this->assertSame(1 * 1024 * 1024, $udfController->getMaximumAllowedEmailAttachmentSize());
$config->set(UserDefinedFormController::class, 'maximum_email_attachment_size', '5M');
$this->assertSame(5 * 1024 * 1024, $udfController->getMaximumAllowedEmailAttachmentSize());
}
public function getParseByteSizeStringTestValues()
{
return [
['9846', 9846],
['1048576', 1048576],
['1k', 1024],
['1K', 1024],
['4k', 4096],
['4K', 4096],
['1kb', 1024],
['1KB', 1024],
['4kB', 4096],
['4Kb', 4096],
['1m', 1048576],
['1M', 1048576],
['4mb', 4194304],
['4MB', 4194304],
['25mB', 26214400],
['25Mb', 26214400],
['1g', 1073741824],
['2GB', 2147483648],
];
}
/**
* @dataProvider getParseByteSizeStringTestValues
*/
public function testParseByteSizeString($input, $expectedOutput)
{
$controller = new SizeStringTestableController(); // extends UserDefinedFormController
$this->assertSame($expectedOutput, $controller->convertSizeStringToBytes($input));
}
public function getParseByteSizeStringTestBadValues()
{
return [
['1234b'],
['9846B'],
['1kilobyte'],
['1 K'],
['Four kilobytes'],
['4Mbs'],
['12Gigs'],
];
}
/**
* @dataProvider getParseByteSizeStringTestBadValues
* @expectedException \InvalidArgumentException
*/
public function testParseByteSizeStringBadValuesThrowException($input)
{
$this->expectException('\InvalidArgumentException');
$controller = new SizeStringTestableController(); // extends UserDefinedFormController
$controller->convertSizeStringToBytes($input);
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace SilverStripe\UserForms\Tests\Control\fixtures;
use SilverStripe\Dev\TestOnly;
use SilverStripe\UserForms\Control\UserDefinedFormController;
class SizeStringTestableController extends UserDefinedFormController implements TestOnly
{
public function convertSizeStringToBytes($sizeString)
{
return $this->parseByteSizeString($sizeString);
}
}