Add Action Availability Checker Interface

This commit is contained in:
p.kumar 2021-05-25 13:35:44 +05:30
parent 25edd0e30b
commit bf974c4321
11 changed files with 395 additions and 38 deletions

View file

@ -50,6 +50,8 @@ services:
tags: [ 'view.definition.mapper' ]
App\Data\LegacyHandler\PresetListDataHandlerInterface:
tags: [ 'app.data.preset.handler' ]
App\Engine\Service\ActionAvailabilityChecker\ActionAvailabilityCheckerInterface:
tags: [ 'app.engine.service.action.availability.checker' ]
App\Data\LegacyHandler\FilterMapper\FilterMapperInterface:
tags: [ 'app.data.filter.mapper' ]
App\Statistics\Service\StatisticsProviderInterface:
@ -171,6 +173,11 @@ services:
arguments:
- !tagged { tag: 'app.data.filter.mapper' }
App\Engine\Service\ActionAvailabilityChecker\ActionAvailabilityChecker:
# inject all services tagged with app.engine.service.action.availability.checker as first argument
arguments:
- !tagged { tag: 'app.engine.service.action.availability.checker' }
App\ViewDefinitions\LegacyHandler\SubpanelButtonMappers:
# inject all services tagged with subpanel.button.definition.mapper as first argument
arguments:

View file

@ -66,8 +66,9 @@ parameters:
modes:
- detail
- edit
acl:
- audit
availability:
- audited
- acls
modules:
employees:
exclude:

View file

@ -28,7 +28,7 @@
namespace App\Data\Service;
use App\Engine\Service\AclManagerInterface;
use App\Engine\Service\ActionAvailabilityChecker\ActionAvailabilityChecker;
use App\Process\Service\ActionDefinitionProvider;
class RecordActionDefinitionProvider extends ActionDefinitionProvider implements RecordActionDefinitionProviderInterface
@ -41,11 +41,11 @@ class RecordActionDefinitionProvider extends ActionDefinitionProvider implements
/**
* BulkActionDefinitionProvider constructor.
* @param array $recordViewActions
* @param AclManagerInterface $aclManager
* @param ActionAvailabilityChecker $actionChecker
*/
public function __construct(array $recordViewActions, AclManagerInterface $aclManager)
public function __construct(array $recordViewActions, ActionAvailabilityChecker $actionChecker)
{
parent::__construct($aclManager);
parent::__construct($actionChecker);
$this->recordViewActions = $recordViewActions;
}

View file

@ -0,0 +1,107 @@
<?php
/**
* SuiteCRM is a customer relationship management program developed by SalesAgility Ltd.
* Copyright (C) 2021 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
* Free Software Foundation with the addition of the following permission added
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
* IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Supercharged by SuiteCRM".
*/
namespace App\Engine\LegacyHandler\ActionAvailabilityChecker\Checkers;
use App\Engine\LegacyHandler\LegacyHandler;
use App\Engine\LegacyHandler\LegacyScopeState;
use App\Engine\Service\ActionAvailabilityChecker\ActionAvailabilityCheckerInterface;
use App\Module\Service\ModuleNameMapperInterface;
use BeanFactory;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class AuditActionChecker extends LegacyHandler implements ActionAvailabilityCheckerInterface
{
/**
* @var ModuleNameMapperInterface
*/
protected $moduleNameMapper;
/**
* AuditActionChecker constructor.
* @param string $projectDir
* @param string $legacyDir
* @param string $legacySessionName
* @param string $defaultSessionName
* @param LegacyScopeState $legacyScopeState
* @param SessionInterface $session
* @param ModuleNameMapperInterface $moduleNameMapper
*/
public function __construct(
string $projectDir,
string $legacyDir,
string $legacySessionName,
string $defaultSessionName,
LegacyScopeState $legacyScopeState,
SessionInterface $session,
ModuleNameMapperInterface $moduleNameMapper
)
{
parent::__construct($projectDir, $legacyDir, $legacySessionName, $defaultSessionName, $legacyScopeState, $session);
$this->moduleNameMapper = $moduleNameMapper;
}
/**
* @inheritDoc
*/
public function getHandlerKey(): string
{
return 'audit-availability-checker';
}
/**
* key corresponds to the definition of the action/function as defined in module vardefs
*
* @return string
*/
public function getType(): string
{
return 'audited';
}
/**
* check availability status of the action/function as defined under module vardefs
*
* @param string $module - the active module
* @return bool
*/
public function checkAvailability(string $module): bool
{
$this->init();
$bean = BeanFactory::newBean($this->moduleNameMapper->toLegacy($module));
if (empty($bean)) {
$result = false;
} else {
$result = $bean->is_AuditEnabled();
}
$this->close();
return $result;
}
}

