diff --git a/application/Espo/Classes/Acl/Email/LinkCheckers/ParentLinkChecker.php b/application/Espo/Classes/Acl/Email/LinkCheckers/ParentLinkChecker.php new file mode 100644 index 0000000000..865497eea6 --- /dev/null +++ b/application/Espo/Classes/Acl/Email/LinkCheckers/ParentLinkChecker.php @@ -0,0 +1,80 @@ +. + * + * 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\Classes\Acl\Email\LinkCheckers; + +use Espo\Core\Acl\LinkChecker; +use Espo\Core\AclManager; +use Espo\Entities\Email; +use Espo\Entities\User; +use Espo\ORM\Entity; +use Espo\ORM\EntityManager; + +/** + * @implements LinkChecker + * @noinspection PhpUnused + */ +class ParentLinkChecker implements LinkChecker +{ + public function __construct( + private EntityManager $entityManager, + private AclManager $aclManager + ) {} + + public function check(User $user, Entity $entity, Entity $foreignEntity): bool + { + if ($this->aclManager->checkEntityRead($user, $foreignEntity)) { + return true; + } + + if (!$entity->getReplied()) { + return false; + } + + $replied = $this->entityManager + ->getRepositoryByClass(Email::class) + ->getById($entity->getReplied()->getId()); + + if (!$replied) { + return false; + } + + $parentLink = $replied->getParent(); + + if ( + !$parentLink || + $parentLink->getId() !== $foreignEntity->getId() || + $parentLink->getEntityType() !== $foreignEntity->getEntityType() + ) { + return false; + } + + return $this->aclManager->checkEntityRead($user, $replied); + } +} diff --git a/application/Espo/Resources/i18n/en_US/Global.json b/application/Espo/Resources/i18n/en_US/Global.json index c1ae4b5f94..ca330becdd 100644 --- a/application/Espo/Resources/i18n/en_US/Global.json +++ b/application/Espo/Resources/i18n/en_US/Global.json @@ -376,7 +376,7 @@ "loggedOutLeaveOut": "Logged out. The session is inactive. You may lose unsaved form data after page refresh. You may need to make a copy.", "noAccessToRecord": "Operation requires `{action}` access to record.", "noAccessToForeignRecord": "Operation requires `{action}` access to foreign record.", - "noLinkAccess": "Can't relate with {foreignEntity} record through the link {link}. No access.", + "noLinkAccess": "Can't relate with {foreignEntityType} record through the link '{link}'. No access.", "cannotUnrelateRequiredLink": "Can't unrelate required link.", "cannotRelateNonExisting": "Can't relate with non-existing {foreignEntityType} record.", "cannotRelateForbidden": "Can't relate with forbidden {foreignEntityType} record. `{action}` access required.", diff --git a/application/Espo/Resources/metadata/aclDefs/Email.json b/application/Espo/Resources/metadata/aclDefs/Email.json index 8fe35a3411..7663998b9a 100644 --- a/application/Espo/Resources/metadata/aclDefs/Email.json +++ b/application/Espo/Resources/metadata/aclDefs/Email.json @@ -4,5 +4,8 @@ "portalAccessCheckerClassName": "Espo\\Classes\\AclPortal\\Email\\AccessChecker", "portalOwnershipCheckerClassName": "Espo\\Classes\\AclPortal\\Email\\OwnershipChecker", "assignmentCheckerClassName": "Espo\\Classes\\Acl\\Email\\AssignmentChecker", - "readOwnerUserField": "users" + "readOwnerUserField": "users", + "linkCheckerClassNameMap": { + "parent": "Espo\\Classes\\Acl\\Email\\LinkCheckers\\ParentLinkChecker" + } }