Disallow trashing single dynamic segment with active email

[MAILPOET-3463]
This commit is contained in:
Rostislav Wolny
2021-03-19 16:31:21 +01:00
committed by Veljko V
parent 9ffc3372e6
commit f066bc8fdd
3 changed files with 65 additions and 1 deletions

View File

@ -10,6 +10,7 @@ use MailPoet\API\JSON\ResponseBuilders\DynamicSegmentsResponseBuilder;
use MailPoet\Config\AccessControl; use MailPoet\Config\AccessControl;
use MailPoet\Entities\SegmentEntity; use MailPoet\Entities\SegmentEntity;
use MailPoet\Listing\Handler; use MailPoet\Listing\Handler;
use MailPoet\Newsletter\Segment\NewsletterSegmentRepository;
use MailPoet\Segments\DynamicSegments\DynamicSegmentsListingRepository; use MailPoet\Segments\DynamicSegments\DynamicSegmentsListingRepository;
use MailPoet\Segments\DynamicSegments\Exceptions\InvalidFilterException; use MailPoet\Segments\DynamicSegments\Exceptions\InvalidFilterException;
use MailPoet\Segments\DynamicSegments\FilterDataMapper; use MailPoet\Segments\DynamicSegments\FilterDataMapper;
@ -46,6 +47,9 @@ class DynamicSegments extends APIEndpoint {
/** @var FilterDataMapper */ /** @var FilterDataMapper */
private $filterDataMapper; private $filterDataMapper;
/** @var NewsletterSegmentRepository */
private $newsletterSegmentRepository;
public function __construct( public function __construct(
Handler $handler, Handler $handler,
DynamicSegmentsListingRepository $dynamicSegmentsListingRepository, DynamicSegmentsListingRepository $dynamicSegmentsListingRepository,
@ -53,7 +57,8 @@ class DynamicSegments extends APIEndpoint {
SegmentsRepository $segmentsRepository, SegmentsRepository $segmentsRepository,
SegmentSubscribersRepository $segmentSubscribersRepository, SegmentSubscribersRepository $segmentSubscribersRepository,
FilterDataMapper $filterDataMapper, FilterDataMapper $filterDataMapper,
SegmentSaveController $saveController SegmentSaveController $saveController,
NewsletterSegmentRepository $newsletterSegmentRepository
) { ) {
$this->listingHandler = $handler; $this->listingHandler = $handler;
$this->dynamicSegmentsListingRepository = $dynamicSegmentsListingRepository; $this->dynamicSegmentsListingRepository = $dynamicSegmentsListingRepository;
@ -62,6 +67,7 @@ class DynamicSegments extends APIEndpoint {
$this->saveController = $saveController; $this->saveController = $saveController;
$this->segmentSubscribersRepository = $segmentSubscribersRepository; $this->segmentSubscribersRepository = $segmentSubscribersRepository;
$this->filterDataMapper = $filterDataMapper; $this->filterDataMapper = $filterDataMapper;
$this->newsletterSegmentRepository = $newsletterSegmentRepository;
} }
public function get($data = []) { public function get($data = []) {
@ -148,6 +154,17 @@ class DynamicSegments extends APIEndpoint {
]); ]);
} }
$activelyUsedNewslettersSubjects = $this->newsletterSegmentRepository->getSubjectsOfActivelyUsedEmailsForSegments([$segment->getId()]);
if (isset($activelyUsedNewslettersSubjects[$segment->getId()])) {
return $this->badRequest([
Error::BAD_REQUEST => str_replace(
'%$1s',
$activelyUsedNewslettersSubjects[$segment->getId()][0],
_x('List cannot be deleted because its used for %$1s email', 'Alert shown when trying to delete segment, which is assigned to any automatic emails.')
),
]);
}
$this->segmentsRepository->bulkTrash([$segment->getId()], SegmentEntity::TYPE_DYNAMIC); $this->segmentsRepository->bulkTrash([$segment->getId()], SegmentEntity::TYPE_DYNAMIC);
return $this->successResponse( return $this->successResponse(
$this->segmentsResponseBuilder->build($segment), $this->segmentsResponseBuilder->build($segment),

View File

@ -14,6 +14,32 @@ class NewsletterSegmentRepository extends Repository {
return NewsletterSegmentEntity::class; return NewsletterSegmentEntity::class;
} }
public function getSubjectsOfActivelyUsedEmailsForSegments(array $segmentIds): array {
$results = $this->doctrineRepository->createQueryBuilder('ns')
->join('ns.newsletter', 'n')
->leftJoin('n.queues', 'q')
->leftJoin('q.task', 't')
->select('IDENTITY(ns.segment) AS segment_id, n.subject')
->where('(n.type IN (:types) OR n.status = :scheduled OR (t.id IS NOT NULL AND t.status IS NULL))')
->andWhere('ns.segment IN (:segmentIds)')
->setParameter('types', [
NewsletterEntity::TYPE_AUTOMATIC,
NewsletterEntity::TYPE_WELCOME,
NewsletterEntity::TYPE_NOTIFICATION,
])
->setParameter('segmentIds', $segmentIds)
->setParameter('scheduled', NewsletterEntity::STATUS_SCHEDULED)
->addGroupBy('n.id, q.id, t.id')
->getQuery()
->getResult();
$nameMap = [];
foreach ($results as $result) {
$nameMap[(string)$result['segment_id']][] = $result['subject'];
}
return $nameMap;
}
public function getAutomatedEmailSubjectsBySegmentIds(array $segmentIds): array { public function getAutomatedEmailSubjectsBySegmentIds(array $segmentIds): array {
$results = $this->doctrineRepository->createQueryBuilder('ns') $results = $this->doctrineRepository->createQueryBuilder('ns')
->join('ns.newsletter', 'n') ->join('ns.newsletter', 'n')

View File

@ -2,9 +2,12 @@
namespace MailPoet\API\JSON\v1; namespace MailPoet\API\JSON\v1;
use MailPoet\API\JSON\Response as APIResponse;
use MailPoet\DI\ContainerWrapper; use MailPoet\DI\ContainerWrapper;
use MailPoet\Entities\DynamicSegmentFilterData; use MailPoet\Entities\DynamicSegmentFilterData;
use MailPoet\Entities\DynamicSegmentFilterEntity; use MailPoet\Entities\DynamicSegmentFilterEntity;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\NewsletterSegmentEntity;
use MailPoet\Entities\SegmentEntity; use MailPoet\Entities\SegmentEntity;
class DynamicSegmentsTest extends \MailPoetTest { class DynamicSegmentsTest extends \MailPoetTest {
@ -83,6 +86,22 @@ class DynamicSegmentsTest extends \MailPoetTest {
expect($dynamicSegment->getDeletedAt())->notNull(); expect($dynamicSegment->getDeletedAt())->notNull();
} }
public function testItReturnsErrorWhenTrashingSegmentWithActiveNewsletter() {
$dynamicSegment = $this->createDynamicSegmentEntity('Trash test 2', 'description');
$newsletter = new NewsletterEntity();
$newsletter->setSubject('Subject');
$newsletter->setType(NewsletterEntity::TYPE_WELCOME);
$newsletterSegment = new NewsletterSegmentEntity($newsletter, $dynamicSegment);
$this->entityManager->persist($newsletter);
$this->entityManager->persist($newsletterSegment);
$this->entityManager->flush();
$response = $this->endpoint->trash(['id' => $dynamicSegment->getId()]);
$this->entityManager->refresh($dynamicSegment);
expect($response->status)->equals(APIResponse::STATUS_BAD_REQUEST);
expect($response->errors[0]['message'])->equals("List cannot be deleted because its used for 'Subject' email");
}
public function testItCanRestoreASegment() { public function testItCanRestoreASegment() {
$dynamicSegment = $this->createDynamicSegmentEntity('Trash test', 'description'); $dynamicSegment = $this->createDynamicSegmentEntity('Trash test', 'description');
@ -187,5 +206,7 @@ class DynamicSegmentsTest extends \MailPoetTest {
parent::_after(); parent::_after();
$this->truncateEntity(SegmentEntity::class); $this->truncateEntity(SegmentEntity::class);
$this->truncateEntity(DynamicSegmentFilterEntity::class); $this->truncateEntity(DynamicSegmentFilterEntity::class);
$this->truncateEntity(NewsletterSegmentEntity::class);
$this->truncateEntity(NewsletterEntity::class);
} }
} }