Skip to content

Commit

Permalink
Merge branch 'b-7.2.x-prepare-module-block-list-OXDEV-8489-revised2' …
Browse files Browse the repository at this point in the history
…into b-7.2.x
  • Loading branch information
MarcelOxid committed Aug 16, 2024
2 parents fd156b2 + 8603b62 commit aa43f6d
Show file tree
Hide file tree
Showing 32 changed files with 436 additions and 50 deletions.
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Theme list and filtering option on basis of theme name and status
- Module list and filtering option on basis of module name and status
- Activation of given theme by themeId
- Mutations to activate and deactive a module.
- Mutations to de/activate a module.
- Prevention of de/activation of certain modules mentioned in modules_blocklist.yaml.

## [1.1.0] - 2024-07-05
This is stable release for v1.1.0. No changes have been made since v1.1.0-rc.1.

## [1.1.0-rc.1] - 2024-05-30
[.gitignore](.gitignore)
### Added
- PHP 8.2 support
- Module activation dependency on GraphQL Base module
- Activate a given theme by themeId.

### Changed
- PHPUnit upgraded to version 10.x
Expand All @@ -33,6 +32,7 @@ This is stable release for v1.1.0. No changes have been made since v1.1.0-rc.1.

- Initial release

[1.2.0]: https://github.com/OXID-eSales/graphql-configuration-access/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/OXID-eSales/graphql-configuration-access/compare/v1.1.0-rc.1...v1.1.0
[1.1.0-rc.1]: https://github.com/OXID-eSales/graphql-configuration-access/compare/v1.0.0...v1.1.0-rc.1
[1.0.0]: https://github.com/OXID-eSales/graphql-configuration-access/releases/tag/v1.0.0
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ $ vendor/bin/oe-console oe:module:activate oe_graphql_configuration_access