View file

@ -0,0 +1,104 @@
<?php
/**
* SuiteCRM is a customer relationship management program developed by SalesAgility Ltd.
* Copyright (C) 2021 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
* Free Software Foundation with the addition of the following permission added
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
* IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Supercharged by SuiteCRM".
*/
namespace App\Engine\Service\ActionAvailabilityChecker;
use ApiPlatform\Core\Exception\ItemNotFoundException;
class ActionAvailabilityChecker
{
protected const MSG_HANDLER_NOT_FOUND = 'Action availability checker is not defined';
/**
* @var ActionAvailabilityCheckerInterface[]
*/
protected $registry = [];
/**
* ActionAvailabilityChecker constructor.
* @param iterable $handlers
*/
public function __construct(iterable $handlers)
{
/**
* @var ActionAvailabilityCheckerInterface[]
*/
if (!empty($handlers)) {
$handlers = iterator_to_array($handlers);
}
foreach ($handlers as $handler) {
$type = $handler->getType();
$this->registry[$type] = $handler;
}
}
/**
* Get the checker for action key
* @param string $type
* @return ActionAvailabilityCheckerInterface
* @throws ItemNotFoundException
*/
public function get(string $type): ActionAvailabilityCheckerInterface
{
if (empty($this->registry[$type])) {
throw new ItemNotFoundException(self::MSG_HANDLER_NOT_FOUND);
}
return $this->registry[$type];
}
/**
* check if the action key exists in the registry
* @param string $type
* @return bool
*/
public function hasChecker(string $type): bool
{
return !(empty($this->registry[$type]));
}
/**
* check the availability status of the action key, if found in registry
* @param string $module
* @param string $type
* action key/type to check the availability for defined inside a configuration file e.g. actions.yaml in the format
* - availability
* - audited
* - acls
* @return bool
*/
public function checkAvailability(string $module, string $type): bool
{
if ($this->hasChecker($type)) {
return $this->get($type)->checkAvailability($module);
}
return true;
}
}

View file

@ -0,0 +1,44 @@
<?php
/**
* SuiteCRM is a customer relationship management program developed by SalesAgility Ltd.
* Copyright (C) 2021 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
* Free Software Foundation with the addition of the following permission added
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
* IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Supercharged by SuiteCRM".
*/
namespace App\Engine\Service\ActionAvailabilityChecker;
interface ActionAvailabilityCheckerInterface
{
/**
* the unique action key, the availability/accessibility to be checked for
* @return string
*/
public function getType(): string;
/**
* @param string $module
* @return bool
*/
public function checkAvailability(string $module): bool;
}

View file

