Add unsubscribe API method
It can be used by calling: ``` $mailpoet_api = \MailPoet\API\API::MP('v1'); $mailpoet_api->unsubscribe($subscriberId); ``` [MAILPOET-5152]
This commit is contained in:
committed by
Aschepikov
parent
d37b961c2b
commit
c507229dd2
@ -68,6 +68,10 @@ class API {
|
||||
return $this->subscribers->unsubscribeFromLists($subscriberId, $listIds);
|
||||
}
|
||||
|
||||
public function unsubscribe($subscriberIdOrEmail) {
|
||||
return $this->subscribers->unsubscribe($subscriberIdOrEmail);
|
||||
}
|
||||
|
||||
public function getLists(): array {
|
||||
return $this->segments->getAll();
|
||||
}
|
||||
|
@ -24,4 +24,5 @@ class APIException extends \Exception {
|
||||
const LIST_USED_IN_FORM = 21;
|
||||
const FAILED_TO_DELETE_LIST = 22;
|
||||
const LIST_TYPE_IS_NOT_SUPPORTED = 23;
|
||||
const SUBSCRIBER_ALREADY_UNSUBSCRIBED = 24;
|
||||
}
|
||||
|
@ -4,11 +4,13 @@ namespace MailPoet\API\MP\v1;
|
||||
|
||||
use MailPoet\API\JSON\ResponseBuilders\SubscribersResponseBuilder;
|
||||
use MailPoet\Entities\SegmentEntity;
|
||||
use MailPoet\Entities\StatisticsUnsubscribeEntity;
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoet\Listing\ListingDefinition;
|
||||
use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
|
||||
use MailPoet\Segments\SegmentsRepository;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Statistics\Track\Unsubscribes;
|
||||
use MailPoet\Subscribers\ConfirmationEmailMailer;
|
||||
use MailPoet\Subscribers\NewSubscriberNotificationMailer;
|
||||
use MailPoet\Subscribers\RequiredCustomFieldValidator;
|
||||
@ -62,6 +64,9 @@ class Subscribers {
|
||||
/** @var SubscriberListingRepository */
|
||||
private $subscriberListingRepository;
|
||||
|
||||
/** @var Unsubscribes */
|
||||
private $unsubscribesTracker;
|
||||
|
||||
public function __construct (
|
||||
ConfirmationEmailMailer $confirmationEmailMailer,
|
||||
NewSubscriberNotificationMailer $newSubscriberNotificationMailer,
|
||||
@ -74,7 +79,8 @@ class Subscribers {
|
||||
WelcomeScheduler $welcomeScheduler,
|
||||
RequiredCustomFieldValidator $requiredCustomFieldsValidator,
|
||||
SubscriberListingRepository $subscriberListingRepository,
|
||||
WPFunctions $wp
|
||||
WPFunctions $wp,
|
||||
Unsubscribes $unsubscribesTracker
|
||||
) {
|
||||
$this->confirmationEmailMailer = $confirmationEmailMailer;
|
||||
$this->newSubscriberNotificationMailer = $newSubscriberNotificationMailer;
|
||||
@ -88,6 +94,7 @@ class Subscribers {
|
||||
$this->requiredCustomFieldsValidator = $requiredCustomFieldsValidator;
|
||||
$this->wp = $wp;
|
||||
$this->subscriberListingRepository = $subscriberListingRepository;
|
||||
$this->unsubscribesTracker = $unsubscribesTracker;
|
||||
}
|
||||
|
||||
public function getSubscriber($subscriberIdOrEmail): array {
|
||||
@ -229,6 +236,28 @@ class Subscribers {
|
||||
return $this->subscribersResponseBuilder->build($subscriber);
|
||||
}
|
||||
|
||||
public function unsubscribe($subscriberIdOrEmail): array {
|
||||
$this->checkSubscriberParam($subscriberIdOrEmail);
|
||||
$subscriber = $this->findSubscriber($subscriberIdOrEmail);
|
||||
|
||||
if ($subscriber->getStatus() === SubscriberEntity::STATUS_UNSUBSCRIBED) {
|
||||
throw new APIException(__('This subscriber is already unsubscribed.', 'mailpoet'), APIException::SUBSCRIBER_ALREADY_UNSUBSCRIBED);
|
||||
}
|
||||
|
||||
$this->unsubscribesTracker->track(
|
||||
(int)$subscriber->getId(),
|
||||
StatisticsUnsubscribeEntity::SOURCE_MP_API
|
||||
);
|
||||
|
||||
$subscriber->setStatus(SubscriberEntity::STATUS_UNSUBSCRIBED);
|
||||
$this->subscribersRepository->persist($subscriber);
|
||||
$this->subscribersRepository->flush();
|
||||
|
||||
$this->subscribersSegmentRepository->unsubscribeFromSegments($subscriber);
|
||||
|
||||
return $this->subscribersResponseBuilder->build($subscriber);
|
||||
}
|
||||
|
||||
public function unsubscribeFromLists($subscriberIdOrEmail, array $listIds): array {
|
||||
$this->checkSubscriberAndListParams($subscriberIdOrEmail, $listIds);
|
||||
$subscriber = $this->findSubscriber($subscriberIdOrEmail);
|
||||
@ -321,6 +350,13 @@ class Subscribers {
|
||||
if (empty($listIds)) {
|
||||
throw new APIException(__('At least one segment ID is required.', 'mailpoet'), APIException::SEGMENT_REQUIRED);
|
||||
}
|
||||
$this->checkSubscriberParam($subscriberIdOrEmail);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws APIException
|
||||
*/
|
||||
private function checkSubscriberParam($subscriberIdOrEmail): void {
|
||||
if (empty($subscriberIdOrEmail)) {
|
||||
throw new APIException(__('A subscriber is required.', 'mailpoet'), APIException::SUBSCRIBER_NOT_EXISTS);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ class StatisticsUnsubscribeEntity {
|
||||
const SOURCE_ADMINISTRATOR = 'admin';
|
||||
const SOURCE_ORDER_CHECKOUT = 'order_checkout';
|
||||
const SOURCE_AUTOMATION = 'automation';
|
||||
const SOURCE_MP_API = 'mp_api';
|
||||
|
||||
const METHOD_LINK = 'link';
|
||||
const METHOD_ONE_CLICK = 'one_click';
|
||||
|
@ -14,6 +14,7 @@ use MailPoet\Config\Changelog;
|
||||
use MailPoet\CustomFields\CustomFieldsRepository;
|
||||
use MailPoet\Entities\CustomFieldEntity;
|
||||
use MailPoet\Entities\SegmentEntity;
|
||||
use MailPoet\Entities\StatisticsUnsubscribeEntity;
|
||||
use MailPoet\Entities\SubscriberEntity;
|
||||
use MailPoet\Entities\SubscriberSegmentEntity;
|
||||
use MailPoet\Models\ScheduledTask;
|
||||
@ -284,6 +285,75 @@ class SubscribersTest extends \MailPoetTest {
|
||||
$API->subscribeToLists($subscriber->getId(), [$segment->getId()], $options);
|
||||
}
|
||||
|
||||
public function testUnsubscribeRaisesExceptionWhenSubscriberIdIsNotPassed() {
|
||||
try {
|
||||
$this->getApi()->unsubscribe(false);
|
||||
$this->fail('Subscriber does not exist exception should have been thrown.');
|
||||
} catch (\Exception $e) {
|
||||
expect($e->getMessage())->equals('A subscriber is required.');
|
||||
}
|
||||
}
|
||||
|
||||
public function testUnsubscribeRaisesExceptionWhenSubscriberDoesNotExist() {
|
||||
try {
|
||||
$this->getApi()->unsubscribe('asdf');
|
||||
$this->fail('Subscriber does not exist exception should have been thrown.');
|
||||
} catch (\Exception $e) {
|
||||
expect($e->getMessage())->equals('This subscriber does not exist.');
|
||||
}
|
||||
}
|
||||
|
||||
public function testUnsubscribeRaisesExceptionIfSubscriberAlreadyUnsubscribed() {
|
||||
$subscriber = $this->subscriberFactory
|
||||
->withStatus(SubscriberEntity::STATUS_UNSUBSCRIBED)
|
||||
->create();
|
||||
|
||||
try {
|
||||
$this->getApi()->unsubscribe($subscriber->getId());
|
||||
$this->fail('Subscriber already unsubscribed exception should have been thrown.');
|
||||
} catch (\Exception $e) {
|
||||
expect($e->getMessage())->equals('This subscriber is already unsubscribed.');
|
||||
}
|
||||
}
|
||||
|
||||
public function testUnsubscribesSubscriberFromAllListsAndChangesItsStatus() {
|
||||
$subscriber = $this->subscriberFactory->create();
|
||||
$segment1 = $this->getSegment('Segment 1');
|
||||
$segment2 = $this->getSegment('Segment 2');
|
||||
$this->getApi()->subscribeToLists($subscriber->getId(), [$segment1->getId(), $segment2->getId()]);
|
||||
$this->assertSame(SubscriberEntity::STATUS_SUBSCRIBED, $subscriber->getStatus());
|
||||
|
||||
$result = $this->getApi()->unsubscribe($subscriber->getId());
|
||||
$this->assertSame(SubscriberEntity::STATUS_UNSUBSCRIBED, $subscriber->getStatus());
|
||||
|
||||
foreach ($subscriber->getSubscriberSegments() as $subscriberSegment) {
|
||||
$this->assertSame(SubscriberEntity::STATUS_UNSUBSCRIBED, $subscriberSegment->getStatus());
|
||||
}
|
||||
|
||||
$this->assertSame(SubscriberEntity::STATUS_UNSUBSCRIBED, $result['status']);
|
||||
$this->assertSame(SubscriberEntity::STATUS_UNSUBSCRIBED, $result['subscriptions'][0]['status']);
|
||||
$this->assertSame(SubscriberEntity::STATUS_UNSUBSCRIBED, $result['subscriptions'][1]['status']);
|
||||
}
|
||||
|
||||
public function testUnsubscribesSubscriberFromAllListsAndChangesItsStatusUsingEmailInsteadOfId() {
|
||||
$subscriber = $this->subscriberFactory->create();
|
||||
$segment1 = $this->getSegment('Segment 1');
|
||||
$segment2 = $this->getSegment('Segment 2');
|
||||
$this->getApi()->subscribeToLists($subscriber->getId(), [$segment1->getId(), $segment2->getId()]);
|
||||
$this->assertSame(SubscriberEntity::STATUS_SUBSCRIBED, $subscriber->getStatus());
|
||||
|
||||
$result = $this->getApi()->unsubscribe($subscriber->getEmail());
|
||||
$this->assertSame(SubscriberEntity::STATUS_UNSUBSCRIBED, $subscriber->getStatus());
|
||||
|
||||
foreach ($subscriber->getSubscriberSegments() as $subscriberSegment) {
|
||||
$this->assertSame(SubscriberEntity::STATUS_UNSUBSCRIBED, $subscriberSegment->getStatus());
|
||||
}
|
||||
|
||||
$this->assertSame(SubscriberEntity::STATUS_UNSUBSCRIBED, $result['status']);
|
||||
$this->assertSame(SubscriberEntity::STATUS_UNSUBSCRIBED, $result['subscriptions'][0]['status']);
|
||||
$this->assertSame(SubscriberEntity::STATUS_UNSUBSCRIBED, $result['subscriptions'][1]['status']);
|
||||
}
|
||||
|
||||
public function testItDoesNotUnsubscribeWhenSubscriberIdNotPassedFromLists() {
|
||||
try {
|
||||
$this->getApi()->unsubscribeFromLists(false, [1,2,3]);
|
||||
@ -961,6 +1031,7 @@ class SubscribersTest extends \MailPoetTest {
|
||||
}
|
||||
|
||||
public function _after() {
|
||||
$this->truncateEntity(StatisticsUnsubscribeEntity::class);
|
||||
$this->truncateEntity(SubscriberSegmentEntity::class);
|
||||
$this->truncateEntity(SubscriberEntity::class);
|
||||
$this->truncateEntity(SegmentEntity::class);
|
||||
|
Reference in New Issue
Block a user