From 860cb3efd56175434a71d19eb518beb5b84930cb Mon Sep 17 00:00:00 2001 From: Wouter van der Loop Date: Wed, 24 May 2023 13:42:57 +0200 Subject: [PATCH] [Notifier] Add Novu bridge --- .../FrameworkExtension.php | 1 + .../Resources/config/notifier_transports.php | 8 +- .../Notifier/Bridge/Novu/.gitattributes | 4 + .../Component/Notifier/Bridge/Novu/.gitignore | 3 + .../Notifier/Bridge/Novu/CHANGELOG.md | 7 ++ .../Component/Notifier/Bridge/Novu/LICENSE | 19 ++++ .../Notifier/Bridge/Novu/NovuOptions.php | 49 ++++++++++ .../Bridge/Novu/NovuSubscriberRecipient.php | 66 +++++++++++++ .../Notifier/Bridge/Novu/NovuTransport.php | 97 +++++++++++++++++++ .../Bridge/Novu/NovuTransportFactory.php | 43 ++++++++ .../Component/Notifier/Bridge/Novu/README.md | 73 ++++++++++++++ .../Bridge/Novu/Tests/NovuOptionsTest.php | 47 +++++++++ .../Novu/Tests/NovuTransportFactoryTest.php | 48 +++++++++ .../Bridge/Novu/Tests/NovuTransportTest.php | 68 +++++++++++++ .../Notifier/Bridge/Novu/composer.json | 30 ++++++ .../Notifier/Bridge/Novu/phpunit.xml.dist | 31 ++++++ .../Exception/UnsupportedSchemeException.php | 4 + .../UnsupportedSchemeExceptionTest.php | 2 + src/Symfony/Component/Notifier/Transport.php | 1 + 19 files changed, 599 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/.gitattributes create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/.gitignore create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/CHANGELOG.md create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/LICENSE create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/NovuOptions.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/NovuSubscriberRecipient.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/NovuTransport.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/NovuTransportFactory.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/README.md create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuOptionsTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuTransportFactoryTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuTransportTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/composer.json create mode 100644 src/Symfony/Component/Notifier/Bridge/Novu/phpunit.xml.dist diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 3a780a8eaa35c..a5d1286f6e3db 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -2741,6 +2741,7 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ NotifierBridge\MessageMedia\MessageMediaTransportFactory::class => 'notifier.transport_factory.message-media', NotifierBridge\MicrosoftTeams\MicrosoftTeamsTransportFactory::class => 'notifier.transport_factory.microsoft-teams', NotifierBridge\Mobyt\MobytTransportFactory::class => 'notifier.transport_factory.mobyt', + NotifierBridge\Novu\NovuTransportFactory::class => 'notifier.transport_factory.novu', NotifierBridge\Octopush\OctopushTransportFactory::class => 'notifier.transport_factory.octopush', NotifierBridge\OneSignal\OneSignalTransportFactory::class => 'notifier.transport_factory.one-signal', NotifierBridge\OrangeSms\OrangeSmsTransportFactory::class => 'notifier.transport_factory.orange-sms', diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php index 1573aa0bea0a4..5dc43096c0ba6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php @@ -279,13 +279,17 @@ ->set('notifier.transport_factory.simple-textin', Bridge\SimpleTextin\SimpleTextinTransportFactory::class) ->parent('notifier.transport_factory.abstract') ->tag('texter.transport_factory') - + ->set('notifier.transport_factory.click-send', Bridge\ClickSend\ClickSendTransportFactory::class) ->parent('notifier.transport_factory.abstract') ->tag('texter.transport_factory') - + ->set('notifier.transport_factory.smsmode', Bridge\Smsmode\SmsmodeTransportFactory::class) ->parent('notifier.transport_factory.abstract') ->tag('texter.transport_factory') + + ->set('notifier.transport_factory.novu', Bridge\Novu\NovuTransportFactory::class) + ->parent('notifier.transport_factory.abstract') + ->tag('texter.transport_factory') ; }; diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/.gitattributes b/src/Symfony/Component/Notifier/Bridge/Novu/.gitattributes new file mode 100644 index 0000000000000..84c7add058fb5 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/.gitattributes @@ -0,0 +1,4 @@ +/Tests export-ignore +/phpunit.xml.dist export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/.gitignore b/src/Symfony/Component/Notifier/Bridge/Novu/.gitignore new file mode 100644 index 0000000000000..c49a5d8df5c65 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/CHANGELOG.md b/src/Symfony/Component/Notifier/Bridge/Novu/CHANGELOG.md new file mode 100644 index 0000000000000..7e873f81cb0fe --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +6.4 +--- + +* Add the bridge diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/LICENSE b/src/Symfony/Component/Notifier/Bridge/Novu/LICENSE new file mode 100644 index 0000000000000..3ed9f412ce53d --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2023-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/NovuOptions.php b/src/Symfony/Component/Notifier/Bridge/Novu/NovuOptions.php new file mode 100644 index 0000000000000..16bd950096062 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/NovuOptions.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Novu; + +use Symfony\Component\Notifier\Message\MessageOptionsInterface; + +/** + * @author Wouter van der Loop + */ +class NovuOptions implements MessageOptionsInterface +{ + public function __construct( + private readonly string|null $subscriberId = null, + private readonly string|null $firstName = null, + private readonly string|null $lastName = null, + private readonly string|null $email = null, + private readonly string|null $phone = null, + private readonly string|null $avatar = null, + private readonly string|null $locale = null, + private readonly array $options = [], + ) { + } + + public function toArray(): array + { + return array_merge($this->options, [ + 'firstName' => $this->firstName, + 'lastName' => $this->lastName, + 'email' => $this->email, + 'phone' => $this->phone, + 'avatar' => $this->avatar, + 'locale' => $this->locale, + ]); + } + + public function getRecipientId(): ?string + { + return $this->subscriberId ?? null; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/NovuSubscriberRecipient.php b/src/Symfony/Component/Notifier/Bridge/Novu/NovuSubscriberRecipient.php new file mode 100644 index 0000000000000..027c39876e017 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/NovuSubscriberRecipient.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Novu; + +use Symfony\Component\Notifier\Recipient\RecipientInterface; + +/** + * @author Wouter van der Loop + */ +class NovuSubscriberRecipient implements RecipientInterface +{ + public function __construct( + private readonly string $subscriberId, + private readonly string|null $firstName = null, + private readonly string|null $lastName = null, + private readonly string|null $email = null, + private readonly string|null $phone = null, + private readonly string|null $avatar = null, + private readonly string|null $locale = null, + ) { + } + + public function getSubscriberId(): string + { + return $this->subscriberId; + } + + public function getFirstName(): ?string + { + return $this->firstName; + } + + public function getLastName(): ?string + { + return $this->lastName; + } + + public function getEmail(): ?string + { + return $this->email; + } + + public function getPhone(): ?string + { + return $this->phone; + } + + public function getAvatar(): ?string + { + return $this->avatar; + } + + public function getLocale(): ?string + { + return $this->locale; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/NovuTransport.php b/src/Symfony/Component/Notifier/Bridge/Novu/NovuTransport.php new file mode 100644 index 0000000000000..dc6b7a46e9ad8 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/NovuTransport.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Novu; + +use Symfony\Component\Notifier\Exception\TransportException; +use Symfony\Component\Notifier\Exception\TransportExceptionInterface; +use Symfony\Component\Notifier\Exception\UnsupportedMessageTypeException; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\PushMessage; +use Symfony\Component\Notifier\Message\SentMessage; +use Symfony\Component\Notifier\Transport\AbstractTransport; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Wouter van der Loop + */ +class NovuTransport extends AbstractTransport +{ + protected const HOST = 'web.novu.co'; + + public function __construct( + #[\SensitiveParameter] + protected string $apiKey, + HttpClientInterface $client = null, + EventDispatcherInterface $dispatcher = null + ) { + $this->apiKey = $apiKey; + parent::__construct($client, $dispatcher); + } + + public function __toString(): string + { + return sprintf('novu://%s', $this->getEndpoint()); + } + + public function supports(MessageInterface $message): bool + { + return $message instanceof PushMessage && (null === $message->getOptions() || $message->getOptions() instanceof NovuOptions); + } + + protected function doSend(MessageInterface $message): SentMessage + { + if (!$message instanceof PushMessage) { + throw new UnsupportedMessageTypeException(__CLASS__, PushMessage::class, $message); + } + + $options = $message->getOptions()?->toArray() ?? []; + + $body = [ + 'name' => $message->getSubject(), + 'to' => [ + 'subscriberId' => $message->getRecipientId(), + 'firstName' => $options['firstName'], + 'lastName' => $options['lastName'], + 'email' => $options['email'], + 'phone' => $options['phone'], + 'avatar' => $options['avatar'], + 'locale' => $options['locale'], + ], + 'payload' => json_decode($message->getContent()), + ]; + + $endpoint = sprintf('https://%s/v1/events/trigger', $this->getEndpoint()); + $response = $this->client->request('POST', $endpoint, [ + 'body' => $body, + 'headers' => [ + 'Authorization' => sprintf('ApiKey %s', $this->apiKey), + 'Content-Type' => 'application/json', + ], + ]); + + try { + $statusCode = $response->getStatusCode(); + } catch (TransportExceptionInterface $e) { + throw new TransportException('Could not reach the remote Novu server.', $response, 0, $e); + } + + if (201 !== $statusCode) { + $originalContent = $message->getSubject(); + $result = $response->toArray(false); + $error = $result['message']; + throw new TransportException(sprintf('Unable to post the Novu message: "%s" (%d: "%s").', $originalContent, $statusCode, $error), $response); + } + + return new SentMessage($message, (string) $this); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/NovuTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Novu/NovuTransportFactory.php new file mode 100644 index 0000000000000..09310cb4446cc --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/NovuTransportFactory.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Novu; + +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; +use Symfony\Component\Notifier\Transport\AbstractTransportFactory; +use Symfony\Component\Notifier\Transport\Dsn; + +/** + * @author Wouter van der Loop + */ +class NovuTransportFactory extends AbstractTransportFactory +{ + private const SCHEME = 'novu'; + + protected function getSupportedSchemes(): array + { + return [self::SCHEME]; + } + + public function create(Dsn $dsn): NovuTransport + { + $scheme = $dsn->getScheme(); + if (self::SCHEME !== $scheme) { + throw new UnsupportedSchemeException($dsn, self::SCHEME, $this->getSupportedSchemes()); + } + + $key = $this->getUser($dsn); + $host = 'default' === $dsn->getHost() ? null : $dsn->getHost(); + $port = $dsn->getPort(); + + return (new NovuTransport($key, $this->client, $this->dispatcher))->setHost($host)->setPort($port); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/README.md b/src/Symfony/Component/Notifier/Bridge/Novu/README.md new file mode 100644 index 0000000000000..9dd92568e1176 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/README.md @@ -0,0 +1,73 @@ +Novu Notifier +============= + +Provides [Novu](https://novu.co/) integration for Symfony Notifier. + +DSN example +----------- + +``` +NOVU_DSN=novu://API_KEY@default +``` + +Notification example +-------------------- + +```php +class NovuNotification extends Notification implements PushNotificationInterface +{ + public function asPushMessage( + NovuSubscriberRecipient|RecipientInterface $recipient, + ?string $transport = null, + ): ?PushMessage { + return new PushMessage( + $this->getSubject(), + $this->getContent(), + new NovuOptions( + $recipient->getSubscriberId(), + $recipient->getFirstName(), + $recipient->getLastName(), + $recipient->getEmail(), + $recipient->getPhone(), + $recipient->getAvatar(), + $recipient->getLocale(), + [], + ), + ); + } +} +``` + +```php +$notification = new NovuNotification; +$notification->subject('test'); +$notification->channels(['push']); +$notification->content( + json_encode( + [ + 'param1' => 'Lorum Ipsum', + ] + ) +); + +$this->notifier->send( + $notification, + new NovuSubscriberRecipient( + "123", + 'Wouter', + 'van der Loop', + 'woutervdl@toppy.nl', + null, + null, + null, + ), +); +``` + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuOptionsTest.php b/src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuOptionsTest.php new file mode 100644 index 0000000000000..6d1125bf18bb0 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuOptionsTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Novu\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\Novu\NovuOptions; + +class NovuOptionsTest extends TestCase +{ + /** + * @group legacy + */ + public function testToArray() + { + $options = new NovuOptions( + 123, + 'Joe', + 'Smith', + 'test@example.com', + null, + null, + null, + [], + ); + + $this->assertSame( + [ + 'firstName' => 'Joe', + 'lastName' => 'Smith', + 'email' => 'test@example.com', + 'phone' => null, + 'avatar' => null, + 'locale' => null, + ], + $options->toArray() + ); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuTransportFactoryTest.php new file mode 100644 index 0000000000000..99044057ce68a --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuTransportFactoryTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Novu\Tests; + +use Symfony\Component\Notifier\Bridge\Novu\NovuTransportFactory; +use Symfony\Component\Notifier\Test\TransportFactoryTestCase; +use Symfony\Component\Notifier\Transport\TransportFactoryInterface; + +class NovuTransportFactoryTest extends TransportFactoryTestCase +{ + public function createFactory(): TransportFactoryInterface + { + return new NovuTransportFactory(); + } + + public static function supportsProvider(): iterable + { + yield [true, 'novu://host']; + yield [false, 'somethingElse://host']; + } + + public static function createProvider(): iterable + { + yield [ + 'novu://host.test', + 'novu://token@host.test', + ]; + } + + public static function incompleteDsnProvider(): iterable + { + yield 'missing key' => ['novu://host.test']; + } + + public static function unsupportedSchemeProvider(): iterable + { + yield ['somethingElse://token@host']; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuTransportTest.php new file mode 100644 index 0000000000000..b94183e4f464c --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/Tests/NovuTransportTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\Novu\Tests; + +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\Notifier\Bridge\Novu\NovuOptions; +use Symfony\Component\Notifier\Bridge\Novu\NovuTransport; +use Symfony\Component\Notifier\Exception\TransportException; +use Symfony\Component\Notifier\Message\PushMessage; +use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Component\Notifier\Test\TransportTestCase; +use Symfony\Component\Notifier\Tests\Transport\DummyMessage; +use Symfony\Component\Notifier\Transport\TransportInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +class NovuTransportTest extends TransportTestCase +{ + public static function createTransport(HttpClientInterface $client = null): TransportInterface + { + return (new NovuTransport('9c9ced75881ddc65c033273f466b42d1', $client ?? new MockHttpClient()))->setHost('host.test'); + } + + public static function toStringProvider(): iterable + { + yield ['novu://host.test', self::createTransport()]; + } + + public static function supportedMessagesProvider(): iterable + { + yield [new PushMessage('test', '{}', new NovuOptions(123, null, null, 'test@example.com', null, null, null, []))]; + } + + public static function unsupportedMessagesProvider(): iterable + { + yield [new SmsMessage('0611223344', 'Hello!')]; + yield [new DummyMessage()]; + } + + public function testWithErrorResponseThrows() + { + $response = $this->createMock(ResponseInterface::class); + $response->expects($this->exactly(2)) + ->method('getStatusCode') + ->willReturn(400); + $response->expects($this->once()) + ->method('getContent') + ->willReturn(json_encode(['error' => 'Bad request', 'message' => 'subscriberId under property to is not configured'])); + + $client = new MockHttpClient(static fn (): ResponseInterface => $response); + + $transport = $this->createTransport($client); + + $this->expectException(TransportException::class); + $this->expectExceptionMessageMatches('/400: "subscriberId under property to is not configured"/'); + + $transport->send(new PushMessage('test', '{}', new NovuOptions(123, null, null, 'test@example.com', null, null, null, []))); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/composer.json b/src/Symfony/Component/Notifier/Bridge/Novu/composer.json new file mode 100644 index 0000000000000..539bd870cef9f --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/composer.json @@ -0,0 +1,30 @@ +{ + "name": "symfony/novu-notifier", + "type": "symfony-notifier-bridge", + "description": "Provides Novu integration for Symfony Notifier.", + "keywords": ["novu", "notifier"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Wouter van der Loop", + "email": "woutervdl@toppy.nl" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=8.1", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/notifier": "^6.4" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Notifier\\Bridge\\Novu\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/src/Symfony/Component/Notifier/Bridge/Novu/phpunit.xml.dist b/src/Symfony/Component/Notifier/Bridge/Novu/phpunit.xml.dist new file mode 100644 index 0000000000000..36bca0d250731 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Novu/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php index b11264ce610cf..7a3413aee69f3 100644 --- a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php +++ b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php @@ -152,6 +152,10 @@ class UnsupportedSchemeException extends LogicException 'class' => Bridge\Mobyt\MobytTransportFactory::class, 'package' => 'symfony/mobyt-notifier', ], + 'novu' => [ + 'class' => Bridge\Novu\NovuTransportFactory::class, + 'package' => 'symfony/novu-notifier', + ], 'octopush' => [ 'class' => Bridge\Octopush\OctopushTransportFactory::class, 'package' => 'symfony/octopush-notifier', diff --git a/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php b/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php index d211d15422e8f..2edb9ae59f1c1 100644 --- a/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php +++ b/src/Symfony/Component/Notifier/Tests/Exception/UnsupportedSchemeExceptionTest.php @@ -60,6 +60,7 @@ public static function setUpBeforeClass(): void Bridge\MessageMedia\MessageMediaTransportFactory::class => false, Bridge\MicrosoftTeams\MicrosoftTeamsTransportFactory::class => false, Bridge\Mobyt\MobytTransportFactory::class => false, + Bridge\Novu\NovuTransportFactory::class => false, Bridge\Octopush\OctopushTransportFactory::class => false, Bridge\OneSignal\OneSignalTransportFactory::class => false, Bridge\OrangeSms\OrangeSmsTransportFactory::class => false, @@ -138,6 +139,7 @@ public static function messageWhereSchemeIsPartOfSchemeToPackageMapProvider(): \ yield ['messagemedia', 'symfony/message-media-notifier']; yield ['microsoftteams', 'symfony/microsoft-teams-notifier']; yield ['mobyt', 'symfony/mobyt-notifier']; + yield ['novu', 'symfony/novu-notifier']; yield ['octopush', 'symfony/octopush-notifier']; yield ['onesignal', 'symfony/one-signal-notifier']; yield ['ovhcloud', 'symfony/ovh-cloud-notifier']; diff --git a/src/Symfony/Component/Notifier/Transport.php b/src/Symfony/Component/Notifier/Transport.php index db21d16134598..0428e2bba3538 100644 --- a/src/Symfony/Component/Notifier/Transport.php +++ b/src/Symfony/Component/Notifier/Transport.php @@ -62,6 +62,7 @@ final class Transport Bridge\MessageMedia\MessageMediaTransportFactory::class, Bridge\MicrosoftTeams\MicrosoftTeamsTransportFactory::class, Bridge\Mobyt\MobytTransportFactory::class, + Bridge\Novu\NovuTransportFactory::class, Bridge\Octopush\OctopushTransportFactory::class, Bridge\OneSignal\OneSignalTransportFactory::class, Bridge\OrangeSms\OrangeSmsTransportFactory::class, pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy