diff --git a/Block/Adminhtml/Product/Edit/NewVideo.php b/Block/Adminhtml/Product/Edit/NewVideo.php index 88e20d0d..700bfc6c 100644 --- a/Block/Adminhtml/Product/Edit/NewVideo.php +++ b/Block/Adminhtml/Product/Edit/NewVideo.php @@ -5,37 +5,65 @@ */ namespace Cloudinary\Cloudinary\Block\Adminhtml\Product\Edit; +use Cloudinary\Cloudinary\Core\ConfigurationBuilder; +use Cloudinary\Cloudinary\Core\ConfigurationInterface; +use Magento\Backend\Block\Template\Context; +use Magento\Framework\Data\FormFactory; +use Magento\Framework\Json\EncoderInterface; +use Magento\Framework\Registry; +use Magento\Framework\UrlInterface; +use Magento\ProductVideo\Helper\Media; + /** * @SuppressWarnings(PHPMD.DepthOfInheritance) */ class NewVideo extends \Magento\ProductVideo\Block\Adminhtml\Product\Edit\NewVideo { + /** + * @var array|null + */ protected $_cloudinaryConfig; /** - * @var \Cloudinary\Cloudinary\Core\ConfigurationBuilder + * @var ConfigurationInterface + */ + private $configuration; + + /** + * @var ConfigurationBuilder */ protected $_cloudinaryConfigurationBuilder; /** - * @param \Magento\Backend\Block\Template\Context $context - * @param \Magento\Framework\Registry $registry - * @param \Magento\Framework\Data\FormFactory $formFactory - * @param \Magento\ProductVideo\Helper\Media $mediaHelper - * @param \Magento\Framework\Json\EncoderInterface $jsonEncoder - * @param \Cloudinary\Cloudinary\Core\ConfigurationBuilder $cloudinaryConfigurationBuilder - * @param array $data + * @method __construct + * @param Context $context + * @param Registry $registry + * @param FormFactory $formFactory + * @param Media $mediaHelper + * @param EncoderInterface $jsonEncoder + * @param ConfigurationInterface $configuration + * @param ConfigurationBuilder $cloudinaryConfigurationBuilder + * @param array $data */ public function __construct( - \Magento\Backend\Block\Template\Context $context, - \Magento\Framework\Registry $registry, - \Magento\Framework\Data\FormFactory $formFactory, - \Magento\ProductVideo\Helper\Media $mediaHelper, - \Magento\Framework\Json\EncoderInterface $jsonEncoder, - \Cloudinary\Cloudinary\Core\ConfigurationBuilder $cloudinaryConfigurationBuilder, + Context $context, + Registry $registry, + FormFactory $formFactory, + Media $mediaHelper, + EncoderInterface $jsonEncoder, + ConfigurationInterface $configuration, + ConfigurationBuilder $cloudinaryConfigurationBuilder, array $data = [] ) { - parent::__construct($context, $registry, $formFactory, $mediaHelper, $jsonEncoder, $data); + parent::__construct( + $context, + $registry, + $formFactory, + $mediaHelper, + $jsonEncoder, + $data + ); + $this->configuration = $configuration; $this->_cloudinaryConfigurationBuilder = $cloudinaryConfigurationBuilder; } @@ -67,7 +95,7 @@ public function getWidgetOptions() 'htmlId' => $this->getHtmlId(), 'youTubeApiKey' => $this->mediaHelper->getYouTubeApiKey(), 'videoSelector' => $this->videoSelector, - 'cloudinaryPlaceholder' => $this->getViewFileUrl('Cloudinary_Cloudinary::images/cloudinary_vertical_logo_for_white_bg.svg') + 'cloudinaryPlaceholder' => $this->getPlaceholderUrl(), ] ); } @@ -110,4 +138,24 @@ protected function getCloudinaryConfigUrl() ] ); } + + /** + * @return string + */ + protected function getPlaceholderUrl() + { + $storeManager = $this->configuration->getStoreManager(); + $configPaths = [ + 'catalog/placeholder/image_placeholder', + 'catalog/placeholder/small_image_placeholder', + 'thumbnail_placeholder', + ]; + foreach ($configPaths as $configPath) { + if (($path = $storeManager->getStore()->getConfig($configPath))) { + return $storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_MEDIA) . 'catalog/product/placeholder/' . $path; + break; + } + } + return $this->getViewFileUrl('Cloudinary_Cloudinary::images/cloudinary_cloud_glyph_blue.png'); + } } diff --git a/Command/DownloadImages.php b/Command/DownloadImages.php index 2709401b..13f2b7c1 100644 --- a/Command/DownloadImages.php +++ b/Command/DownloadImages.php @@ -5,6 +5,7 @@ use Cloudinary\Cloudinary\Model\BatchDownloader; use Cloudinary\Cloudinary\Model\Configuration; use Cloudinary\Cloudinary\Model\Logger\OutputLogger; +use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Registry; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -27,9 +28,9 @@ class DownloadImages extends Command private $_override = false; /** - * @var BatchDownloader + * @var ObjectManagerInterface */ - private $batchDownloader; + private $objectManager; /** * @var OutputLogger @@ -41,20 +42,25 @@ class DownloadImages extends Command */ private $coreRegistry; + /** + * @var BatchDownloader + */ + private $batchDownloader; + /** * @method __construct - * @param BatchDownloader $batchDownloader + * @param ObjectManagerInterface $objectManager * @param OutputLogger $outputLogger * @param Registry $coreRegistry */ public function __construct( - BatchDownloader $batchDownloader, + ObjectManagerInterface $objectManager, OutputLogger $outputLogger, Registry $coreRegistry ) { parent::__construct('cloudinary:download:all'); - $this->batchDownloader = $batchDownloader; + $this->objectManager = $objectManager; $this->outputLogger = $outputLogger; $this->coreRegistry = $coreRegistry; } @@ -100,6 +106,9 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { try { + $this->batchDownloader = $this->objectManager + ->get(\Cloudinary\Cloudinary\Model\BatchDownloader::class); + if ($input->getOption(self::OVERRIDE) && $this->confirmQuestion(self::OVERRIDE_CONFIRM_MESSAGE, $input, $output)) { $this->_override = true; } diff --git a/Command/ProductGalleryApiQueueProcess.php b/Command/ProductGalleryApiQueueProcess.php index 65d29615..bbfc422b 100644 --- a/Command/ProductGalleryApiQueueProcess.php +++ b/Command/ProductGalleryApiQueueProcess.php @@ -2,8 +2,8 @@ namespace Cloudinary\Cloudinary\Command; -use Cloudinary\Cloudinary\Cron\ProductGalleryApiQueue; use Magento\Framework\App\State as AppState; +use Magento\Framework\ObjectManagerInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -11,28 +11,28 @@ class ProductGalleryApiQueueProcess extends Command { /** - * @var AppState + * @var ObjectManagerInterface */ - private $appState; + private $objectManager; /** - * @var ProductGalleryApiQueue + * @var AppState */ - private $job; + private $appState; /** * @method __construct + * @param ObjectManagerInterface $objectManager * @param AppState $appState - * @param ProductGalleryApiQueue $job */ public function __construct( - AppState $appState, - ProductGalleryApiQueue $job + ObjectManagerInterface $objectManager, + AppState $appState ) { parent::__construct('cloudinary:product-gallery-api-queue:process'); + $this->objectManager = $objectManager; $this->appState = $appState; - $this->job = $job; } /** @@ -54,6 +54,9 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { + $this->job = $this->objectManager + ->get(\Cloudinary\Cloudinary\Cron\ProductGalleryApiQueue::class); + $this->appState->setAreaCode(\Magento\Framework\App\Area::AREA_CRONTAB); return $this->job ->setOutput($output) diff --git a/Command/ResetAll.php b/Command/ResetAll.php index 4faa8202..a61f0380 100644 --- a/Command/ResetAll.php +++ b/Command/ResetAll.php @@ -2,15 +2,16 @@ namespace Cloudinary\Cloudinary\Command; +use Cloudinary\Cloudinary\Helper\Reset; +use Magento\Framework\ObjectManagerInterface; +use Magento\User\Model\User; +use Magento\User\Model\UserFactory; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Question\ConfirmationQuestion; -use Symfony\Component\Console\Helper\QuestionHelper; -use Magento\User\Model\UserFactory; -use Magento\User\Model\User; -use Cloudinary\Cloudinary\Helper\Reset; +use Symfony\Component\Console\Question\Question; class ResetAll extends Command { @@ -36,6 +37,11 @@ class ResetAll extends Command const COMPLETE_MESSAGE1 = 'All Cloudinary module data has been reset.'; const COMPLETE_MESSAGE2 = 'Please clear your configuration cache to ensure changes take effect.'; + /** + * @var ObjectManagerInterface + */ + private $objectManager; + /** * @var UserFactory */ @@ -46,12 +52,18 @@ class ResetAll extends Command */ private $resetHelper; - - public function __construct(UserFactory $userFactory, Reset $resetHelper) - { + /** + * @method __construct + * @param ObjectManagerInterface $objectManager + * @param UserFactory $userFactory + */ + public function __construct( + ObjectManagerInterface $objectManager, + UserFactory $userFactory + ) { parent::__construct('cloudinary:reset'); + $this->objectManager = $objectManager; $this->userFactory = $userFactory; - $this->resetHelper = $resetHelper; } protected function configure() @@ -67,6 +79,9 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { + $this->resetHelper = $this->objectManager + ->get(\Cloudinary\Cloudinary\Helper\Reset::class); + $this->displayPreActionMessage($output); $helper = $this->getHelper('question'); diff --git a/Command/StopMigration.php b/Command/StopMigration.php index e04164ef..8e9035ea 100644 --- a/Command/StopMigration.php +++ b/Command/StopMigration.php @@ -3,6 +3,7 @@ namespace Cloudinary\Cloudinary\Command; use Cloudinary\Cloudinary\Model\MigrationTask; +use Magento\Framework\ObjectManagerInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -12,19 +13,24 @@ class StopMigration extends Command const NOP_MESSAGE = 'No upload/download running to stop.'; const STOPPED_MESSAGE = 'Upload/Download manually stopped.'; + /** + * @var ObjectManagerInterface + */ + private $objectManager; + /** * @var MigrationTask */ private $migrationTask; /** - * @param MigrationTask $migrationTask + * @param ObjectManagerInterface $objectManager */ - public function __construct(MigrationTask $migrationTask) + public function __construct(ObjectManagerInterface $objectManager) { parent::__construct('cloudinary:migration:stop'); - $this->migrationTask = $migrationTask; + $this->objectManager = $objectManager; } /** @@ -45,6 +51,9 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { + $this->migrationTask = $this->objectManager + ->get(\Cloudinary\Cloudinary\Model\MigrationTask::class); + if ($this->migrationTask->hasStarted()) { $this->migrationTask->stop(); $output->writeln(self::STOPPED_MESSAGE); diff --git a/Command/UploadImages.php b/Command/UploadImages.php index 25e63fe1..3d1b4946 100644 --- a/Command/UploadImages.php +++ b/Command/UploadImages.php @@ -5,6 +5,7 @@ use Cloudinary\Cloudinary\Model\BatchUploader; use Cloudinary\Cloudinary\Model\Configuration; use Cloudinary\Cloudinary\Model\Logger\OutputLogger; +use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Registry; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; @@ -21,9 +22,9 @@ class UploadImages extends Command /**#@- */ /** - * @var BatchUploader + * @var ObjectManagerInterface */ - private $batchUploader; + private $objectManager; /** * @var OutputLogger @@ -35,20 +36,25 @@ class UploadImages extends Command */ private $coreRegistry; + /** + * @var BatchUploader + */ + private $batchUploader; + /** * @method __construct - * @param BatchUploader $batchUploader - * @param OutputLogger $outputLogger - * @param Registry $coreRegistry + * @param ObjectManagerInterface $objectManager + * @param OutputLogger $outputLogger + * @param Registry $coreRegistry */ public function __construct( - BatchUploader $batchUploader, + ObjectManagerInterface $objectManager, OutputLogger $outputLogger, Registry $coreRegistry ) { parent::__construct('cloudinary:upload:all'); - $this->batchUploader = $batchUploader; + $this->objectManager = $objectManager; $this->outputLogger = $outputLogger; $this->coreRegistry = $coreRegistry; } @@ -88,6 +94,9 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { try { + $this->batchUploader = $this->objectManager + ->get(\Cloudinary\Cloudinary\Model\BatchUploader::class); + if (($env = $input->getOption(self::ENV))) { $this->coreRegistry->register(Configuration::CONFIG_PATH_ENVIRONMENT_VARIABLE, $env); } diff --git a/Controller/Adminhtml/Ajax/RetrieveImage.php b/Controller/Adminhtml/Ajax/RetrieveImage.php index 4c5164c6..86c4fb92 100644 --- a/Controller/Adminhtml/Ajax/RetrieveImage.php +++ b/Controller/Adminhtml/Ajax/RetrieveImage.php @@ -31,6 +31,11 @@ class RetrieveImage extends \Magento\Backend\App\Action */ private $remoteFileUrl; + /** + * @var bool + */ + private $usingPlaceholderFallback = false; + /** * @var array */ @@ -278,6 +283,8 @@ protected function appendResultSaveRemoteImage($localUniqFilePath, $baseTmpMedia $result['url'] = $this->storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_MEDIA) . $localUniqFilePath; $result['tmp_name'] = $this->appendAbsoluteFileSystemPath($localUniqFilePath); $result['file'] = $tmpFileName; + $result['using_placeholder_fallback'] = (bool) $this->usingPlaceholderFallback; + return $result; } @@ -294,7 +301,18 @@ protected function retrieveRemoteImage($fileUrl, $localFilePath) $this->curl->setConfig(['header' => false]); $this->curl->write('GET', $fileUrl); $image = $this->curl->read(); + + if (empty($image) && $this->getRequest()->getParam('asset')["resource_type"] === 'video') { + //Fallback for video thumbnail image, use placeholder or store logo + $this->usingPlaceholderFallback = true; + $this->curl->close(); + $this->curl->setConfig(['header' => false, 'verifypeer' => false, 'verifyhost' => 0]); + $this->curl->write('GET', $this->getPlaceholderUrl()); + $image = $this->curl->read(); + } + if (empty($image)) { + $this->usingPlaceholderFallback = false; throw new LocalizedException( __('The preview image information is unavailable. Check your connection and try again.') ); @@ -337,4 +355,22 @@ private function saveCloudinaryMapping() ->setFreeTransformation($this->parsedRemoteFileUrl["transformations_string"]) ->save(); } + + /** + * @return string + */ + private function getPlaceholderUrl() + { + $configPaths = [ + 'catalog/placeholder/image_placeholder', + 'catalog/placeholder/small_image_placeholder', + ]; + foreach ($configPaths as $configPath) { + if (($path = $this->storeManager->getStore()->getConfig($configPath))) { + //return $this->storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_MEDIA) . 'catalog/product/placeholder/' . $path; + //break; + } + } + return $this->_view->getLayout()->createBlock("Magento\Theme\Block\Html\Header\Logo")->getViewFileUrl('Cloudinary_Cloudinary::images/cloudinary_cloud_glyph_blue.png'); + } } diff --git a/Core/AutoUploadMapping/ApiClient.php b/Core/AutoUploadMapping/ApiClient.php index c76bf8df..eedf842e 100644 --- a/Core/AutoUploadMapping/ApiClient.php +++ b/Core/AutoUploadMapping/ApiClient.php @@ -96,6 +96,7 @@ public function prepareMapping($folder, $url) */ private function parseFetchMappingsResponse(Response $response) { + $response = (array)$response; if (!array_key_exists(self::MAPPINGS_KEY, $response) || !is_array($response[self::MAPPINGS_KEY])) { throw new \Exception('Illegal mapping response'); } diff --git a/Core/CloudinaryImageManager.php b/Core/CloudinaryImageManager.php index 53ddee0e..f35dfeb4 100644 --- a/Core/CloudinaryImageManager.php +++ b/Core/CloudinaryImageManager.php @@ -27,18 +27,26 @@ class CloudinaryImageManager */ private $synchronisationRepository; + /** + * @var ConfigurationInterface + */ + private $configuration; + /** * CloudinaryImageManager constructor. * * @param ImageProvider $cloudinaryImageProvider * @param SynchroniseAssetsRepositoryInterface $synchronisationRepository + * @param ConfigurationInterface $configuration */ public function __construct( ImageProvider $cloudinaryImageProvider, - SynchroniseAssetsRepositoryInterface $synchronisationRepository + SynchroniseAssetsRepositoryInterface $synchronisationRepository, + ConfigurationInterface $configuration ) { $this->cloudinaryImageProvider = $cloudinaryImageProvider; $this->synchronisationRepository = $synchronisationRepository; + $this->configuration = $configuration; } /** @@ -48,6 +56,10 @@ public function __construct( */ public function uploadAndSynchronise(Image $image, OutputInterface $output = null, $retryAttempt = 0) { + if (!$this->configuration->isEnabled() || !$this->configuration->hasEnvironmentVariable()) { + return; + } + try { $this->report($output, sprintf(self::MESSAGE_UPLOADING_IMAGE, $image)); $this->cloudinaryImageProvider->upload($image); @@ -78,6 +90,10 @@ public function uploadAndSynchronise(Image $image, OutputInterface $output = nul */ public function removeAndUnSynchronise(Image $image) { + if (!$this->configuration->isEnabled() || !$this->configuration->hasEnvironmentVariable()) { + return; + } + $this->cloudinaryImageProvider->delete($image); $this->synchronisationRepository->removeSynchronised($image->getRelativePath()); } diff --git a/Model/Api/ProductGalleryManagement.php b/Model/Api/ProductGalleryManagement.php index be8cd803..b8bc6069 100644 --- a/Model/Api/ProductGalleryManagement.php +++ b/Model/Api/ProductGalleryManagement.php @@ -246,6 +246,7 @@ public function addProductMedia($sku, $urls) ] ]; try { + $this->checkEnvHeader(); if (!$this->configuration->isEnabled()) { throw new LocalizedException( __("Cloudinary module is disabled. Please enable it first in order to use this API.") @@ -310,6 +311,7 @@ public function addItems($items) "message" => "" ]; try { + $this->checkEnvHeader(); if (!$this->configuration->isEnabled()) { throw new LocalizedException( __("Cloudinary module is disabled. Please enable it first in order to use this API.") @@ -553,6 +555,19 @@ private function retrieveImage($remoteFileUrl) return $result; } + /** + * @method checkEnvHeader + * @return $this + */ + private function checkEnvHeader() + { + if (($envVar = $this->request->getHeader('CLD-ENV-VAR'))) { + $this->configuration->setRegistryEnabled(true); + $this->configuration->setRegistryEnvVar($envVar); + } + return $this; + } + private function getLocalTmpFileName($remoteFileUrl) { $localFileName = Uploader::getCorrectFileName(basename($remoteFileUrl)); diff --git a/Model/Api/ResourcesManagement.php b/Model/Api/ResourcesManagement.php index 88233eb8..5ab7259d 100644 --- a/Model/Api/ResourcesManagement.php +++ b/Model/Api/ResourcesManagement.php @@ -70,7 +70,7 @@ private function initialize() if (!$this->initialized) { $this->initialized = true; if (($id = $this->_request->getParam("id"))) { - $this->setId($id); + $this->setId(\rawurldecode($id)); } if (($maxResults = $this->_request->getParam("max_results"))) { $this->setMaxResults($maxResults); diff --git a/Model/Configuration.php b/Model/Configuration.php index 5eb6f5b2..f706ef55 100644 --- a/Model/Configuration.php +++ b/Model/Configuration.php @@ -305,7 +305,7 @@ public function getFormatsToPreserve() */ public function getMigratedPath($file) { - return sprintf('%s/%s', DirectoryList::MEDIA, $file); + return preg_match("#^" . preg_quote(DirectoryList::MEDIA . DIRECTORY_SEPARATOR, '/') . "#i", $file) ? $file : sprintf('%s/%s', DirectoryList::MEDIA, $file); } /** @@ -674,4 +674,24 @@ public function log($message, $data = [], $prefix = '[Cloudinary Log] ') $this->cloudinaryLogger->info($prefix . json_encode($message), $data); return $this; } + + /** + * @method setRegistryEnabled + * @param string|null $val + */ + public function setRegistryEnabled($val) + { + $this->coreRegistry->register(self::CONFIG_PATH_ENABLED, $val); + return $this; + } + + /** + * @method setRegistryEnvVar + * @param bool $val + */ + public function setRegistryEnvVar($val) + { + $this->coreRegistry->register(self::CONFIG_PATH_ENVIRONMENT_VARIABLE, ($val ? true : false)); + return $this; + } } diff --git a/Model/ImageRepository.php b/Model/ImageRepository.php index 56e95866..e43adec8 100644 --- a/Model/ImageRepository.php +++ b/Model/ImageRepository.php @@ -59,6 +59,9 @@ public function findUnsynchronisedImages() continue; } $relativePath = $this->mediaDirectory->getRelativePath($absolutePath); + if (!preg_match("#^" . preg_quote(DirectoryList::MEDIA . DIRECTORY_SEPARATOR, '/') . "#i", $relativePath)) { + $relativePath = DirectoryList::MEDIA . DIRECTORY_SEPARATOR . $relativePath; + } if ($this->isValidImageFile($item) && !$this->synchronizationChecker->isSynchronized($relativePath)) { $images[] = Image::fromPath($absolutePath, $relativePath); } diff --git a/Model/Observer/CatalogProductImportBunchSaveAfter.php b/Model/Observer/CatalogProductImportBunchSaveAfter.php index 482aa1ce..75f40426 100644 --- a/Model/Observer/CatalogProductImportBunchSaveAfter.php +++ b/Model/Observer/CatalogProductImportBunchSaveAfter.php @@ -97,7 +97,11 @@ public function execute(Observer $observer) protected function cleanConfigCache() { - $this->cacheTypeList->cleanType(\Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER); + try { + $this->cacheTypeList->cleanType(\Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER); + } catch (\Exception $e) { + $this->messageManager->addNoticeMessage(__('For some reason, Cloudinary couldn\'t clear your config cache, please clear the cache manually. (Exception message: %1)', $e->getMessage())); + } return $this; } } diff --git a/Model/Observer/Configuration.php b/Model/Observer/Configuration.php index a876bc48..9164d19c 100644 --- a/Model/Observer/Configuration.php +++ b/Model/Observer/Configuration.php @@ -84,7 +84,6 @@ public function execute(Observer $observer) ) > 0 ) { $this->cleanConfigCache(); - $this->appConfig->reinit(); } if (!$this->configuration->isEnabled()) { @@ -98,11 +97,8 @@ public function execute(Observer $observer) protected function cleanConfigCache() { - try { - $this->cacheTypeList->cleanType(\Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER); - } catch (\Exception $e) { - $this->messageManager->addNoticeMessage(__('For some reason, Cloudinary couldn\'t clear your config cache, please clear the cache manually. (Exception message: %1)', $e->getMessage())); - } + $this->cacheTypeList->cleanType(\Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER); + $this->appConfig->reinit(); return $this; } } diff --git a/Plugin/FileRemover.php b/Plugin/FileRemover.php index 0ae904df..c51fb958 100644 --- a/Plugin/FileRemover.php +++ b/Plugin/FileRemover.php @@ -3,6 +3,7 @@ namespace Cloudinary\Cloudinary\Plugin; use Cloudinary\Cloudinary\Core\CloudinaryImageManager; +use Cloudinary\Cloudinary\Core\ConfigurationInterface; use Cloudinary\Cloudinary\Core\Image; use Magento\Cms\Model\Wysiwyg\Images\Storage; use Magento\Framework\App\Filesystem\DirectoryList; @@ -22,15 +23,24 @@ class FileRemover private $mediaDirectory; /** - * @param CloudinaryImageManager $cloudinaryImageManager - * @param Filesystem $filesystem + * @var ConfigurationInterface + */ + private $configuration; + + /** + * @method __construct + * @param CloudinaryImageManager $cloudinaryImageManager + * @param Filesystem $filesystem + * @param ConfigurationInterface $configuration */ public function __construct( CloudinaryImageManager $cloudinaryImageManager, - Filesystem $filesystem + Filesystem $filesystem, + ConfigurationInterface $configuration ) { $this->cloudinaryImageManager = $cloudinaryImageManager; $this->mediaDirectory = $filesystem->getDirectoryRead(DirectoryList::MEDIA); + $this->configuration = $configuration; } /** @@ -41,6 +51,10 @@ public function __construct( */ public function beforeDeleteFile(Storage $storage, $target) { + if (!$this->configuration->isEnabled() || !$this->configuration->hasEnvironmentVariable()) { + return [$target]; + } + $this->cloudinaryImageManager->removeAndUnSynchronise( Image::fromPath($target, $this->mediaDirectory->getRelativePath($target)) ); diff --git a/Plugin/FileUploader.php b/Plugin/FileUploader.php index e36ef853..db6a44ad 100644 --- a/Plugin/FileUploader.php +++ b/Plugin/FileUploader.php @@ -3,6 +3,7 @@ namespace Cloudinary\Cloudinary\Plugin; use Cloudinary\Cloudinary\Core\CloudinaryImageManager; +use Cloudinary\Cloudinary\Core\ConfigurationInterface; use Cloudinary\Cloudinary\Core\Image; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\File\Uploader; @@ -22,15 +23,24 @@ class FileUploader private $directoryList; /** - * @param CloudinaryImageManager $cloudinaryImageManager - * @param DirectoryList $directoryList + * @var ConfigurationInterface + */ + private $configuration; + + /** + * @method __construct + * @param CloudinaryImageManager $cloudinaryImageManager + * @param DirectoryList $directoryList + * @param ConfigurationInterface $configuration */ public function __construct( CloudinaryImageManager $cloudinaryImageManager, - DirectoryList $directoryList + DirectoryList $directoryList, + ConfigurationInterface $configuration ) { $this->cloudinaryImageManager = $cloudinaryImageManager; $this->directoryList = $directoryList; + $this->configuration = $configuration; } /** @@ -40,6 +50,10 @@ public function __construct( */ public function afterSave(Uploader $uploader, $result) { + if (!$this->configuration->isEnabled() || !$this->configuration->hasEnvironmentVariable()) { + return $result; + } + $filepath = $this->absoluteFilePath($result); if ($this->isAllowedImageExtension($filepath) && $this->isMediaFilePath($filepath) && !$this->isMediaTmpFilePath($filepath)) { diff --git a/composer.json b/composer.json index 7ed13ac2..f507f251 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "cloudinary/cloudinary-magento2", "description": "Cloudinary Magento 2 Integration.", "type": "magento2-module", - "version": "1.14.7", + "version": "1.14.8", "license": "MIT", "require": { "cloudinary/cloudinary_php": "^1.20.0" diff --git a/etc/module.xml b/etc/module.xml index 54b47e0c..87cebd17 100644 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,6 +1,6 @@ - + diff --git a/marketplace.composer.json b/marketplace.composer.json index 122e62d4..425e670d 100644 --- a/marketplace.composer.json +++ b/marketplace.composer.json @@ -2,7 +2,7 @@ "name": "cloudinary/cloudinary", "description": "Cloudinary Magento 2 Integration.", "type": "magento2-module", - "version": "1.14.7", + "version": "1.14.8", "license": "MIT", "require": { "cloudinary/cloudinary_php": "^1.20.0" diff --git a/view/adminhtml/web/js/cloudinary-media-library-modal.js b/view/adminhtml/web/js/cloudinary-media-library-modal.js index 408fcede..3790c113 100644 --- a/view/adminhtml/web/js/cloudinary-media-library-modal.js +++ b/view/adminhtml/web/js/cloudinary-media-library-modal.js @@ -87,6 +87,13 @@ define([ this.cloudinary_ml.show(this.options.cloudinaryMLshowOptions); }, + /** + * Escape Regex + */ + escapeRegex: function(string) { + return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + }, + /** * Fired on trigger "cloudinaryInsertHandler" */ @@ -108,7 +115,7 @@ define([ asset.asset_derived_image_url .replace(new RegExp('^.*cloudinary.com/(' + this.options.cloudinaryMLoptions.cloud_name + '/)?' + asset.resource_type + '/' + asset.type + '/'), '') .replace(/\.[^/.]+$/, '') - .replace(new RegExp('\/' + asset.public_id + '$'), '') + .replace(new RegExp('\/' + widget.escapeRegex(encodeURIComponent(asset.public_id)) + '$'), '') .replace(new RegExp('\/v[0-9]{1,10}$'), '') .replace(new RegExp('\/'), ','); if (widget.options.useDerived) { @@ -116,7 +123,10 @@ define([ } } if (asset.resource_type === "video") { - asset.asset_image_url = asset.asset_url.replace(/\.[^/.]+$/, "").replace(new RegExp('\/v[0-9]{1,10}\/'), '/').replace(new RegExp('\/(' + asset.public_id + ')$'), '/so_auto/$1.jpg'); + asset.asset_image_url = asset.asset_url + .replace(/\.[^/.]+$/, "") + .replace(new RegExp('\/v[0-9]{1,10}\/'), '/') + .replace(new RegExp('\/(' + widget.escapeRegex(encodeURIComponent(asset.public_id)) + ')$'), '/so_auto/$1.jpg'); } $.ajax({ url: widget.options.imageUploaderUrl, @@ -140,6 +150,15 @@ define([ file.video_url = asset.asset_url; file.video_title = context.caption || context.alt || asset.public_id || ""; file.video_description = (context.description || context.alt || context.caption || "").replace(/( |<([^>]+)>)/ig, ''); + if (file.using_placeholder_fallback) { + notification().add({ + error: false, + message: $t("Couldn't automatically generate Cloudinary video thumbnail, using fallback placeholder instead. You can always replace that manually later"), + insertMethod: function(constructedMessage) { + aggregatedErrorMessages.push(constructedMessage); + } + }); + } } else { file.media_type = "image"; file.label = asset.label = context.alt || context.caption || asset.public_id || ""; diff --git a/view/adminhtml/web/js/get-video-information.js b/view/adminhtml/web/js/get-video-information.js index a0b1d786..e9823019 100644 --- a/view/adminhtml/web/js/get-video-information.js +++ b/view/adminhtml/web/js/get-video-information.js @@ -613,6 +613,7 @@ define( context, thumbnail, thumbnail_bytes; + var self = this; try { data = JSON.parse(data); @@ -637,7 +638,23 @@ define( context = (tmp.context && tmp.context.custom) ? tmp.context.custom : {}; tmp.derived = tmp.derived || []; - thumbnail = videoInfo.videoSrc.replace(/\.[^/.]+$/, "").replace(new RegExp('\/v[0-9]{1,10}\/'), '/').replace(new RegExp('\/(' + tmp.public_id + ')$'), '/so_auto/$1.jpg') || this.options.cloudinaryPlaceholder; + thumbnail = videoInfo.videoSrc + .replace(/\.[^/.]+$/, "") + .replace(new RegExp('\/v[0-9]{1,10}\/'), '/') + .replace(new RegExp('\/(' + this._escapeRegex(encodeURIComponent(tmp.public_id)) + ')$'), '/so_auto/$1.jpg'); + + //Fallback for video thumbnail image, use placeholder or store logo + $.ajax({ + type: "GET", + url: thumbnail, + async: false, + error: function(request, status, error) { + thumbnail = self.options.cloudinaryPlaceholder; + /*alert({ + content: "Couldn't automatically generate Cloudinary video thumbnail, using fallback placeholder instead. You can always replace that manually later" + });*/ + } + }); respData = { duration: 'unknown', @@ -781,6 +798,13 @@ define( return re.exec(str)[1]; }, + /** + * @private + */ + _escapeRegex: function(string) { + return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + }, + /** * @private */ diff --git a/view/adminhtml/web/js/product_free_transform.js b/view/adminhtml/web/js/product_free_transform.js index 007047fc..af819acf 100644 --- a/view/adminhtml/web/js/product_free_transform.js +++ b/view/adminhtml/web/js/product_free_transform.js @@ -111,10 +111,27 @@ define( tableRows: {} }, + /** + * Called when another element was added to current component. + * + * @param {Object} elem - Instance of an element that was added. + * @returns {Collection} Chainable. + */ + initElement: function(elem) { + elem.initContainer(this); + this.ajaxUrl = this.ajaxUrl || this.getAjaxUrl(); + return this; + }, + + getTransforms: function() { return registry.get('product_form.product_form_data_source').data.product.cloudinary_transforms; }, + getAjaxUrl: function() { + return registry.get('product_form.product_form_data_source').data.product.cloudinary_ajax_url; + }, + createRow: function(params) { return FreeTransformRow().configure(params); }, diff --git a/view/base/web/images/cloudinary_cloud_glyph_blue.png b/view/base/web/images/cloudinary_cloud_glyph_blue.png new file mode 100644 index 00000000..49af8db9 Binary files /dev/null and b/view/base/web/images/cloudinary_cloud_glyph_blue.png differ