diff --git a/application/Espo/Classes/Acl/Note/OwnershipChecker.php b/application/Espo/Classes/Acl/Note/OwnershipChecker.php index bbbcd1e17f..06e2c74096 100644 --- a/application/Espo/Classes/Acl/Note/OwnershipChecker.php +++ b/application/Espo/Classes/Acl/Note/OwnershipChecker.php @@ -41,6 +41,7 @@ class OwnershipChecker implements OwnershipOwnChecker { public function checkOwn(User $user, Entity $entity): bool { + if ($entity->get('type') === 'Post' && $user->getId() === $entity->get('createdById')) { return true; } diff --git a/application/Espo/AclPortal/Attachment.php b/application/Espo/Classes/AclPortal/Attachment/AccessChecker.php similarity index 78% rename from application/Espo/AclPortal/Attachment.php rename to application/Espo/Classes/AclPortal/Attachment/AccessChecker.php index d250d19cb7..a16fef6b99 100644 --- a/application/Espo/AclPortal/Attachment.php +++ b/application/Espo/Classes/AclPortal/Attachment/AccessChecker.php @@ -27,22 +27,45 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -namespace Espo\AclPortal; +namespace Espo\Classes\AclPortal\Attachment; -use Espo\Entities\User as EntityUser; -use Espo\Entities\Note; +use Espo\Entities\{ + User, + Note, +}; use Espo\ORM\Entity; use Espo\Core\{ + ORM\EntityManager, + Portal\AclManager, Acl\ScopeData, - Acl\Table, - AclPortal\Acl as Acl, + Acl\AccessEntityCREDChecker, + Portal\Acl\DefaultAccessChecker, + Portal\Acl\Traits\DefaultAccessCheckerDependency, }; -class Attachment extends Acl +class AccessChecker implements AccessEntityCREDChecker { - public function checkEntityRead(EntityUser $user, Entity $entity, ScopeData $data): bool + use DefaultAccessCheckerDependency; + + private $defaultAccessChecker; + + private $aclManager; + + private $entityManager; + + public function __construct( + DefaultAccessChecker $defaultAccessChecker, + AclManager $aclManager, + EntityManager $entityManager + ) { + $this->defaultAccessChecker = $defaultAccessChecker; + $this->aclManager = $aclManager; + $this->entityManager = $entityManager; + } + + public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool { if ($entity->get('parentType') === 'Settings') { return true; @@ -77,14 +100,14 @@ class Attachment extends Acl return true; } - if ($this->checkEntity($user, $entity, $data, Table::ACTION_READ)) { + if ($this->defaultAccessChecker->checkEntityRead($user, $entity, $data)) { return true; } return false; } - protected function checkEntityReadNoteParent(EntityUser $user, Note $note): ?bool + private function checkEntityReadNoteParent(User $user, Note $note): ?bool { if ($note->isInternal()) { return false; @@ -128,13 +151,4 @@ class Attachment extends Acl return null; } - - public function checkIsOwner(EntityUser $user, Entity $entity) - { - if ($user->getId() === $entity->get('createdById')) { - return true; - } - - return false; - } } diff --git a/application/Espo/AclPortal/Note.php b/application/Espo/Classes/AclPortal/Attachment/OwnershipChecker.php similarity index 59% rename from application/Espo/AclPortal/Note.php rename to application/Espo/Classes/AclPortal/Attachment/OwnershipChecker.php index f7781efb1d..1d6300b16c 100644 --- a/application/Espo/AclPortal/Note.php +++ b/application/Espo/Classes/AclPortal/Attachment/OwnershipChecker.php @@ -27,50 +27,26 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -namespace Espo\AclPortal; +namespace Espo\Classes\AclPortal\Attachment; + +use Espo\Entities\User; -use Espo\Entities\User as EntityUser; use Espo\ORM\Entity; use Espo\Core\{ - Acl\ScopeData, - Acl\Table, - AclPortal\Acl as Acl, + Acl\OwnershipOwnChecker, }; -class Note extends Acl +class OwnershipChecker implements OwnershipOwnChecker { - public function checkIsOwner(EntityUser $user, Entity $entity) + private const ATTR_CREATED_BY_ID = 'createdById'; + + public function checkOwn(User $user, Entity $entity): bool { - if ($entity->get('type') === 'Post' && $user->id === $entity->get('createdById')) { + if ($user->getId() === $entity->get(self::ATTR_CREATED_BY_ID)) { return true; } return false; } - - public function checkEntityCreate(EntityUser $user, Entity $entity, ScopeData $data): bool - { - if ($entity->get('type') !== 'Post') { - return false; - } - - if ($entity->get('type') === 'Post' && $entity->get('targetType')) { - return false; - } - - if (!$entity->get('parentId') || !$entity->get('parentType')) { - return false; - } - - $parent = $this->entityManager->getEntity($entity->get('parentType'), $entity->get('parentId')); - - if ($parent) { - if ($this->aclManager->checkEntity($user, $parent, Table::ACTION_STREAM)) { - return true; - } - } - - return false; - } } diff --git a/application/Espo/AclPortal/Email.php b/application/Espo/Classes/AclPortal/Email/AccessChecker.php similarity index 68% rename from application/Espo/AclPortal/Email.php rename to application/Espo/Classes/AclPortal/Email/AccessChecker.php index 9f29d02bc0..bafab21755 100644 --- a/application/Espo/AclPortal/Email.php +++ b/application/Espo/Classes/AclPortal/Email/AccessChecker.php @@ -27,23 +27,40 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -namespace Espo\AclPortal; +namespace Espo\Classes\AclPortal\Email; -use Espo\Entities\User as EntityUser; +use Espo\Entities\User; use Espo\ORM\Entity; use Espo\Core\{ - Acl\ScopeData, + Portal\AclManager, Acl\Table, - AclPortal\Acl as Acl, + Acl\ScopeData, + Acl\AccessEntityCREDChecker, + Portal\Acl\DefaultAccessChecker, + Portal\Acl\Traits\DefaultAccessCheckerDependency, }; -class Email extends Acl +class AccessChecker implements AccessEntityCREDChecker { - public function checkEntityRead(EntityUser $user, Entity $entity, ScopeData $data): bool + use DefaultAccessCheckerDependency; + + private $defaultAccessChecker; + + private $aclManager; + + public function __construct( + DefaultAccessChecker $defaultAccessChecker, + AclManager $aclManager + ) { + $this->defaultAccessChecker = $defaultAccessChecker; + $this->aclManager = $aclManager; + } + + public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool { - if ($this->checkEntity($user, $entity, $data, Table::ACTION_READ)) { + if ($this->defaultAccessChecker->checkEntityRead($user, $entity, $data)) { return true; } @@ -55,11 +72,7 @@ class Email extends Acl return false; } - if (!$entity->has('usersIds')) { - $entity->loadLinkMultipleField('users'); - } - - $userIdList = $entity->get('usersIds'); + $userIdList = $entity->getLinkMultipleIdLIst('users'); if (is_array($userIdList) && in_array($user->getId(), $userIdList)) { return true; @@ -67,14 +80,4 @@ class Email extends Acl return false; } - - public function checkIsOwner(EntityUser $user, Entity $entity) - { - if ($user->getId() === $entity->get('createdById')) { - return true; - } - - return false; - } } - diff --git a/application/Espo/Classes/AclPortal/Email/OwnershipChecker.php b/application/Espo/Classes/AclPortal/Email/OwnershipChecker.php new file mode 100644 index 0000000000..6a421fc97f --- /dev/null +++ b/application/Espo/Classes/AclPortal/Email/OwnershipChecker.php @@ -0,0 +1,50 @@ +getId() === $entity->get('createdById')) { + return true; + } + + return false; + } +} diff --git a/application/Espo/Classes/AclPortal/Note/AccessChecker.php b/application/Espo/Classes/AclPortal/Note/AccessChecker.php new file mode 100644 index 0000000000..f7fbcae4a8 --- /dev/null +++ b/application/Espo/Classes/AclPortal/Note/AccessChecker.php @@ -0,0 +1,189 @@ +defaultAccessChecker = $defaultAccessChecker; + $this->aclManager = $aclManager; + $this->entityManager = $entityManager; + $this->config = $config; + } + + public function checkEntityCreate(User $user, Entity $entity, ScopeData $data): bool + { + $parentId = $entity->get('parentId'); + $parentType = $entity->get('parentType'); + + if (!$parentId || !$parentType) { + return $this->defaultAccessChecker->checkEntityCreate($user, $entity, $data); + } + + $parent = $this->entityManager->getEntity($parentType, $parentId); + + if ($parent && $this->aclManager->checkEntityStream($user, $parent)) { + return true; + } + + return $this->defaultAccessChecker->checkEntityCreate($user, $entity, $data); + } + + public function checkEntityRead(User $user, Entity $entity, ScopeData $data): bool + { + if ($entity->get('type') !== 'Post') { + return false; + } + + if ($entity->get('type') === 'Post' && $entity->get('targetType')) { + return false; + } + + if (!$entity->get('parentId') || !$entity->get('parentType')) { + return false; + } + + $parent = $this->entityManager->getEntity($entity->get('parentType'), $entity->get('parentId')); + + if ($parent) { + if ($this->aclManager->checkEntityStream($user, $parent)) { + return true; + } + } + + return false; + } + + public function checkEntityEdit(User $user, Entity $entity, ScopeData $data): bool + { + if (!$this->defaultAccessChecker->checkEntityEdit($user, $entity, $data)) { + return false; + } + + if (!$this->aclManager->checkOwnershipOwn($user, $entity)) { + return true; + } + + $createdAt = $entity->get('createdAt'); + + if (!$createdAt) { + return true; + } + + $noteEditThresholdPeriod = + '-' . $this->config->get('noteEditThresholdPeriod', self::EDIT_PERIOD); + + $dt = new DateTime(); + + $dt->modify($noteEditThresholdPeriod); + + try { + if ($dt->format('U') > (new DateTime($createdAt))->format('U')) { + return false; + } + } + catch (Exception $e) { + return false; + } + + return true; + } + + public function checkEntityDelete(User $user, Entity $entity, ScopeData $data): bool + { + if (!$this->defaultAccessChecker->checkEntityDelete($user, $entity, $data)) { + return false; + } + + if (!$this->aclManager->checkOwnershipOwn($user, $entity)) { + return true; + } + + $createdAt = $entity->get('createdAt'); + + if (!$createdAt) { + return true; + } + + $deleteThresholdPeriod = + '-' . $this->config->get('noteDeleteThresholdPeriod', self::DELETE_PERIOD); + + $dt = new DateTime(); + + $dt->modify($deleteThresholdPeriod); + + try { + if ($dt->format('U') > (new DateTime($createdAt))->format('U')) { + return false; + } + } + catch (Exception $e) { + return false; + } + + return true; + } +} diff --git a/application/Espo/Classes/AclPortal/Note/OwnershipChecker.php b/application/Espo/Classes/AclPortal/Note/OwnershipChecker.php new file mode 100644 index 0000000000..ab1176663c --- /dev/null +++ b/application/Espo/Classes/AclPortal/Note/OwnershipChecker.php @@ -0,0 +1,50 @@ +get('type') === 'Post' && $user->getId() === $entity->get('createdById')) { + return true; + } + + return false; + } +} diff --git a/application/Espo/Resources/metadata/aclDefs/Attachment.json b/application/Espo/Resources/metadata/aclDefs/Attachment.json index 8f89639041..bbe202cbe7 100644 --- a/application/Espo/Resources/metadata/aclDefs/Attachment.json +++ b/application/Espo/Resources/metadata/aclDefs/Attachment.json @@ -1,4 +1,6 @@ { "accessCheckerClassName": "Espo\\Classes\\Acl\\Attachment\\AccessChecker", - "ownershipCheckerClassName": "Espo\\Classes\\Acl\\Attachment\\OwnershipChecker" + "ownershipCheckerClassName": "Espo\\Classes\\Acl\\Attachment\\OwnershipChecker", + "portalAccessCheckerClassName": "Espo\\Classes\\AclPortal\\Attachment\\AccessChecker", + "portalOwnershipCheckerClassName": "Espo\\Classes\\AclPortal\\Attachment\\OwnershipChecker" } diff --git a/application/Espo/Resources/metadata/aclDefs/Email.json b/application/Espo/Resources/metadata/aclDefs/Email.json index 36821aa618..a9ef77831b 100644 --- a/application/Espo/Resources/metadata/aclDefs/Email.json +++ b/application/Espo/Resources/metadata/aclDefs/Email.json @@ -1,5 +1,7 @@ { "accessCheckerClassName": "Espo\\Classes\\Acl\\Email\\AccessChecker", "ownershipCheckerClassName": "Espo\\Classes\\Acl\\Email\\OwnershipChecker", + "portalAccessCheckerClassName": "Espo\\Classes\\AclPortal\\Email\\AccessChecker", + "portalOwnershipCheckerClassName": "Espo\\Classes\\AclPortal\\Email\\OwnershipChecker", "readOwnerUserField": "users" } diff --git a/application/Espo/Resources/metadata/aclDefs/Note.json b/application/Espo/Resources/metadata/aclDefs/Note.json index f58a806f3e..39e3056518 100644 --- a/application/Espo/Resources/metadata/aclDefs/Note.json +++ b/application/Espo/Resources/metadata/aclDefs/Note.json @@ -1,4 +1,6 @@ { "accessCheckerClassName": "Espo\\Classes\\Acl\\Note\\AccessChecker", - "ownershipCheckerClassName": "Espo\\Classes\\Acl\\Note\\OwnershipChecker" + "ownershipCheckerClassName": "Espo\\Classes\\Acl\\Note\\OwnershipChecker", + "portalAccessCheckerClassName": "Espo\\Classes\\AclPortal\\Note\\AccessChecker", + "portalOwnershipCheckerClassName": "Espo\\Classes\\AclPortal\\Note\\OwnershipChecker" }