From defa18724c61cf51bf0521f4cddf2f2f6c8d76b9 Mon Sep 17 00:00:00 2001 From: Yuri Kuznetsov Date: Tue, 4 May 2021 11:15:30 +0300 Subject: [PATCH] merge test and fix --- .../Espo/Core/Action/Actions/Merge/Merger.php | 11 +- tests/integration/Espo/Actions/ActionTest.php | 258 +++++++++++++++++- 2 files changed, 267 insertions(+), 2 deletions(-) diff --git a/application/Espo/Core/Action/Actions/Merge/Merger.php b/application/Espo/Core/Action/Actions/Merge/Merger.php index 9fcedd0c96..5633203cbd 100644 --- a/application/Espo/Core/Action/Actions/Merge/Merger.php +++ b/application/Espo/Core/Action/Actions/Merge/Merger.php @@ -250,7 +250,7 @@ class Merger ]) ->where([ 'type' => ['Post', 'EmailSent', 'EmailReceived'], - 'parentId' => $sourceEntity->id, + 'parentId' => $sourceEntity->getId(), 'parentType' => $sourceEntity->getEntityType(), ]) ->build(); @@ -284,10 +284,19 @@ class Merger $entityDefs = $this->entityManager->getDefs()->getEntity($entityType); + $ignoreList = [ + 'emailAddresses', + 'phoneNumbers', + ]; + foreach ($entityDefs->getRelationList() as $relationDefs) { $name = $relationDefs->getName(); $type = $relationDefs->getType(); + if (in_array($name, $ignoreList)) { + continue; + } + $notMergeable = $this->metadata ->get(['entityDefs', $entityType, 'links', $name, 'notMergeable']); diff --git a/tests/integration/Espo/Actions/ActionTest.php b/tests/integration/Espo/Actions/ActionTest.php index 6721d59593..83d38e916f 100644 --- a/tests/integration/Espo/Actions/ActionTest.php +++ b/tests/integration/Espo/Actions/ActionTest.php @@ -35,6 +35,14 @@ use Espo\Core\{ ORM\EntityManager, Application, Exceptions\Forbidden, + Fields\EmailAddress, + Fields\PhoneNumber, + Action\Actions\Merge\Merger, + Action\Params, +}; + +use Espo\Modules\Crm\Entities\{ + Contact, }; class ActionTest extends \tests\integration\Core\BaseTestCase @@ -54,6 +62,11 @@ class ActionTest extends \tests\integration\Core\BaseTestCase */ private $actionProcessor; + /** + * @var Merger + */ + private $merger; + private function init(): void { $this->app = $this->createApplication(); @@ -65,7 +78,12 @@ class ActionTest extends \tests\integration\Core\BaseTestCase $this->actionProcessor = $this->app ->getContainer() ->get('injectableFactory') - ->create(ActionProcessor::class);; + ->create(ActionProcessor::class); + + $this->merger = $this->app + ->getContainer() + ->get('injectableFactory') + ->create(Merger::class); } public function testActionNotAllowed(): void @@ -92,4 +110,242 @@ class ActionTest extends \tests\integration\Core\BaseTestCase $this->actionProcessor->process('Action', 'process', $request, $response); } + + public function testActionMerge1(): void + { + $this->createUser('tester', [ + 'assignmentPermission' => 'all', + 'data' => [ + 'Contact' => [ + 'create' => 'all', + 'read' => 'all', + 'edit' => 'all', + 'delete' => 'all', + ], + ], + ]); + + $this->auth('tester'); + + $this->init(); + + $team1 = $this->entityManager->createEntity('Team', []); + $team2 = $this->entityManager->createEntity('Team', []); + + $account1 = $this->entityManager->createEntity('Account', []); + $account2 = $this->entityManager->createEntity('Account', []); + + /* @var $contact1 Contact */ + $contact1 = $this->entityManager->getEntity('Contact'); + + $emailAddressGroup1 = $contact1->getEmailAddressGroup() + ->withAdded(EmailAddress::fromAddress('c1a@test.com')) + ->withAdded(EmailAddress::fromAddress('c1b@test.com')->invalid()); + + $contact1->setEmailAddressGroup($emailAddressGroup1); + + $phoneNumberGroup1 = $contact1->getPhoneNumberGroup() + ->withAdded(PhoneNumber::fromNumber('+1a')) + ->withAdded(PhoneNumber::fromNumber('+1b')->invalid()); + + $contact1->setPhoneNumberGroup($phoneNumberGroup1); + + $contact1->set('accountId', $account1->getId()); + + $contact1->set('teamsIds', [$team1->getId()]); + + /* @var $contact2 Contact */ + $contact2 = $this->entityManager->getEntity('Contact'); + + $emailAddressGroup2 = $contact1->getEmailAddressGroup() + ->withAdded(EmailAddress::fromAddress('c2a@test.com')) + ->withAdded(EmailAddress::fromAddress('c2b@test.com')->optedOut()); + + $contact2->setEmailAddressGroup($emailAddressGroup2); + + $phoneNumberGroup2 = $contact2->getPhoneNumberGroup() + ->withAdded(PhoneNumber::fromNumber('+2a')) + ->withAdded(PhoneNumber::fromNumber('+2b')->optedOut()); + + $contact2->setPhoneNumberGroup($phoneNumberGroup2); + + $contact2->set('accountId', $account2->getId()); + + $contact2->set('teamsIds', [$team2->getId()]); + + $this->entityManager->saveEntity($contact1); + $this->entityManager->saveEntity($contact2); + + $this->entityManager->createEntity('Note', [ + 'type' => 'Post', + 'parentType' => 'Contact', + 'parentId' => $contact1->getId(), + ]); + + $note2 = $this->entityManager->createEntity('Note', [ + 'type' => 'Post', + 'parentType' => 'Contact', + 'parentId' => $contact2->getId(), + ]); + + $opportunity1 = $this->entityManager->createEntity('Opportunity', []); + $opportunity2 = $this->entityManager->createEntity('Opportunity', []); + + $this->entityManager + ->getRDBRepository('Contact') + ->getRelation($contact1, 'opportunities') + ->relate($opportunity1); + + $this->entityManager + ->getRDBRepository('Contact') + ->getRelation($contact2, 'opportunities') + ->relate($opportunity2); + + $data = [ + 'entityType' => 'Contact', + 'action' => 'merge', + 'id' => $contact1->getId(), + 'data' => (object) [ + 'attributes' => (object) [ + 'description' => 'merged', + ], + 'sourceIdList' => [$contact2->getId()], + ], + ]; + + $request = $this->createRequest( + 'POST', + [], + ['Content-Type' => 'application/json'], + json_encode($data) + ); + + $response = $this->createMock(Response::class); + + $this->actionProcessor->process('Action', 'process', $request, $response); + + /* @var $contact1Reloaded Contact */ + $contact1Reloaded = $this->entityManager->getEntity('Contact', $contact1->getId()); + $contact2Reloaded = $this->entityManager->getEntity('Contact', $contact2->getId()); + + $this->assertEquals('merged', $contact1Reloaded->get('description')); + + $this->assertNull($contact2Reloaded); + + $emailAddressGroup = $contact1Reloaded->getEmailAddressGroup(); + $phoneNumberGroup = $contact1Reloaded->getPhoneNumberGroup(); + + $this->assertEquals(4, $emailAddressGroup->getCount()); + $this->assertEquals(4, $phoneNumberGroup->getCount()); + + $this->assertEquals( + 'c1a@test.com', + $emailAddressGroup->getPrimary()->getAddress() + ); + + $this->assertEquals( + '+1a', + $phoneNumberGroup->getPrimary()->getNumber() + ); + + $this->assertTrue( + $emailAddressGroup->getByAddress('c2b@test.com')->isOptedOut() + ); + + $this->assertTrue( + $emailAddressGroup->getByAddress('c1b@test.com')->isInvalid() + ); + + $this->assertTrue( + $phoneNumberGroup->getByNumber('+2b')->isOptedOut() + ); + + $this->assertTrue( + $phoneNumberGroup->getByNumber('+1b')->isInvalid() + ); + + $this->assertEquals( + $contact1->getId(), + $this->entityManager + ->getEntity('Note', $note2->getId()) + ->get('parentId') + ); + + $this->assertEquals( + 2, + $this->entityManager + ->getRDBRepository('Contact') + ->getRelation($contact1Reloaded, 'opportunities') + ->count() + ); + + $this->assertEquals( + 2, + $this->entityManager + ->getRDBRepository('Contact') + ->getRelation($contact1Reloaded, 'teams') + ->count() + ); + + $this->assertEquals( + 2, + count($contact1Reloaded->getLinkMultipleIdList('accounts')) + ); + } + + public function testMergeNoEditAccess(): void + { + $this->createUser('tester', [ + 'assignmentPermission' => 'all', + 'data' => [ + 'Contact' => [ + 'create' => 'own', + 'read' => 'all', + 'edit' => 'own', + 'delete' => 'no', + ], + ], + ]); + + $this->auth('tester'); + + $this->init(); + + $contact1 = $this->entityManager->createEntity('Contact', []); + $contact2 = $this->entityManager->createEntity('Contact', []); + + $params = new Params('Contact', $contact1->getId()); + + $this->expectException(Forbidden::class); + + $this->merger->process($params, [$contact2->getId()], (object) []); + } + + public function testMergeNoDeleteAccess(): void + { + $this->createUser('tester', [ + 'assignmentPermission' => 'all', + 'data' => [ + 'Contact' => [ + 'create' => 'own', + 'read' => 'all', + 'edit' => 'all', + 'delete' => 'no', + ], + ], + ]); + + $this->auth('tester'); + + $this->init(); + + $contact1 = $this->entityManager->createEntity('Contact', []); + $contact2 = $this->entityManager->createEntity('Contact', []); + + $params = new Params('Contact', $contact1->getId()); + + $this->expectException(Forbidden::class); + + $this->merger->process($params, [$contact2->getId()], (object) []); + } }