Skip to content

Commit

Permalink
Merge pull request #40 from pmarjan/2.3-develop
Browse files Browse the repository at this point in the history
Remote file upload processor (#33)
  • Loading branch information
Volodymyr Kublytskyi authored Feb 26, 2019
2 parents 7d150f1 + 8d4a6b4 commit 05d01d5
Show file tree
Hide file tree
Showing 9 changed files with 495 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ interface SourceUploadResponseInterface

const ERROR = 'error';

const SOURCE_MODEL = 'source';

/**
* Get file ID
*
Expand All @@ -45,6 +47,13 @@ public function getStatus();
*/
public function getError();

/**
* Get source
*
* @return \Magento\ImportService\Api\Data\SourceInterface
*/
public function getSource();

/**
* @param $sourceId
* @return mixed
Expand All @@ -62,4 +71,10 @@ public function setStatus($status);
* @return mixed
*/
public function setError($error);

/**
* @param \Magento\ImportService\Api\Data\SourceInterface $source
* @return mixed
*/
public function setSource(\Magento\ImportService\Api\Data\SourceInterface $source);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\ImportService\Model\Import\Processor;

use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem;
use Magento\ImportService\Exception as ImportServiceException;
use Magento\ImportService\Model\Import\SourceProcessorPool;
use Magento\ImportService\Model\Source\Validator;

/**
* CSV files processor for asynchronous import
*/
class ExternalFileProcessor implements SourceProcessorInterface
{
/**
* @var \Magento\Framework\Filesystem
*/
private $fileSystem;

/**
* @var \Magento\ImportService\Model\Source\Validator
*/
private $validator;

/**
* LocalPathFileProcessor constructor
*
* @param FileSystem $fileSystem
* @param Validator $validator
*/
public function __construct(
FileSystem $fileSystem,
Validator $validator
) {
$this->fileSystem = $fileSystem;
$this->validator = $validator;
}

/**
* {@inheritdoc}
*/
public function processUpload(\Magento\ImportService\Api\Data\SourceInterface $source, \Magento\ImportService\Api\Data\SourceUploadResponseInterface $response)
{
/** Validate the $source object */
if ($errors = $this->validator->validateRequest($source)) {
throw new ImportServiceException(
__('Invalid request: %1', implode(", ", $errors))
);
}

/** Check if the domain exists and the file within that domain exists */
if (!$this->validator->checkIfRemoteFileExists($source->getImportData())) {
throw new ImportServiceException(
__('Remote file %1 does not exist.', $source->getImportData())
);
}

/** Validate the remote file content type */
if (!$this->validator->validateMimeTypeForRemoteFile($source->getImportData())) {
throw new ImportServiceException(
__('Invalid mime type, expected is one of: %1', implode(", ", $this->validator->getAllowedMimeTypes()))
);
}

/** @var string $workingDirectory */
$workingDirectory = SourceProcessorPool::WORKING_DIR;

/** @var string $fileName */
$fileName = uniqid() . '.' . $source->getSourceType();

/** @var \Magento\Framework\Filesystem\Directory\WriteInterface $writeInterface */
$writeInterface = $this->fileSystem->getDirectoryWrite(DirectoryList::VAR_DIR);

/** If the directory is not present, it will be created */
$writeInterface->create($workingDirectory);

/** @var string $copyFileFullPath*/
$copyFileFullPath = $writeInterface->getAbsolutePath($workingDirectory) . $fileName;

/** Attempt a copy, may throw \Magento\Framework\Exception\FileSystemException */
$writeInterface->getDriver()->copy($source->getImportData(), $copyFileFullPath);

return $response->setSource($source->setImportData($fileName))
->setStatus($response::STATUS_UPLOADED);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
*/
class SourceProcessorPool
{
/**
* Working directory
*
* @var string
*/
const WORKING_DIR = 'importservice/';

/**
* @var array
Expand Down
4 changes: 2 additions & 2 deletions app/code/Magento/ImportService/Model/Source.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@

namespace Magento\ImportService\Model;

use Magento\Framework\Model\AbstractModel;
use Magento\Framework\Model\AbstractExtensibleModel;
use Magento\ImportService\Api\Data\SourceExtensionInterface;
use Magento\ImportService\Api\Data\SourceInterface;
use Magento\ImportService\Model\ResourceModel\Source as SourceResource;

/**
* Class Source
*/
class Source extends AbstractModel implements SourceInterface
class Source extends AbstractExtensibleModel implements SourceInterface
{
const CACHE_TAG = 'magento_import_service_source';

Expand Down
157 changes: 157 additions & 0 deletions app/code/Magento/ImportService/Model/Source/Validator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\ImportService\Model\Source;

use Magento\Framework\File\Mime\Proxy as Mime;
use Magento\Framework\Filesystem\Driver\Http\Proxy as Http;

/**
* Class Validator
*/
class Validator
{
/**
* @var string[]
*/
private $allowedMimeTypes;

/**
* @var \Magento\Framework\File\Mime\Proxy
*/
private $mime;

/**
* @var \Magento\Framework\Filesystem\Driver\Http
*/
private $httpDriver;

/**
* @param string[] $allowedMimeTypes
* @param Mime $mime
* @param Http $httpDriver
*/
public function __construct(
array $allowedMimeTypes,
Mime $mime,
Http $httpDriver
) {
$this->allowedMimeTypes = $allowedMimeTypes;
$this->mime = $mime;
$this->httpDriver = $httpDriver;
}

/**
* @return string[]
*/
public function getAllowedMimeTypes()
{
return $this->allowedMimeTypes;
}

/**
* @param \Magento\ImportService\Model\Source $source
* @return array|null
*/
public function validateRequest(\Magento\ImportService\Model\Source $source)
{
$errors = [];

if (!$this->validateSourceType($source)) {
$errors[] = __('%1 cannot be empty', $source::SOURCE_TYPE);
}

if (!$this->validateImportData($source)) {
$errors[] = __('%1 cannot be empty', $source::IMPORT_DATA);
}

if (count($errors) > 0) {
return $errors;
}

return null;
}

/**
* @param \Magento\ImportService\Model\Source $source
* @return bool
*/
public function validateSourceType(\Magento\ImportService\Model\Source $source)
{
if (!$source->getSourceType()) {
return false;
}

return true;
}

/**
* @param \Magento\ImportService\Model\Source $source
* @return bool
*/
public function validateImportData(\Magento\ImportService\Model\Source $source)
{
if (!$source->getImportData()) {
return false;
}

return true;
}

/**
* @param string $absoluteFilePath
* @return bool
*/
public function validateMimeTypeForLocalFile(string $absoluteFilePath)
{
/** @var string $mimeType */
$mimeType = $this->mime->getMimeType($absoluteFilePath);

if (!in_array($mimeType, $this->allowedMimeTypes)) {
return false;
}

return true;
}

/**
* @param string $url
* @return bool
*/
public function validateMimeTypeForRemoteFile(string $url)
{
/** @var array $stat */
$stat = $this->httpDriver->stat($this->getSourceLocation($url));

if (!isset($stat['type']) || !in_array($stat['type'], $this->getAllowedMimeTypes())) {
return false;
}

return true;
}

/**
* @param string $url
* @return bool
* @throws \Magento\Framework\Exception\FileSystemException
*/
public function checkIfRemoteFileExists($url)
{
if (!$this->httpDriver->isExists($this->getSourceLocation($url))) {
return false;
}

return true;
}

/**
* @param string $url
* @return string
*/
private function getSourceLocation($url)
{
return preg_replace("(^https?://)", "", $url);
}
}
20 changes: 20 additions & 0 deletions app/code/Magento/ImportService/Model/SourceUploadResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use Magento\Framework\Model\AbstractModel;
use Magento\ImportService\Api\Data\SourceUploadResponseInterface;
use Magento\ImportService\Api\Data\SourceInterface;

class SourceUploadResponse extends AbstractModel implements SourceUploadResponseInterface
{
Expand Down Expand Up @@ -42,6 +43,16 @@ public function getError()
return $this->getData(self::ERROR);
}

/**
* Get source
*
* @return SourceInterface
*/
public function getSource()
{
return $this->getData(self::SOURCE_MODEL);
}

/**
* @param $sourceId
* @return SourceUploadResponse|mixed
Expand All @@ -68,4 +79,13 @@ public function setError($error)
{
return $this->setData(self::ERROR, $error);
}

/**
* @param SourceInterface $source
* @return mixed
*/
public function setSource(SourceInterface $source)
{
return $this->setData(self::SOURCE_MODEL, $source);
}
}
12 changes: 12 additions & 0 deletions app/code/Magento/ImportService/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@
<item name="processor" xsi:type="object">Magento\ImportService\Model\Import\Processor\LocalPathFileProcessor\Proxy</item>
<item name="import_type" xsi:type="string">local_path</item>
</item>
<item name="external" xsi:type="array">
<item name="processor" xsi:type="object">Magento\ImportService\Model\Import\Processor\ExternalFileProcessor\Proxy</item>
<item name="import_type" xsi:type="string">external</item>
</item>
</argument>
</arguments>
</type>
<type name="\Magento\ImportService\Model\Source\Validator">
<arguments>
<argument name="allowedMimeTypes" xsi:type="array">
<item name="plain" xsi:type="string">text/plain</item>
<item name="csv" xsi:type="string">text/csv</item>
</argument>
</arguments>
</type>
Expand Down
5 changes: 5 additions & 0 deletions app/code/Magento/ImportService/i18n/en_US.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ImportService,ImportService
"Remote file %1 does not exist", "Remote file %1 does not exist"
"Invalid mime type, expected is one of: %1", "Invalid mime type, expected is one of: %1"
"Invalid request: %1", "Invalid request: %1"
"%1 cannot be empty", "%1 cannot be empty"
Loading

0 comments on commit 05d01d5

Please sign in to comment.