A good starting point is to check the [How to use section in the GraphQL Base Module](https://github.com/OXID-eSales/graphql-base-module/#how-to-use)

## Blocking modules from de/activation via GraphQL

The file module_blockilst.yaml contains a list of modules which are necessary to handle configurations or de/activate
modules via GraphQL or should be blocked for de/activation via GraphQL in general. Modules like ``oe_graphql_base`` and
``oe_graphql_configuration_access`` are listed there.

## Testing

### Linting, syntax check, static analysis
Expand Down
3 changes: 3 additions & 0 deletions module_blocklist.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
modules:
- oe_graphql_base
- oe_graphql_configuration_access
22 changes: 22 additions & 0 deletions src/Module/Exception/ModuleActivationBlockedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/**
* Copyright © OXID eSales AG. All rights reserved.
* See LICENSE file for license details.
*/

declare(strict_types=1);

namespace OxidEsales\GraphQL\ConfigurationAccess\Module\Exception;

use OxidEsales\GraphQL\Base\Exception\NotFound;

final class ModuleActivationBlockedException extends NotFound
{
private const EXCEPTION_MESSAGE = 'Module "%s" is in the blocklist and cannot be activated.';

public function __construct(string $moduleId)
{
parent::__construct(sprintf(self::EXCEPTION_MESSAGE, $moduleId));
}
}
4 changes: 2 additions & 2 deletions src/Module/Exception/ModuleActivationException.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

namespace OxidEsales\GraphQL\ConfigurationAccess\Module\Exception;

use OxidEsales\GraphQL\Base\Exception\NotFound;
use OxidEsales\GraphQL\Base\Exception\Error;

final class ModuleActivationException extends NotFound
final class ModuleActivationException extends Error
{
private const EXCEPTION_MESSAGE = "An error occurred while activating the module.";

Expand Down
22 changes: 22 additions & 0 deletions src/Module/Exception/ModuleDeactivationBlockedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/**
* Copyright © OXID eSales AG. All rights reserved.
* See LICENSE file for license details.
*/

declare(strict_types=1);

namespace OxidEsales\GraphQL\ConfigurationAccess\Module\Exception;

use OxidEsales\GraphQL\Base\Exception\NotFound;

final class ModuleDeactivationBlockedException extends NotFound
{
private const EXCEPTION_MESSAGE = 'Module "%s" is in the blocklist and cannot be deactivated.';

public function __construct(string $moduleId)
{
parent::__construct(sprintf(self::EXCEPTION_MESSAGE, $moduleId));
}
}
4 changes: 2 additions & 2 deletions src/Module/Exception/ModuleDeactivationException.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

namespace OxidEsales\GraphQL\ConfigurationAccess\Module\Exception;

use OxidEsales\GraphQL\Base\Exception\NotFound;
use OxidEsales\GraphQL\Base\Exception\Error;

final class ModuleDeactivationException extends NotFound
final class ModuleDeactivationException extends Error
{
private const EXCEPTION_MESSAGE = "An error occurred while deactivating the module.";

Expand Down
13 changes: 12 additions & 1 deletion src/Module/Service/ModuleActivationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
use OxidEsales\EshopCommunity\Internal\Framework\Module\Setup\Bridge\ModuleActivationBridgeInterface;
use OxidEsales\EshopCommunity\Internal\Transition\Utility\ContextInterface;
use OxidEsales\GraphQL\ConfigurationAccess\Module\Exception\ModuleActivationException;
use OxidEsales\GraphQL\ConfigurationAccess\Module\Exception\ModuleActivationBlockedException;
use OxidEsales\GraphQL\ConfigurationAccess\Module\Exception\ModuleDeactivationBlockedException;
use OxidEsales\GraphQL\ConfigurationAccess\Module\Exception\ModuleDeactivationException;

class ModuleActivationService implements ModuleActivationServiceInterface
{
public function __construct(
private readonly ContextInterface $context,
private readonly ModuleActivationBridgeInterface $moduleActivationBridge
private readonly ModuleActivationBridgeInterface $moduleActivationBridge,
private readonly ModuleBlocklistServiceInterface $moduleBlocklistService
) {
}

Expand All @@ -27,6 +30,10 @@ public function __construct(
*/
public function activateModule(string $moduleId): bool
{
if ($this->moduleBlocklistService->isModuleBlocked($moduleId)) {
throw new ModuleActivationBlockedException($moduleId);
}

$shopId = $this->context->getCurrentShopId();

try {
Expand All @@ -43,6 +50,10 @@ public function activateModule(string $moduleId): bool
*/
public function deactivateModule(string $moduleId): bool
{
if ($this->moduleBlocklistService->isModuleBlocked($moduleId)) {
throw new ModuleDeactivationBlockedException($moduleId);
}

$shopId = $this->context->getCurrentShopId();

try {
Expand Down
2 changes: 2 additions & 0 deletions src/Module/Service/ModuleActivationServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use OxidEsales\GraphQL\ConfigurationAccess\Module\Exception\ModuleActivationException;
use OxidEsales\GraphQL\ConfigurationAccess\Module\Exception\ModuleDeactivationException;
use OxidEsales\GraphQL\ConfigurationAccess\Module\Exception\ModuleDeactivationBlockedException;

interface ModuleActivationServiceInterface
{
Expand All @@ -19,6 +20,7 @@ public function activateModule(string $moduleId): bool;

/**
* @throws ModuleDeactivationException
* @throws ModuleDeactivationBlockedException
*/
public function deactivateModule(string $moduleId): bool;
}
30 changes: 30 additions & 0 deletions src/Module/Service/ModuleBlocklistService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/**
* Copyright © OXID eSales AG. All rights reserved.
* See LICENSE file for license details.
*/

declare(strict_types=1);

namespace OxidEsales\GraphQL\ConfigurationAccess\Module\Service;

use OxidEsales\EshopCommunity\Internal\Framework\DIContainer\Dao\ProjectYamlDaoInterface;

class ModuleBlocklistService implements ModuleBlocklistServiceInterface
{
public function __construct(
private readonly string $moduleBlocklistPath,
private readonly ProjectYamlDaoInterface $projectYamlDao
) {
}

public function isModuleBlocked(string $moduleId): bool
{
$resolvedPath = dirname(__FILE__) . '/../' . $this->moduleBlocklistPath;
$configWrapper = $this->projectYamlDao->loadDIConfigFile($resolvedPath);
$blocklistData = $configWrapper->getConfigAsArray();

return in_array($moduleId, $blocklistData['modules'], true);
}
}
13 changes: 13 additions & 0 deletions src/Module/Service/ModuleBlocklistServiceInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

/**
* Copyright © OXID eSales AG. All rights reserved.
* See LICENSE file for license details.
*/

namespace OxidEsales\GraphQL\ConfigurationAccess\Module\Service;

interface ModuleBlocklistServiceInterface
{
public function isModuleBlocked(string $moduleId): bool;
}
8 changes: 8 additions & 0 deletions src/Module/services.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
parameters:
oxidesales.graphqlconfigurationaccess.modules_block_list_path: '../../module_blocklist.yaml'

services:
_defaults:
public: false
Expand All @@ -21,3 +24,8 @@ services:

OxidEsales\GraphQL\ConfigurationAccess\Module\Service\ModuleActivationServiceInterface:
class: OxidEsales\GraphQL\ConfigurationAccess\Module\Service\ModuleActivationService

OxidEsales\GraphQL\ConfigurationAccess\Module\Service\ModuleBlocklistServiceInterface:
class: OxidEsales\GraphQL\ConfigurationAccess\Module\Service\ModuleBlocklistService
arguments:
$moduleBlocklistPath: '%oxidesales.graphqlconfigurationaccess.modules_block_list_path%'
6 changes: 3 additions & 3 deletions src/Theme/Controller/ThemeSwitchController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ public function __construct(

/**
* Mutation of Configuration Access Module
* @param string $identifier
* @param string $themeId
* @return bool
*/
#[Mutation]
#[Logged]
#[Right('CHANGE_CONFIGURATION')]
public function switchTheme(string $identifier): bool
public function switchTheme(string $themeId): bool
{
return $this->themeSwitchService->switchTheme($identifier);
return $this->themeSwitchService->switchTheme($themeId);
}
}
9 changes: 0 additions & 9 deletions src/Theme/DataType/ThemeDataType.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,4 @@
#[Type]
class ThemeDataType extends AbstractComponentDataType implements ThemeDataTypeInterface
{
public function __construct(
string $id,
string $title,
string $version,
string $description,
bool $active
) {
parent::__construct($id, $title, $version, $description, $active);
}
}
4 changes: 2 additions & 2 deletions src/Theme/Infrastructure/ThemeSwitchInfrastructure.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ public function __construct(
) {
}

public function switchTheme(string $identifier): bool
public function switchTheme(string $themeId): bool
{
try {
$coreThemeService = $this->coreThemeFactory->create();
if (!$coreThemeService->load($identifier)) {
if (!$coreThemeService->load($themeId)) {
throw new ThemeActivationException(self::THEME_NOT_EXIST);
}
$coreThemeService->activate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ interface ThemeSwitchInfrastructureInterface
/**
*@throws ThemeActivationException
*/
public function switchTheme(string $identifier): bool;
public function switchTheme(string $themeId): bool;
}
4 changes: 2 additions & 2 deletions src/Theme/Service/ThemeSwitchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public function __construct(
private readonly ThemeSwitchInfrastructureInterface $themeSwitchInfrastructure
) {
}
public function switchTheme(string $identifier): bool
public function switchTheme(string $themeId): bool
{
return $this->themeSwitchInfrastructure->switchTheme(identifier: $identifier);
return $this->themeSwitchInfrastructure->switchTheme(themeId: $themeId);
}
}
2 changes: 1 addition & 1 deletion src/Theme/Service/ThemeSwitchServiceInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@

interface ThemeSwitchServiceInterface
{
public function switchTheme(string $identifier): bool;
public function switchTheme(string $themeId): bool;
}
2 changes: 2 additions & 0 deletions tests/Codeception/Acceptance/Module/ModuleSettingBaseCest.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ protected function removeConfiguration(string $moduleId): void
{
$shopConfiguration = $this->getShopConfiguration();
$shopConfiguration->deleteModuleConfiguration($moduleId);
$shopConfigurationDao = $this->getShopConfigurationDao();
$shopConfigurationDao->save($shopConfiguration, 1);
}

protected function getShopConfigurationDao(): ShopConfigurationDao
Expand Down
60 changes: 60 additions & 0 deletions tests/Codeception/Acceptance/Module/ModuleSwitchCest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

/**
* Copyright © OXID eSales AG. All rights reserved.
* See LICENSE file for license details.
*/

declare(strict_types=1);

namespace OxidEsales\GraphQL\ConfigurationAccess\Tests\Codeception\Acceptance\Module;

use Codeception\Attribute\DataProvider;
use OxidEsales\GraphQL\ConfigurationAccess\Tests\Codeception\AcceptanceTester;

/**
* @group module_switch
* @group theme_switch
* @group setting_access
* @group oe_graphql_configuration_access
*/
final class ModuleSwitchCest extends ModuleSettingBaseCest
{
#[DataProvider('moduleSwitchDataProvider')]
public function testModuleSwitchAuthorized(AcceptanceTester $I, \Codeception\Example $example): void
{
$I->login($this->getAdminUsername(), $this->getAdminPassword());

$result = $this->runModuleMutation(
I: $I,
queryName: $example['queryName'],
field: $example['field']
);

$I->assertArrayNotHasKey('errors', $result);
$response = $result['data'][$example['queryName']];
$I->assertTrue($response);
}

private function runModuleMutation(
AcceptanceTester $I,
string $queryName,
string $field
): array {
$I->login($this->getAdminUsername(), $this->getAdminPassword());
$I->sendGQLQuery(
'mutation {
' . $queryName . '(' . $field . ': "' . self::TEST_MODULE_ID . '")
}'
);

$I->seeResponseIsJson();
return $I->grabJsonResponseAsArray();
}

protected function moduleSwitchDataProvider(): \Generator
{
yield ['queryName' => 'activateModule', 'field' => 'moduleId'];
yield ['queryName' => 'deactivateModule', 'field' => 'moduleId'];
}
}
2 changes: 1 addition & 1 deletion tests/Codeception/Acceptance/Theme/ThemeSwitchCest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ private function runThemeSwitchMutation(AcceptanceTester $I): array

$I->sendGQLQuery(
'mutation switchThemeCest{
switchTheme(identifier: "' . $themeId . '")
switchTheme(themeId: "' . $themeId . '")
}'
);

Expand Down
Loading

0 comments on commit aa43f6d

Please sign in to comment.