Initial commit
This commit is contained in:
104
application/Espo/Core/Portal/Acl.php
Normal file
104
application/Espo/Core/Portal/Acl.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\Acl as BaseAcl;
|
||||
|
||||
class Acl extends BaseAcl
|
||||
{
|
||||
public function __construct(AclManager $aclManager, User $user)
|
||||
{
|
||||
parent::__construct($aclManager, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether 'read' access is set to 'account' for a specific scope.
|
||||
*/
|
||||
public function checkReadOnlyAccount(string $scope): bool
|
||||
{
|
||||
/** @var AclManager $aclManager */
|
||||
$aclManager = $this->aclManager;
|
||||
|
||||
return $aclManager->checkReadOnlyAccount($this->user, $scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether 'read' access is set to 'contact' for a specific scope.
|
||||
*/
|
||||
public function checkReadOnlyContact(string $scope): bool
|
||||
{
|
||||
/** @var AclManager $aclManager */
|
||||
$aclManager = $this->aclManager;
|
||||
|
||||
return $aclManager->checkReadOnlyContact($this->user, $scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an entity belongs to a user account.
|
||||
*/
|
||||
public function checkOwnershipAccount(Entity $entity): bool
|
||||
{
|
||||
/** @var AclManager $aclManager */
|
||||
$aclManager = $this->aclManager;
|
||||
|
||||
return $aclManager->checkOwnershipAccount($this->user, $entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an entity belongs to a user contact.
|
||||
*/
|
||||
public function checkOwnershipContact(Entity $entity): bool
|
||||
{
|
||||
/** @var AclManager $aclManager */
|
||||
$aclManager = $this->aclManager;
|
||||
|
||||
return $aclManager->checkOwnershipContact($this->user, $entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecate
|
||||
*/
|
||||
public function checkInAccount(Entity $entity): bool
|
||||
{
|
||||
return $this->checkOwnershipAccount($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecate
|
||||
*/
|
||||
public function checkIsOwnContact(Entity $entity): bool
|
||||
{
|
||||
return $this->checkOwnershipContact($entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\AccessChecker;
|
||||
|
||||
use Espo\Core\Acl\AccessChecker;
|
||||
use Espo\Core\Acl\Exceptions\NotImplemented;
|
||||
use Espo\Core\AclManager;
|
||||
use Espo\Core\Binding\Binder;
|
||||
use Espo\Core\Binding\BindingContainer;
|
||||
use Espo\Core\Binding\BindingData;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\Portal\Acl\DefaultAccessChecker;
|
||||
use Espo\Core\Portal\AclManager as PortalAclManager;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
|
||||
class AccessCheckerFactory
|
||||
{
|
||||
/** @var class-string<AccessChecker> */
|
||||
private $defaultClassName = DefaultAccessChecker::class;
|
||||
|
||||
public function __construct(
|
||||
private Metadata $metadata,
|
||||
private InjectableFactory $injectableFactory
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Create an access checker.
|
||||
*
|
||||
* @throws NotImplemented
|
||||
*/
|
||||
public function create(string $scope, PortalAclManager $aclManager): AccessChecker
|
||||
{
|
||||
$className = $this->getClassName($scope);
|
||||
|
||||
$bindingContainer = $this->createBindingContainer($className, $aclManager, $scope);
|
||||
|
||||
return $this->injectableFactory->createWithBinding($className, $bindingContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string<AccessChecker>
|
||||
*/
|
||||
private function getClassName(string $scope): string
|
||||
{
|
||||
/** @var ?class-string<AccessChecker> $className1 */
|
||||
$className1 = $this->metadata->get(['aclDefs', $scope, 'portalAccessCheckerClassName']);
|
||||
|
||||
if ($className1) {
|
||||
return $className1;
|
||||
}
|
||||
|
||||
if (!$this->metadata->get(['scopes', $scope])) {
|
||||
throw new NotImplemented();
|
||||
}
|
||||
|
||||
return $this->defaultClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<AccessChecker> $className
|
||||
*/
|
||||
private function createBindingContainer(
|
||||
string $className,
|
||||
PortalAclManager $aclManager,
|
||||
string $scope
|
||||
): BindingContainer {
|
||||
|
||||
$bindingData = new BindingData();
|
||||
$binder = new Binder($bindingData);
|
||||
|
||||
$binder
|
||||
->bindInstance(PortalAclManager::class, $aclManager)
|
||||
->bindInstance(AclManager::class, $aclManager);
|
||||
|
||||
$binder
|
||||
->for($className)
|
||||
->bindValue('$entityType', $scope);
|
||||
|
||||
return new BindingContainer($bindingData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\AccessChecker;
|
||||
|
||||
use Espo\Core\Acl\ScopeData;
|
||||
use Espo\Core\Portal\Acl\Table;
|
||||
|
||||
/**
|
||||
* Checks scope access.
|
||||
*/
|
||||
class ScopeChecker
|
||||
{
|
||||
public function __construct()
|
||||
{}
|
||||
|
||||
public function check(ScopeData $data, ?string $action = null, ?ScopeCheckerData $checkerData = null): bool
|
||||
{
|
||||
if ($data->isFalse()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($data->isTrue()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($action === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$level = $data->get($action);
|
||||
|
||||
if ($level === Table::LEVEL_ALL || $level === Table::LEVEL_YES) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($level === Table::LEVEL_NO) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$checkerData) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($level === Table::LEVEL_OWN || $level === Table::LEVEL_ACCOUNT || $level === Table::LEVEL_CONTACT) {
|
||||
if ($checkerData->isOwn()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($level === Table::LEVEL_ACCOUNT || $level === Table::LEVEL_CONTACT) {
|
||||
if ($checkerData->inContact()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($level === Table::LEVEL_ACCOUNT) {
|
||||
if ($checkerData->inAccount()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\AccessChecker;
|
||||
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* Scope checker data.
|
||||
*/
|
||||
class ScopeCheckerData
|
||||
{
|
||||
public function __construct(
|
||||
private Closure $isOwnChecker,
|
||||
private Closure $inAccountChecker,
|
||||
private Closure $inContactChecker
|
||||
) {}
|
||||
|
||||
public function isOwn(): bool
|
||||
{
|
||||
return ($this->isOwnChecker)();
|
||||
}
|
||||
|
||||
public function inAccount(): bool
|
||||
{
|
||||
return ($this->inAccountChecker)();
|
||||
}
|
||||
|
||||
public function inContact(): bool
|
||||
{
|
||||
return ($this->inContactChecker)();
|
||||
}
|
||||
|
||||
public static function createBuilder(): ScopeCheckerDataBuilder
|
||||
{
|
||||
return new ScopeCheckerDataBuilder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\AccessChecker;
|
||||
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* Builds scope checker data.
|
||||
*/
|
||||
class ScopeCheckerDataBuilder
|
||||
{
|
||||
private Closure $isOwnChecker;
|
||||
private Closure $inAccountChecker;
|
||||
private Closure $inContactChecker;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->isOwnChecker = function (): bool {
|
||||
return false;
|
||||
};
|
||||
|
||||
$this->inAccountChecker = function (): bool {
|
||||
return false;
|
||||
};
|
||||
|
||||
$this->inContactChecker = function (): bool {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
public function setIsOwn(bool $value): self
|
||||
{
|
||||
if ($value) {
|
||||
$this->isOwnChecker = function (): bool {
|
||||
return true;
|
||||
};
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->isOwnChecker = function (): bool {
|
||||
return false;
|
||||
};
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setInAccount(bool $value): self
|
||||
{
|
||||
if ($value) {
|
||||
$this->inAccountChecker = function (): bool {
|
||||
return true;
|
||||
};
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->inAccountChecker = function (): bool {
|
||||
return false;
|
||||
};
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setInContact(bool $value): self
|
||||
{
|
||||
if ($value) {
|
||||
$this->inContactChecker = function (): bool {
|
||||
return true;
|
||||
};
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->inContactChecker = function (): bool {
|
||||
return false;
|
||||
};
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Closure(): bool $checker
|
||||
*/
|
||||
public function setIsOwnChecker(Closure $checker): self
|
||||
{
|
||||
$this->isOwnChecker = $checker;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Closure(): bool $checker
|
||||
*/
|
||||
public function setInAccountChecker(Closure $checker): self
|
||||
{
|
||||
$this->inAccountChecker = $checker;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Closure(): bool $checker
|
||||
*/
|
||||
public function setInContactChecker(Closure $checker): self
|
||||
{
|
||||
$this->inContactChecker = $checker;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function build(): ScopeCheckerData
|
||||
{
|
||||
return new ScopeCheckerData($this->isOwnChecker, $this->inAccountChecker, $this->inContactChecker);
|
||||
}
|
||||
}
|
||||
157
application/Espo/Core/Portal/Acl/DefaultAccessChecker.php
Normal file
157
application/Espo/Core/Portal/Acl/DefaultAccessChecker.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl;
|
||||
|
||||
use Espo\Entities\User;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\Acl\AccessEntityCreateChecker;
|
||||
use Espo\Core\Acl\AccessEntityDeleteChecker;
|
||||
use Espo\Core\Acl\AccessEntityEditChecker;
|
||||
use Espo\Core\Acl\AccessEntityReadChecker;
|
||||
use Espo\Core\Acl\AccessEntityStreamChecker;
|
||||
use Espo\Core\Acl\ScopeData;
|
||||
use Espo\Core\Portal\Acl\AccessChecker\ScopeChecker;
|
||||
use Espo\Core\Portal\Acl\AccessChecker\ScopeCheckerData;
|
||||
use Espo\Core\Portal\AclManager as PortalAclManager;
|
||||
|
||||
/**
|
||||
* A default implementation for access checking for portal.
|
||||
*
|
||||
* @implements AccessEntityCreateChecker<Entity>
|
||||
* @implements AccessEntityReadChecker<Entity>
|
||||
* @implements AccessEntityEditChecker<Entity>
|
||||
* @implements AccessEntityDeleteChecker<Entity>
|
||||
* @implements AccessEntityStreamChecker<Entity>
|
||||
*/
|
||||
class DefaultAccessChecker implements
|
||||
|
||||
AccessEntityCreateChecker,
|
||||
AccessEntityReadChecker,
|
||||
AccessEntityEditChecker,
|
||||
AccessEntityDeleteChecker,
|
||||
AccessEntityStreamChecker
|
||||
{
|
||||
public function __construct(
|
||||
private PortalAclManager $aclManager,
|
||||
private ScopeChecker $scopeChecker
|
||||
) {}
|
||||
|
||||
private function checkEntity(User $user, Entity $entity, ScopeData $data, string $action): bool
|
||||
{
|
||||
$checkerData = ScopeCheckerData
|
||||
::createBuilder()
|
||||
->setIsOwnChecker(
|
||||
function () use ($user, $entity): bool {
|
||||
return $this->aclManager->checkOwnershipOwn($user, $entity);
|
||||
}
|
||||
)
|
||||
->setInAccountChecker(
|
||||
function () use ($user, $entity): bool {
|
||||
return $this->aclManager->checkOwnershipAccount($user, $entity);
|
||||
}
|
||||
)
|
||||
->setInContactChecker(
|
||||
function () use ($user, $entity): bool {
|
||||
return $this->aclManager->checkOwnershipContact($user, $entity);
|
||||
}
|
||||
)
|
||||
->build();
|
||||
|
||||
return $this->scopeChecker->check($data, $action, $checkerData);
|
||||
}
|
||||
|
||||
private function checkScope(User $user, ScopeData $data, ?string $action = null): bool
|
||||
{
|
||||
$checkerData = ScopeCheckerData
|
||||
::createBuilder()
|
||||
->setIsOwn(true)
|
||||
->setInAccount(true)
|
||||
->setInContact(true)
|
||||
->build();
|
||||
|
||||
return $this->scopeChecker->check($data, $action, $checkerData);
|
||||
}
|
||||
|
||||
public function check(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkScope($user, $data);
|
||||
}
|
||||
|
||||
public function checkCreate(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkScope($user, $data, Table::ACTION_CREATE);
|
||||
}
|
||||
|
||||
public function checkRead(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkScope($user, $data, Table::ACTION_READ);
|
||||
}
|
||||
|
||||
public function checkEdit(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkScope($user, $data, Table::ACTION_EDIT);
|
||||
}
|
||||
|
||||
public function checkDelete(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkScope($user, $data, Table::ACTION_DELETE);
|
||||
}
|
||||
|
||||
public function checkStream(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkScope($user, $data, Table::ACTION_STREAM);
|
||||
}
|
||||
|
||||
public function checkEntityCreate(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkEntity($user, $entity, $data, Table::ACTION_CREATE);
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkEntity($user, $entity, $data, Table::ACTION_READ);
|
||||
}
|
||||
|
||||
public function checkEntityEdit(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkEntity($user, $entity, $data, Table::ACTION_EDIT);
|
||||
}
|
||||
|
||||
public function checkEntityStream(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkEntity($user, $entity, $data, Table::ACTION_STREAM);
|
||||
}
|
||||
|
||||
public function checkEntityDelete(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->checkEntity($user, $entity, $data, Table::ACTION_DELETE);
|
||||
}
|
||||
}
|
||||
189
application/Espo/Core/Portal/Acl/DefaultOwnershipChecker.php
Normal file
189
application/Espo/Core/Portal/Acl/DefaultOwnershipChecker.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl;
|
||||
|
||||
use Espo\Core\Field\Link;
|
||||
use Espo\Core\Field\LinkParent;
|
||||
use Espo\Core\Name\Field;
|
||||
use Espo\Core\ORM\Type\FieldType;
|
||||
use Espo\Core\Portal\Acl\OwnershipChecker\MetadataProvider;
|
||||
use Espo\Modules\Crm\Entities\Account;
|
||||
use Espo\Modules\Crm\Entities\Contact;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Core\Acl\OwnershipOwnChecker;
|
||||
use Espo\ORM\Type\RelationType;
|
||||
|
||||
/**
|
||||
* A default implementation for ownership checking for portal.
|
||||
*
|
||||
* @implements OwnershipOwnChecker<\Espo\Core\ORM\Entity>
|
||||
* @implements OwnershipAccountChecker<\Espo\Core\ORM\Entity>
|
||||
* @implements OwnershipContactChecker<\Espo\Core\ORM\Entity>
|
||||
*/
|
||||
class DefaultOwnershipChecker implements
|
||||
OwnershipOwnChecker,
|
||||
OwnershipAccountChecker,
|
||||
OwnershipContactChecker
|
||||
{
|
||||
private const ATTR_CREATED_BY_ID = Field::CREATED_BY . 'Id';
|
||||
|
||||
public function __construct(
|
||||
private EntityManager $entityManager,
|
||||
private MetadataProvider $metadataProvider,
|
||||
) {}
|
||||
|
||||
public function checkOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
if ($entity->hasAttribute(self::ATTR_CREATED_BY_ID)) {
|
||||
if (
|
||||
$entity->has(self::ATTR_CREATED_BY_ID) &&
|
||||
$user->getId() === $entity->get(self::ATTR_CREATED_BY_ID)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkAccount(User $user, Entity $entity): bool
|
||||
{
|
||||
$linkDefs = $this->metadataProvider->getAccountLink($entity->getEntityType());
|
||||
|
||||
if (!$linkDefs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$link = $linkDefs->getName();
|
||||
|
||||
$accountIds = $user->getAccounts()->getIdList();
|
||||
|
||||
if ($accountIds === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$fieldDefs = $this->entityManager
|
||||
->getDefs()
|
||||
->getEntity($entity->getEntityType())
|
||||
->tryGetField($link);
|
||||
|
||||
if (
|
||||
$linkDefs->getType() === RelationType::BELONGS_TO &&
|
||||
$fieldDefs?->getType() === FieldType::LINK
|
||||
) {
|
||||
$setAccountLink = $entity->getValueObject($link);
|
||||
|
||||
if (!$setAccountLink instanceof Link) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array($setAccountLink->getId(), $accountIds);
|
||||
}
|
||||
|
||||
if (
|
||||
$linkDefs->getType() === RelationType::BELONGS_TO_PARENT &&
|
||||
$fieldDefs?->getType() === FieldType::LINK_PARENT
|
||||
) {
|
||||
$setLink = $entity->getValueObject($link);
|
||||
|
||||
if (!$setLink instanceof LinkParent || $setLink->getEntityType() !== Account::ENTITY_TYPE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array($setLink->getId(), $accountIds);
|
||||
}
|
||||
|
||||
foreach ($accountIds as $accountId) {
|
||||
$isRelated = $this->entityManager
|
||||
->getRelation($entity, $link)
|
||||
->isRelatedById($accountId);
|
||||
|
||||
if ($isRelated) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkContact(User $user, Entity $entity): bool
|
||||
{
|
||||
$linkDefs = $this->metadataProvider->getContactLink($entity->getEntityType());
|
||||
|
||||
if (!$linkDefs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$link = $linkDefs->getName();
|
||||
|
||||
$contactId = $user->getContactId();
|
||||
|
||||
if (!$contactId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$fieldDefs = $this->entityManager
|
||||
->getDefs()
|
||||
->getEntity($entity->getEntityType())
|
||||
->tryGetField($link);
|
||||
|
||||
if (
|
||||
$linkDefs->getType() === RelationType::BELONGS_TO &&
|
||||
$fieldDefs?->getType() === FieldType::LINK
|
||||
) {
|
||||
$setContactLink = $entity->getValueObject($link);
|
||||
|
||||
if (!$setContactLink instanceof Link) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $setContactLink->getId() === $contactId;
|
||||
}
|
||||
|
||||
if (
|
||||
$linkDefs->getType() === RelationType::BELONGS_TO_PARENT &&
|
||||
$fieldDefs?->getType() === FieldType::LINK_PARENT
|
||||
) {
|
||||
$setLink = $entity->getValueObject($link);
|
||||
|
||||
if (!$setLink instanceof LinkParent || $setLink->getEntityType() !== Contact::ENTITY_TYPE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $setLink->getId() === $contactId;
|
||||
}
|
||||
|
||||
return$this->entityManager
|
||||
->getRelation($entity, $link)
|
||||
->isRelatedById($contactId);
|
||||
}
|
||||
}
|
||||
45
application/Espo/Core/Portal/Acl/Map/CacheKeyProvider.php
Normal file
45
application/Espo/Core/Portal/Acl/Map/CacheKeyProvider.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\Map;
|
||||
|
||||
use Espo\Entities\Portal;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Core\Acl\Map\CacheKeyProvider as CacheKeyProviderInterface;
|
||||
|
||||
class CacheKeyProvider implements CacheKeyProviderInterface
|
||||
{
|
||||
public function __construct(private User $user, private Portal $portal)
|
||||
{}
|
||||
|
||||
public function get(): string
|
||||
{
|
||||
return 'aclPortalMap/' . $this->portal->getId() . '/' . $this->user->getId();
|
||||
}
|
||||
}
|
||||
74
application/Espo/Core/Portal/Acl/Map/MapFactory.php
Normal file
74
application/Espo/Core/Portal/Acl/Map/MapFactory.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\Map;
|
||||
|
||||
use Espo\Entities\Portal;
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\Acl\Map\CacheKeyProvider;
|
||||
use Espo\Core\Acl\Map\Map;
|
||||
use Espo\Core\Acl\Map\MetadataProvider;
|
||||
use Espo\Core\Acl\Table;
|
||||
use Espo\Core\Binding\Binder;
|
||||
use Espo\Core\Binding\BindingContainer;
|
||||
use Espo\Core\Binding\BindingData;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\Portal\Acl\Map\CacheKeyProvider as PortalCacheKeyProvider;
|
||||
use Espo\Core\Portal\Acl\Map\MetadataProvider as PortalMetadataProvider;
|
||||
use Espo\Core\Portal\Acl\Table as PortalTable;
|
||||
|
||||
class MapFactory
|
||||
{
|
||||
public function __construct(private InjectableFactory $injectableFactory)
|
||||
{}
|
||||
|
||||
public function create(User $user, PortalTable $table, Portal $portal): Map
|
||||
{
|
||||
$bindingContainer = $this->createBindingContainer($user, $table, $portal);
|
||||
|
||||
return $this->injectableFactory->createWithBinding(Map::class, $bindingContainer);
|
||||
}
|
||||
|
||||
private function createBindingContainer(User $user, PortalTable $table, Portal $portal): BindingContainer
|
||||
{
|
||||
$bindingData = new BindingData();
|
||||
|
||||
$binder = new Binder($bindingData);
|
||||
|
||||
$binder
|
||||
->bindInstance(User::class, $user)
|
||||
->bindInstance(Table::class, $table)
|
||||
->bindInstance(Portal::class, $portal)
|
||||
->bindImplementation(MetadataProvider::class, PortalMetadataProvider::class)
|
||||
->bindImplementation(CacheKeyProvider::class, PortalCacheKeyProvider::class);
|
||||
|
||||
return new BindingContainer($bindingData);
|
||||
}
|
||||
}
|
||||
37
application/Espo/Core/Portal/Acl/Map/MetadataProvider.php
Normal file
37
application/Espo/Core/Portal/Acl/Map/MetadataProvider.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\Map;
|
||||
|
||||
use Espo\Core\Acl\Map\MetadataProvider as BaseMetadataProvider;
|
||||
|
||||
class MetadataProvider extends BaseMetadataProvider
|
||||
{
|
||||
protected string $type = 'aclPortal';
|
||||
}
|
||||
48
application/Espo/Core/Portal/Acl/OwnershipAccountChecker.php
Normal file
48
application/Espo/Core/Portal/Acl/OwnershipAccountChecker.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\Acl\OwnershipChecker;
|
||||
|
||||
/**
|
||||
* @template TEntity of Entity
|
||||
*/
|
||||
interface OwnershipAccountChecker extends OwnershipChecker
|
||||
{
|
||||
/**
|
||||
* Check whether an entity belongs to a portal user account.
|
||||
*
|
||||
* @param TEntity $entity
|
||||
*/
|
||||
public function checkAccount(User $user, Entity $entity): bool;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\OwnershipChecker;
|
||||
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\ORM\Defs;
|
||||
use Espo\ORM\Defs\RelationDefs;
|
||||
|
||||
class MetadataProvider
|
||||
{
|
||||
public function __construct(
|
||||
private Metadata $metadata,
|
||||
private Defs $defs,
|
||||
) {}
|
||||
|
||||
public function getAccountLink(string $entityType): ?RelationDefs
|
||||
{
|
||||
$link = $this->metadata->get("aclDefs.$entityType.accountLink");
|
||||
|
||||
if (!$link) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->defs->getEntity($entityType)->tryGetRelation($link);
|
||||
}
|
||||
|
||||
public function getContactLink(string $entityType): ?RelationDefs
|
||||
{
|
||||
$link = $this->metadata->get("aclDefs.$entityType.contactLink");
|
||||
|
||||
if (!$link) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->defs->getEntity($entityType)->tryGetRelation($link);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\OwnershipChecker;
|
||||
|
||||
use Espo\Core\Acl\Exceptions\NotImplemented;
|
||||
use Espo\Core\Acl\OwnershipChecker;
|
||||
use Espo\Core\AclManager;
|
||||
use Espo\Core\Binding\Binder;
|
||||
use Espo\Core\Binding\BindingContainer;
|
||||
use Espo\Core\Binding\BindingData;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\Portal\Acl\DefaultOwnershipChecker;
|
||||
use Espo\Core\Portal\AclManager as PortalAclManager;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
|
||||
class OwnershipCheckerFactory
|
||||
{
|
||||
/** @var class-string<OwnershipChecker> */
|
||||
private $defaultClassName = DefaultOwnershipChecker::class;
|
||||
|
||||
public function __construct(
|
||||
private Metadata $metadata,
|
||||
private InjectableFactory $injectableFactory
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Create an ownership checker.
|
||||
*
|
||||
* @throws NotImplemented
|
||||
*/
|
||||
public function create(string $scope, PortalAclManager $aclManager): OwnershipChecker
|
||||
{
|
||||
$className = $this->getClassName($scope);
|
||||
|
||||
$bindingContainer = $this->createBindingContainer($className, $aclManager, $scope);
|
||||
|
||||
return $this->injectableFactory->createWithBinding($className, $bindingContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class-string<OwnershipChecker>
|
||||
*/
|
||||
private function getClassName(string $scope): string
|
||||
{
|
||||
$className = $this->metadata->get(['aclDefs', $scope, 'portalOwnershipCheckerClassName']);
|
||||
|
||||
if ($className) {
|
||||
/** @var class-string<OwnershipChecker> */
|
||||
return $className;
|
||||
}
|
||||
|
||||
if (!$this->metadata->get(['scopes', $scope])) {
|
||||
throw new NotImplemented();
|
||||
}
|
||||
|
||||
return $this->defaultClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param class-string<OwnershipChecker> $className
|
||||
*/
|
||||
private function createBindingContainer(
|
||||
string $className,
|
||||
PortalAclManager $aclManager,
|
||||
string $scope
|
||||
): BindingContainer {
|
||||
|
||||
$bindingData = new BindingData();
|
||||
|
||||
$binder = new Binder($bindingData);
|
||||
|
||||
$binder
|
||||
->bindInstance(PortalAclManager::class, $aclManager)
|
||||
->bindInstance(AclManager::class, $aclManager);
|
||||
|
||||
$binder
|
||||
->for($className)
|
||||
->bindValue('$entityType', $scope);
|
||||
|
||||
return new BindingContainer($bindingData);
|
||||
}
|
||||
}
|
||||
48
application/Espo/Core/Portal/Acl/OwnershipContactChecker.php
Normal file
48
application/Espo/Core/Portal/Acl/OwnershipContactChecker.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\Acl\OwnershipChecker;
|
||||
|
||||
/**
|
||||
* @template TEntity of Entity
|
||||
*/
|
||||
interface OwnershipContactChecker extends OwnershipChecker
|
||||
{
|
||||
/**
|
||||
* Check whether an entity belongs to a portal user contact.
|
||||
*
|
||||
* @param TEntity $entity
|
||||
*/
|
||||
public function checkContact(User $user, Entity $entity): bool;
|
||||
}
|
||||
102
application/Espo/Core/Portal/Acl/Table.php
Normal file
102
application/Espo/Core/Portal/Acl/Table.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl;
|
||||
|
||||
use Espo\Core\Acl\Table\DefaultTable as BaseTable;
|
||||
|
||||
use stdClass;
|
||||
|
||||
class Table extends BaseTable
|
||||
{
|
||||
public const LEVEL_ACCOUNT = 'account';
|
||||
public const LEVEL_CONTACT = 'contact';
|
||||
|
||||
protected string $type = 'aclPortal';
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $levelList = [
|
||||
self::LEVEL_YES,
|
||||
self::LEVEL_ALL,
|
||||
self::LEVEL_ACCOUNT,
|
||||
self::LEVEL_CONTACT,
|
||||
self::LEVEL_OWN,
|
||||
self::LEVEL_NO,
|
||||
];
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getScopeWithAclList(): array
|
||||
{
|
||||
$scopeList = [];
|
||||
|
||||
$scopes = $this->metadata->get('scopes');
|
||||
|
||||
foreach ($scopes as $scope => $item) {
|
||||
if (empty($item['acl'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (empty($item['aclPortal'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$scopeList[] = $scope;
|
||||
}
|
||||
|
||||
return $scopeList;
|
||||
}
|
||||
|
||||
protected function applyDefault(stdClass &$table, stdClass &$fieldTable): void
|
||||
{
|
||||
parent::applyDefault($table, $fieldTable);
|
||||
|
||||
foreach ($this->getScopeList() as $scope) {
|
||||
if (!isset($table->$scope)) {
|
||||
$table->$scope = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyDisabled(stdClass $table, stdClass $fieldTable): void
|
||||
{
|
||||
foreach ($this->getScopeList() as $scope) {
|
||||
$item = $this->metadata->get(['scopes', $scope]) ?? [];
|
||||
|
||||
if (!empty($item['disabled']) || !empty($item['portalDisabled'])) {
|
||||
$table->$scope = false;
|
||||
|
||||
unset($fieldTable->$scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
46
application/Espo/Core/Portal/Acl/Table/CacheKeyProvider.php
Normal file
46
application/Espo/Core/Portal/Acl/Table/CacheKeyProvider.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\Table;
|
||||
|
||||
use Espo\Entities\Portal;
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\Acl\Table\CacheKeyProvider as CacheKeyProviderInterface;
|
||||
|
||||
class CacheKeyProvider implements CacheKeyProviderInterface
|
||||
{
|
||||
public function __construct(private User $user, private Portal $portal)
|
||||
{}
|
||||
|
||||
public function get(): string
|
||||
{
|
||||
return 'aclPortal/' . $this->portal->getId() . '/' . $this->user->getId();
|
||||
}
|
||||
}
|
||||
83
application/Espo/Core/Portal/Acl/Table/RoleListProvider.php
Normal file
83
application/Espo/Core/Portal/Acl/Table/RoleListProvider.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\Table;
|
||||
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
use Espo\Entities\Portal;
|
||||
use Espo\Entities\PortalRole;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Core\Acl\Table\Role;
|
||||
use Espo\Core\Acl\Table\RoleEntityWrapper;
|
||||
use Espo\Core\Acl\Table\RoleListProvider as RoleListProviderInterface;
|
||||
|
||||
class RoleListProvider implements RoleListProviderInterface
|
||||
{
|
||||
public function __construct(
|
||||
private User $user,
|
||||
private Portal $portal,
|
||||
private EntityManager $entityManager
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return Role[]
|
||||
*/
|
||||
public function get(): array
|
||||
{
|
||||
$roleList = [];
|
||||
|
||||
/** @var iterable<PortalRole> $userRoleList */
|
||||
$userRoleList = $this->entityManager
|
||||
->getRDBRepository(User::ENTITY_TYPE)
|
||||
->getRelation($this->user, 'portalRoles')
|
||||
->find();
|
||||
|
||||
foreach ($userRoleList as $role) {
|
||||
$roleList[] = $role;
|
||||
}
|
||||
|
||||
/** @var iterable<PortalRole> $portalRoleList */
|
||||
$portalRoleList = $this->entityManager
|
||||
->getRDBRepository(Portal::ENTITY_TYPE)
|
||||
->getRelation($this->portal, 'portalRoles')
|
||||
->find();
|
||||
|
||||
foreach ($portalRoleList as $role) {
|
||||
$roleList[] = $role;
|
||||
}
|
||||
|
||||
return array_map(
|
||||
function (PortalRole $role): RoleEntityWrapper {
|
||||
return new RoleEntityWrapper($role);
|
||||
},
|
||||
$roleList
|
||||
);
|
||||
}
|
||||
}
|
||||
74
application/Espo/Core/Portal/Acl/Table/TableFactory.php
Normal file
74
application/Espo/Core/Portal/Acl/Table/TableFactory.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\Table;
|
||||
|
||||
use Espo\Entities\Portal;
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\Acl\Table\CacheKeyProvider;
|
||||
use Espo\Core\Acl\Table\RoleListProvider;
|
||||
use Espo\Core\Binding\Binder;
|
||||
use Espo\Core\Binding\BindingContainer;
|
||||
use Espo\Core\Binding\BindingData;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\Portal\Acl\Table;
|
||||
use Espo\Core\Portal\Acl\Table\CacheKeyProvider as PortalCacheKeyProvider;
|
||||
use Espo\Core\Portal\Acl\Table\RoleListProvider as PortalRoleListProvider;
|
||||
|
||||
class TableFactory
|
||||
{
|
||||
public function __construct(private InjectableFactory $injectableFactory)
|
||||
{}
|
||||
|
||||
/**
|
||||
* Create a table.
|
||||
*/
|
||||
public function create(User $user, Portal $portal): Table
|
||||
{
|
||||
$bindingContainer = $this->createBindingContainer($user, $portal);
|
||||
|
||||
return $this->injectableFactory->createWithBinding(Table::class, $bindingContainer);
|
||||
}
|
||||
|
||||
private function createBindingContainer(User $user, Portal $portal): BindingContainer
|
||||
{
|
||||
$bindingData = new BindingData();
|
||||
|
||||
$binder = new Binder($bindingData);
|
||||
|
||||
$binder
|
||||
->bindInstance(User::class, $user)
|
||||
->bindInstance(Portal::class, $portal)
|
||||
->bindImplementation(RoleListProvider::class, PortalRoleListProvider::class)
|
||||
->bindImplementation(CacheKeyProvider::class, PortalCacheKeyProvider::class);
|
||||
|
||||
return new BindingContainer($bindingData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Acl\Traits;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Entities\User;
|
||||
use Espo\Core\Acl\ScopeData;
|
||||
use Espo\Core\Portal\Acl\DefaultAccessChecker;
|
||||
|
||||
trait DefaultAccessCheckerDependency
|
||||
{
|
||||
private DefaultAccessChecker $defaultAccessChecker;
|
||||
|
||||
public function check(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->defaultAccessChecker->check($user, $data);
|
||||
}
|
||||
|
||||
public function checkCreate(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->defaultAccessChecker->checkCreate($user, $data);
|
||||
}
|
||||
|
||||
public function checkRead(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->defaultAccessChecker->checkRead($user, $data);
|
||||
}
|
||||
|
||||
public function checkEdit(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->defaultAccessChecker->checkEdit($user, $data);
|
||||
}
|
||||
|
||||
public function checkDelete(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->defaultAccessChecker->checkDelete($user, $data);
|
||||
}
|
||||
|
||||
public function checkStream(User $user, ScopeData $data): bool
|
||||
{
|
||||
return $this->defaultAccessChecker->checkStream($user, $data);
|
||||
}
|
||||
|
||||
public function checkEntityCreate(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->defaultAccessChecker->checkEntityCreate($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->defaultAccessChecker->checkEntityRead($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityEdit(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->defaultAccessChecker->checkEntityEdit($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityDelete(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->defaultAccessChecker->checkEntityDelete($user, $entity, $data);
|
||||
}
|
||||
|
||||
public function checkEntityStream(User $user, Entity $entity, ScopeData $data): bool
|
||||
{
|
||||
return $this->defaultAccessChecker->checkEntityStream($user, $entity, $data);
|
||||
}
|
||||
}
|
||||
341
application/Espo/Core/Portal/AclManager.php
Normal file
341
application/Espo/Core/Portal/AclManager.php
Normal file
@@ -0,0 +1,341 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal;
|
||||
|
||||
use Espo\Core\Acl\Permission;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\ORM\EntityManager;
|
||||
|
||||
use Espo\Entities\Portal;
|
||||
use Espo\Entities\User;
|
||||
|
||||
use Espo\Core\Acl\GlobalRestriction;
|
||||
use Espo\Core\Acl\Map\Map;
|
||||
use Espo\Core\Acl\OwnerUserFieldProvider;
|
||||
use Espo\Core\Acl\Table;
|
||||
use Espo\Core\AclManager as InternalAclManager;
|
||||
use Espo\Core\Portal\Acl\AccessChecker\AccessCheckerFactory as PortalAccessCheckerFactory;
|
||||
use Espo\Core\Portal\Acl\Map\MapFactory as PortalMapFactory;
|
||||
use Espo\Core\Portal\Acl\OwnershipAccountChecker;
|
||||
use Espo\Core\Portal\Acl\OwnershipChecker\OwnershipCheckerFactory as PortalOwnershipCheckerFactory;
|
||||
use Espo\Core\Portal\Acl\OwnershipContactChecker;
|
||||
use Espo\Core\Portal\Acl\Table as PortalTable;
|
||||
use Espo\Core\Portal\Acl\Table\TableFactory as PortalTableFactory;
|
||||
|
||||
use stdClass;
|
||||
use RuntimeException;
|
||||
|
||||
class AclManager extends InternalAclManager
|
||||
{
|
||||
/** @var class-string */
|
||||
protected $userAclClassName = Acl::class;
|
||||
|
||||
private InternalAclManager $internalAclManager;
|
||||
private ?Portal $portal = null;
|
||||
private PortalTableFactory $portalTableFactory;
|
||||
private PortalMapFactory $portalMapFactory;
|
||||
|
||||
public function __construct(
|
||||
PortalAccessCheckerFactory $accessCheckerFactory,
|
||||
PortalOwnershipCheckerFactory $ownershipCheckerFactory,
|
||||
PortalTableFactory $portalTableFactory,
|
||||
PortalMapFactory $portalMapFactory,
|
||||
GlobalRestriction $globalRestriction,
|
||||
OwnerUserFieldProvider $ownerUserFieldProvider,
|
||||
EntityManager $entityManager,
|
||||
InternalAclManager $internalAclManager
|
||||
) {
|
||||
$this->accessCheckerFactory = $accessCheckerFactory;
|
||||
$this->ownershipCheckerFactory = $ownershipCheckerFactory;
|
||||
$this->portalTableFactory = $portalTableFactory;
|
||||
$this->portalMapFactory = $portalMapFactory;
|
||||
$this->globalRestriction = $globalRestriction;
|
||||
$this->ownerUserFieldProvider = $ownerUserFieldProvider;
|
||||
$this->entityManager = $entityManager;
|
||||
$this->internalAclManager = $internalAclManager;
|
||||
}
|
||||
|
||||
public function setPortal(Portal $portal): void
|
||||
{
|
||||
$this->portal = $portal;
|
||||
}
|
||||
|
||||
protected function getPortal(): Portal
|
||||
{
|
||||
if (!$this->portal) {
|
||||
throw new RuntimeException("Portal is not set.");
|
||||
}
|
||||
|
||||
return $this->portal;
|
||||
}
|
||||
|
||||
protected function getTable(User $user): Table
|
||||
{
|
||||
$key = $user->hasId() ? $user->getId() : spl_object_hash($user);
|
||||
|
||||
if (!array_key_exists($key, $this->tableHashMap)) {
|
||||
$this->tableHashMap[$key] = $this->portalTableFactory->create($user, $this->getPortal());
|
||||
}
|
||||
|
||||
return $this->tableHashMap[$key];
|
||||
}
|
||||
|
||||
protected function getMap(User $user): Map
|
||||
{
|
||||
$key = $user->hasId() ? $user->getId() : spl_object_hash($user);
|
||||
|
||||
if (!array_key_exists($key, $this->mapHashMap)) {
|
||||
/** @var PortalTable $table */
|
||||
$table = $this->getTable($user);
|
||||
|
||||
$this->mapHashMap[$key] = $this->portalMapFactory->create($user, $table, $this->getPortal());
|
||||
}
|
||||
|
||||
return $this->mapHashMap[$key];
|
||||
}
|
||||
|
||||
public function getMapData(User $user): stdClass
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->getMapData($user);
|
||||
}
|
||||
|
||||
return parent::getMapData($user);
|
||||
}
|
||||
|
||||
public function getLevel(User $user, string $scope, string $action): string
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->getLevel($user, $scope, $action);
|
||||
}
|
||||
|
||||
return parent::getLevel($user, $scope, $action);
|
||||
}
|
||||
|
||||
public function getPermissionLevel(User $user, string $permission): string
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->getPermissionLevel($user, $permission);
|
||||
}
|
||||
|
||||
return parent::getPermissionLevel($user, $permission);
|
||||
}
|
||||
|
||||
public function checkReadOnlyTeam(User $user, string $scope): bool
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->checkReadOnlyTeam($user, $scope);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkReadNo(User $user, string $scope): bool
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->checkReadNo($user, $scope);
|
||||
}
|
||||
|
||||
return parent::checkReadNo($user, $scope);
|
||||
}
|
||||
|
||||
public function checkReadOnlyOwn(User $user, string $scope): bool
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->checkReadOnlyOwn($user, $scope);
|
||||
}
|
||||
|
||||
return parent::checkReadOnlyOwn($user, $scope);
|
||||
}
|
||||
|
||||
public function checkReadAll(User $user, string $scope): bool
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->checkReadAll($user, $scope);
|
||||
}
|
||||
|
||||
return parent::checkReadAll($user, $scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether 'read' access is set to 'account' for a specific scope.
|
||||
*/
|
||||
public function checkReadOnlyAccount(User $user, string $scope): bool
|
||||
{
|
||||
return $this->getLevel($user, $scope, Table::ACTION_READ) === PortalTable::LEVEL_ACCOUNT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether 'read' access is set to 'contact' for a specific scope.
|
||||
*/
|
||||
public function checkReadOnlyContact(User $user, string $scope): bool
|
||||
{
|
||||
return $this->getLevel($user, $scope, Table::ACTION_READ)=== PortalTable::LEVEL_CONTACT;
|
||||
}
|
||||
|
||||
public function check(User $user, $subject, ?string $action = null): bool
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->check($user, $subject, $action);
|
||||
}
|
||||
|
||||
return parent::check($user, $subject, $action);
|
||||
}
|
||||
|
||||
public function checkEntity(User $user, Entity $entity, string $action = Table::ACTION_READ): bool
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->checkEntity($user, $entity, $action);
|
||||
}
|
||||
|
||||
return parent::checkEntity($user, $entity, $action);
|
||||
}
|
||||
|
||||
public function checkUserPermission(User $user, $target, string $permissionType = Permission::USER): bool
|
||||
{
|
||||
return $this->internalAclManager->checkUserPermission($user, $target, $permissionType);
|
||||
}
|
||||
|
||||
public function checkOwnershipOwn(User $user, Entity $entity): bool
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->checkOwnershipOwn($user, $entity);
|
||||
}
|
||||
|
||||
return parent::checkOwnershipOwn($user, $entity);
|
||||
}
|
||||
|
||||
public function checkOwnershipShared(User $user, Entity $entity, string $action): bool
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->checkOwnershipShared($user, $entity, $action);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkOwnershipTeam(User $user, Entity $entity): bool
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->checkOwnershipTeam($user, $entity);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an entity belongs to a user account.
|
||||
*/
|
||||
public function checkOwnershipAccount(User $user, Entity $entity): bool
|
||||
{
|
||||
$checker = $this->getOwnershipChecker($entity->getEntityType());
|
||||
|
||||
if (!$checker instanceof OwnershipAccountChecker) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $checker->checkAccount($user, $entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether an entity belongs to a user account.
|
||||
*/
|
||||
public function checkOwnershipContact(User $user, Entity $entity): bool
|
||||
{
|
||||
$checker = $this->getOwnershipChecker($entity->getEntityType());
|
||||
|
||||
if (!$checker instanceof OwnershipContactChecker) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $checker->checkContact($user, $entity);
|
||||
}
|
||||
|
||||
public function checkScope(User $user, string $scope, ?string $action = null): bool
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->checkScope($user, $scope, $action);
|
||||
}
|
||||
|
||||
return parent::checkScope($user, $scope, $action);
|
||||
}
|
||||
|
||||
public function checkUser(User $user, string $permission, User $entity): bool
|
||||
{
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager->checkUser($user, $permission, $entity);
|
||||
}
|
||||
|
||||
return parent::checkUser($user, $permission, $entity);
|
||||
}
|
||||
|
||||
public function getScopeForbiddenAttributeList(
|
||||
User $user,
|
||||
string $scope,
|
||||
string $action = PortalTable::ACTION_READ,
|
||||
string $thresholdLevel = PortalTable::LEVEL_NO
|
||||
): array {
|
||||
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager
|
||||
->getScopeForbiddenAttributeList($user, $scope, $action, $thresholdLevel);
|
||||
}
|
||||
|
||||
return parent::getScopeForbiddenAttributeList($user, $scope, $action, $thresholdLevel);
|
||||
}
|
||||
|
||||
public function getScopeForbiddenFieldList(
|
||||
User $user,
|
||||
string $scope,
|
||||
string $action = Table::ACTION_READ,
|
||||
string $thresholdLevel = Table::LEVEL_NO
|
||||
): array {
|
||||
|
||||
if ($this->checkUserIsNotPortal($user)) {
|
||||
return $this->internalAclManager
|
||||
->getScopeForbiddenFieldList($user, $scope, $action, $thresholdLevel);
|
||||
}
|
||||
|
||||
return parent::getScopeForbiddenFieldList($user, $scope, $action, $thresholdLevel);
|
||||
}
|
||||
|
||||
protected function checkUserIsNotPortal(User $user): bool
|
||||
{
|
||||
return !$user->isPortal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated As of v6.0. Use `getPermissionLevel` instead.
|
||||
*/
|
||||
public function get(User $user, string $permission): string
|
||||
{
|
||||
return $this->getPermissionLevel($user, $permission);
|
||||
}
|
||||
}
|
||||
68
application/Espo/Core/Portal/AclManagerContainer.php
Normal file
68
application/Espo/Core/Portal/AclManagerContainer.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal;
|
||||
|
||||
use Espo\Entities\Portal;
|
||||
use Espo\Core\InjectableFactory;
|
||||
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* Used when logged to CRM (not to portal) to provide an access checking ability for a specific portal.
|
||||
* E.g. check whether a portal user has access to some record within a specific portal.
|
||||
*/
|
||||
class AclManagerContainer
|
||||
{
|
||||
/**
|
||||
* @var array<string, AclManager>
|
||||
*/
|
||||
private $data = [];
|
||||
|
||||
public function __construct(private InjectableFactory $injectableFactory)
|
||||
{}
|
||||
|
||||
public function get(Portal $portal): AclManager
|
||||
{
|
||||
if (!$portal->hasId()) {
|
||||
throw new LogicException("AclManagerContainer: portal should have ID.");
|
||||
}
|
||||
|
||||
$id = $portal->getId();
|
||||
|
||||
if (!isset($this->data[$id])) {
|
||||
$aclManager = $this->injectableFactory->create(AclManager::class);
|
||||
$aclManager->setPortal($portal);
|
||||
|
||||
$this->data[$id] = $aclManager;
|
||||
}
|
||||
|
||||
return $this->data[$id];
|
||||
}
|
||||
}
|
||||
64
application/Espo/Core/Portal/Api/Starter.php
Normal file
64
application/Espo/Core/Portal/Api/Starter.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Api;
|
||||
|
||||
use Espo\Core\Api\MiddlewareProvider;
|
||||
use Espo\Core\Api\Starter as StarterBase;
|
||||
use Espo\Core\ApplicationState;
|
||||
use Espo\Core\Portal\Utils\Route as RouteUtil;
|
||||
use Espo\Core\Api\RouteProcessor;
|
||||
use Espo\Core\Api\Route\RouteParamsFetcher;
|
||||
use Espo\Core\Utils\Config\SystemConfig;
|
||||
use Espo\Core\Utils\Log;
|
||||
|
||||
class Starter extends StarterBase
|
||||
{
|
||||
public function __construct(
|
||||
RouteProcessor $requestProcessor,
|
||||
RouteUtil $routeUtil,
|
||||
RouteParamsFetcher $routeParamsFetcher,
|
||||
MiddlewareProvider $middlewareProvider,
|
||||
Log $log,
|
||||
SystemConfig $systemConfig,
|
||||
ApplicationState $applicationState
|
||||
) {
|
||||
$routeCacheFile = 'data/cache/application/slim-routes-portal-' . $applicationState->getPortalId() . '.php';
|
||||
|
||||
parent::__construct(
|
||||
$requestProcessor,
|
||||
$routeUtil,
|
||||
$routeParamsFetcher,
|
||||
$middlewareProvider,
|
||||
$log,
|
||||
$systemConfig,
|
||||
$routeCacheFile
|
||||
);
|
||||
}
|
||||
}
|
||||
127
application/Espo/Core/Portal/Application.php
Normal file
127
application/Espo/Core/Portal/Application.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal;
|
||||
|
||||
use Espo\Core\Application\ApplicationParams;
|
||||
use Espo\Entities\Portal;
|
||||
use Espo\ORM\EntityManager;
|
||||
use Espo\Core\Exceptions\Forbidden;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Application as BaseApplication;
|
||||
use Espo\Core\Container\ContainerBuilder;
|
||||
use Espo\Core\Portal\Container as PortalContainer;
|
||||
use Espo\Core\Portal\Container\ContainerConfiguration as PortalContainerConfiguration;
|
||||
use Espo\Core\Portal\Utils\Config;
|
||||
use LogicException;
|
||||
|
||||
class Application extends BaseApplication
|
||||
{
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
* @noinspection PhpMissingParentConstructorInspection
|
||||
*/
|
||||
public function __construct(
|
||||
?string $portalId,
|
||||
?ApplicationParams $params = null,
|
||||
) {
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
$this->initContainer($params);
|
||||
$this->initPortal($portalId);
|
||||
$this->initAutoloads();
|
||||
$this->initPreloads();
|
||||
}
|
||||
|
||||
protected function initContainer(?ApplicationParams $params): void
|
||||
{
|
||||
$container = (new ContainerBuilder())
|
||||
->withConfigClassName(Config::class)
|
||||
->withContainerClassName(PortalContainer::class)
|
||||
->withContainerConfigurationClassName(PortalContainerConfiguration::class)
|
||||
->withParams($params)
|
||||
->build();
|
||||
|
||||
if (!$container instanceof PortalContainer) {
|
||||
throw new LogicException("Wrong container created.");
|
||||
}
|
||||
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Forbidden
|
||||
* @throws NotFound
|
||||
*/
|
||||
protected function initPortal(?string $portalId): void
|
||||
{
|
||||
if (!$portalId) {
|
||||
throw new LogicException("Portal ID was not passed to Portal\Application.");
|
||||
}
|
||||
|
||||
$entityManager = $this->container->getByClass(EntityManager::class);
|
||||
|
||||
$portal = $entityManager->getEntityById(Portal::ENTITY_TYPE, $portalId);
|
||||
|
||||
if (!$portal) {
|
||||
$portal = $entityManager
|
||||
->getRDBRepositoryByClass(Portal::class)
|
||||
->where(['customId' => $portalId])
|
||||
->findOne();
|
||||
}
|
||||
|
||||
if (!$portal) {
|
||||
throw new NotFound("Portal $portalId not found.");
|
||||
}
|
||||
|
||||
if (!$portal->isActive()) {
|
||||
throw new Forbidden("Portal $portalId is not active.");
|
||||
}
|
||||
|
||||
$container = $this->container;
|
||||
|
||||
if (!$container instanceof PortalContainer) {
|
||||
throw new LogicException();
|
||||
}
|
||||
|
||||
$container->setPortal($portal);
|
||||
}
|
||||
|
||||
protected function initPreloads(): void
|
||||
{
|
||||
parent::initPreloads();
|
||||
|
||||
foreach ($this->getMetadata()->get(['app', 'portalContainerServices']) ?? [] as $name => $defs) {
|
||||
if ($defs['preload'] ?? false) {
|
||||
$this->container->get($name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
application/Espo/Core/Portal/ApplicationRunners/Api.php
Normal file
44
application/Espo/Core/Portal/ApplicationRunners/Api.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\ApplicationRunners;
|
||||
|
||||
use Espo\Core\Application\Runner;
|
||||
use Espo\Core\Portal\Api\Starter;
|
||||
|
||||
class Api implements Runner
|
||||
{
|
||||
public function __construct(private Starter $starter)
|
||||
{}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$this->starter->start();
|
||||
}
|
||||
}
|
||||
57
application/Espo/Core/Portal/ApplicationRunners/Client.php
Normal file
57
application/Espo/Core/Portal/ApplicationRunners/Client.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\ApplicationRunners;
|
||||
|
||||
use Espo\Core\Application\Runner;
|
||||
use Espo\Core\ApplicationState;
|
||||
use Espo\Core\Utils\ClientManager;
|
||||
|
||||
/**
|
||||
* Displays the main HTML page for a portal.
|
||||
*/
|
||||
class Client implements Runner
|
||||
{
|
||||
public function __construct(
|
||||
private ClientManager $clientManager,
|
||||
private ApplicationState $applicationState
|
||||
) {}
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$portalId = $this->applicationState->getPortal()->getId();
|
||||
|
||||
$this->clientManager->display(null, null, [
|
||||
'portalId' => $portalId,
|
||||
'applicationId' => $portalId,
|
||||
'apiUrl' => 'api/v1/portal-access/' . $portalId,
|
||||
'appClientClassName' => 'app-portal',
|
||||
]);
|
||||
}
|
||||
}
|
||||
81
application/Espo/Core/Portal/Container.php
Normal file
81
application/Espo/Core/Portal/Container.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal;
|
||||
|
||||
use Espo\Core\Container\Exceptions\NotSettableException;
|
||||
use Espo\Entities\Portal as PortalEntity;
|
||||
use Espo\Core\Portal\Utils\Config;
|
||||
use Espo\Core\Container as BaseContainer;
|
||||
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
use LogicException;
|
||||
|
||||
class Container extends BaseContainer
|
||||
{
|
||||
private const ID_PORTAL = 'portal';
|
||||
private const ID_CONFIG = 'config';
|
||||
private const ID_ACL_MANAGER = 'aclManager';
|
||||
|
||||
private bool $portalIsSet = false;
|
||||
|
||||
/**
|
||||
* @throws NotSettableException
|
||||
*/
|
||||
public function setPortal(PortalEntity $portal): void
|
||||
{
|
||||
if ($this->portalIsSet) {
|
||||
throw new NotSettableException("Can't set portal second time.");
|
||||
}
|
||||
|
||||
$this->portalIsSet = true;
|
||||
|
||||
$this->setForced(self::ID_PORTAL, $portal);
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($portal->getSettingsAttributeList() as $attribute) {
|
||||
$data[$attribute] = $portal->get($attribute);
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var Config $config */
|
||||
$config = $this->get(self::ID_CONFIG);
|
||||
$config->setPortalParameters($data);
|
||||
|
||||
/** @var AclManager $aclManager */
|
||||
$aclManager = $this->get(self::ID_ACL_MANAGER);
|
||||
} catch (NotFoundExceptionInterface) {
|
||||
throw new LogicException();
|
||||
}
|
||||
|
||||
$aclManager->setPortal($portal);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Container;
|
||||
|
||||
use Espo\Core\Container\ContainerConfiguration as BaseContainerConfiguration;
|
||||
|
||||
class ContainerConfiguration extends BaseContainerConfiguration
|
||||
{
|
||||
/**
|
||||
* @return ?class-string
|
||||
*/
|
||||
public function getLoaderClassName(string $name): ?string
|
||||
{
|
||||
$className = null;
|
||||
|
||||
try {
|
||||
$className = $this->metadata->get(['app', 'portalContainerServices', $name, 'loaderClassName']);
|
||||
} catch (\Exception) {}
|
||||
|
||||
if ($className && class_exists($className)) {
|
||||
return $className;
|
||||
}
|
||||
|
||||
$className = 'Espo\Custom\Core\Portal\Loaders\\' . ucfirst($name);
|
||||
if (!class_exists($className)) {
|
||||
$className = 'Espo\Core\Portal\Loaders\\' . ucfirst($name);
|
||||
}
|
||||
|
||||
if (class_exists($className)) {
|
||||
return $className;
|
||||
}
|
||||
|
||||
return parent::getLoaderClassName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ?class-string
|
||||
*/
|
||||
public function getServiceClassName(string $name): ?string
|
||||
{
|
||||
return $this->metadata->get(['app', 'portalContainerServices', $name, 'className']) ??
|
||||
parent::getServiceClassName($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ?string[]
|
||||
*/
|
||||
public function getServiceDependencyList(string $name): ?array
|
||||
{
|
||||
return
|
||||
$this->metadata->get(['app', 'portalContainerServices', $name, 'dependencyList']) ??
|
||||
parent::getServiceDependencyList($name);
|
||||
}
|
||||
|
||||
public function isSettable(string $name): bool
|
||||
{
|
||||
return
|
||||
$this->metadata->get(['app', 'portalContainerServices', $name, 'settable']) ??
|
||||
parent::isSettable($name);
|
||||
}
|
||||
}
|
||||
59
application/Espo/Core/Portal/Loaders/Acl.php
Normal file
59
application/Espo/Core/Portal/Loaders/Acl.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Loaders;
|
||||
|
||||
use Espo\Core\Portal\AclManager as PortalAclManager;
|
||||
use Espo\Core\AclManager;
|
||||
use Espo\Core\Container\Loader;
|
||||
use Espo\Core\Portal\Acl as AclService;
|
||||
use Espo\Entities\User;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Acl implements Loader
|
||||
{
|
||||
private PortalAclManager $aclManager;
|
||||
private User $user;
|
||||
|
||||
public function __construct(AclManager $aclManager, User $user)
|
||||
{
|
||||
if (!$aclManager instanceof PortalAclManager) {
|
||||
throw new InvalidArgumentException();
|
||||
}
|
||||
|
||||
$this->aclManager = $aclManager;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function load(): AclService
|
||||
{
|
||||
return new AclService($this->aclManager, $this->user);
|
||||
}
|
||||
}
|
||||
50
application/Espo/Core/Portal/Loaders/AclManager.php
Normal file
50
application/Espo/Core/Portal/Loaders/AclManager.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Loaders;
|
||||
|
||||
use Espo\Core\AclManager as InternalAclManager;
|
||||
use Espo\Core\Container\Loader;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\Portal\AclManager as PortalAclManager;
|
||||
|
||||
class AclManager implements Loader
|
||||
{
|
||||
public function __construct(
|
||||
private InjectableFactory $injectableFactory,
|
||||
private InternalAclManager $internalAclManager
|
||||
) {}
|
||||
|
||||
public function load(): PortalAclManager
|
||||
{
|
||||
return $this->injectableFactory->createWith(PortalAclManager::class,[
|
||||
'internalAclManager' => $this->internalAclManager,
|
||||
]);
|
||||
}
|
||||
}
|
||||
45
application/Espo/Core/Portal/Loaders/InternalAclManager.php
Normal file
45
application/Espo/Core/Portal/Loaders/InternalAclManager.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Loaders;
|
||||
|
||||
use Espo\Core\AclManager as InternalAclManagerService;
|
||||
use Espo\Core\Container\Loader;
|
||||
use Espo\Core\InjectableFactory;
|
||||
|
||||
class InternalAclManager implements Loader
|
||||
{
|
||||
public function __construct(private InjectableFactory $injectableFactory)
|
||||
{}
|
||||
|
||||
public function load(): InternalAclManagerService
|
||||
{
|
||||
return $this->injectableFactory->create(InternalAclManagerService::class);
|
||||
}
|
||||
}
|
||||
54
application/Espo/Core/Portal/Loaders/Language.php
Normal file
54
application/Espo/Core/Portal/Loaders/Language.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Loaders;
|
||||
|
||||
use Espo\Core\Container\Loader;
|
||||
use Espo\Core\InjectableFactory;
|
||||
use Espo\Core\Portal\Utils\Language as LanguageService;
|
||||
use Espo\Core\Utils\Config;
|
||||
|
||||
use Espo\Entities\Preferences;
|
||||
|
||||
class Language implements Loader
|
||||
{
|
||||
public function __construct(
|
||||
private InjectableFactory $injectableFactory,
|
||||
private Config $config,
|
||||
private Preferences $preferences
|
||||
) {}
|
||||
|
||||
public function load(): LanguageService
|
||||
{
|
||||
return $this->injectableFactory->createWith(LanguageService::class, [
|
||||
'language' => LanguageService::detectLanguage($this->config, $this->preferences),
|
||||
'useCache' => $this->config->get('useCache') ?? false,
|
||||
]);
|
||||
}
|
||||
}
|
||||
160
application/Espo/Core/Portal/Utils/Config.php
Normal file
160
application/Espo/Core/Portal/Utils/Config.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Utils;
|
||||
|
||||
use Espo\Core\Utils\Config as BaseConfig;
|
||||
|
||||
use RuntimeException;
|
||||
use stdClass;
|
||||
|
||||
class Config extends BaseConfig
|
||||
{
|
||||
private bool $portalParamsSet = false;
|
||||
|
||||
/**
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
private $portalData = [];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private $portalParamList = [
|
||||
'applicationName',
|
||||
'companyLogoId',
|
||||
'tabList',
|
||||
'quickCreateList',
|
||||
'dashboardLayout',
|
||||
'dashletsOptions',
|
||||
'theme',
|
||||
'themeParams',
|
||||
'language',
|
||||
'timeZone',
|
||||
'dateFormat',
|
||||
'timeFormat',
|
||||
'weekStart',
|
||||
'defaultCurrency',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param mixed $default
|
||||
* @return mixed
|
||||
*/
|
||||
public function get(string $name, $default = null)
|
||||
{
|
||||
if (array_key_exists($name, $this->portalData)) {
|
||||
return $this->portalData[$name];
|
||||
}
|
||||
|
||||
return parent::get($name, $default);
|
||||
}
|
||||
|
||||
public function has(string $name): bool
|
||||
{
|
||||
if (array_key_exists($name, $this->portalData)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::has($name);
|
||||
}
|
||||
|
||||
public function getAllNonInternalData(): stdClass
|
||||
{
|
||||
$data = parent::getAllNonInternalData();
|
||||
|
||||
foreach ($this->portalData as $k => $v) {
|
||||
$data->$k = $v;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override parameters for a portal. Can be called only once.
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
public function setPortalParameters(array $data = []): void
|
||||
{
|
||||
if ($this->portalParamsSet) {
|
||||
throw new RuntimeException("Can't set portal params second time.");
|
||||
}
|
||||
|
||||
$this->portalParamsSet = true;
|
||||
|
||||
if (empty($data['applicationName'])) {
|
||||
unset($data['applicationName']);
|
||||
}
|
||||
|
||||
if (empty($data['language'])) {
|
||||
unset($data['language']);
|
||||
}
|
||||
|
||||
if (empty($data['theme'])) {
|
||||
unset($data['theme']);
|
||||
}
|
||||
|
||||
if (empty($data['timeZone'])) {
|
||||
unset($data['timeZone']);
|
||||
}
|
||||
|
||||
if (empty($data['dateFormat'])) {
|
||||
unset($data['dateFormat']);
|
||||
}
|
||||
|
||||
if (empty($data['timeFormat'])) {
|
||||
unset($data['timeFormat']);
|
||||
}
|
||||
|
||||
if (empty($data['defaultCurrency'])) {
|
||||
unset($data['defaultCurrency']);
|
||||
}
|
||||
|
||||
if (isset($data['weekStart']) && $data['weekStart'] === -1) {
|
||||
unset($data['weekStart']);
|
||||
}
|
||||
|
||||
if (array_key_exists('weekStart', $data) && is_null($data['weekStart'])) {
|
||||
unset($data['weekStart']);
|
||||
}
|
||||
|
||||
if ($this->get('webSocketInPortalDisabled')) {
|
||||
$this->portalData['useWebSocket'] = false;
|
||||
}
|
||||
|
||||
foreach ($data as $attribute => $value) {
|
||||
if (!in_array($attribute, $this->portalParamList)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->portalData[$attribute] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
application/Espo/Core/Portal/Utils/Language.php
Normal file
32
application/Espo/Core/Portal/Utils/Language.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Utils;
|
||||
|
||||
class Language extends \Espo\Core\Utils\Language {}
|
||||
66
application/Espo/Core/Portal/Utils/Route.php
Normal file
66
application/Espo/Core/Portal/Utils/Route.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Utils;
|
||||
|
||||
use Espo\Core\Api\Route as RouteItem;
|
||||
use Espo\Core\Utils\Route as BaseRoute;
|
||||
|
||||
class Route extends BaseRoute
|
||||
{
|
||||
public function getFullList(): array
|
||||
{
|
||||
$originalRouteList = parent::getFullList();
|
||||
|
||||
$newRouteList = [];
|
||||
|
||||
foreach ($originalRouteList as $route) {
|
||||
$path = $route->getAdjustedRoute();
|
||||
|
||||
if ($path[0] !== '/') {
|
||||
$path = '/' . $path;
|
||||
}
|
||||
|
||||
$path = '/{portalId}' . $path;
|
||||
|
||||
$newRoute = new RouteItem(
|
||||
$route->getMethod(),
|
||||
$route->getRoute(),
|
||||
$path,
|
||||
$route->getParams(),
|
||||
$route->noAuth(),
|
||||
$route->getActionClassName()
|
||||
);
|
||||
|
||||
$newRouteList[] = $newRoute;
|
||||
}
|
||||
|
||||
return $newRouteList;
|
||||
}
|
||||
}
|
||||
63
application/Espo/Core/Portal/Utils/ThemeManager.php
Normal file
63
application/Espo/Core/Portal/Utils/ThemeManager.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Utils;
|
||||
|
||||
use Espo\Core\Utils\Config;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
use Espo\Core\Utils\Theme\MetadataProvider;
|
||||
use Espo\Entities\Portal;
|
||||
use Espo\Core\Utils\ThemeManager as BaseThemeManager;
|
||||
|
||||
class ThemeManager extends BaseThemeManager
|
||||
{
|
||||
private Portal $portal;
|
||||
|
||||
public function __construct(
|
||||
Config $config,
|
||||
Metadata $metadata,
|
||||
MetadataProvider $metadataProvider,
|
||||
Portal $portal,
|
||||
) {
|
||||
parent::__construct($config, $metadata, $metadataProvider);
|
||||
|
||||
$this->portal = $portal;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
$theme = $this->portal->get('theme');
|
||||
|
||||
if ($theme) {
|
||||
return $theme;
|
||||
}
|
||||
|
||||
return parent::getName();
|
||||
}
|
||||
}
|
||||
160
application/Espo/Core/Portal/Utils/Url.php
Normal file
160
application/Espo/Core/Portal/Utils/Url.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2025 EspoCRM, Inc.
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* The interactive user interfaces in modified source and object code versions
|
||||
* of this program must display Appropriate Legal Notices, as required under
|
||||
* Section 5 of the GNU Affero General Public License version 3.
|
||||
*
|
||||
* 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 "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Core\Portal\Utils;
|
||||
|
||||
class Url
|
||||
{
|
||||
public static function detectPortalIdForApi(): ?string
|
||||
{
|
||||
$portalId = filter_input(INPUT_GET, 'portalId');
|
||||
|
||||
if ($portalId) {
|
||||
return $portalId;
|
||||
}
|
||||
|
||||
$url = $_SERVER['REQUEST_URI'] ?? null;
|
||||
$scriptName = $_SERVER['SCRIPT_NAME'];
|
||||
|
||||
if (!$url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$scriptNameModified = str_replace('public/api/', 'api/', $scriptName);
|
||||
|
||||
return explode('/', $url)[count(explode('/', $scriptNameModified)) - 1] ?? null;
|
||||
}
|
||||
|
||||
public static function getPortalIdFromEnv(): ?string
|
||||
{
|
||||
return $_SERVER['ESPO_PORTAL_ID'] ?? null;
|
||||
}
|
||||
|
||||
public static function detectPortalId(): ?string
|
||||
{
|
||||
$portalId = self::getPortalIdFromEnv();
|
||||
|
||||
if ($portalId) {
|
||||
return $portalId;
|
||||
}
|
||||
|
||||
$url = $_SERVER['REQUEST_URI'] ?? null;
|
||||
$scriptName = $_SERVER['SCRIPT_NAME'];
|
||||
|
||||
$scriptNameModified = str_replace('public/api/', 'api/', $scriptName);
|
||||
|
||||
$idIndex = count(explode('/', $scriptNameModified)) - 1;
|
||||
|
||||
if ($url) {
|
||||
$portalId = explode('/', $url)[$idIndex] ?? null;
|
||||
|
||||
if (str_contains($url, '=')) {
|
||||
$portalId = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($portalId) {
|
||||
return $portalId;
|
||||
}
|
||||
|
||||
$url = $_SERVER['REDIRECT_URL'] ?? null;
|
||||
|
||||
if (!$url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$portalId = explode('/', $url)[$idIndex] ?? null;
|
||||
|
||||
if ($portalId === '') {
|
||||
$portalId = null;
|
||||
}
|
||||
|
||||
return $portalId;
|
||||
}
|
||||
|
||||
protected static function detectIsCustomUrl(): bool
|
||||
{
|
||||
return (bool) ($_SERVER['ESPO_PORTAL_IS_CUSTOM_URL'] ?? false);
|
||||
}
|
||||
|
||||
public static function detectIsInPortalDir(): bool
|
||||
{
|
||||
$isCustomUrl = self::detectIsCustomUrl();
|
||||
|
||||
if ($isCustomUrl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$a = explode('?', $_SERVER['REQUEST_URI']);
|
||||
|
||||
$url = rtrim($a[0], '/');
|
||||
|
||||
return str_contains($url, '/portal');
|
||||
}
|
||||
|
||||
public static function detectIsInPortalWithId(): bool
|
||||
{
|
||||
if (!self::detectIsInPortalDir()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$url = $_SERVER['REQUEST_URI'];
|
||||
|
||||
$a = explode('?', $url);
|
||||
|
||||
$url = rtrim($a[0], '/');
|
||||
|
||||
$folders = explode('/', $url);
|
||||
|
||||
if (count($folders) > 1 && $folders[count($folders) - 2] === 'portal') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function getRedirectUrlWithTrailingSlash(): ?string
|
||||
{
|
||||
$uri = $_SERVER['REQUEST_URI'];
|
||||
|
||||
if ($uri === '' || $uri === '/' || str_ends_with($uri, '/')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$output = $uri . '/';
|
||||
|
||||
$queryString = $_SERVER['QUERY_STRING'] ?? null;
|
||||
|
||||
if ($queryString !== null && $queryString !== '') {
|
||||
$output .= '?' . $_SERVER['QUERY_STRING'];
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user