@ -0,0 +1,91 @@
<?php
/**
* SuiteCRM is a customer relationship management program developed by SalesAgility Ltd.
* Copyright (C) 2021 SalesAgility Ltd.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by the
* Free Software Foundation with the addition of the following permission added
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
* IN WHICH THE COPYRIGHT IS OWNED BY SALESAGILITY, SALESAGILITY DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Supercharged by SuiteCRM" logo. If the display of the logos is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Supercharged by SuiteCRM".
*/
namespace App\Engine\Service\ActionAvailabilityChecker\Checkers;
use App\Engine\Service\AclManagerInterface;
use App\Engine\Service\ActionAvailabilityChecker\ActionAvailabilityCheckerInterface;
class ACLActionChecker implements ActionAvailabilityCheckerInterface
{
/**
* @var AclManagerInterface
*/
protected $aclManager;
/**
* ACLActionChecker constructor.
* @param AclManagerInterface $aclManager
*/
public function __construct(AclManagerInterface $aclManager)
{
$this->aclManager = $aclManager;
}
/**
* @inheritDoc
*/
public function getType(): string
{
return 'acls';
}
/**
* Check availability status of the action/function to the user
*
* @param string $module
* @return bool
*/
public function checkAvailability(string $module): bool
{
return $this->checkAccess($module, $entry['acl'] ?? [], $this->aclManager);
}
/**
* Check accessibility status of the action/function to the user
*
* @param string $module - module to be queried
* @param array $aclList - list of the actions against which the accessibility to be checked e.g. delete, edit
* @param AclManagerInterface $aclManager
* @return bool
*/
public function checkAccess(string $module, array $aclList, AclManagerInterface $aclManager): bool
{
if (empty($aclList)) {
return true;
}
foreach ($aclList as $acl) {
if ($aclManager->checkAccess($module, $acl, true) === false) {
return false;
}
}
return true;
}
}

View file

