PublicEmailController.php
1 month ago
PublicEmailRoute.php
1 month ago
ShareMetadataBuilder.php
2 months ago
ShareVisibility.php
2 months ago
index.php
2 months ago
PublicEmailController.php
90 lines
| 1 | <?php declare(strict_types = 1); |
| 2 | |
| 3 | namespace MailPoet\Newsletter\Sharing; |
| 4 | |
| 5 | if (!defined('ABSPATH')) exit; |
| 6 | |
| 7 | |
| 8 | use InvalidArgumentException; |
| 9 | use MailPoet\Entities\NewsletterEntity; |
| 10 | use MailPoet\Newsletter\NewslettersRepository; |
| 11 | use MailPoet\Newsletter\Sending\SendingQueuesRepository; |
| 12 | use MailPoet\Newsletter\Url as NewsletterUrl; |
| 13 | use MailPoet\Newsletter\ViewInBrowser\ViewInBrowserRenderer; |
| 14 | |
| 15 | class PublicEmailController { |
| 16 | /** @var NewslettersRepository */ |
| 17 | private $newslettersRepository; |
| 18 | |
| 19 | /** @var SendingQueuesRepository */ |
| 20 | private $sendingQueuesRepository; |
| 21 | |
| 22 | /** @var NewsletterUrl */ |
| 23 | private $newsletterUrl; |
| 24 | |
| 25 | /** @var ShareVisibility */ |
| 26 | private $shareVisibility; |
| 27 | |
| 28 | /** @var ViewInBrowserRenderer */ |
| 29 | private $viewInBrowserRenderer; |
| 30 | |
| 31 | /** @var ShareMetadataBuilder */ |
| 32 | private $shareMetadataBuilder; |
| 33 | |
| 34 | public function __construct( |
| 35 | NewslettersRepository $newslettersRepository, |
| 36 | SendingQueuesRepository $sendingQueuesRepository, |
| 37 | NewsletterUrl $newsletterUrl, |
| 38 | ShareVisibility $shareVisibility, |
| 39 | ViewInBrowserRenderer $viewInBrowserRenderer, |
| 40 | ShareMetadataBuilder $shareMetadataBuilder |
| 41 | ) { |
| 42 | $this->newslettersRepository = $newslettersRepository; |
| 43 | $this->sendingQueuesRepository = $sendingQueuesRepository; |
| 44 | $this->newsletterUrl = $newsletterUrl; |
| 45 | $this->shareVisibility = $shareVisibility; |
| 46 | $this->viewInBrowserRenderer = $viewInBrowserRenderer; |
| 47 | $this->shareMetadataBuilder = $shareMetadataBuilder; |
| 48 | } |
| 49 | |
| 50 | public function getNewsletter(string $identifier): NewsletterEntity { |
| 51 | $data = $this->newsletterUrl->parsePublicShareIdentifier($identifier); |
| 52 | if (!$data) { |
| 53 | throw new InvalidArgumentException('Invalid public email identifier.'); |
| 54 | } |
| 55 | |
| 56 | $newsletter = $this->newslettersRepository->findOneBy(['hash' => $data['hash']]); |
| 57 | if (!$newsletter instanceof NewsletterEntity || !$this->shareVisibility->canShare($newsletter)) { |
| 58 | throw new InvalidArgumentException('Email is not publicly shareable.'); |
| 59 | } |
| 60 | |
| 61 | return $newsletter; |
| 62 | } |
| 63 | |
| 64 | public function isCanonicalIdentifier(string $identifier, NewsletterEntity $newsletter): bool { |
| 65 | return $this->normalizeIdentifierForCanonicalComparison($identifier) |
| 66 | === $this->normalizeIdentifierForCanonicalComparison($this->newsletterUrl->getPublicShareIdentifier($newsletter)); |
| 67 | } |
| 68 | |
| 69 | public function getCanonicalUrl(NewsletterEntity $newsletter): string { |
| 70 | return $this->newsletterUrl->getPublicShareUrl($newsletter); |
| 71 | } |
| 72 | |
| 73 | public function render(NewsletterEntity $newsletter): string { |
| 74 | $queue = $this->sendingQueuesRepository->findLatestCompletedByNewsletter($newsletter); |
| 75 | $canonicalUrl = $this->getCanonicalUrl($newsletter); |
| 76 | $html = $this->viewInBrowserRenderer->renderPublicShare($newsletter, $queue); |
| 77 | $html = $this->shareMetadataBuilder->injectShareToolbar($html, $newsletter, $canonicalUrl); |
| 78 | return $this->shareMetadataBuilder->injectMetadata($html, $newsletter, $canonicalUrl); |
| 79 | } |
| 80 | |
| 81 | private function normalizeIdentifierForCanonicalComparison(string $identifier): string { |
| 82 | // Normalize only URL percent-escape hex digits, e.g. %F0 -> %f0. |
| 83 | // The slug text remains strict so genuinely stale slugs still redirect. |
| 84 | $normalized = preg_replace_callback('/%[0-9A-Fa-f]{2}/', function (array $matches): string { |
| 85 | return strtolower($matches[0]); |
| 86 | }, $identifier); |
| 87 | return is_string($normalized) ? $normalized : $identifier; |
| 88 | } |
| 89 | } |
| 90 |