acl portal changes and tests

This commit is contained in:
yuri
2019-08-28 11:57:12 +03:00
parent a6a6ce6722
commit 0fda920610
5 changed files with 305 additions and 38 deletions
+11 -7
View File
@@ -104,6 +104,13 @@ class Base extends \Espo\Core\Acl\Base
}
if ($inAccount) {
return true;
} else {
if (is_null($isOwnContact) && $entity) {
$isOwnContact = $this->checkIsOwnContact($user, $entity);
}
if ($isOwnContact) {
return true;
}
}
}
@@ -117,7 +124,6 @@ class Base extends \Espo\Core\Acl\Base
}
return false;
}
public function checkReadOnlyAccount(User $user, $data)
@@ -152,13 +158,13 @@ class Base extends \Espo\Core\Acl\Base
{
$accountIdList = $user->getLinkMultipleIdList('accounts');
if (count($accountIdList)) {
if ($entity->hasAttribute('accountId')) {
if ($entity->hasAttribute('accountId') && $entity->getRelationParam('account', 'entity') === 'Account') {
if (in_array($entity->get('accountId'), $accountIdList)) {
return true;
}
}
if ($entity->hasRelation('accounts')) {
if ($entity->hasRelation('accounts') && $entity->getRelationParam('accounts', 'entity') === 'Account') {
$repository = $this->getEntityManager()->getRepository($entity->getEntityType());
foreach ($accountIdList as $accountId) {
if ($repository->isRelated($entity, 'accounts', $accountId)) {
@@ -183,13 +189,13 @@ class Base extends \Espo\Core\Acl\Base
{
$contactId = $user->get('contactId');
if ($contactId) {
if ($entity->hasAttribute('contactId')) {
if ($entity->hasAttribute('contactId') && $entity->getRelationParam('contact', 'entity') === 'Contact') {
if ($entity->get('contactId') === $contactId) {
return true;
}
}
if ($entity->hasRelation('contacts')) {
if ($entity->hasRelation('contacts') && $entity->getRelationParam('contacts', 'entity') === 'Contact') {
$repository = $this->getEntityManager()->getRepository($entity->getEntityType());
if ($repository->isRelated($entity, 'contacts', $contactId)) {
return true;
@@ -207,6 +213,4 @@ class Base extends \Espo\Core\Acl\Base
return false;
}
}
+39 -27
View File
@@ -552,16 +552,16 @@ class Base
return;
}
$d = [
$or = [
'teamsAccess.id' => $this->getUser()->getLinkMultipleIdList('teams')
];
if ($this->hasAssignedUserField()) {
$d['assignedUserId'] = $this->getUser()->id;
$or['assignedUserId'] = $this->getUser()->id;
} else if ($this->hasCreatedByField()) {
$d['createdById'] = $this->getUser()->id;
$or['createdById'] = $this->getUser()->id;
}
$result['whereClause'][] = [
'OR' => $d
'OR' => $or
];
}
@@ -580,38 +580,42 @@ class Base
protected function accessPortalOnlyContact(&$result)
{
$d = [];
$or = [];
$contactId = $this->getUser()->get('contactId');
if ($contactId) {
if ($this->getSeed()->hasAttribute('contactId')) {
$d['contactId'] = $contactId;
if (
$this->getSeed()->hasAttribute('contactId') && $this->getSeed()->getRelationParam('contact', 'entity') === 'Contact'
) {
$or['contactId'] = $contactId;
}
if ($this->getSeed()->hasRelation('contacts')) {
if (
$this->getSeed()->hasRelation('contacts') && $this->getSeed()->getRelationParam('contacts', 'entity') === 'Contact'
) {
$this->addLeftJoin(['contacts', 'contactsAccess'], $result);
$this->setDistinct(true, $result);
$d['contactsAccess.id'] = $contactId;
$or['contactsAccess.id'] = $contactId;
}
}
if ($this->getSeed()->hasAttribute('createdById')) {
$d['createdById'] = $this->getUser()->id;
$or['createdById'] = $this->getUser()->id;
}
if ($this->getSeed()->hasAttribute('parentId') && $this->getSeed()->hasRelation('parent')) {
$contactId = $this->getUser()->get('contactId');
if ($contactId) {
$d[] = [
$or[] = [
'parentType' => 'Contact',
'parentId' => $contactId
];
}
}
if (!empty($d)) {
if (!empty($or)) {
$result['whereClause'][] = [
'OR' => $d
'OR' => $or
];
} else {
$result['whereClause'][] = [
@@ -622,27 +626,31 @@ class Base
protected function accessPortalOnlyAccount(&$result)
{
$d = [];
$or = [];
$accountIdList = $this->getUser()->getLinkMultipleIdList('accounts');
$contactId = $this->getUser()->get('contactId');
if (count($accountIdList)) {
if ($this->getSeed()->hasAttribute('accountId')) {
$d['accountId'] = $accountIdList;
if (
$this->getSeed()->hasAttribute('accountId') && $this->getSeed()->getRelationParam('account', 'entity') === 'Account'
) {
$or['accountId'] = $accountIdList;
}
if ($this->getSeed()->hasRelation('accounts')) {
if (
$this->getSeed()->hasRelation('accounts') && $this->getSeed()->getRelationParam('accounts', 'entity') === 'Account'
) {
$this->addLeftJoin(['accounts', 'accountsAccess'], $result);
$this->setDistinct(true, $result);
$d['accountsAccess.id'] = $accountIdList;
$or['accountsAccess.id'] = $accountIdList;
}
if ($this->getSeed()->hasAttribute('parentId') && $this->getSeed()->hasRelation('parent')) {
$d[] = [
$or[] = [
'parentType' => 'Account',
'parentId' => $accountIdList
];
if ($contactId) {
$d[] = [
$or[] = [
'parentType' => 'Contact',
'parentId' => $contactId
];
@@ -651,23 +659,27 @@ class Base
}
if ($contactId) {
if ($this->getSeed()->hasAttribute('contactId')) {
$d['contactId'] = $contactId;
if (
$this->getSeed()->hasAttribute('contactId') && $this->getSeed()->getRelationParam('contact', 'entity') === 'Contact'
) {
$or['contactId'] = $contactId;
}
if ($this->getSeed()->hasRelation('contacts')) {
if (
$this->getSeed()->hasRelation('contacts') && $this->getSeed()->getRelationParam('contacts', 'entity') === 'Contact'
) {
$this->addLeftJoin(['contacts', 'contactsAccess'], $result);
$this->setDistinct(true, $result);
$d['contactsAccess.id'] = $contactId;
$or['contactsAccess.id'] = $contactId;
}
}
if ($this->getSeed()->hasAttribute('createdById')) {
$d['createdById'] = $this->getUser()->id;
$or['createdById'] = $this->getUser()->id;
}
if (!empty($d)) {
if (!empty($or)) {
$result['whereClause'][] = [
'OR' => $d
'OR' => $or
];
} else {
$result['whereClause'][] = [
+2 -2
View File
@@ -67,9 +67,9 @@ abstract class BaseTestCase extends \PHPUnit\Framework\TestCase
protected $initData = null;
protected function createApplication($clearCache = true)
protected function createApplication($clearCache = true, $portalId = null)
{
return $this->espoTester->getApplication(true, $clearCache);
return $this->espoTester->getApplication(true, $clearCache, $portalId);
}
protected function auth($userName, $password = null, $portalId = null, $authenticationMethod = null)
+5 -2
View File
@@ -117,15 +117,18 @@ class Tester
$this->authenticationMethod = $authenticationMethod;
}
public function getApplication($reload = false, $clearCache = true)
public function getApplication($reload = false, $clearCache = true, $portalId = null)
{
$portalId = $portalId ?? $this->portalId ?? null;
if (!isset($this->application) || $reload) {
if ($clearCache) {
$this->clearCache();
}
$this->application = empty($this->portalId) ? new \Espo\Core\Application() : new \Espo\Core\Portal\Application($this->portalId);
$this->application = !$portalId ? new \Espo\Core\Application() : new \Espo\Core\Portal\Application($portalId);
$auth = new \Espo\Core\Utils\Auth($this->application->getContainer());
if (isset($this->userName)) {
+248
View File
@@ -0,0 +1,248 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2019 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://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 General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace tests\integration\Espo\Portal;
class AclTest extends \tests\integration\Core\BaseTestCase
{
public function testAccessContact()
{
$app = $this->createApplication();
$em = $app->getContainer()->get('entityManager');
$contact = $em->createEntity('Contact', []);
$portal = $em->createEntity('Portal', [
'name' => 'Portal',
]);
$this->createUser([
'userName' => 'tester',
'portalsIds' => [$portal->id],
'contactId' => $contact->id,
], [
'data' => [
'Case' => [
'create' => 'no',
'read' => 'contact',
'edit' => 'no',
'delete' => 'no',
'stream' => 'contact',
]
],
], true);
$this->auth('tester', null, $portal->id);
$app = $this->createApplication(true, $portal->id);
$em = $app->getContainer()->get('entityManager');
$acl = $app->getContainer()->get('acl');
$case1 = $em->createEntity('Case', [
'contactId' => $contact->id,
], ['createdById' => '1']);
$case2 = $em->createEntity('Case', [
'contactsIds' => [$contact->id],
], ['createdById' => '1']);
$case3 = $em->createEntity('Case', [
], ['createdById' => '1']);
$this->assertFalse($acl->check('Case', 'create'));
$this->assertFalse($acl->check('Case', 'edit'));
$this->assertFalse($acl->check('Case', 'delete'));
$this->assertTrue($acl->check($case1, 'read'));
$this->assertTrue($acl->check($case2, 'read'));
$this->assertFalse($acl->check($case3, 'read'));
$service = $app->getContainer()->get('serviceFactory')->create('Case');
$result = $service->find([]);
$idList = [];
foreach ($result['collection'] as $e) {
$idList[] = $e->id;
}
$this->assertTrue(in_array($case1->id, $idList));
$this->assertTrue(in_array($case2->id, $idList));
$this->assertFalse(in_array($case3->id, $idList));
}
public function testAccessAccount()
{
$app = $this->createApplication();
$em = $app->getContainer()->get('entityManager');
$contact = $em->createEntity('Contact', []);
$account = $em->createEntity('Account', []);
$portal = $em->createEntity('Portal', [
'name' => 'Portal',
]);
$this->createUser([
'userName' => 'tester',
'portalsIds' => [$portal->id],
'contactId' => $contact->id,
'accountsIds' => [$account->id],
], [
'data' => [
'Case' => [
'create' => 'no',
'read' => 'account',
'edit' => 'no',
'delete' => 'no',
'stream' => 'account',
]
],
], true);
$this->auth('tester', null, $portal->id);
$app = $this->createApplication(true, $portal->id);
$em = $app->getContainer()->get('entityManager');
$acl = $app->getContainer()->get('acl');
$case1 = $em->createEntity('Case', [
'contactId' => $contact->id,
], ['createdById' => '1']);
$case2 = $em->createEntity('Case', [
'contactsIds' => [$contact->id],
], ['createdById' => '1']);
$case3 = $em->createEntity('Case', [
], ['createdById' => '1']);
$case4 = $em->createEntity('Case', [
'accountId' => $account->id,
], ['createdById' => '1']);
$this->assertFalse($acl->check('Case', 'create'));
$this->assertFalse($acl->check('Case', 'edit'));
$this->assertFalse($acl->check('Case', 'delete'));
$this->assertTrue($acl->check($case1, 'read'));
$this->assertTrue($acl->check($case2, 'read'));
$this->assertFalse($acl->check($case3, 'read'));
$this->assertTrue($acl->check($case4, 'read'));
$service = $app->getContainer()->get('serviceFactory')->create('Case');
$result = $service->find([]);
$idList = [];
foreach ($result['collection'] as $e) {
$idList[] = $e->id;
}
$this->assertTrue(in_array($case1->id, $idList));
$this->assertTrue(in_array($case2->id, $idList));
$this->assertFalse(in_array($case3->id, $idList));
$this->assertTrue(in_array($case4->id, $idList));
}
public function testAccessOwn()
{
$app = $this->createApplication();
$em = $app->getContainer()->get('entityManager');
$contact = $em->createEntity('Contact', []);
$account = $em->createEntity('Account', []);
$portal = $em->createEntity('Portal', [
'name' => 'Portal',
]);
$this->createUser([
'userName' => 'tester',
'portalsIds' => [$portal->id],
'contactId' => $contact->id,
'accountsIds' => [$account->id],
], [
'data' => [
'Case' => [
'create' => 'no',
'read' => 'own',
'edit' => 'no',
'delete' => 'no',
'stream' => 'own',
]
],
], true);
$this->auth('tester', null, $portal->id);
$app = $this->createApplication(true, $portal->id);
$em = $app->getContainer()->get('entityManager');
$acl = $app->getContainer()->get('acl');
$user = $app->getContainer()->get('user');
$case1 = $em->createEntity('Case', [
'contactId' => $contact->id,
], ['createdById' => '1']);
$case2 = $em->createEntity('Case', [
'contactsIds' => [$contact->id],
], ['createdById' => '1']);
$case3 = $em->createEntity('Case', [
], ['createdById' => '1']);
$case4 = $em->createEntity('Case', [
'accountId' => $account->id,
], ['createdById' => '1']);
$case5 = $em->createEntity('Case', [
'accountId' => $account->id,
], ['createdById' => $user->id]);
$this->assertFalse($acl->check('Case', 'create'));
$this->assertFalse($acl->check('Case', 'edit'));
$this->assertFalse($acl->check('Case', 'delete'));
$this->assertFalse($acl->check($case1, 'read'));
$this->assertFalse($acl->check($case2, 'read'));
$this->assertFalse($acl->check($case3, 'read'));
$this->assertFalse($acl->check($case4, 'read'));
$this->assertTrue($acl->check($case5, 'read'));
$service = $app->getContainer()->get('serviceFactory')->create('Case');
$result = $service->find([]);
$idList = [];
foreach ($result['collection'] as $e) {
$idList[] = $e->id;
}
$this->assertFalse(in_array($case1->id, $idList));
$this->assertFalse(in_array($case2->id, $idList));
$this->assertFalse(in_array($case3->id, $idList));
$this->assertFalse(in_array($case4->id, $idList));
$this->assertTrue(in_array($case5->id, $idList));
}
}