Skip to content

Commit

Permalink
Add validation to prevent accidental submit with interrupted uploads
Browse files Browse the repository at this point in the history
  • Loading branch information
xificurk committed Jan 20, 2024
1 parent 053cfa9 commit 95bdeb7
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 0 deletions.
4 changes: 4 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,7 @@ parameters:
message: "#^Invalid var phpdoc of \\$files\\. Cannot assign array.* to array\\<int, Nette\\\\Http\\\\FileUpload\\>$#"
count: 1
path: src/FileUploadControl/FileUploadControl.php
- # false positive
message: "#^Parameter \\#1 \\$validator of method Nepada\\\\FileUploadControl\\\\FileUploadControl\\:\\:addCondition\\(\\) expects \\(callable\\(\\)\\: mixed\\)\\|string, true given\\.$#"
count: 1
path: src/FileUploadControl/FileUploadControl.php
9 changes: 9 additions & 0 deletions src/FileUploadControl/FileUploadControl.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
use Nepada\FileUploadControl\Storage\UploadNamespace;
use Nepada\FileUploadControl\Thumbnail\NullThumbnailProvider;
use Nepada\FileUploadControl\Thumbnail\ThumbnailProvider;
use Nepada\FileUploadControl\Validation\FakeUploadControl;
use Nepada\FileUploadControl\Validation\UploadValidation;
use Nette;
use Nette\Bridges\ApplicationLatte\Template;
use Nette\Forms\Form;
use Nette\Http\FileUpload;
use Nette\Utils\Arrays;
use Nette\Utils\Html;
use Nette\Utils\Strings;
use Nextras\FormComponents\Fragments\UIControl\BaseControl;
Expand Down Expand Up @@ -58,6 +60,13 @@ public function __construct(StorageManager $storageManager, string|\Stringable|n
$this->addComponent(new Nette\Forms\Controls\UploadControl($caption, true), 'upload');
$this->addComponent(new Nette\Forms\Controls\HiddenField(), 'namespace');
$this->initializeValidation($this);
$this->addCondition(true) // avoid export to JS
->addRule($this->validateUploadSuccess(...), Nette\Forms\Validator::$messages[Nette\Forms\Controls\UploadControl::Valid]);
}

private function validateUploadSuccess(FakeUploadControl $control): bool
{
return Arrays::every($control->getValue(), fn (FileUpload $upload): bool => $upload->isOk());
}

public function setThumbnailProvider(ThumbnailProvider $thumbnailProvider): void
Expand Down
1 change: 1 addition & 0 deletions src/FileUploadControl/Validation/FakeUploadControl.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public function __construct(FileUploadControl $fileUploadControl)
$this->fileUploadControl = $fileUploadControl;
$fileUploadControl->monitor(Form::class, function (Form $form): void {
$this->setParent(null, $this->fileUploadControl->getName());
$this->control->name = $this->fileUploadControl->getComponent('upload')->getHtmlName();
});
}

Expand Down
17 changes: 17 additions & 0 deletions tests/FileUploadControl/FileUploadControlValidationTest.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ declare(strict_types = 1);
namespace NepadaTests\FileUploadControl;

use Nepada\FileUploadControl\FileUploadControl;
use Nepada\FileUploadControl\Storage\ContentRange;
use Nepada\FileUploadControl\Storage\FileUploadChunk;
use Nepada\FileUploadControl\Storage\Storage;
use NepadaTests\Environment;
use NepadaTests\FileUploadControl\Fixtures\TestPresenter;
Expand Down Expand Up @@ -86,6 +88,21 @@ class FileUploadControlValidationTest extends TestCase
Assert::same(['translated:max 1 upload allowed'], $control->getErrors());
}

public function testSubmittedWithInterruptedUpload(): void
{
$storage = InMemoryStorage::createWithFiles();
$storage->save(FileUploadChunk::partialUpload(
FileUploadFactory::createFromFile(__DIR__ . '/Fixtures/test.txt', 'partial.txt'),
ContentRange::fromHttpHeaderValue('bytes 0-8/100'),
)); // interrupted partial upload

$control = $this->createFileUploadControl($storage);

$this->submitForm($control);

Assert::same(['translated:Upload error'], $control->getErrors());
}

public function testUploadWithFailedUpload(): void
{
$control = $this->createFileUploadControl();
Expand Down

0 comments on commit 95bdeb7

Please sign in to comment.