This commit is contained in:
emmymayo
2025-02-05 23:15:46 +01:00
commit 7269c99357
16995 changed files with 3389680 additions and 0 deletions
@@ -0,0 +1,75 @@
<?php declare(strict_types = 1);
namespace MailPoet\Router\Endpoints;
if (!defined('ABSPATH')) exit;
use MailPoet\Captcha\CaptchaRenderer;
use MailPoet\Captcha\PageRenderer;
use MailPoet\Config\AccessControl;
class Captcha {
const ENDPOINT = 'captcha';
const ACTION_RENDER = 'render';
const ACTION_IMAGE = 'image';
const ACTION_AUDIO = 'audio';
const ACTION_REFRESH = 'refresh';
private PageRenderer $pageRenderer;
private CaptchaRenderer $captchaRenderer;
public $allowedActions = [
self::ACTION_RENDER,
self::ACTION_IMAGE,
self::ACTION_AUDIO,
self::ACTION_REFRESH,
];
public $permissions = [
'global' => AccessControl::NO_ACCESS_RESTRICTION,
];
public function __construct(
PageRenderer $renderer,
CaptchaRenderer $captchaRenderer
) {
$this->pageRenderer = $renderer;
$this->captchaRenderer = $captchaRenderer;
}
public function render($data) {
$this->pageRenderer->render($data);
}
public function image($data) {
$width = !empty($data['width']) ? (int)$data['width'] : null;
$height = !empty($data['height']) ? (int)$data['height'] : null;
$sessionId = $data['captcha_session_id'] ?? null;
if (!$sessionId) {
return;
}
$this->captchaRenderer->renderImage($sessionId, $width, $height);
exit;
}
public function audio($data) {
$sessionId = $data['captcha_session_id'] ?? null;
if (!$sessionId) {
return;
}
$this->captchaRenderer->renderAudio($sessionId);
exit;
}
public function refresh($data) {
$sessionId = $data['captcha_session_id'] ?? null;
if (!$sessionId) {
return;
}
$this->captchaRenderer->refreshPhrase($sessionId);
}
}
@@ -0,0 +1,52 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Router\Endpoints;
if (!defined('ABSPATH')) exit;
use MailPoet\Config\AccessControl;
use MailPoet\Cron\CronHelper;
use MailPoet\Cron\DaemonHttpRunner;
class CronDaemon {
const ENDPOINT = 'cron_daemon';
const ACTION_RUN = 'run';
const ACTION_PING = 'ping';
const ACTION_PING_RESPONSE = 'pingResponse';
public $allowedActions = [
self::ACTION_RUN,
self::ACTION_PING,
self::ACTION_PING_RESPONSE,
];
public $data;
public $permissions = [
'global' => AccessControl::NO_ACCESS_RESTRICTION,
];
/** @var DaemonHttpRunner */
private $daemonRunner;
/** @var CronHelper */
private $cronHelper;
public function __construct(
DaemonHttpRunner $daemonRunner,
CronHelper $cronHelper
) {
$this->daemonRunner = $daemonRunner;
$this->cronHelper = $cronHelper;
}
public function run($data) {
$this->daemonRunner->run($data);
}
public function ping() {
die(esc_html($this->cronHelper->pingDaemon()));
}
public function pingResponse() {
$this->daemonRunner->ping();
}
}
@@ -0,0 +1,57 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Router\Endpoints;
if (!defined('ABSPATH')) exit;
use MailPoet\Config\AccessControl;
use MailPoet\Form\PreviewPage;
use MailPoet\WP\Functions as WPFunctions;
class FormPreview {
const ENDPOINT = 'form_preview';
const ACTION_VIEW = 'view';
/** @var WPFunctions */
private $wp;
/** @var array|null */
private $data;
/** @var PreviewPage */
private $formPreviewPage;
public $allowedActions = [self::ACTION_VIEW];
public $permissions = [
'global' => AccessControl::NO_ACCESS_RESTRICTION,
];
public function __construct(
WPFunctions $wp,
PreviewPage $formPreviewPage
) {
$this->wp = $wp;
$this->formPreviewPage = $formPreviewPage;
}
public function view(array $data) {
$this->data = $data;
$this->wp->addFilter('the_content', [$this, 'renderContent'], 10);
$this->wp->addFilter('the_title', [$this->formPreviewPage, 'renderTitle'], 10, 2);
$this->wp->addFilter('show_admin_bar', function () {
return false;
});
}
public function renderContent(): string {
if (!array_key_exists('id', $this->data ?? []) || !isset($this->data['form_type'])) {
return '';
}
return $this->formPreviewPage->renderPage(
(int)$this->data['id'],
(string)$this->data['form_type'],
(string)$this->data['editor_url']
);
}
}
@@ -0,0 +1,98 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Router\Endpoints;
if (!defined('ABSPATH')) exit;
use MailPoet\Config\AccessControl;
use MailPoet\Entities\StatisticsUnsubscribeEntity;
use MailPoet\Subscription as UserSubscription;
use MailPoet\Util\Request;
use MailPoet\WP\Functions as WPFunctions;
class Subscription {
const ENDPOINT = 'subscription';
const ACTION_CONFIRM = 'confirm';
const ACTION_MANAGE = 'manage';
const ACTION_UNSUBSCRIBE = 'unsubscribe';
const ACTION_CONFIRM_UNSUBSCRIBE = 'confirmUnsubscribe';
const ACTION_RE_ENGAGEMENT = 'reEngagement';
public $allowedActions = [
self::ACTION_CONFIRM,
self::ACTION_MANAGE,
self::ACTION_UNSUBSCRIBE,
self::ACTION_CONFIRM_UNSUBSCRIBE,
self::ACTION_RE_ENGAGEMENT,
];
public $permissions = [
'global' => AccessControl::NO_ACCESS_RESTRICTION,
];
/** @var UserSubscription\Pages */
private $subscriptionPages;
/** @var WPFunctions */
private $wp;
/*** @var Request */
private $request;
public function __construct(
UserSubscription\Pages $subscriptionPages,
WPFunctions $wp,
Request $request
) {
$this->subscriptionPages = $subscriptionPages;
$this->wp = $wp;
$this->request = $request;
}
public function confirm($data) {
$subscription = $this->initSubscriptionPage(UserSubscription\Pages::ACTION_CONFIRM, $data);
$subscription->confirm();
}
public function confirmUnsubscribe($data) {
$enableUnsubscribeConfirmation = $this->wp->applyFilters('mailpoet_unsubscribe_confirmation_enabled', true);
if ($this->request->isPost()) {
$this->applyOneClickUnsubscribeStrategy($data);
exit;
}
if ($enableUnsubscribeConfirmation) {
$this->initSubscriptionPage(UserSubscription\Pages::ACTION_CONFIRM_UNSUBSCRIBE, $data);
} else {
$this->unsubscribe($data);
}
}
public function manage($data) {
$this->initSubscriptionPage(UserSubscription\Pages::ACTION_MANAGE, $data);
}
public function unsubscribe($data) {
if ($this->request->isPost()) {
$this->applyOneClickUnsubscribeStrategy($data);
exit;
} else {
$subscription = $this->initSubscriptionPage(UserSubscription\Pages::ACTION_UNSUBSCRIBE, $data);
$subscription->unsubscribe(StatisticsUnsubscribeEntity::METHOD_LINK);
}
}
public function reEngagement($data) {
$this->initSubscriptionPage(UserSubscription\Pages::ACTION_RE_ENGAGEMENT, $data);
}
private function initSubscriptionPage($action, $data) {
return $this->subscriptionPages->init($action, $data, true, true);
}
private function applyOneClickUnsubscribeStrategy($data): void {
$subscription = $this->initSubscriptionPage(UserSubscription\Pages::ACTION_UNSUBSCRIBE, $data);
$subscription->unsubscribe(StatisticsUnsubscribeEntity::METHOD_ONE_CLICK);
}
}
@@ -0,0 +1,41 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Router\Endpoints;
if (!defined('ABSPATH')) exit;
use MailPoet\Config\AccessControl;
use MailPoet\NewsletterTemplates\TemplateImageLoader;
class TemplateImage {
const ENDPOINT = 'template_image';
const ACTION_GET_EXTERNAL_IMAGE = 'getExternalImage';
/** @var TemplateImageLoader */
private $templateImageLoader;
public $allowedActions = [self::ACTION_GET_EXTERNAL_IMAGE];
public $permissions = [
'global' => AccessControl::PERMISSION_MANAGE_EMAILS,
];
public function __construct(
TemplateImageLoader $templateImageLoader
) {
$this->templateImageLoader = $templateImageLoader;
}
public function getExternalImage($data = [], $return = false) {
if (empty($_GET['url'])) {
return false;
}
$result = $this->templateImageLoader->loadExternalImage(
sanitize_text_field(wp_unslash($_GET['url']))
);
if ($return) {
return $result;
}
exit;
}
}
@@ -0,0 +1,130 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Router\Endpoints;
if (!defined('ABSPATH')) exit;
use MailPoet\Config\AccessControl;
use MailPoet\Cron\Workers\StatsNotifications\NewsletterLinkRepository;
use MailPoet\Entities\SendingQueueEntity;
use MailPoet\Newsletter\Links\Links;
use MailPoet\Newsletter\NewslettersRepository;
use MailPoet\Newsletter\Sending\SendingQueuesRepository;
use MailPoet\Statistics\Track\Clicks;
use MailPoet\Statistics\Track\Opens;
use MailPoet\Subscribers\LinkTokens;
use MailPoet\Subscribers\SubscribersRepository;
use MailPoet\WP\Functions as WPFunctions;
class Track {
const ENDPOINT = 'track';
const ACTION_CLICK = 'click';
const ACTION_OPEN = 'open';
public $allowedActions = [
self::ACTION_CLICK,
self::ACTION_OPEN,
];
public $permissions = [
'global' => AccessControl::NO_ACCESS_RESTRICTION,
];
/** @var Clicks */
private $clicks;
/** @var Opens */
private $opens;
/** @var LinkTokens */
private $linkTokens;
/** @var SendingQueuesRepository */
private $sendingQueuesRepository;
/** @var SubscribersRepository */
private $subscribersRepository;
/** @var NewslettersRepository */
private $newslettersRepository;
/** @var NewsletterLinkRepository */
private $newsletterLinkRepository;
/** @var Links */
private $links;
public function __construct(
Clicks $clicks,
Opens $opens,
SendingQueuesRepository $sendingQueuesRepository,
SubscribersRepository $subscribersRepository,
NewslettersRepository $newslettersRepository,
NewsletterLinkRepository $newsletterLinkRepository,
LinkTokens $linkTokens,
Links $links
) {
$this->clicks = $clicks;
$this->opens = $opens;
$this->linkTokens = $linkTokens;
$this->sendingQueuesRepository = $sendingQueuesRepository;
$this->subscribersRepository = $subscribersRepository;
$this->newslettersRepository = $newslettersRepository;
$this->newsletterLinkRepository = $newsletterLinkRepository;
$this->links = $links;
}
public function click($data) {
return $this->clicks->track($this->_processTrackData($data));
}
public function open($data) {
return $this->opens->track($this->_processTrackData($data));
}
public function _processTrackData($data) {
$data = (object)$this->links->transformUrlDataObject($data);
if (
empty($data->queue_id) || // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
empty($data->subscriber_id) || // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
empty($data->subscriber_token) // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
) {
return false;
}
$data->queue = $this->sendingQueuesRepository->findOneById($data->queue_id);// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
$data->subscriber = $this->subscribersRepository->findOneById($data->subscriber_id); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
$data->newsletter = (isset($data->newsletter_id)) ? $this->newslettersRepository->findOneById($data->newsletter_id) : null; // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
if (!$data->newsletter && ($data->queue instanceof SendingQueueEntity)) {
$data->newsletter = $data->queue->getNewsletter();
}
if (!empty($data->link_hash)) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
$data->link = $this->newsletterLinkRepository->findOneBy([
'hash' => $data->link_hash, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
'queue' => $data->queue_id, // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
]);
}
$data->userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : null;
return $this->_validateTrackData($data);
}
public function _validateTrackData($data) {
if (!$data->subscriber || !$data->queue || !$data->newsletter) return false;
$subscriberTokenMatch = $this->linkTokens->verifyToken($data->subscriber, $data->subscriber_token); // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
if (!$subscriberTokenMatch) {
$this->terminate(403);
}
// return if this is a WP user previewing the newsletter
if ($data->subscriber->isWPUser() && $data->preview) {
return $data;
}
// check if the newsletter was sent to the subscriber
return ($this->sendingQueuesRepository->isSubscriberProcessed($data->queue, $data->subscriber)) ?
$data :
false;
}
public function terminate($code) {
WPFunctions::get()->statusHeader($code);
WPFunctions::get()->getTemplatePart((string)$code);
exit;
}
}
@@ -0,0 +1,54 @@
<?php // phpcs:ignore SlevomatCodingStandard.TypeHints.DeclareStrictTypes.DeclareStrictTypesMissing
namespace MailPoet\Router\Endpoints;
if (!defined('ABSPATH')) exit;
use MailPoet\Config\AccessControl;
use MailPoet\Newsletter\ViewInBrowser\ViewInBrowserController;
use MailPoet\WP\Functions as WPFunctions;
class ViewInBrowser {
const ENDPOINT = 'view_in_browser';
const ACTION_VIEW = 'view';
public $allowedActions = [self::ACTION_VIEW];
public $permissions = [
'global' => AccessControl::NO_ACCESS_RESTRICTION,
];
/** @var ViewInBrowserController */
private $viewInBrowserController;
public function __construct(
ViewInBrowserController $viewInBrowserController
) {
$this->viewInBrowserController = $viewInBrowserController;
}
public function view(array $data) {
try {
$viewData = $this->viewInBrowserController->view($data);
$this->displayNewsletter($viewData);
} catch (\InvalidArgumentException $e) {
$this->abort();
}
}
private function displayNewsletter($result) {
if ($result) {
header('Content-Type: text/html; charset=utf-8');
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $result;
}
exit;
}
private function abort() {
global $wp_query;// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
WPFunctions::get()->statusHeader(404);
$wp_query->set_404();// phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
exit;
}
}
@@ -0,0 +1 @@
<?php