From 1b8709ee7244883cf509076cbb35d8fe22ff9ab0 Mon Sep 17 00:00:00 2001 From: noniagriconomie Date: Wed, 12 Feb 2020 14:27:47 +0100 Subject: [PATCH] Add Free Mobile notifier --- .../FrameworkExtension.php | 2 + .../Resources/config/notifier_transports.xml | 4 + .../Notifier/Bridge/FreeMobile/.gitattributes | 3 + .../Notifier/Bridge/FreeMobile/CHANGELOG.md | 7 ++ .../Bridge/FreeMobile/FreeMobileTransport.php | 74 +++++++++++++++++++ .../FreeMobile/FreeMobileTransportFactory.php | 52 +++++++++++++ .../Notifier/Bridge/FreeMobile/LICENSE | 19 +++++ .../Notifier/Bridge/FreeMobile/README.md | 14 ++++ .../Tests/FreeMobileTransportFactoryTest.php | 68 +++++++++++++++++ .../Tests/FreeMobileTransportTest.php | 54 ++++++++++++++ .../Notifier/Bridge/FreeMobile/composer.json | 36 +++++++++ .../Bridge/FreeMobile/phpunit.xml.dist | 31 ++++++++ .../Exception/UnsupportedSchemeException.php | 4 + src/Symfony/Component/Notifier/Transport.php | 2 + 14 files changed, 370 insertions(+) create mode 100644 src/Symfony/Component/Notifier/Bridge/FreeMobile/.gitattributes create mode 100644 src/Symfony/Component/Notifier/Bridge/FreeMobile/CHANGELOG.md create mode 100644 src/Symfony/Component/Notifier/Bridge/FreeMobile/FreeMobileTransport.php create mode 100644 src/Symfony/Component/Notifier/Bridge/FreeMobile/FreeMobileTransportFactory.php create mode 100644 src/Symfony/Component/Notifier/Bridge/FreeMobile/LICENSE create mode 100644 src/Symfony/Component/Notifier/Bridge/FreeMobile/README.md create mode 100644 src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportFactoryTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php create mode 100644 src/Symfony/Component/Notifier/Bridge/FreeMobile/composer.json create mode 100644 src/Symfony/Component/Notifier/Bridge/FreeMobile/phpunit.xml.dist diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index cef82f8ce1..578e83bf1a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -92,6 +92,7 @@ use Symfony\Component\Messenger\Transport\TransportInterface; use Symfony\Component\Mime\MimeTypeGuesserInterface; use Symfony\Component\Mime\MimeTypes; use Symfony\Component\Notifier\Bridge\Firebase\FirebaseTransportFactory; +use Symfony\Component\Notifier\Bridge\FreeMobile\FreeMobileTransportFactory; use Symfony\Component\Notifier\Bridge\Mattermost\MattermostTransportFactory; use Symfony\Component\Notifier\Bridge\Nexmo\NexmoTransportFactory; use Symfony\Component\Notifier\Bridge\OvhCloud\OvhCloudTransportFactory; @@ -2044,6 +2045,7 @@ class FrameworkExtension extends Extension RocketChatTransportFactory::class => 'notifier.transport_factory.rocketchat', TwilioTransportFactory::class => 'notifier.transport_factory.twilio', FirebaseTransportFactory::class => 'notifier.transport_factory.firebase', + FreeMobileTransportFactory::class => 'notifier.transport_factory.freemobile', OvhCloudTransportFactory::class => 'notifier.transport_factory.ovhcloud', SinchTransportFactory::class => 'notifier.transport_factory.sinch', ]; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.xml index 4680ad89a6..045eb52a1b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.xml @@ -38,6 +38,10 @@ + + + + diff --git a/src/Symfony/Component/Notifier/Bridge/FreeMobile/.gitattributes b/src/Symfony/Component/Notifier/Bridge/FreeMobile/.gitattributes new file mode 100644 index 0000000000..ebb9287043 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/.gitattributes @@ -0,0 +1,3 @@ +/Tests export-ignore +/phpunit.xml.dist export-ignore +/.gitignore export-ignore diff --git a/src/Symfony/Component/Notifier/Bridge/FreeMobile/CHANGELOG.md b/src/Symfony/Component/Notifier/Bridge/FreeMobile/CHANGELOG.md new file mode 100644 index 0000000000..23daab7466 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +5.1.0 +----- + + * Added the bridge as `@experimental` diff --git a/src/Symfony/Component/Notifier/Bridge/FreeMobile/FreeMobileTransport.php b/src/Symfony/Component/Notifier/Bridge/FreeMobile/FreeMobileTransport.php new file mode 100644 index 0000000000..71c2067d6a --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/FreeMobileTransport.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\FreeMobile; + +use Symfony\Component\Notifier\Exception\LogicException; +use Symfony\Component\Notifier\Exception\TransportException; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Component\Notifier\Transport\AbstractTransport; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Antoine Makdessi + * + * @experimental in 5.1 + */ +final class FreeMobileTransport extends AbstractTransport +{ + protected const HOST = 'https://smsapi.free-mobile.fr/sendmsg'; + + private $login; + private $password; + private $phone; + + public function __construct(string $login, string $password, string $phone, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null) + { + $this->login = $login; + $this->password = $password; + $this->phone = $phone; + + parent::__construct($client, $dispatcher); + } + + public function __toString(): string + { + return sprintf('freemobile://%s?phone=%s', $this->getEndpoint(), $this->phone); + } + + public function supports(MessageInterface $message): bool + { + return $message instanceof SmsMessage && $this->phone === $message->getPhone(); + } + + protected function doSend(MessageInterface $message): void + { + if (!$this->supports($message)) { + throw new LogicException(sprintf('The "%s" transport only supports instances of "%s" (instance of "%s" given) and configured with your phone number.', __CLASS__, SmsMessage::class, \get_class($message))); + } + + $response = $this->client->request('POST', $this->getEndpoint(), [ + 'json' => [ + 'user' => $this->login, + 'pass' => $this->password, + 'msg' => $message->getSubject(), + ], + ]); + + if (200 !== $response->getStatusCode()) { + $error = $response->toArray(false); + + throw new TransportException(sprintf('Unable to send the SMS: "%s" (see "%s").', $error['message'], $error['more_info']), $response); + } + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/FreeMobile/FreeMobileTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/FreeMobile/FreeMobileTransportFactory.php new file mode 100644 index 0000000000..4afa966b65 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/FreeMobileTransportFactory.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\FreeMobile; + +use Symfony\Component\Notifier\Exception\IncompleteDsnException; +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; +use Symfony\Component\Notifier\Transport\AbstractTransportFactory; +use Symfony\Component\Notifier\Transport\Dsn; +use Symfony\Component\Notifier\Transport\TransportInterface; + +/** + * @author Antoine Makdessi + * + * @experimental in 5.1 + */ +final class FreeMobileTransportFactory extends AbstractTransportFactory +{ + /** + * @return FreeMobileTransport + */ + public function create(Dsn $dsn): TransportInterface + { + $scheme = $dsn->getScheme(); + $login = $this->getUser($dsn); + $password = $this->getPassword($dsn); + $phone = $dsn->getOption('phone'); + + if (null === $phone || '' === $phone) { + throw new IncompleteDsnException('Missing phone.'); + } + + if ('freemobile' === $scheme) { + return new FreeMobileTransport($login, $password, $phone, $this->client, $this->dispatcher); + } + + throw new UnsupportedSchemeException($dsn, 'freemobile', $this->getSupportedSchemes()); + } + + protected function getSupportedSchemes(): array + { + return ['freemobile']; + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/FreeMobile/LICENSE b/src/Symfony/Component/Notifier/Bridge/FreeMobile/LICENSE new file mode 100644 index 0000000000..5593b1d84f --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020 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/FreeMobile/README.md b/src/Symfony/Component/Notifier/Bridge/FreeMobile/README.md new file mode 100644 index 0000000000..a117b04c66 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/README.md @@ -0,0 +1,14 @@ +Free Mobile Notifier +==================== + +Provides Free Mobile integration for Symfony Notifier. +This provider allows you to receive an SMS notification +on your personal mobile number. + +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/FreeMobile/Tests/FreeMobileTransportFactoryTest.php b/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportFactoryTest.php new file mode 100644 index 0000000000..88cb0e7172 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportFactoryTest.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\FreeMobile\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\FreeMobile\FreeMobileTransportFactory; +use Symfony\Component\Notifier\Exception\IncompleteDsnException; +use Symfony\Component\Notifier\Exception\UnsupportedSchemeException; +use Symfony\Component\Notifier\Transport\Dsn; + +final class FreeMobileTransportFactoryTest extends TestCase +{ + public function testCreateWithDsn(): void + { + $factory = $this->initFactory(); + + $dsn = 'freemobile://login:pass@default?phone=0611223344'; + $transport = $factory->create(Dsn::fromString($dsn)); + $transport->setHost('host.test'); + + $this->assertSame('freemobile://host.test?phone=0611223344', (string) $transport); + } + + public function testCreateWithNoPhoneThrowsMalformed(): void + { + $factory = $this->initFactory(); + + $this->expectException(IncompleteDsnException::class); + + $dsnIncomplete = 'freemobile://login:pass@default'; + $factory->create(Dsn::fromString($dsnIncomplete)); + } + + public function testSupportsFreeMobileScheme(): void + { + $factory = $this->initFactory(); + + $dsn = 'freemobile://login:pass@default?phone=0611223344'; + $dsnUnsupported = 'foobarmobile://login:pass@default?phone=0611223344'; + + $this->assertTrue($factory->supports(Dsn::fromString($dsn))); + $this->assertFalse($factory->supports(Dsn::fromString($dsnUnsupported))); + } + + public function testNonFreeMobileSchemeThrows(): void + { + $factory = $this->initFactory(); + + $this->expectException(UnsupportedSchemeException::class); + + $dsnUnsupported = 'foobarmobile://login:pass@default?phone=0611223344'; + $factory->create(Dsn::fromString($dsnUnsupported)); + } + + private function initFactory(): FreeMobileTransportFactory + { + return new FreeMobileTransportFactory(); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php b/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php new file mode 100644 index 0000000000..58b279b999 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Notifier\Bridge\FreeMobile\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Notifier\Bridge\FreeMobile\FreeMobileTransport; +use Symfony\Component\Notifier\Exception\LogicException; +use Symfony\Component\Notifier\Message\MessageInterface; +use Symfony\Component\Notifier\Message\SmsMessage; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +final class FreeMobileTransportTest extends TestCase +{ + public function testToStringContainsProperties(): void + { + $transport = $this->initTransport(); + + $this->assertSame('freemobile://host.test?phone=0611223344', (string) $transport); + } + + public function testSupportsMessageInterface(): void + { + $transport = $this->initTransport(); + + $this->assertTrue($transport->supports(new SmsMessage('0611223344', 'Hello!'))); + $this->assertFalse($transport->supports(new SmsMessage('0699887766', 'Hello!'))); + $this->assertFalse($transport->supports($this->createMock(MessageInterface::class), 'Hello!')); + } + + public function testSendNonSmsMessageThrowsException(): void + { + $transport = $this->initTransport(); + + $this->expectException(LogicException::class); + + $transport->send(new SmsMessage('0699887766', 'Hello!')); + } + + private function initTransport(): FreeMobileTransport + { + return (new FreeMobileTransport( + 'login', 'pass', '0611223344', $this->createMock(HttpClientInterface::class) + ))->setHost('host.test'); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/FreeMobile/composer.json b/src/Symfony/Component/Notifier/Bridge/FreeMobile/composer.json new file mode 100644 index 0000000000..e9bc752003 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/composer.json @@ -0,0 +1,36 @@ +{ + "name": "symfony/freemobile-notifier", + "type": "symfony-bridge", + "description": "Symfony Free Mobile Notifier Bridge", + "keywords": ["sms", "FreeMobile", "notifier", "alerting"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Antoine Makdessi", + "email": "amakdessi@me.com", + "homepage": "http://antoine.makdessi.free.fr" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": "^7.2.5", + "symfony/http-client": "^4.3|^5.1", + "symfony/notifier": "^5.1" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Notifier\\Bridge\\FreeMobile\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "5.1-dev" + } + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/FreeMobile/phpunit.xml.dist b/src/Symfony/Component/Notifier/Bridge/FreeMobile/phpunit.xml.dist new file mode 100644 index 0000000000..fc288ee8c2 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/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 8c4146666c..8e5b2ffd90 100644 --- a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php +++ b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php @@ -50,6 +50,10 @@ class UnsupportedSchemeException extends LogicException 'class' => Bridge\Firebase\FirebaseTransportFactory::class, 'package' => 'symfony/firebase-notifier', ], + 'freemobile' => [ + 'class' => Bridge\FreeMobile\FreeMobileTransportFactory::class, + 'package' => 'symfony/freemobile-notifier', + ], 'ovhcloud' => [ 'class' => Bridge\OvhCloud\OvhCloudTransportFactory::class, 'package' => 'symfony/ovhcloud-notifier', diff --git a/src/Symfony/Component/Notifier/Transport.php b/src/Symfony/Component/Notifier/Transport.php index 508f754798..6cfddf9eeb 100644 --- a/src/Symfony/Component/Notifier/Transport.php +++ b/src/Symfony/Component/Notifier/Transport.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Notifier; use Symfony\Component\Notifier\Bridge\Firebase\FirebaseTransportFactory; +use Symfony\Component\Notifier\Bridge\FreeMobile\FreeMobileTransportFactory; use Symfony\Component\Notifier\Bridge\Mattermost\MattermostTransportFactory; use Symfony\Component\Notifier\Bridge\Nexmo\NexmoTransportFactory; use Symfony\Component\Notifier\Bridge\OvhCloud\OvhCloudTransportFactory; @@ -48,6 +49,7 @@ class Transport OvhCloudTransportFactory::class, FirebaseTransportFactory::class, SinchTransportFactory::class, + FreeMobileTransportFactory::class, ]; private $factories;