Skip to content

Commit 4a6e28e

Browse files
authored
Merge pull request #3011 from irontec/PROVIDER-2324-fix-carrierServer-deletion-restrictions
[PROVIDER-2324] Allow removal of CarrierServers only if the Carrier does not become serverless
2 parents 9c155f9 + b78df9b commit 4a6e28e

File tree

11 files changed

+301
-5
lines changed

11 files changed

+301
-5
lines changed

library/Ivoz/Kam/Domain/Service/TrunksLcrRuleTarget/UpdateByCarrierServer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ public static function getSubscribedEvents()
3737
public function execute(CarrierServerInterface $carrierServer)
3838
{
3939
$isNew = $carrierServer->isNew();
40-
$isDeleted = $carrierServer->hasBeenDeleted();
41-
if (!$isDeleted && !$isNew) {
40+
41+
if (!$isNew) {
4242
return;
4343
}
4444

library/Ivoz/Provider/Domain/Model/OutgoingRouting/OutgoingRoutingRepository.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@
55
use Doctrine\Common\Collections\Selectable;
66
use Doctrine\Persistence\ObjectRepository;
77
use Ivoz\Provider\Domain\Model\RoutingPattern\RoutingPatternInterface;
8-
use Ivoz\Provider\Domain\Model\RoutingPatternGroup\RoutingPatternGroupInterface;
8+
use Ivoz\Provider\Domain\Model\OutgoingRouting\OutgoingRoutingInterface;
99

1010
interface OutgoingRoutingRepository extends ObjectRepository, Selectable
1111
{
1212
public function findByRoutingPattern(RoutingPatternInterface $routingPattern): array;
13+
14+
/**
15+
* @return OutgoingRoutingInterface[]
16+
*/
17+
public function findByCarrier(int $carrierId): array;
1318
}

library/Ivoz/Provider/Domain/Model/OutgoingRoutingRelCarrier/OutgoingRoutingRelCarrierRepository.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44

55
use Doctrine\Common\Collections\Selectable;
66
use Doctrine\Persistence\ObjectRepository;
7+
use Ivoz\Provider\Domain\Model\OutgoingRoutingRelCarrier\OutgoingRoutingRelCarrierInterface;
78

89
interface OutgoingRoutingRelCarrierRepository extends ObjectRepository, Selectable
910
{
11+
/**
12+
* @return OutgoingRoutingRelCarrierInterface[]
13+
*/
14+
public function findByCarrier(int $carrierId): array;
1015
}

library/Ivoz/Provider/Domain/Service/CarrierServer/CarrierServerLifecycleServiceCollection.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ class CarrierServerLifecycleServiceCollection implements LifecycleServiceCollect
2222
\Ivoz\Kam\Domain\Service\TrunksLcrGateway\UpdateByCarrierServer::class => 10,
2323
\Ivoz\Kam\Domain\Service\TrunksLcrRuleTarget\UpdateByCarrierServer::class => 20,
2424
],
25+
"pre_remove" =>
26+
[
27+
\Ivoz\Provider\Domain\Service\CarrierServer\DeleteProtection::class => 200,
28+
],
2529
"post_remove" =>
2630
[
2731
\Ivoz\Kam\Domain\Service\TrunksLcrRuleTarget\UpdateByCarrierServer::class => 200,
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
namespace Ivoz\Provider\Domain\Service\CarrierServer;
4+
5+
use Ivoz\Provider\Domain\Model\CarrierServer\CarrierServerInterface;
6+
use Ivoz\Provider\Domain\Model\CarrierServer\CarrierServerRepository;
7+
use Ivoz\Provider\Domain\Model\OutgoingRouting\OutgoingRoutingRepository;
8+
use Ivoz\Provider\Domain\Model\OutgoingRoutingRelCarrier\OutgoingRoutingRelCarrierRepository;
9+
10+
class DeleteProtection implements CarrierServerLifecycleEventHandlerInterface
11+
{
12+
public const PRE_REMOVE_PRIORITY = self::PRIORITY_NORMAL;
13+
14+
public function __construct(
15+
private CarrierServerRepository $carrierServerRepository,
16+
private OutgoingRoutingRepository $outgoingRoutingRepository,
17+
private OutgoingRoutingRelCarrierRepository $outgoingRoutingRelCarrierRepository
18+
) {
19+
}
20+
21+
/**
22+
* @return array<string, int>
23+
*/
24+
public static function getSubscribedEvents(): array
25+
{
26+
return [
27+
self::EVENT_PRE_REMOVE => self::PRE_REMOVE_PRIORITY
28+
];
29+
}
30+
31+
public function execute(CarrierServerInterface $carrierServer): void
32+
{
33+
$carrier = $carrierServer->getCarrier();
34+
$carrierId = $carrier->getId();
35+
36+
if (!$carrierId) {
37+
return;
38+
}
39+
40+
$isCarrierInUse = $this->isCarrierInUse($carrierId);
41+
42+
if (!$isCarrierInUse) {
43+
return;
44+
}
45+
46+
$carrierServers = $this->carrierServerRepository->findByCarrierId($carrierId);
47+
$isLastCarrierServer = count($carrierServers) === 1;
48+
if ($isLastCarrierServer) {
49+
throw new \DomainException(
50+
'Cannot delete the last CarrierServer from a Carrier that is being used in outgoing routes. ' .
51+
'At least one CarrierServer must remain.',
52+
403
53+
);
54+
}
55+
}
56+
57+
private function isCarrierInUse(int $carrierId): bool
58+
{
59+
$staticRoutes = $this->outgoingRoutingRepository->findByCarrier($carrierId);
60+
61+
if (!empty($staticRoutes)) {
62+
return true;
63+
}
64+
65+
$lcrRoutes = $this->outgoingRoutingRelCarrierRepository->findByCarrier($carrierId);
66+
67+
return !empty($lcrRoutes);
68+
}
69+
}

library/Ivoz/Provider/Infrastructure/Persistence/Doctrine/OutgoingRoutingDoctrineRepository.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
66
use Ivoz\Provider\Domain\Model\OutgoingRouting\OutgoingRouting;
77
use Ivoz\Provider\Domain\Model\OutgoingRouting\OutgoingRoutingRepository;
8+
use Ivoz\Provider\Domain\Model\OutgoingRouting\OutgoingRoutingInterface;
89
use Ivoz\Provider\Domain\Model\RoutingPattern\RoutingPatternInterface;
910
use Doctrine\Persistence\ManagerRegistry;
1011

@@ -43,4 +44,17 @@ public function findByRoutingPattern(RoutingPatternInterface $routingPattern): a
4344
$query->getResult()
4445
);
4546
}
47+
48+
/**
49+
* @return OutgoingRoutingInterface[]
50+
*/
51+
public function findByCarrier(int $carrierId): array
52+
{
53+
/** @var OutgoingRouting[] $response */
54+
$response = $this->findBy([
55+
"carrier" => $carrierId
56+
]);
57+
58+
return $response;
59+
}
4660
}