@ -28,21 +28,25 @@
namespace App\Engine\Service;
use App\Engine\Service\ActionAvailabilityChecker\ActionAvailabilityChecker;
trait DefinitionEntryHandlingTrait
{
/**
* @param string $module
* @param string $entryName
* @param array $config
* @param AclManagerInterface $aclManager
* @param ActionAvailabilityChecker $actionAvailabilityChecker
* @return array
*/
public function filterDefinitionEntries(
string $module,
string $entryName,
array &$config,
AclManagerInterface $aclManager
): array {
ActionAvailabilityChecker $actionAvailabilityChecker
): array
{
$defaults = $config['default'] ?? [];
$defaultEntries = $defaults[$entryName] ?? [];
$modulesConfig = $config['modules'] ?? [];
@ -52,43 +56,42 @@ trait DefinitionEntryHandlingTrait
$entries = array_merge($defaultEntries, $moduleEntries);
$filteredEntries = [];
foreach ($entries as $entryKey => $entry) {
if (in_array($entryKey, $exclude, true)) {
continue;
}
if ($this->checkAccess($module, $entry['acl'] ?? [], $aclManager) === false) {
if ($this->checkAvailability($module, $entry['availability'] ?? ['acls'], $actionAvailabilityChecker) === false) {
continue;
}
$filteredEntries[$entryKey] = $entry;
}
return $filteredEntries;
}
/**
* Check access
* Check availability/accessibility status of the action/function to the user
*
* @param string $module
* @param array $aclList
* @param AclManagerInterface $aclManager
* @param string $module - module to be queried
* @param array $actionList
* @param ActionAvailabilityChecker $actionAvailabilityChecker
* @return bool
*/
public function checkAccess(string $module, array $aclList, AclManagerInterface $aclManager): bool
public function checkAvailability(string $module, array $actionList, ActionAvailabilityChecker $actionAvailabilityChecker): bool
{
if (empty($aclList)) {
if (empty($actionList)) {
return true;
}
foreach ($aclList as $acl) {
if ($aclManager->checkAccess($module, $acl, true) === false) {
foreach ($actionList as $action) {
if ($actionAvailabilityChecker->checkAvailability($module, $action) === false) {
return false;
}
}
return true;
}
}

View file

@ -28,7 +28,7 @@
namespace App\Process\Service;
use App\Engine\Service\AclManagerInterface;
use App\Engine\Service\ActionAvailabilityChecker\ActionAvailabilityChecker;
use App\Engine\Service\DefinitionEntryHandlingTrait;
class ActionDefinitionProvider
@ -37,17 +37,17 @@ class ActionDefinitionProvider
use DefinitionEntryHandlingTrait;
/**
* @var AclManagerInterface
* @var ActionAvailabilityChecker
*/
protected $aclManager;
protected $actionChecker;
/**
* BulkActionDefinitionProvider constructor.
* @param AclManagerInterface $aclManager
* @param ActionAvailabilityChecker $actionChecker
*/
public function __construct(AclManagerInterface $aclManager)
public function __construct(ActionAvailabilityChecker $actionChecker)
{
$this->aclManager = $aclManager;
$this->actionChecker = $actionChecker;
}
/**
@ -57,6 +57,6 @@ class ActionDefinitionProvider
*/
public function filterActions(string $module, array &$config): array
{
return $this->filterDefinitionEntries($module, 'actions', $config, $this->aclManager);
return $this->filterDefinitionEntries($module, 'actions', $config, $this->actionChecker);
}
}

View file

@ -28,7 +28,7 @@
namespace App\Process\Service;
use App\Engine\Service\AclManagerInterface;
use App\Engine\Service\ActionAvailabilityChecker\ActionAvailabilityChecker;
class BulkActionDefinitionProvider extends ActionDefinitionProvider implements BulkActionDefinitionProviderInterface
{
@ -40,11 +40,11 @@ class BulkActionDefinitionProvider extends ActionDefinitionProvider implements B
/**
* BulkActionDefinitionProvider constructor.
* @param array $listViewBulkActions
* @param AclManagerInterface $aclManager
* @param ActionAvailabilityChecker $availabilityChecker
*/
public function __construct(array $listViewBulkActions, AclManagerInterface $aclManager)
public function __construct(array $listViewBulkActions, ActionAvailabilityChecker $availabilityChecker)
{
parent::__construct($aclManager);
parent::__construct($availabilityChecker);
$this->listViewBulkActions = $listViewBulkActions;
}

View file

@ -28,7 +28,7 @@
namespace App\ViewDefinitions\Service;
use App\Engine\Service\AclManagerInterface;
use App\Engine\Service\ActionAvailabilityChecker\ActionAvailabilityChecker;
use App\Engine\Service\DefinitionEntryHandlingTrait;
/**
@ -40,9 +40,9 @@ class ListViewSidebarWidgetDefinitionProvider implements ListViewSidebarWidgetDe
use DefinitionEntryHandlingTrait;
/**
* @var AclManagerInterface
* @var ActionAvailabilityChecker
*/
protected $aclManager;
protected $actionChecker;
/**
* @var array
*/
@ -51,12 +51,12 @@ class ListViewSidebarWidgetDefinitionProvider implements ListViewSidebarWidgetDe
/**
* ListViewSidebarWidgetDefinitionProvider constructor.
* @param array $listViewSidebarWidgets
* @param AclManagerInterface $aclManager
* @param ActionAvailabilityChecker $actionChecker
*/
public function __construct(array $listViewSidebarWidgets, AclManagerInterface $aclManager)
public function __construct(array $listViewSidebarWidgets, ActionAvailabilityChecker $actionChecker)
{
$this->widgets = $listViewSidebarWidgets;
$this->aclManager = $aclManager;
$this->actionChecker = $actionChecker;
}
/**
@ -64,7 +64,7 @@ class ListViewSidebarWidgetDefinitionProvider implements ListViewSidebarWidgetDe
*/
public function getSidebarWidgets(string $module): array
{
$widgets = $this->filterDefinitionEntries($module, 'widgets', $this->widgets, $this->aclManager);
$widgets = $this->filterDefinitionEntries($module, 'widgets', $this->widgets, $this->actionChecker);
foreach ($widgets as $index => $widget) {
$widgets[$index]['refreshOn'] = $widget['refreshOn'] ?? 'data-update';