metadata aclDependency anyScopeList

This commit is contained in:
Yuri Kuznetsov
2025-10-25 12:47:21 +03:00
parent 4e0d5a2267
commit 599646c397
5 changed files with 68 additions and 23 deletions

View File

@@ -31,10 +31,14 @@ namespace Espo\Tools\App\Metadata;
class AclDependencyItem
{
/**
* @param ?string[] $anyScopeList
*/
public function __construct(
private string $target,
private string $scope,
private ?string $field
private ?string $scope,
private ?string $field,
private ?array $anyScopeList = null,
) {}
/**
@@ -45,7 +49,7 @@ class AclDependencyItem
return $this->target;
}
public function getScope(): string
public function getScope(): ?string
{
return $this->scope;
}
@@ -54,4 +58,13 @@ class AclDependencyItem
{
return $this->field;
}
/**
* @return ?string[]
* @since 9.2.5
*/
public function getAnyScopeList(): ?array
{
return $this->anyScopeList;
}
}

View File

@@ -95,15 +95,13 @@ class AclDependencyProvider
$data = [];
foreach (($this->metadata->get(['app', 'metadata', 'aclDependencies']) ?? []) as $target => $item) {
$anyScopeList = $item['anyScopeList'] ?? null;
$scope = $item['scope'] ?? null;
$field = $item['field'] ?? null;
if (!$scope) {
continue;
}
$data[] = [
'target' => $target,
'anyScopeList' => $anyScopeList,
'scope' => $scope,
'field' => $field,
];
@@ -196,8 +194,14 @@ class AclDependencyProvider
$target = $rawItem['target'] ?? null;
$scope = $rawItem['scope'] ?? null;
$field = $rawItem['field'] ?? null;
$anyScopeList = $rawItem['anyScopeList'] ?? null;
$list[] = new AclDependencyItem($target, $scope, $field);
$list[] = new AclDependencyItem(
target: $target,
scope: $scope,
field: $field,
anyScopeList: $anyScopeList,
);
}
return $list;

View File

@@ -178,20 +178,32 @@ class MetadataService
foreach ($this->aclDependencyProvider->get() as $dependencyItem) {
$aclScope = $dependencyItem->getScope();
$aclField = $dependencyItem->getField();
$anyScopeList = $dependencyItem->getAnyScopeList();
if (!$aclScope) {
continue;
if ($anyScopeList) {
$skip = true;
foreach ($anyScopeList as $itemScope) {
if ($this->acl->tryCheck($itemScope)) {
$skip = false;
break;
}
}
if ($skip) {
continue;
}
}
if (!$this->acl->tryCheck($aclScope)) {
continue;
}
if ($aclScope) {
if (!$this->acl->tryCheck($aclScope)) {
continue;
}
if (
$aclField &&
in_array($aclField, $this->acl->getScopeForbiddenFieldList($aclScope))
) {
continue;
if ($aclField && in_array($aclField, $this->acl->getScopeForbiddenFieldList($aclScope))) {
continue;
}
}
$targetArr = explode('.', $dependencyItem->getTarget());

View File

@@ -44,21 +44,21 @@
},
"aclDependencies": {
"type": "object",
"description": "Rules making a metadata sections available for a user when they don't have access to a scope.",
"description": "Rules making a metadata sections available for the user when they don't have access to the scope.",
"additionalProperties": {
"description": "A metadata path, items are separated by dots.",
"properties": {
"scope": {
"type": "string",
"description": "If a user have access to the scope, they will have access to a metadata section defined by a key."
"description": "If the user has access to the scope, they will have access to the metadata section defined by the key."
},
"field": {
"type": "string",
"description": "If a user have access to the field (of a scope), they will have access to a metadata section defined by a key."
"description": "If the user has access to the field (of the scope), they will have access to the metadata section defined by the key."
},
"anyScopeList": {
"type": "array",
"description": "Not supported. TBD.",
"description": "If the user has access to any of the list scopes, they will have access to the metadata section defined by the key. As of v9.2.5.",
"items": {
"type": "string"
}

View File

@@ -29,6 +29,7 @@
namespace tests\integration\Espo\Tools\App;
use Espo\Core\Utils\Metadata;
use Espo\Tools\App\MetadataService;
use tests\integration\Core\BaseTestCase;
@@ -36,6 +37,20 @@ class MetadataTest extends BaseTestCase
{
public function testAclDependency(): void
{
$metadata = $this->getContainer()->getByClass(Metadata::class);
$metadata->set('app', 'metadata', [
'aclDependencies' => [
'entityDefs.Campaign' => [
'anyScopeList' => ['Opportunity'],
],
],
]);
$metadata->save();
$this->reCreateApplication();
$this->createUser('tester', [
'data' => [
'Lead' => false,
@@ -55,6 +70,7 @@ class MetadataTest extends BaseTestCase
$data = $this->getInjectableFactory()->create(MetadataService::class)->getDataForFrontend();
$this->assertIsArray($data?->entityDefs?->Lead?->fields?->source?->options);
$this->assertNull($data->entityDefs->Lead->fields?->name ?? null);
$this->assertNull($data->entityDefs->Lead->fields->name ?? null);
$this->assertNotNull($data?->entityDefs->Campaign ?? null);
}
}