2015-10-19 06:27:27 +02:00
|
|
|
<?php
|
|
|
|
|
2016-10-14 03:30:05 +02:00
|
|
|
namespace SilverStripe\Forms\Tests;
|
|
|
|
|
|
|
|
use SilverStripe\Assets\Folder;
|
|
|
|
use SilverStripe\Control\HTTPResponse;
|
2016-06-15 06:03:16 +02:00
|
|
|
use SilverStripe\ORM\Versioning\Versioned;
|
2016-08-19 00:51:35 +02:00
|
|
|
use SilverStripe\Assets\Filesystem;
|
|
|
|
use SilverStripe\Assets\File;
|
|
|
|
use SilverStripe\Dev\CSSContentParser;
|
|
|
|
use SilverStripe\Dev\FunctionalTest;
|
|
|
|
use SilverStripe\Control\Session;
|
|
|
|
use SilverStripe\Control\Controller;
|
|
|
|
use SilverStripe\Forms\AssetField;
|
|
|
|
use SilverStripe\Forms\FieldList;
|
|
|
|
use SilverStripe\Forms\Form;
|
2016-10-14 03:30:05 +02:00
|
|
|
use SilverStripe\Forms\Tests\AssetFieldTest\TestForm;
|
|
|
|
use SilverStripe\Forms\Tests\AssetFieldTest\TestController;
|
|
|
|
use SilverStripe\Forms\Tests\AssetFieldTest\TestObject;
|
|
|
|
use SilverStripe\Assets\Tests\Storage\AssetStoreTest\TestAssetStore;
|
2016-08-19 00:51:35 +02:00
|
|
|
|
2015-10-19 06:27:27 +02:00
|
|
|
class AssetFieldTest extends FunctionalTest {
|
|
|
|
|
|
|
|
protected static $fixture_file = 'AssetFieldTest.yml';
|
|
|
|
|
|
|
|
protected $extraDataObjects = array(
|
2016-10-14 03:30:05 +02:00
|
|
|
TestObject::class
|
2015-10-19 06:27:27 +02:00
|
|
|
);
|
|
|
|
|
2016-10-14 03:30:05 +02:00
|
|
|
protected $extraControllers = [
|
|
|
|
TestController::class
|
|
|
|
];
|
|
|
|
|
2015-10-19 06:27:27 +02:00
|
|
|
public function setUp() {
|
|
|
|
parent::setUp();
|
|
|
|
|
2016-01-26 04:56:07 +01:00
|
|
|
$this->logInWithPermission('ADMIN');
|
2016-03-02 06:18:10 +01:00
|
|
|
Versioned::set_stage(Versioned::DRAFT);
|
2016-01-26 04:56:07 +01:00
|
|
|
|
2015-10-19 06:27:27 +02:00
|
|
|
// Set backend root to /AssetFieldTest
|
2016-10-14 03:30:05 +02:00
|
|
|
TestAssetStore::activate('AssetFieldTest');
|
2015-10-19 06:27:27 +02:00
|
|
|
$create = function($path) {
|
|
|
|
Filesystem::makeFolder(dirname($path));
|
|
|
|
$fh = fopen($path, "w+");
|
|
|
|
fwrite($fh, str_repeat('x', 1000000));
|
|
|
|
fclose($fh);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Write all DBFile references
|
2016-10-14 03:30:05 +02:00
|
|
|
foreach(TestObject::get() as $object) {
|
|
|
|
$path = TestAssetStore::getLocalPath($object->File);
|
2015-10-19 06:27:27 +02:00
|
|
|
$create($path);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a test files for each of the fixture references
|
2016-10-14 03:30:05 +02:00
|
|
|
$files = File::get()->exclude('ClassName', Folder::class);
|
2015-10-19 06:27:27 +02:00
|
|
|
foreach($files as $file) {
|
2016-10-14 03:30:05 +02:00
|
|
|
$path = TestAssetStore::getLocalPath($file);
|
2015-10-19 06:27:27 +02:00
|
|
|
$create($path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function tearDown() {
|
2016-10-14 03:30:05 +02:00
|
|
|
TestAssetStore::reset();
|
2015-10-19 06:27:27 +02:00
|
|
|
parent::tearDown();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test that files can be uploaded against an object with no relation
|
|
|
|
*/
|
|
|
|
public function testUploadNoRelation() {
|
2016-08-19 00:51:35 +02:00
|
|
|
$this->logInWithPermission('ADMIN');
|
2015-10-19 06:27:27 +02:00
|
|
|
|
|
|
|
$tmpFileName = 'testUploadBasic.txt';
|
|
|
|
$response = $this->mockFileUpload('NoRelationField', $tmpFileName);
|
|
|
|
$responseJSON = json_decode($response->getBody(), true);
|
|
|
|
$this->assertFalse($response->isError());
|
|
|
|
$this->assertEquals('MyDocuments/testUploadBasic.txt', $responseJSON[0]['filename']);
|
|
|
|
$this->assertEquals('315ae4c3d44412baa0c81515b6fb35829a337a5a', $responseJSON[0]['hash']);
|
|
|
|
$this->assertEmpty($responseJSON[0]['variant']);
|
|
|
|
$this->assertFileExists(
|
2016-01-26 04:56:07 +01:00
|
|
|
BASE_PATH . '/assets/AssetFieldTest/.protected/MyDocuments/315ae4c3d4/testUploadBasic.txt'
|
2015-10-19 06:27:27 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test that an object can be uploaded against a DBFile field
|
2016-08-19 00:51:35 +02:00
|
|
|
*
|
|
|
|
* @skipUpgrade
|
2015-10-19 06:27:27 +02:00
|
|
|
*/
|
|
|
|
public function testUploadDBFile() {
|
2016-08-19 00:51:35 +02:00
|
|
|
$this->logInWithPermission('ADMIN');
|
2015-10-19 06:27:27 +02:00
|
|
|
|
|
|
|
// Unset existing has_one relation before re-uploading
|
2016-10-14 03:30:05 +02:00
|
|
|
$record = $this->objFromFixture(TestObject::class, 'object1');
|
2015-10-19 06:27:27 +02:00
|
|
|
$record->FileFilename = null;
|
|
|
|
$record->FileHash = null;
|
|
|
|
$record->write();
|
|
|
|
|
|
|
|
// Firstly, ensure the file can be uploaded
|
|
|
|
$tmpFileName = 'testUploadHasOneRelation.txt';
|
|
|
|
$response = $this->mockFileUpload('File', $tmpFileName);
|
|
|
|
$responseJSON = json_decode($response->getBody(), true);
|
|
|
|
$this->assertFalse($response->isError());
|
|
|
|
$this->assertFileExists(
|
2016-01-26 04:56:07 +01:00
|
|
|
BASE_PATH . '/assets/AssetFieldTest/.protected/MyFiles/315ae4c3d4/testUploadHasOneRelation.txt'
|
2015-10-19 06:27:27 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
// Secondly, ensure that simply uploading an object does not save the file against the relation
|
2016-10-14 03:30:05 +02:00
|
|
|
$record = TestObject::get()->byID($record->ID);
|
2015-10-19 06:27:27 +02:00
|
|
|
$this->assertFalse($record->File->exists());
|
|
|
|
|
|
|
|
// Thirdly, test submitting the form with the encoded data
|
|
|
|
$response = $this->mockUploadFileSave(
|
|
|
|
'File',
|
|
|
|
$responseJSON[0]['filename'],
|
|
|
|
$responseJSON[0]['hash'],
|
|
|
|
$responseJSON[0]['variant']
|
|
|
|
);
|
|
|
|
$this->assertEmpty($response['errors']);
|
2016-10-14 03:30:05 +02:00
|
|
|
$record = TestObject::get()->byID($record->ID);
|
2015-10-19 06:27:27 +02:00
|
|
|
$this->assertTrue($record->File->exists());
|
|
|
|
$this->assertEquals('315ae4c3d44412baa0c81515b6fb35829a337a5a', $record->File->Hash);
|
|
|
|
$this->assertEquals('MyFiles/testUploadHasOneRelation.txt', $record->File->Filename);
|
|
|
|
$this->assertEmpty($record->File->Variant);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Partially covered by {@link UploadTest->testUploadAcceptsAllowedExtension()},
|
|
|
|
* but this test additionally verifies that those constraints are actually enforced
|
|
|
|
* in this controller method.
|
2016-08-19 00:51:35 +02:00
|
|
|
*
|
|
|
|
* @skipUpgrade
|
2015-10-19 06:27:27 +02:00
|
|
|
*/
|
|
|
|
public function testAllowedExtensions() {
|
2016-08-19 00:51:35 +02:00
|
|
|
$this->logInWithPermission('ADMIN');
|
2015-10-19 06:27:27 +02:00
|
|
|
|
|
|
|
// Test invalid file
|
|
|
|
// Relies on Upload_Validator failing to allow this extension
|
|
|
|
$response = $this->mockFileUpload('File', 'invalid.php');
|
|
|
|
$response = json_decode($response->getBody(), true);
|
|
|
|
$this->assertTrue(array_key_exists('error', $response[0]));
|
|
|
|
$this->assertContains('Extension is not allowed', $response[0]['error']);
|
|
|
|
|
|
|
|
// Test valid file
|
|
|
|
$response = $this->mockFileUpload('File', 'valid.txt');
|
|
|
|
$response = json_decode($response->getBody(), true);
|
|
|
|
$this->assertFalse(array_key_exists('error', $response[0]));
|
|
|
|
|
|
|
|
// Test that allowed files cannot be uploaded to restricted field
|
|
|
|
$response = $this->mockFileUpload('Image', 'valid.txt');
|
|
|
|
$response = json_decode($response->getBody(), true);
|
|
|
|
$this->assertTrue(array_key_exists('error', $response[0]));
|
|
|
|
$this->assertContains('Extension is not allowed', $response[0]['error']);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test that files can be removed from an existing field
|
|
|
|
*/
|
|
|
|
public function testRemoveFromHasOne() {
|
2016-10-14 03:30:05 +02:00
|
|
|
$record = $this->objFromFixture(TestObject::class, 'object1');
|
2015-10-19 06:27:27 +02:00
|
|
|
|
|
|
|
// Check record exists
|
|
|
|
$this->assertTrue($record->File->exists());
|
2016-10-14 03:30:05 +02:00
|
|
|
$filePath = TestAssetStore::getLocalPath($record->File);
|
2015-10-19 06:27:27 +02:00
|
|
|
$this->assertFileExists($filePath);
|
|
|
|
|
|
|
|
// Remove from record
|
2016-10-14 03:30:05 +02:00
|
|
|
$response = $this->mockUploadFileSave(File::class, null, null, null);
|
2015-10-19 06:27:27 +02:00
|
|
|
$this->assertEmpty($response['errors']);
|
|
|
|
|
|
|
|
// Check file is removed
|
2016-10-14 03:30:05 +02:00
|
|
|
$record = TestObject::get()->byID($record->ID);
|
2015-10-19 06:27:27 +02:00
|
|
|
$this->assertFalse($record->File->exists());
|
|
|
|
|
|
|
|
// Check file object itself exists
|
2016-01-26 04:56:07 +01:00
|
|
|
$this->assertFileNotExists($filePath, 'File is deleted once detached');
|
2015-10-19 06:27:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test control output html
|
|
|
|
*/
|
|
|
|
public function testView() {
|
2016-08-19 00:51:35 +02:00
|
|
|
$this->logInWithPermission('ADMIN');
|
2015-10-19 06:27:27 +02:00
|
|
|
|
2016-10-14 03:30:05 +02:00
|
|
|
$record = $this->objFromFixture(TestObject::class, 'object1');
|
2015-10-19 06:27:27 +02:00
|
|
|
|
|
|
|
// Requesting form is not an error
|
|
|
|
$response = $this->get('AssetFieldTest_Controller');
|
|
|
|
$this->assertFalse($response->isError());
|
|
|
|
|
|
|
|
// File exists in this response
|
|
|
|
$parser = new CSSContentParser($response->getBody());
|
|
|
|
$tuple = array();
|
|
|
|
$result = $parser->getBySelector(
|
2016-10-14 03:30:05 +02:00
|
|
|
"#TestForm_Form_File_Holder .ss-uploadfield-files .ss-uploadfield-item input[type='hidden']"
|
2015-10-19 06:27:27 +02:00
|
|
|
);
|
|
|
|
foreach($result as $part) {
|
|
|
|
$name = (string)$part['name'];
|
|
|
|
$value = (string)$part['value'];
|
|
|
|
switch($name) {
|
|
|
|
case 'File[Filename]':
|
|
|
|
$tuple['Filename'] = $value;
|
|
|
|
break;
|
|
|
|
case 'File[Hash]':
|
|
|
|
$tuple['Hash'] = $value;
|
|
|
|
break;
|
|
|
|
case 'File[Variant]':
|
|
|
|
$tuple['Variant'] = $value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assert this value is correct
|
|
|
|
$expected = array(
|
|
|
|
'Filename' => 'MyFiles/subfolder1/file-subfolder.txt',
|
|
|
|
'Hash' => '55b443b60176235ef09801153cca4e6da7494a0c',
|
|
|
|
'Variant' => '',
|
|
|
|
);
|
|
|
|
$this->assertEquals($expected, $record->File->getValue());
|
|
|
|
$this->assertEquals($expected, $tuple);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testGetRecord() {
|
2016-10-14 03:30:05 +02:00
|
|
|
$record = $this->objFromFixture(TestObject::class, 'object1');
|
2015-10-19 06:27:27 +02:00
|
|
|
$form = $this->getMockForm();
|
|
|
|
|
|
|
|
$field = AssetField::create('MyField');
|
|
|
|
$field->setForm($form);
|
|
|
|
$this->assertNull($field->getRecord(), 'Returns no record by default');
|
|
|
|
|
|
|
|
$field = AssetField::create('MyField');
|
|
|
|
$field->setForm($form);
|
|
|
|
$form->loadDataFrom($record);
|
|
|
|
$this->assertEquals($record, $field->getRecord(), 'Returns record from form if available');
|
|
|
|
|
|
|
|
$field = AssetField::create('MyField');
|
|
|
|
$field->setForm($form);
|
|
|
|
$field->setRecord($record);
|
|
|
|
$this->assertEquals($record, $field->getRecord(), 'Returns record when set explicitly');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test that getValue() / Value() methods work
|
2016-08-19 00:51:35 +02:00
|
|
|
*
|
|
|
|
* @skipUpgrade
|
2015-10-19 06:27:27 +02:00
|
|
|
*/
|
|
|
|
public function testValue() {
|
2016-10-14 03:30:05 +02:00
|
|
|
$record = $this->objFromFixture(TestObject::class, 'object1');
|
2015-10-19 06:27:27 +02:00
|
|
|
|
|
|
|
// File field
|
|
|
|
$field = AssetField::create('File');
|
|
|
|
$this->assertEmpty($field->Value());
|
|
|
|
$field->setValue(null, $record);
|
|
|
|
$this->assertEquals(array(
|
|
|
|
'Filename' => 'MyFiles/subfolder1/file-subfolder.txt',
|
|
|
|
'Hash' => '55b443b60176235ef09801153cca4e6da7494a0c',
|
|
|
|
'Variant' => null,
|
|
|
|
), $field->Value());
|
|
|
|
|
|
|
|
// Empty field
|
|
|
|
$field = AssetField::create('Image');
|
|
|
|
$this->assertEmpty($field->Value());
|
|
|
|
$field->setValue(null, $record);
|
|
|
|
$this->assertEmpty($field->Value());
|
|
|
|
|
|
|
|
// Set via file (copies only tuple not the actual file reference)
|
2016-10-14 03:30:05 +02:00
|
|
|
$file = $this->objFromFixture(File::class, 'file1');
|
2015-10-19 06:27:27 +02:00
|
|
|
$field->setValue($file);
|
|
|
|
$this->assertEquals(array(
|
|
|
|
'Filename' => 'MyAssets/file1.txt',
|
|
|
|
'Hash' => '55b443b60176235ef09801153cca4e6da7494a0c',
|
|
|
|
'Variant' => null,
|
|
|
|
), $field->Value());
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testCanUploadWithPermissionCode() {
|
2016-01-26 04:56:07 +01:00
|
|
|
Session::clear("loggedInAs");
|
2015-10-19 06:27:27 +02:00
|
|
|
$field = AssetField::create('MyField');
|
|
|
|
|
|
|
|
$field->setCanUpload(true);
|
|
|
|
$this->assertTrue($field->canUpload());
|
|
|
|
|
|
|
|
$field->setCanUpload(false);
|
|
|
|
$this->assertFalse($field->canUpload());
|
|
|
|
|
|
|
|
$field->setCanUpload('ADMIN');
|
|
|
|
$this->assertFalse($field->canUpload());
|
|
|
|
|
2016-08-19 00:51:35 +02:00
|
|
|
$this->logInWithPermission('ADMIN');
|
2015-10-19 06:27:27 +02:00
|
|
|
|
|
|
|
$field->setCanUpload(false);
|
|
|
|
$this->assertFalse($field->canUpload());
|
|
|
|
|
|
|
|
$field->setCanUpload('ADMIN');
|
|
|
|
$this->assertTrue($field->canUpload());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected function getMockForm() {
|
2016-08-19 00:51:35 +02:00
|
|
|
/** @skipUpgrade */
|
2015-10-19 06:27:27 +02:00
|
|
|
return new Form(new Controller(), 'Form', new FieldList(), new FieldList());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-08-19 00:51:35 +02:00
|
|
|
* @param string $tmpFileName
|
|
|
|
* @return array Emulating an entry in the $_FILES superglobal
|
2015-10-19 06:27:27 +02:00
|
|
|
*/
|
|
|
|
protected function getUploadFile($tmpFileName = 'AssetFieldTest-testUpload.txt') {
|
|
|
|
$tmpFilePath = TEMP_FOLDER . '/' . $tmpFileName;
|
|
|
|
$tmpFileContent = '';
|
|
|
|
for($i=0; $i<10000; $i++) $tmpFileContent .= '0';
|
|
|
|
file_put_contents($tmpFilePath, $tmpFileContent);
|
|
|
|
|
|
|
|
// emulates the $_FILES array
|
|
|
|
// Notice that unlike UploadFieldTest::getUploadFile the key is 'Upload' not 'Uploads'
|
|
|
|
// and the value is a literal not an array
|
|
|
|
return array(
|
|
|
|
'name' => array('Upload' => $tmpFileName),
|
|
|
|
'type' => array('Upload' => 'text/plaintext'),
|
|
|
|
'size' => array('Upload' => filesize($tmpFilePath)),
|
|
|
|
'tmp_name' => array('Upload' => $tmpFilePath),
|
|
|
|
'error' => array('Upload' => UPLOAD_ERR_OK),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Simulates a form post to the test controller with the specified file tuple (Filename, Hash, Variant)
|
|
|
|
*
|
|
|
|
* @param string $fileField Name of field to assign ids to
|
2016-08-19 00:51:35 +02:00
|
|
|
* @param string $filename
|
|
|
|
* @param string $hash
|
|
|
|
* @param string $variant
|
|
|
|
* @return array Array with key 'errors'
|
2015-10-19 06:27:27 +02:00
|
|
|
*/
|
|
|
|
protected function mockUploadFileSave($fileField, $filename, $hash, $variant = null) {
|
|
|
|
// collate file ids
|
|
|
|
$data = array(
|
|
|
|
'action_submit' => 1,
|
|
|
|
$fileField => array(
|
|
|
|
'Filename' => $filename,
|
|
|
|
'Hash' => $hash,
|
|
|
|
'Variant' => $variant
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2016-10-14 03:30:05 +02:00
|
|
|
$form = new TestForm();
|
2015-10-19 06:27:27 +02:00
|
|
|
$form->loadDataFrom($data, true);
|
2016-11-23 06:09:10 +01:00
|
|
|
if($form->validationResult()->isValid()) {
|
2015-10-19 06:27:27 +02:00
|
|
|
$record = $form->getRecord();
|
|
|
|
$form->saveInto($record);
|
|
|
|
$record->write();
|
|
|
|
return array('errors' => null);
|
|
|
|
} else {
|
|
|
|
return array('errors' => $form->getValidator()->getErrors());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Simulates a file upload
|
|
|
|
*
|
|
|
|
* @param string $fileField Name of the field to mock upload for
|
|
|
|
* @param array $tmpFileName Name of temporary file to upload
|
2016-09-09 08:43:05 +02:00
|
|
|
* @return HTTPResponse form response
|
2015-10-19 06:27:27 +02:00
|
|
|
*/
|
|
|
|
protected function mockFileUpload($fileField, $tmpFileName) {
|
|
|
|
$upload = $this->getUploadFile($tmpFileName);
|
|
|
|
$_FILES = array($fileField => $upload);
|
|
|
|
return $this->post(
|
|
|
|
"AssetFieldTest_Controller/Form/field/{$fileField}/upload",
|
|
|
|
array($fileField => $upload)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|