library/Ivoz/Provider/Infrastructure/Persistence/Doctrine/OutgoingRoutingRelCarrierDoctrineRepository.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
66
use Ivoz\Provider\Domain\Model\OutgoingRoutingRelCarrier\OutgoingRoutingRelCarrier;
77
use Ivoz\Provider\Domain\Model\OutgoingRoutingRelCarrier\OutgoingRoutingRelCarrierRepository;
8+
use Ivoz\Provider\Domain\Model\OutgoingRoutingRelCarrier\OutgoingRoutingRelCarrierInterface;
89
use Doctrine\Persistence\ManagerRegistry;
910

1011
/**
@@ -21,4 +22,17 @@ public function __construct(ManagerRegistry $registry)
2122
{
2223
parent::__construct($registry, OutgoingRoutingRelCarrier::class);
2324
}
25+
26+
/**
27+
* @return OutgoingRoutingRelCarrierInterface[]
28+
*/
29+
public function findByCarrier(int $carrierId): array
30+
{
31+
/** @var OutgoingRoutingRelCarrier[] $response */
32+
$response = $this->findBy([
33+
"carrier" => $carrierId
34+
]);
35+
36+
return $response;
37+
}
2438
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
namespace Tests\Provider\CarrierServer;
4+
5+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
6+
use Tests\DbIntegrationTestHelperTrait;
7+
use Ivoz\Provider\Domain\Model\CarrierServer\CarrierServer;
8+
use Ivoz\Provider\Domain\Model\CarrierServer\CarrierServerDto;
9+
use Ivoz\Provider\Domain\Model\Carrier\Carrier;
10+
use Ivoz\Provider\Domain\Model\Carrier\CarrierDto;
11+
use Ivoz\Provider\Domain\Model\OutgoingRouting\OutgoingRouting;
12+
use Ivoz\Provider\Domain\Model\OutgoingRouting\OutgoingRoutingDto;
13+
14+
class CarrierServerDeleteProtectionTest extends KernelTestCase
15+
{
16+
use DbIntegrationTestHelperTrait;
17+
18+
/**
19+
* @test
20+
*/
21+
public function test_runner()
22+
{
23+
$this->it_can_delete_server_from_unused_carrier();
24+
$this->it_cannot_delete_last_server_from_used_carrier();
25+
}
26+
27+
public function it_can_delete_server_from_unused_carrier()
28+
{
29+
$carrierDto = new CarrierDto();
30+
$carrierDto
31+
->setName('Test Unused Carrier')
32+
->setDescription('Test carrier for deletion test')
33+
->setBrandId(1)
34+
->setProxyTrunkId(1);
35+
36+
/** @var Carrier $unusedCarrier */
37+
$unusedCarrier = $this->entityTools
38+
->persistDto($carrierDto, null, true);
39+
40+
$carrierServerDto = new CarrierServerDto();
41+
$carrierServerDto
42+
->setHostname('unused-carrier.example.com')
43+
->setPort(5060)
44+
->setUriScheme(1)
45+
->setTransport(1)
46+
->setSipProxy('unused-carrier.example.com')
47+
->setCarrierId($unusedCarrier->getId())
48+
->setBrandId(1);
49+
50+
/** @var CarrierServer $carrierServer */
51+
$carrierServer = $this->entityTools
52+
->persistDto($carrierServerDto, null, true);
53+
54+
$this->entityTools->remove($carrierServer);
55+
56+
$this->addToAssertionCount(1);
57+
}
58+
59+
public function it_cannot_delete_last_server_from_used_carrier()
60+
{
61+
$carrierDto = new CarrierDto();
62+
$carrierDto
63+
->setName('Test Used Carrier')
64+
->setDescription('Test carrier used in routes')
65+
->setBrandId(1)
66+
->setProxyTrunkId(1);
67+
68+
/** @var Carrier $usedCarrier */
69+
$usedCarrier = $this->entityTools
70+
->persistDto($carrierDto, null, true);
71+
72+
$outgoingRoutingDto = new OutgoingRoutingDto();
73+
$outgoingRoutingDto
74+
->setType('pattern')
75+
->setPriority(999)
76+
->setWeight(1)
77+
->setBrandId(1)
78+
->setRoutingMode('static')
79+
->setCarrierId($usedCarrier->getId());
80+
81+
/** @var OutgoingRouting $outgoingRouting */
82+
$outgoingRouting = $this->entityTools
83+
->persistDto($outgoingRoutingDto, null, true);
84+
85+
$carrierServerDto = new CarrierServerDto();
86+
$carrierServerDto
87+
->setHostname('used-carrier.example.com')
88+
->setPort(5060)
89+
->setUriScheme(1)
90+
->setTransport(1)
91+
->setSipProxy('used-carrier.example.com')
92+
->setCarrierId($usedCarrier->getId())
93+
->setBrandId(1);
94+
95+
/** @var CarrierServer $carrierServer */
96+
$carrierServer = $this->entityTools
97+
->persistDto($carrierServerDto, null, true);
98+
99+
$this->expectException(\DomainException::class);
100+
$this->expectExceptionMessage(
101+
'Cannot delete the last CarrierServer from a Carrier that is being used in outgoing routes'
102+
);
103+
104+
$this->entityTools->remove($carrierServer);
105+
}
106+
}

