campaign unsubscribe change
This commit is contained in:
@@ -1,108 +0,0 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM – Open Source CRM application.
|
||||
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://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 Affero General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Modules\Crm\EntryPoints;
|
||||
|
||||
use Espo\Core\Utils\Client\ActionRenderer;
|
||||
use Espo\Modules\Crm\Tools\MassEmail\UnsubscribeService;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\EntryPoint\EntryPoint;
|
||||
use Espo\Core\EntryPoint\Traits\NoAuth;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Core\Exceptions\NotFound;
|
||||
use Espo\Core\Utils\Metadata;
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
class SubscribeAgain implements EntryPoint
|
||||
{
|
||||
use NoAuth;
|
||||
|
||||
public function __construct(
|
||||
private Metadata $metadata,
|
||||
private ActionRenderer $actionRenderer,
|
||||
private UnsubscribeService $unsubscribeService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @throws BadRequest
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function run(Request $request, Response $response): void
|
||||
{
|
||||
$id = $request->getQueryParam('id') ?? null;
|
||||
$emailAddress = $request->getQueryParam('emailAddress') ?? null;
|
||||
$hash = $request->getQueryParam('hash') ?? null;
|
||||
|
||||
if ($emailAddress && $hash) {
|
||||
$this->processWithHash($response, $emailAddress, $hash);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$id || !is_string($id)) {
|
||||
throw new BadRequest("No id.");
|
||||
}
|
||||
|
||||
$this->unsubscribeService->subscribeAgain($id);
|
||||
|
||||
$this->display($response, ['queueItemId' => $id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $actionData
|
||||
*/
|
||||
private function display(Response $response, array $actionData): void
|
||||
{
|
||||
$data = [
|
||||
'actionData' => $actionData,
|
||||
'view' => $this->metadata->get(['clientDefs', 'Campaign', 'subscribeView']),
|
||||
'template' => $this->metadata->get(['clientDefs', 'Campaign', 'subscribeTemplate']),
|
||||
];
|
||||
|
||||
$params = ActionRenderer\Params::create('crm:controllers/unsubscribe', 'subscribeAgain', $data);
|
||||
|
||||
$this->actionRenderer->write($response, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotFound
|
||||
*/
|
||||
private function processWithHash(Response $response, string $emailAddress, string $hash): void
|
||||
{
|
||||
$this->unsubscribeService->subscribeAgainWithHash($emailAddress, $hash);
|
||||
|
||||
$this->display($response, [
|
||||
'emailAddress' => $emailAddress,
|
||||
'hash' => $hash,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -72,9 +72,10 @@ class Unsubscribe implements EntryPoint
|
||||
throw new BadRequest("No id.");
|
||||
}
|
||||
|
||||
$this->unsubscribeService->unsubscribe($id);
|
||||
|
||||
$this->display($response, ['queueItemId' => $id]);
|
||||
$this->display($response, [
|
||||
'queueItemId' => $id,
|
||||
'isSubscribed' => $this->unsubscribeService->isSubscribed($id),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,11 +99,10 @@ class Unsubscribe implements EntryPoint
|
||||
*/
|
||||
private function processWithHash(Response $response, string $emailAddress, string $hash): void
|
||||
{
|
||||
$this->unsubscribeService->unsubscribeWithHash($emailAddress, $hash);
|
||||
|
||||
$this->display($response,[
|
||||
$this->display($response, [
|
||||
'emailAddress' => $emailAddress,
|
||||
'hash' => $hash,
|
||||
'isSubscribed' => $this->unsubscribeService->isSubscribedWithHash($emailAddress, $hash),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,5 +65,23 @@
|
||||
"method": "post",
|
||||
"actionClassName": "Espo\\Modules\\Crm\\Tools\\MassEmail\\Api\\PostUnsubscribe",
|
||||
"noAuth": true
|
||||
},
|
||||
{
|
||||
"route": "/Campaign/unsubscribe/:id",
|
||||
"method": "delete",
|
||||
"actionClassName": "Espo\\Modules\\Crm\\Tools\\MassEmail\\Api\\DeleteUnsubscribe",
|
||||
"noAuth": true
|
||||
},
|
||||
{
|
||||
"route": "/Campaign/unsubscribe/:emailAddress/:hash",
|
||||
"method": "post",
|
||||
"actionClassName": "Espo\\Modules\\Crm\\Tools\\MassEmail\\Api\\PostUnsubscribe",
|
||||
"noAuth": true
|
||||
},
|
||||
{
|
||||
"route": "/Campaign/unsubscribe/:emailAddress/:hash",
|
||||
"method": "delete",
|
||||
"actionClassName": "Espo\\Modules\\Crm\\Tools\\MassEmail\\Api\\DeleteUnsubscribe",
|
||||
"noAuth": true
|
||||
}
|
||||
]
|
||||
|
||||
+30
-18
@@ -1,3 +1,4 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
@@ -26,27 +27,38 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/campaign/subscribe-again', ['view'], function (Dep) {
|
||||
namespace Espo\Modules\Crm\Tools\MassEmail\Api;
|
||||
|
||||
return Dep.extend({
|
||||
use Espo\Core\Api\Action;
|
||||
use Espo\Core\Api\Request;
|
||||
use Espo\Core\Api\Response;
|
||||
use Espo\Core\Api\ResponseComposer;
|
||||
use Espo\Core\Exceptions\BadRequest;
|
||||
use Espo\Modules\Crm\Tools\MassEmail\UnsubscribeService;
|
||||
|
||||
template: 'crm:campaign/subscribe-again',
|
||||
/** @noinspection PhpUnused */
|
||||
class DeleteUnsubscribe implements Action
|
||||
{
|
||||
public function __construct(private UnsubscribeService $service) {}
|
||||
|
||||
data: function () {
|
||||
var revertUrl;
|
||||
public function process(Request $request): Response
|
||||
{
|
||||
$id = $request->getRouteParam('id');
|
||||
$hash = $request->getRouteParam('hash');
|
||||
$emailAddress = $request->getRouteParam('emailAddress');
|
||||
|
||||
var actionData = this.options.actionData;
|
||||
if ($hash && $emailAddress) {
|
||||
$this->service->subscribeAgainWithHash($emailAddress, $hash);
|
||||
|
||||
if (actionData.hash && actionData.emailAddress) {
|
||||
revertUrl = '?entryPoint=unsubscribe&emailAddress=' + actionData.emailAddress +
|
||||
'&hash=' + actionData.hash;
|
||||
} else {
|
||||
revertUrl = '?entryPoint=unsubscribe&id=' + actionData.queueItemId;
|
||||
}
|
||||
return ResponseComposer::json(true);
|
||||
}
|
||||
|
||||
return {
|
||||
revertUrl: revertUrl,
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
if (!$id) {
|
||||
throw new BadRequest();
|
||||
}
|
||||
|
||||
$this->service->subscribeAgain($id);
|
||||
|
||||
return ResponseComposer::json(true);
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,14 @@ class PostUnsubscribe implements Action
|
||||
public function process(Request $request): Response
|
||||
{
|
||||
$id = $request->getRouteParam('id');
|
||||
$hash = $request->getRouteParam('hash');
|
||||
$emailAddress = $request->getRouteParam('emailAddress');
|
||||
|
||||
if ($hash && $emailAddress) {
|
||||
$this->service->unsubscribeWithHash($emailAddress, $hash);
|
||||
|
||||
return ResponseComposer::json(true);
|
||||
}
|
||||
|
||||
if (!$id) {
|
||||
throw new BadRequest();
|
||||
|
||||
@@ -42,6 +42,7 @@ use Espo\Modules\Crm\Entities\TargetList;
|
||||
use Espo\Modules\Crm\Tools\Campaign\LogService;
|
||||
use Espo\Modules\Crm\Tools\MassEmail\Util as MassEmailUtil;
|
||||
use Espo\ORM\Collection;
|
||||
use Espo\ORM\Entity;
|
||||
use Espo\Repositories\EmailAddress as EmailAddressRepository;
|
||||
|
||||
class UnsubscribeService
|
||||
@@ -58,6 +59,234 @@ class UnsubscribeService
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function unsubscribe(string $queueItemId): void
|
||||
{
|
||||
[$queueItem, $campaign, $massEmail, $target] = $this->getRecords($queueItemId);
|
||||
|
||||
if ($massEmail->optOutEntirely()) {
|
||||
$emailAddress = $target->get('emailAddress');
|
||||
|
||||
if ($emailAddress) {
|
||||
$address = $this->getEmailAddressRepository()->getByAddress($emailAddress);
|
||||
|
||||
if ($address) {
|
||||
$address->setOptedOut(true);
|
||||
$this->entityManager->saveEntity($address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$link = $this->util->getLinkByEntityType($target->getEntityType());
|
||||
|
||||
/** @var Collection<TargetList> $targetListList */
|
||||
$targetListList = $this->entityManager
|
||||
->getRDBRepository(MassEmail::ENTITY_TYPE)
|
||||
->getRelation($massEmail, 'targetLists')
|
||||
->find();
|
||||
|
||||
foreach ($targetListList as $targetList) {
|
||||
$relation = $this->entityManager
|
||||
->getRDBRepository(TargetList::ENTITY_TYPE)
|
||||
->getRelation($targetList, $link);
|
||||
|
||||
if ($relation->getColumn($target, 'optedOut')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$relation->updateColumnsById($target->getId(), ['optedOut' => true]);
|
||||
|
||||
$hookData = [
|
||||
'link' => $link,
|
||||
'targetId' => $target->getId(),
|
||||
'targetType' => $target->getEntityType(),
|
||||
];
|
||||
|
||||
$this->hookManager->process(
|
||||
TargetList::ENTITY_TYPE,
|
||||
'afterOptOut',
|
||||
$targetList,
|
||||
[],
|
||||
$hookData
|
||||
);
|
||||
}
|
||||
|
||||
$this->hookManager->process($target->getEntityType(), 'afterOptOut', $target);
|
||||
|
||||
if ($campaign) {
|
||||
$this->service->logOptedOut($campaign->getId(), $queueItem, $target);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function subscribeAgain(string $queueItemId): void
|
||||
{
|
||||
[, $campaign, $massEmail, $target] = $this->getRecords($queueItemId);
|
||||
|
||||
if ($massEmail->optOutEntirely()) {
|
||||
$emailAddress = $target->get('emailAddress');
|
||||
|
||||
if ($emailAddress) {
|
||||
$ea = $this->getEmailAddressRepository()->getByAddress($emailAddress);
|
||||
|
||||
if ($ea) {
|
||||
$ea->setOptedOut(false);
|
||||
$this->entityManager->saveEntity($ea);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$link = $this->util->getLinkByEntityType($target->getEntityType());
|
||||
|
||||
/** @var Collection<TargetList> $targetListList */
|
||||
$targetListList = $this->entityManager
|
||||
->getRDBRepository(MassEmail::ENTITY_TYPE)
|
||||
->getRelation($massEmail, 'targetLists')
|
||||
->find();
|
||||
|
||||
foreach ($targetListList as $targetList) {
|
||||
$relation = $this->entityManager
|
||||
->getRDBRepository(TargetList::ENTITY_TYPE)
|
||||
->getRelation($targetList, $link);
|
||||
|
||||
if (!$relation->getColumn($target, 'optedOut')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$relation->updateColumnsById($target->getId(), ['optedOut' => false]);
|
||||
|
||||
$hookData = [
|
||||
'link' => $link,
|
||||
'targetId' => $target->getId(),
|
||||
'targetType' => $target->getEntityType(),
|
||||
];
|
||||
|
||||
$this->hookManager
|
||||
->process(TargetList::ENTITY_TYPE, 'afterCancelOptOut', $targetList, [], $hookData);
|
||||
}
|
||||
|
||||
$this->hookManager->process($target->getEntityType(), 'afterCancelOptOut', $target);
|
||||
|
||||
if ($campaign) {
|
||||
$logRecord = $this->entityManager
|
||||
->getRDBRepository(CampaignLogRecord::ENTITY_TYPE)
|
||||
->where([
|
||||
'queueItemId' => $queueItemId,
|
||||
'action' => CampaignLogRecord::ACTION_OPTED_OUT,
|
||||
])
|
||||
->order('createdAt', true)
|
||||
->findOne();
|
||||
|
||||
if ($logRecord) {
|
||||
$this->entityManager->removeEntity($logRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function unsubscribeWithHash(string $emailAddress, string $hash): void
|
||||
{
|
||||
$address = $this->getEmailAddressWithHash($emailAddress, $hash);
|
||||
|
||||
if ($address->isOptedOut()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$address->setOptedOut(true);
|
||||
$this->entityManager->saveEntity($address);
|
||||
|
||||
$entityList = $this->getEmailAddressRepository()->getEntityListByAddressId($address->getId());
|
||||
|
||||
foreach ($entityList as $entity) {
|
||||
$this->hookManager->process($entity->getEntityType(), 'afterOptOut', $entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function subscribeAgainWithHash(string $emailAddress, string $hash): void
|
||||
{
|
||||
$address = $this->getEmailAddressWithHash($emailAddress, $hash);
|
||||
|
||||
if (!$address->isOptedOut()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$entityList = $this->getEmailAddressRepository()->getEntityListByAddressId($address->getId());
|
||||
|
||||
$address->setOptedOut(false);
|
||||
$this->entityManager->saveEntity($address);
|
||||
|
||||
foreach ($entityList as $entity) {
|
||||
$this->hookManager->process($entity->getEntityType(), 'afterCancelOptOut', $entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function isSubscribed(string $queueItemId): bool
|
||||
{
|
||||
[,, $massEmail, $target] = $this->getRecords($queueItemId);
|
||||
|
||||
if ($massEmail->optOutEntirely()) {
|
||||
$emailAddress = $target->get('emailAddress');
|
||||
|
||||
if ($emailAddress) {
|
||||
$address = $this->getEmailAddressRepository()->getByAddress($emailAddress);
|
||||
|
||||
if ($address && !$address->isOptedOut()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$link = $this->util->getLinkByEntityType($target->getEntityType());
|
||||
|
||||
/** @var Collection<TargetList> $targetListList */
|
||||
$targetListList = $this->entityManager
|
||||
->getRDBRepository(MassEmail::ENTITY_TYPE)
|
||||
->getRelation($massEmail, 'targetLists')
|
||||
->find();
|
||||
|
||||
foreach ($targetListList as $targetList) {
|
||||
$relation = $this->entityManager
|
||||
->getRDBRepository(TargetList::ENTITY_TYPE)
|
||||
->getRelation($targetList, $link);
|
||||
|
||||
if (!$relation->getColumn($target, 'optedOut')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function isSubscribedWithHash(string $emailAddress, string $hash): bool
|
||||
{
|
||||
$address = $this->getEmailAddressWithHash($emailAddress, $hash);
|
||||
|
||||
return !$address->isOptedOut();
|
||||
}
|
||||
|
||||
private function getEmailAddressRepository(): EmailAddressRepository
|
||||
{
|
||||
/** @var EmailAddressRepository */
|
||||
return $this->entityManager->getRepository(EmailAddress::ENTITY_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{EmailQueueItem, ?Campaign, MassEmail, Entity}
|
||||
* @throws NotFound
|
||||
*/
|
||||
private function getRecords(string $queueItemId): array
|
||||
{
|
||||
/** @var ?EmailQueueItem $queueItem */
|
||||
$queueItem = $this->entityManager->getEntityById(EmailQueueItem::ENTITY_TYPE, $queueItemId);
|
||||
@@ -94,165 +323,13 @@ class UnsubscribeService
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
if ($massEmail->optOutEntirely()) {
|
||||
$emailAddress = $target->get('emailAddress');
|
||||
|
||||
if ($emailAddress) {
|
||||
$ea = $this->getEmailAddressRepository()->getByAddress($emailAddress);
|
||||
|
||||
if ($ea) {
|
||||
$ea->setOptedOut(true);
|
||||
$this->entityManager->saveEntity($ea);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$link = $this->util->getLinkByEntityType($target->getEntityType());
|
||||
|
||||
/** @var Collection<TargetList> $targetListList */
|
||||
$targetListList = $this->entityManager
|
||||
->getRDBRepository(MassEmail::ENTITY_TYPE)
|
||||
->getRelation($massEmail, 'targetLists')
|
||||
->find();
|
||||
|
||||
foreach ($targetListList as $targetList) {
|
||||
$relation = $this->entityManager
|
||||
->getRDBRepository(TargetList::ENTITY_TYPE)
|
||||
->getRelation($targetList, $link);
|
||||
|
||||
if ($relation->getColumn($target, 'optedOut')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$relation->updateColumnsById($target->getId(), ['optedOut' => true]);
|
||||
|
||||
$hookData = [
|
||||
'link' => $link,
|
||||
'targetId' => $targetId,
|
||||
'targetType' => $targetType,
|
||||
];
|
||||
|
||||
$this->hookManager->process(
|
||||
TargetList::ENTITY_TYPE,
|
||||
'afterOptOut',
|
||||
$targetList,
|
||||
[],
|
||||
$hookData
|
||||
);
|
||||
}
|
||||
|
||||
$this->hookManager->process($target->getEntityType(), 'afterOptOut', $target);
|
||||
|
||||
if ($campaign) {
|
||||
$this->service->logOptedOut($campaign->getId(), $queueItem, $target);
|
||||
}
|
||||
return [$queueItem, $campaign, $massEmail, $target];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function subscribeAgain(string $queueItemId): void
|
||||
{
|
||||
/** @var ?EmailQueueItem $queueItem */
|
||||
$queueItem = $this->entityManager->getEntity(EmailQueueItem::ENTITY_TYPE, $queueItemId);
|
||||
|
||||
if (!$queueItem) {
|
||||
throw new NotFound("No item.");
|
||||
}
|
||||
|
||||
$campaign = null;
|
||||
$massEmailId = $queueItem->getMassEmailId();
|
||||
|
||||
if (!$massEmailId) {
|
||||
throw new NotFound("No Mass Email ID.");
|
||||
}
|
||||
|
||||
/** @var ?MassEmail $massEmail */
|
||||
$massEmail = $this->entityManager->getEntityById(MassEmail::ENTITY_TYPE, $massEmailId);
|
||||
|
||||
if (!$massEmail) {
|
||||
throw new NotFound("Mass Email not found.");
|
||||
}
|
||||
|
||||
if ($massEmail->getCampaignId()) {
|
||||
/** @var ?Campaign $campaign */
|
||||
$campaign = $this->entityManager->getEntityById(Campaign::ENTITY_TYPE, $massEmail->getCampaignId());
|
||||
}
|
||||
|
||||
$targetType = $queueItem->getTargetType();
|
||||
$targetId = $queueItem->getTargetId();
|
||||
|
||||
$target = $this->entityManager->getEntityById($targetType, $targetId);
|
||||
|
||||
if (!$target) {
|
||||
throw new NotFound("Record not found.");
|
||||
}
|
||||
|
||||
if ($massEmail->optOutEntirely()) {
|
||||
$emailAddress = $target->get('emailAddress');
|
||||
|
||||
if ($emailAddress) {
|
||||
$ea = $this->getEmailAddressRepository()->getByAddress($emailAddress);
|
||||
|
||||
if ($ea) {
|
||||
$ea->setOptedOut(false);
|
||||
$this->entityManager->saveEntity($ea);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$link = $this->util->getLinkByEntityType($target->getEntityType());
|
||||
|
||||
/** @var Collection<TargetList> $targetListList */
|
||||
$targetListList = $this->entityManager
|
||||
->getRDBRepository(MassEmail::ENTITY_TYPE)
|
||||
->getRelation($massEmail, 'targetLists')
|
||||
->find();
|
||||
|
||||
foreach ($targetListList as $targetList) {
|
||||
$relation = $this->entityManager
|
||||
->getRDBRepository(TargetList::ENTITY_TYPE)
|
||||
->getRelation($targetList, $link);
|
||||
|
||||
if (!$relation->getColumn($target, 'optedOut')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$relation->updateColumnsById($target->getId(), ['optedOut' => false]);
|
||||
|
||||
$hookData = [
|
||||
'link' => $link,
|
||||
'targetId' => $targetId,
|
||||
'targetType' => $targetType,
|
||||
];
|
||||
|
||||
$this->hookManager
|
||||
->process(TargetList::ENTITY_TYPE, 'afterCancelOptOut', $targetList, [], $hookData);
|
||||
}
|
||||
|
||||
$this->hookManager->process($target->getEntityType(), 'afterCancelOptOut', $target);
|
||||
|
||||
if ($campaign) {
|
||||
$logRecord = $this->entityManager
|
||||
->getRDBRepository(CampaignLogRecord::ENTITY_TYPE)
|
||||
->where([
|
||||
'queueItemId' => $queueItemId,
|
||||
'action' => CampaignLogRecord::ACTION_OPTED_OUT,
|
||||
])
|
||||
->order('createdAt', true)
|
||||
->findOne();
|
||||
|
||||
if ($logRecord) {
|
||||
$this->entityManager->removeEntity($logRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function unsubscribeWithHash(string $emailAddress, string $hash): void
|
||||
private function getEmailAddressWithHash(string $emailAddress, string $hash): EmailAddress
|
||||
{
|
||||
$hash2 = $this->hasher->hash($emailAddress);
|
||||
|
||||
@@ -260,64 +337,12 @@ class UnsubscribeService
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
$repository = $this->getEmailAddressRepository();
|
||||
|
||||
$address = $repository->getByAddress($emailAddress);
|
||||
$address = $this->getEmailAddressRepository()->getByAddress($emailAddress);
|
||||
|
||||
if (!$address) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
$entityList = $repository->getEntityListByAddressId($address->getId());
|
||||
|
||||
if ($address->isOptedOut()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$address->setOptedOut(true);
|
||||
$this->entityManager->saveEntity($address);
|
||||
|
||||
foreach ($entityList as $entity) {
|
||||
$this->hookManager->process($entity->getEntityType(), 'afterOptOut', $entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NotFound
|
||||
*/
|
||||
public function subscribeAgainWithHash(string $emailAddress, string $hash): void
|
||||
{
|
||||
$hash2 = $this->hasher->hash($emailAddress);
|
||||
|
||||
if ($hash2 !== $hash) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
$repository = $this->getEmailAddressRepository();
|
||||
|
||||
$address = $repository->getByAddress($emailAddress);
|
||||
|
||||
if (!$address) {
|
||||
throw new NotFound();
|
||||
}
|
||||
|
||||
$entityList = $repository->getEntityListByAddressId($address->getId());
|
||||
|
||||
if (!$address->isOptedOut()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$address->setOptedOut(false);
|
||||
$this->entityManager->saveEntity($address);
|
||||
|
||||
foreach ($entityList as $entity) {
|
||||
$this->hookManager->process($entity->getEntityType(), 'afterCancelOptOut', $entity);
|
||||
}
|
||||
}
|
||||
|
||||
private function getEmailAddressRepository(): EmailAddressRepository
|
||||
{
|
||||
/** @var EmailAddressRepository */
|
||||
return $this->entityManager->getRepository(EmailAddress::ENTITY_TYPE);
|
||||
return $address;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<div class="container content">
|
||||
<div class="block-center-md">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
{{translate 'subscribedAgain' category='messages' scope='Campaign'}}
|
||||
</p>
|
||||
<p>
|
||||
<a class="btn btn-default btn-sm" href="{{revertUrl}}">{{translate 'Unsubscribe again' scope='Campaign'}}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -3,10 +3,17 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
{{translate 'unsubscribed' category='messages' scope='Campaign'}}
|
||||
</p>
|
||||
<p>
|
||||
<a class="btn btn-default btn-sm" href="{{revertUrl}}">{{translate 'Subscribe again' scope='Campaign'}}</a>
|
||||
{{#if isSubscribed}}
|
||||
<a
|
||||
class="btn btn-primary"
|
||||
data-action="unsubscribe"
|
||||
>{{translate 'Unsubscribe' scope='Campaign'}}</a>
|
||||
{{else}}
|
||||
<a
|
||||
class="btn btn-default"
|
||||
data-action="subscribe"
|
||||
>{{translate 'Subscribe again' scope='Campaign'}}</a>
|
||||
{{/if}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -41,18 +41,6 @@ class UnsubscribeController extends Controller {
|
||||
view.render();
|
||||
});
|
||||
}
|
||||
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
actionSubscribeAgain(data) {
|
||||
const viewName = data.view || 'crm:views/campaign/subscribe-again';
|
||||
|
||||
this.entire(viewName, {
|
||||
actionData: data.actionData,
|
||||
template: data.template,
|
||||
}, view => {
|
||||
view.render();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default UnsubscribeController;
|
||||
|
||||
@@ -26,24 +26,59 @@
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('crm:views/campaign/unsubscribe', ['view'], function (Dep) {
|
||||
import View from 'view';
|
||||
|
||||
return Dep.extend({
|
||||
class CampaignUnsubscribeView extends View {
|
||||
|
||||
template: 'crm:campaign/unsubscribe',
|
||||
template = 'crm:campaign/unsubscribe'
|
||||
|
||||
data: function () {
|
||||
var revertUrl;
|
||||
data() {
|
||||
return {
|
||||
isSubscribed: this.isSubscribed,
|
||||
};
|
||||
}
|
||||
|
||||
var actionData = this.options.actionData;
|
||||
setup() {
|
||||
super.setup();
|
||||
|
||||
revertUrl = actionData.hash && actionData.emailAddress ?
|
||||
'?entryPoint=subscribeAgain&emailAddress=' + actionData.emailAddress + '&hash=' + actionData.hash :
|
||||
'?entryPoint=subscribeAgain&id=' + actionData.queueItemId;
|
||||
this.actionData = /** @type {Record} */this.options.actionData;
|
||||
|
||||
return {
|
||||
revertUrl: revertUrl,
|
||||
};
|
||||
},
|
||||
});
|
||||
});
|
||||
this.isSubscribed = this.actionData.isSubscribed;
|
||||
|
||||
const endpointUrl = this.actionData.hash && this.actionData.emailAddress ?
|
||||
`Campaign/unsubscribe/${this.actionData.emailAddress}/${this.actionData.hash}`:
|
||||
`Campaign/unsubscribe/${this.actionData.queueItemId}`;
|
||||
|
||||
this.addActionHandler('subscribe', () => {
|
||||
Espo.Ui.notify(' ... ');
|
||||
|
||||
Espo.Ajax.deleteRequest(endpointUrl)
|
||||
.then(() => {
|
||||
this.isSubscribed = true;
|
||||
this.reRender().then(() => {
|
||||
const message = this.translate('subscribedAgain', 'messages', 'Campaign');
|
||||
|
||||
Espo.Ui.notify(message, 'success', 0, {closeButton: true});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.addActionHandler('unsubscribe', () => {
|
||||
Espo.Ui.notify(' ... ');
|
||||
|
||||
Espo.Ajax.postRequest(endpointUrl)
|
||||
.then(() => {
|
||||
Espo.Ui.success(this.translate('unsubscribed', 'messages', 'Campaign'), {closeButton: true});
|
||||
|
||||
this.isSubscribed = false;
|
||||
this.reRender().then(() => {
|
||||
const message = this.translate('unsubscribed', 'messages', 'Campaign');
|
||||
|
||||
Espo.Ui.notify(message, 'success', 0, {closeButton: true});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default CampaignUnsubscribeView;
|
||||
|
||||
Reference in New Issue
Block a user