Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/2.4-develop' into spartans_pr_12…
Browse files Browse the repository at this point in the history
…062024
  • Loading branch information
glo60612 committed Jul 3, 2024
2 parents 5d9fff9 + 35b1b1d commit faa90bb
Show file tree
Hide file tree
Showing 14 changed files with 418 additions and 194 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
/**
* Copyright 2024 Adobe
* All Rights Reserved.
*/
declare(strict_types=1);

namespace Magento\Backend\ViewModel;

/**
* View model interface for requirejs configuration modifier
*/
interface RequireJsConfigModifierInterface
{
/**
* Modifies requirejs configuration
*
* @param array $config requirejs configuration
* @return array
*/
public function modify(array $config): array;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@
*/

/** @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer */
/** @var \Magento\Backend\Block\Page\RequireJs $block */

$requireJsConfig = [
'baseUrl' => $block->getViewFileUrl('/'),
];

$configModifier = $block->getConfigModifier();
$requireJsConfig = $configModifier instanceof \Magento\Backend\ViewModel\RequireJsConfigModifierInterface
? $configModifier->modify($requireJsConfig)
: $requireJsConfig;

$scriptString = '
var BASE_URL = \'' . /* @noEscape */ $block->getUrl('*') . '\';
var FORM_KEY = \'' . /* @noEscape */ $block->getFormKey() . '\';
var require = {
\'baseUrl\': \'' . /* @noEscape */ $block->getViewFileUrl('/') . '\'
};';

echo /* @noEscape */ $secureRenderer->renderTag('script', [], $scriptString, false);
var require = ' . /* @noEscape */ json_encode($requireJsConfig) .';';
?>
<?= /* @noEscape */ $secureRenderer->renderTag('script', [], $scriptString, false) ?>
22 changes: 21 additions & 1 deletion app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Data\Collection;
use Magento\Framework\Exception\LocalizedException;

/**
Expand Down Expand Up @@ -289,6 +290,7 @@ protected function createSubDirectories($path)
*
* @return array
* @deprecated
* @see isDirectoryAllowed
*/
protected function getConditionsForExcludeDirs()
{
Expand Down Expand Up @@ -317,6 +319,7 @@ protected function getConditionsForExcludeDirs()
* @param array $conditions
* @return \Magento\Framework\Data\Collection\Filesystem
* @deprecated
* @see \Magento\Framework\Data\Collection\Filesystem::setDirsFilter
*/
protected function removeItemFromCollection($collection, $conditions)
{
Expand Down Expand Up @@ -415,7 +418,7 @@ public function getFilesCollection($path, $type = null)
$mimeType = $itemStats['mimetype'] ?? $this->mime->getMimeType($item->getFilename());
$item->setMimeType($mimeType);

if ($this->isImage($item->getBasename())) {
if ($this->isImageValid($item)) {
$thumbUrl = $this->getThumbnailUrl($item->getFilename(), true);
// generate thumbnail "on the fly" if it does not exists
if (!$thumbUrl) {
Expand All @@ -435,6 +438,12 @@ public function getFilesCollection($path, $type = null)
$this->logger->notice(sprintf("GetImageSize caused error: %s", $e->getMessage()));
}
} else {
$this->logger->warning(
sprintf(
"The image %s is invalid and cannot be displayed in the gallery.",
$item->getBasename()
)
);
$thumbUrl = $this->_assetRepo->getUrl(self::THUMB_PLACEHOLDER_PATH_SUFFIX);
}

Expand Down Expand Up @@ -1058,4 +1067,15 @@ private function getAllowedDirMask(string $path)

return '/^(' . implode('|', array_unique(array_column($allowedDirs, $subfolderLevel - 1))) . ')$/';
}

/**
* Checks if the file is an image and has a size greater than 0 to validate it can be processes in the gallery.
*
* @param Collection $item
* @return bool
*/
private function isImageValid($item)
{
return $this->isImage($item->getBasename()) && $item->getSize() > 0;
}
}
152 changes: 148 additions & 4 deletions app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
use Magento\Cms\Model\Wysiwyg\Images\Storage\CollectionFactory;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\DataObject;
use Magento\Framework\Exception\FileSystemException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Directory\Write;
Expand All @@ -31,6 +33,7 @@
use Magento\MediaStorage\Model\File\UploaderFactory;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

/**
* @SuppressWarnings(PHPMD.LongVariable)
Expand Down Expand Up @@ -141,6 +144,16 @@ class StorageTest extends TestCase
*/
private $fileMock;

/**
* @var LoggerInterface|MockObject
*/
private $loggerMock;

/**
* @var Repository|MockObject
*/
private $assetRepo;

/**
* @var array
*/
Expand Down Expand Up @@ -206,7 +219,7 @@ function ($path) {
$this->adapterFactoryMock = $this->createMock(AdapterFactory::class);
$this->imageHelperMock = $this->createPartialMock(
Images::class,
['getStorageRoot', 'getCurrentPath']
['getStorageRoot', 'getCurrentPath', 'getCurrentUrl']
);
$this->imageHelperMock->expects(
$this->any()
Expand Down Expand Up @@ -234,6 +247,12 @@ function ($path) {
Database::class
);

$this->loggerMock = $this->getMockBuilder(LoggerInterface::class)
->disableOriginalConstructor()
->getMock();

$this->assetRepo = $this->createMock(Repository::class);

$this->uploaderFactoryMock = $this->getMockBuilder(UploaderFactory::class)
->disableOriginalConstructor()
->getMock();
Expand Down Expand Up @@ -284,7 +303,7 @@ function ($path) {
'coreFileStorageDb' => $this->coreFileStorageMock,
'filesystem' => $this->filesystemMock,
'imageFactory' => $this->adapterFactoryMock,
'assetRepo' => $this->createMock(Repository::class),
'assetRepo' => $this->assetRepo,
'storageCollectionFactory' => $this->storageCollectionFactoryMock,
'storageFileFactory' => $this->storageFileFactoryMock,
'storageDatabaseFactory' => $this->storageDatabaseFactoryMock,
Expand All @@ -299,7 +318,8 @@ function ($path) {
'data' => [],
'file' => $this->fileMock,
'ioFile' => $this->ioFileMock,
'coreConfig' => $this->coreConfigMock
'coreConfig' => $this->coreConfigMock,
'logger' => $this->loggerMock
]
);
}
Expand Down Expand Up @@ -368,6 +388,130 @@ public function testGetDirsCollectionCreateSubDirectories()
);
}

/**
* Test getFilesCollection() with the set of valid and invalid files
*
* @return void
* @throws LocalizedException
* @throws FileSystemException
* @dataProvider fileItemsDataProvider
*/
public function testGetFilesCollection(
int $timesWarningTriggered,
string $thumbnailPath,
DataObject $imageItem
) {
/** @var StorageCollection|MockObject $storageCollectionMock */
$storageCollectionMock = $this->getMockBuilder(StorageCollection::class)
->disableOriginalConstructor()
->getMock();
$storageCollectionMock->expects($this->once())
->method('setCollectDirs')
->willReturnSelf();
$storageCollectionMock->expects($this->once())
->method('setCollectFiles')
->willReturnSelf();
$storageCollectionMock->expects($this->once())
->method('setCollectRecursively')
->willReturnSelf();
$storageCollectionMock->expects($this->once())
->method('setOrder')
->willReturnSelf();
$storageCollectionMock->method('getIterator')
->willReturn(new \ArrayIterator([$imageItem]));

$this->storageCollectionFactoryMock->expects($this->once())
->method('create')
->willReturn($storageCollectionMock);

$this->driverMock->expects(self::once())
->method('stat')
->willReturn($imageItem->toArray());

$this->assetRepo->expects($this->exactly($timesWarningTriggered))
->method('getUrl')
->willReturn($thumbnailPath);

$this->loggerMock->expects($this->exactly($timesWarningTriggered))
->method('warning')
->with(
sprintf(
"The image %s is invalid and cannot be displayed in the gallery.",
$imageItem->getBasename()
)
);

$this->imagesStorage->getFilesCollection('/webroot/pub/media/', 'image');
}

/**
* Returns a set of valid and invalid image files
*
* @return array[]
*/
public function fileItemsDataProvider()
{
return [
// Images files with the size of 0 bytes should generate proper warnings
[
'timesWarningTriggered' => 1,
'thumbnailPath' => Storage::THUMB_PLACEHOLDER_PATH_SUFFIX,
'imageItem' =>
new DataObject(
[
'mtime' => 0,
'size' => 0,
'filename' => '/webroot/pub/media/wysiwyg/zero-bytes.jpg',
'basename' => 'zero-bytes.jpg',
'id' => 1,
'name' => 'zero-bytes.jpg',
'short_name' => 'zero-bytes.jpg',
'url' => 'https://magento.local/pub/media/wysiwyg/zero-bytes.jpg',
'mime_type' => 'image/jpeg'
]
)
],
// Images files with incorrect not allowed extensions should generate proper warnings
[
'timesWarningTriggered' => 1,
'thumbnailPath' => Storage::THUMB_PLACEHOLDER_PATH_SUFFIX,
'imageItem' =>
new DataObject(
[
'mtime' => 0,
'size' => 1024,
'filename' => '/webroot/pub/media/wysiwyg/wrong-image.exe',
'basename' => 'wrong-image.exe',
'id' => 1,
'name' => 'wrong-image.exe',
'short_name' => 'wrong-image.exe',
'url' => 'https://magento.local/pub/media/wysiwyg/wrong-image.exe',
'mime_type' => 'image/jpeg'
]
)
],
// Images with non-zero size and allowed extension should not generate warnings
[
'timesWarningTriggered' => 0,
'thumbnailPath' => '',
'imageItem' =>
new DataObject(
[
'mtime' => 0,
'size' => 1024,
'filename' => '/webroot/pub/media/wysiwyg/image.jpg',
'basename' => 'image.jpg',
'id' => 1,
'name' => 'image.jpg',
'short_name' => 'image.jpg',
'url' => 'https://magento.local/pub/media/wysiwyg/image.jpg',
'mime_type' => 'image/jpeg'
]
)
],
];
}

/**
* @param $path
* @param $callNum
Expand Down Expand Up @@ -432,7 +576,7 @@ public static function dirsCollectionDataProvider()
protected function generalTestGetDirsCollection(string $path, int $callNum, string $dirsFilter)
{
/** @var StorageCollection|MockObject $storageCollectionMock */
$storageCollectionMock = $this->getMockBuilder(\Magento\Cms\Model\Wysiwyg\Images\Storage\Collection::class)
$storageCollectionMock = $this->getMockBuilder(StorageCollection::class)
->disableOriginalConstructor()
->getMock();
$storageCollectionMock->expects($this->once())
Expand Down
15 changes: 15 additions & 0 deletions app/code/Magento/NewRelicReporting/Model/NewRelicWrapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/
class NewRelicWrapper
{
private const NEWRELIC_APPNAME = 'newrelic.appname';

/**
* Wrapper for 'newrelic_add_custom_parameter' function
*
Expand Down Expand Up @@ -69,6 +71,19 @@ public function setTransactionName(string $transactionName): void
}
}

/**
* Wrapper to start background transaction
*
* @return void
*/
public function startBackgroundTransaction()
{
if ($this->isExtensionInstalled()) {
newrelic_start_transaction(ini_get(self::NEWRELIC_APPNAME));
newrelic_background_job();
}
}

/**
* Wrapper for 'newrelic_end_transaction'
*
Expand Down
1 change: 1 addition & 0 deletions app/code/Magento/NewRelicReporting/Plugin/StatPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public function beforeStart(Stat $schedule, ...$args): array
$timerName = current($args);

if ($this->isCronJob($timerName)) {
$this->newRelicWrapper->startBackgroundTransaction();
$this->newRelicWrapper->setTransactionName(
sprintf('Cron %s', $timerName)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ protected function setUp(): void
*/
public function testNewRelicTransactionNameIsNotSetIfNotCronjobPattern()
{
$this->newRelicWrapperMock
->expects($this->never())
->method('startBackgroundTransaction');
$this->newRelicWrapperMock
->expects($this->never())
->method('setTransactionName');
Expand All @@ -71,6 +74,9 @@ public function testNewRelicTransactionNameIsNotSetIfNotCronjobPattern()
*/
public function testNewRelicTransactionNameIsSetForCronjobNamePattern()
{
$this->newRelicWrapperMock
->expects($this->once())
->method('startBackgroundTransaction');
$this->newRelicWrapperMock
->expects($this->once())
->method('setTransactionName');
Expand All @@ -90,7 +96,7 @@ private function getNewRelicWrapperMock(): NewRelicWrapper
if (null === $this->newRelicWrapperMock) {
$this->newRelicWrapperMock = $this->getMockBuilder(NewRelicWrapper::class)
->disableOriginalConstructor()
->onlyMethods(['setTransactionName', 'endTransaction'])
->onlyMethods(['setTransactionName', 'endTransaction', 'startBackgroundTransaction'])
->getMock();
}

Expand Down
1 change: 0 additions & 1 deletion app/code/Magento/NewRelicReporting/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
<type name="Magento\NewRelicReporting\Plugin\CommandPlugin">
<arguments>
<argument name="skipCommands" xsi:type="array">
<item xsi:type="boolean" name="cron:run">true</item>
<item xsi:type="boolean" name="server:run">true</item>
</argument>
</arguments>
Expand Down
Loading

0 comments on commit faa90bb

Please sign in to comment.