schema/tests/Provider/CarrierServer/CarrierServerLifeCycleTest.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,8 +211,7 @@ public function it_triggers_remove_lifecycle_services()
211211
{
212212
$this->removeCarrierServer();
213213
$this->assetChangedEntities([
214-
CarrierServer::class,
215-
TrunksLcrRuleTarget::class
214+
CarrierServer::class
216215
]);
217216
}
218217
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace Tests\Provider\OutgoingRouting;
4+
5+
use Ivoz\Provider\Domain\Model\OutgoingRouting\OutgoingRouting;
6+
use Ivoz\Provider\Infrastructure\Persistence\Doctrine\OutgoingRoutingDoctrineRepository;
7+
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
8+
use Tests\DbIntegrationTestHelperTrait;
9+
10+
class OutgoingRoutingRepositoryTest extends KernelTestCase
11+
{
12+
use DbIntegrationTestHelperTrait;
13+
14+
/**
15+
* @test
16+
*/
17+
public function test_runner()
18+
{
19+
$this->it_finds_outgoing_routing_by_carrier();
20+
}
21+
22+
public function it_finds_outgoing_routing_by_carrier()
23+
{
24+
/** @var OutgoingRoutingDoctrineRepository $repository */
25+
$repository = $this
26+
->em
27+
->getRepository(OutgoingRouting::class);
28+
29+
$result = $repository->findByCarrier(1);
30+
31+
$this->assertIsArray($result);
32+
33+
if (!empty($result)) {
34+
$this->assertInstanceOf(
35+
OutgoingRouting::class,
36+
$result[0]
37+
);
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)