8000 feature #40607 [Notifier] Add LightSms notifier bridge (Vasilij Dusko… · symfony/symfony@71a407d · GitHub
[go: up one dir, main page]

Skip to content

Commit 71a407d

Browse files
committed
feature #40607 [Notifier] Add LightSms notifier bridge (Vasilij Dusko, StaffNowa)
This PR was merged into the 5.3-dev branch. Discussion ---------- [Notifier] Add LightSms notifier bridge | Q | A | ------------- | --- | Branch? | 5.x | Bug fix? | no | New feature? | yes <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | License | MIT | Doc PR | symfony/symfony-docs/pull/15178 | Recipe PR | symfony/recipes#921 LightSms notifier https://github.com/D4DLab/lightsms-notifier Commits ------- 37c665e * LightSmsTransport.php - make fabbot happy 68a12fa * fix tests f1f83b9 * LightSmsTransport.php - use query string parameters 026dcd9 * LightSmsTransport.php - isset 2a9ac2d * LightSmsTransport.php - fix 4213564 * composer.json - fix Fabien comment from another pull request #40646 21e972a * coding standard bea5256 * type cast. On success lightsms return error code like string. On error return integer. 9b2e2d0 * type cast. On success lightsms return error code like string. On error return integer. 0d7488b * type cast. On success lightsms return error code like string. On error return integer. 9a832ef * LightSmsTransport.php - via mistake removed www which return (Closing direction to the user). Removed additional isset which in reality not needed. Added new method which allow to return "unknown error" and throw exception if not successfully 178d9c2 * pull request #40696 95e82f6 Update LightSmsTransport.php a197dee * LightSmsTransport.php - better to remove if we do not have it? 83d2598 * Coding Standard patch 1ff97e4 * LightSmsTransport.php - build signature and use http_build_query, timestamp int 1c993b7 * ERROR_CODES -> int * www. - bug * isset validate ['error'] 1b59a7d * LightSmsTransport.php - string param 58ac708 * LightSmsTransport.php - return back www (without will not work). Now fail tests b9f9ff8 * LightSmsTransport.php - tests fail 265f776 * LightSmsTransport.php - issue with Symfony\Component\Notifier\Bridge\LightSms\Tests\LightSmsTransportTest 23a446a * LightSmsTransport.php - issue with Symfony\Component\Notifier\Bridge\LightSms\Tests\LightSmsTransportTest 08235e5 * LightSmsTransport.php - bug fix 80ef5ba * LightSmsTransport.php - Unable to send the SMS: Closing direction to the user 08b0729 Update LightSmsTransport.php 7180c1f Update LightSmsTransport.php f16b4d2 * phone changed to from 7f13dbf * sender changed to from e20ef1e * LightSmsTransport.php - change + to 00 b0e64b9 * LightSmsTransport.php - not ok throw exception fc13bb2 * LightSmsTransport.php - changed login for validation (the same like we have all places) 5d2e692 * LightSmsTransport.php - escape phone number 8620e82 * LightSmsTransport.php - move timestamp 66c34ba Update README.md 2e0e1d7 Update README.md 7b51e0d Update src/Symfony/Component/Notifier/Bridge/LightSms/LightSmsTransport.php 079406e Update src/Symfony/Component/Notifier/Bridge/LightSms/LightSmsTransport.php 0e41bc9 Update src/Symfony/Component/Notifier/Bridge/LightSms/Tests/LightSmsTransportFactoryTest.php 3d0d79c Update src/Symfony/Component/Notifier/Bridge/LightSms/Tests/LightSmsTransportFactoryTest.php e0a68bd Update src/Symfony/Component/Notifier/Bridge/LightSms/LightSmsTransport.php 1b073c2 Update src/Symfony/Component/Notifier/Bridge/LightSms/LightSmsTransport.php b0891be Update src/Symfony/Component/Notifier/Bridge/LightSms/LightSmsTransport.php 49b4780 Update src/Symfony/Component/Notifier/Bridge/LightSms/LightSmsTransport.php b2e4638 Update src/Symfony/Component/Notifier/Bridge/LightSms/LightSmsTransport.php c02dbbd Update src/Symfony/Component/Notifier/Bridge/LightSms/README.md 9f89014 Update src/Symfony/Component/Notifier/Bridge/LightSms/README.md 5e54dfe * LightSmsTransport.php - quick fix for private constant. 3cbbc85 * HOST split into two parts 9e1809e * small changes febff46 Update src/Symfony/Component/Notifier/Bridge/LightSms/LICENSE 4a11b94 * github account author 728a3e2 * Transport.php - missing use ce41756 * notifier_transports.php - Coding Standard d1ccd46 * Attached file changes which are required to run the lightsms notifier a0fae7d * tests 15686c0 * LightSmsTransport.php - Coding Standard 2f65b92 * LightSmsTransport.php - Coding Standard 6792535 * composer.json - requirements bug fix 167f325 * LightSmsTransport.php - logic error be8f994 * LightSmsTransport.php - return type f2ba226 * LightSmsTransport.php - bug fix b075c0e * LightSms notifier
2 parents de14349 + 37c665e commit 71a407d

File tree

13 files changed

+446
-0
lines changed

13 files changed

+446
-0
lines changed

src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier_transports.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use Symfony\Component\Notifier\Bridge\GoogleChat\GoogleChatTransportFactory;
2424
use Symfony\Component\Notifier\Bridge\Infobip\InfobipTransportFactory;
2525
use Symfony\Component\Notifier\Bridge\Iqsms\IqsmsTransportFactory;
26+
use Symfony\Component\Notifier\Bridge\LightSms\LightSmsTransportFactory;
2627
use Symfony\Component\Notifier\Bridge\LinkedIn\LinkedInTransportFactory;
2728
use Symfony\Component\Notifier\Bridge\Mattermost\MattermostTransportFactory;
2829
use Symfony\Component\Notifier\Bridge\Mercure\MercureTransportFactory;
@@ -164,5 +165,9 @@
164165
->parent('notifier.transport_factory.abstract')
165166
->tag('chatter.transport_factory')
166167
->tag('texter.transport_factory')
168+
169+
->set('notifier.transport_factory.lightsms', LightSmsTransportFactory::class)
170+
->parent('notifier.transport_factory.abstract')
171+
->tag('texter.transport_factory')
167172
;
168173
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/Tests export-ignore
2+
/phpunit.xml.dist export-ignore
3+
/.gitattributes export-ignore
4+
/.gitignore export-ignore
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.lock
3+
phpunit.xml
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2021 Fabien Potencier
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Notifier\Bridge\LightSms;
13+
14+
use Symfony\Component\HttpFoundation\Response;
15+
use Symfony\Component\Notifier\Exception\TransportException;
16+
use Symfony\Component\Notifier\Exception\UnsupportedMessageTypeException;
17+
use Symfony\Component\Notifier\Message\MessageInterface;
18+
use Symfony\Component\Notifier\Message\SentMessage;
19+
use Symfony\Component\Notifier\Message\SmsMessage;
20+
use Symfony\Component\Notifier\Transport\AbstractTransport;
21+
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
22+
use Symfony\Contracts\HttpClient\HttpClientInterface;
23+
24+
/**
25+
* @author Vasilij Duško <vasilij@prado.lt>
26+
*/
27+
final class LightSmsTransport extends AbstractTransport
28+
{
29+
protected const HOST = 'www.lightsms.com';
30+
31+
private $login;
32+
private $password;
33+
private $from;
34+
35+
private const ERROR_CODES = [
36+
1 => 'Missing Signature',
37+< A81 /span>
2 => 'Login not specified',
38+
3 => 'Text not specified',
39+
4 => 'Phone number not specified',
40+
5 => 'Sender not specified',
41+
6 => 'Invalid signature',
42+
7 => 'Invalid login',
43+
8 => 'Invalid sender name',
44+
9 => 'Sender name not registered',
45+
10 => 'Sender name not approved',
46+
11 => 'There are forbidden words in the text',
47+
12 => 'Error in SMS sending',
48+
13 => 'Phone number is in the blackist. SMS sending to this number is forbidden.',
49+
14 => 'There are more than 50 numbers in the request',
50+
15 => 'List not specified',
51+
16 => 'Invalid phone number',
52+
17 => 'SMS ID not specified',
53+
18 => 'Status not obtained',
54+
19 => 'Empty response',
55+
20 => 'The number already exists',
56+
21 => 'No name',
57+
22 => 'Template already exists',
58+
23 => 'Missing Month (Format: YYYY-MM)',
59+
24 => 'Timestamp not specified',
60+
25 => 'Error in access to the list',
61+
26 => 'There are no numbers in the list',
62+
27 => 'No valid numbers',
63+
28 => 'Missing start date (Format: YYYY-MM-DD)',
64+
29 => 'Missing end date (Format: YYYY-MM-DD)',
65+
30 => 'No date (format: YYYY-MM-DD)',
66+
31 => 'Closing direction to the user',
67+
32 => 'Not enough money',
68+
33 => 'Missing phone number',
69+
34 => 'Phone is in stop list',
70+
35 => 'Not enough money',
71+
36 => 'Can not obtain information about phone',
72+
37 => 'Base Id is not set',
73+
38 => 'Phone number already exists in this database',
74+
39 => 'Phone number does not exist in this database',
75+
999 => 'Unknown Error',
76+
];
77+
78+
public function __construct(string $login, string $password, string $from, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null)
79+
{
80+
$this->login = $login;
81+
$this->password = $password;
82+
$this->from = $from;
83+
84+
parent::__construct($client, $dispatcher);
85+
}
86+
87+
public function __toString(): string
88+
{
89+
return sprintf('lightsms://%s?from=%s', $this->getEndpoint(), $this->from);
90+
}
91+
92+
public function supports(MessageInterface $message): bool
93+
{
94+
return $message instanceof SmsMessage;
95+
}
96+
97+
protected function doSend(MessageInterface $message): SentMessage
98+
{
99+
if (!$message instanceof SmsMessage) {
100+
throw new UnsupportedMessageTypeException(__CLASS__, SmsMessage::class, $message);
101+
}
102+
103+
$timestamp = time();
104+
$data = [
105+
'login' => $this->login,
106+
'phone' => $this->escapePhoneNumber($message->getPhone()),
107+
'text' => $message->getSubject(),
108+
'sender' => $this->from,
109+
'timestamp' => $timestamp,
110+
];
111+
$data['signature'] = $this->generateSignature($data, $timestamp);
112+
113+
$endpoint = sprintf('https://%s/external/get/send.php', $this->getEndpoint());
114+
$response = $this->client->request(
115+
'GET',
116+
$endpoint,
117+
[
118+
'query' => $data,
119+
]
120+
);
121+
122+
if (Response::HTTP_OK !== $response->getStatusCode()) {
123+
throw new TransportException('Unable to send the SMS.', $response);
124+
}
125+
126+
$content = $response->toArray(false);
127+
128+
// it happens if the host without www
129+
if (isset($content['']['error'])) {
130+
throw new TransportException('Unable to send the SMS: '.$this->getErrorMsg((int) $content['']['error']), $response);
131+
}
132+
133+
if (isset($content['error'])) {
134+
throw new TransportException('Unable to send the SMS: '.$this->getErrorMsg((int) $content['error']), $response);
135+
}
136+
137+
$phone = $this->escapePhoneNumber($message->getPhone());
138+
if (32 === (int) $content[$phone]['error']) {
139+
throw new TransportException('Unable to send the SMS: '.$this->getErrorMsg((int) $content[$phone]['error']), $response);
140+
}
141+
142+
if (0 === (int) $content[$phone]['error']) {
143+
$sentMessage = new SentMessage($message, (string) $this);
144+
if (isset($content[$phone]['id_sms'])) {
145+
$sentMessage->setMessageId($content[$phone]['id_sms']);
146+
}
147+
148+
return $sentMessage;
149+
}
150+
151+
throw new TransportException('Unable to send the SMS.', $response);
152+
}
153+
154+
private function generateSignature(array $data, int $timestamp): string
155+
{
156+
$params = [
157+
'timestamp' => $timestamp,
158+
'login' => $this->login,
159+
'phone' => $data['phone'],
160+
'sender' => $this->from,
161+
'text' => $data['text'],
162+
];
163+
164+
ksort($params);
165+
reset($params);
166+
167+
return md5(implode('', $params).$this->password);
168+
}
169+
170+
private function escapePhoneNumber(string $phoneNumber): string
171+
{
172+
return str_replace('+', '00', $phoneNumber);
173+
}
174+
175+
private function getErrorMsg(int $err 2D03 orCode): string
176+
{
177+
return self::ERROR_CODES[$errorCode] ?? self::ERROR_CODES[999];
178+
}
179+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Notifier\Bridge\LightSms;
13+
14+
use Symfony\Component\Notifier\Exception\UnsupportedSchemeException;
15+
use Symfony\Component\Notifier\Transport\AbstractTransportFactory;
16+
use Symfony\Component\Notifier\Transport\Dsn;
17+
use Symfony\Component\Notifier\Transport\TransportInterface;
18+
19+
/**
20+
* @author Vasilij Duško <vasilij@prado.lt>
21+
*/
22+
final class LightSmsTransportFactory extends AbstractTransportFactory
23+
{
24+
/**
25+
* @return LightSmsTransport
26+
*/
27+
public function create(Dsn $dsn): TransportInterface
28+
{
29+
$scheme = $dsn->getScheme();
30+
31+
if ('lightsms' !== $scheme) {
32+
throw new UnsupportedSchemeException($dsn, 'lightsms', $this->getSupportedSchemes());
33+
}
34+
35+
$login = $this->getUser($dsn);
36+
$token = $this->getPassword($dsn);
37+
$from = $dsn->getRequiredOption('from');
38+
39+
$host = 'default' === $dsn->getHost() ? null : $dsn->getHost();
40+
$port = $dsn->getPort();
41+
42+
return (new LightSmsTransport($login, $token, $from, $this->client, $this->dispatcher))->setHost($host)->setPort($port);
43+
}
44+
45+
protected function getSupportedSchemes(): array
46+
{
47+
return ['lightsms'];
48+
}
49+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
LightSms Notifier
2+
=================
3+
4+
Provides [LightSms](https://www.lightsms.com/) integration for Symfony Notifier.
5+
6+
DSN example
7+
-----------
8+
9+
```
10+
LIGHTSMS_DSN=lightsms://LOGIN:TOKEN@default?from=PHONE
11+
```
12+
13+
where:
14+
- `LOGIN` is your LightSms login
15+
- `TOKEN` is the token displayed in your account
16+
- `PHONE` is your LightSms sender phone number
17+
18+
See your account info at https://www.lightsms.com/external/client/api/
19+
20+
Resources
21+
---------
22+
23+
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
24+
* [Report issues](https://github.com/symfony/symfony/issues) and
25+
[send Pull Requests](https://github.com/symfony/symfony/pulls)
26+
in the [main Symfony repository](https://github.com/symfony/symfony)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Notifier\Bridge\LightSms\Tests;
13+
14+
use Symfony\Component\Notifier\Bridge\LightSms\LightSmsTransportFactory;
15+
use Symfony\Component\Notifier\Test\TransportFactoryTestCase;
16+
use Symfony\Component\Notifier\Transport\TransportFactoryInterface;
17+
18+
final class LightSmsTransportFactoryTest extends TransportFactoryTestCase
19+
{
20+
/**
21+
* @return LightSmsTransportFactory
22+
*/
23+
public function createFactory(): TransportFactoryInterface
24+
{
25+
return new LightSmsTransportFactory();
26+
}
27+
28+
public function createProvider(): iterable
29+
{
30+
yield [
31+
'lightsms://host.test?from=0611223344',
32+
'lightsms://login:token@host.test?from=0611223344',
33+
];
34+
}
35+
36+
public function supportsProvider(): iterable
37+
{
38+
yield [true, 'lightsms://login:token@default?from=37061234567'];
39+
yield [false, 'somethingElse://login:token@default?from=37061234567'];
40+
}
41+
42+
public function unsupportedSchemeProvider(): iterable
43+
{
44+
yield ['somethingElse://login:token@default?from=37061234567'];
45+
yield ['somethingElse://login:token@default']; // missing "from" option
46+
}
47+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Notifier\Bridge\LightSms\Tests;
13+
14+
use Symfony\Component\Notifier\Bridge\LightSms\LightSmsTransport;
15+
use Symfony\Component\Notifier\Message\ChatMessage;
16+
use Symfony\Component\Notifier\Message\MessageInterface;
17+
use Symfony\Component\Notifier\Message\SmsMessage;
18+
use Symfony\Component\Notifier\Test\TransportTestCase;
19+
use Symfony\Component\Notifier\Transport\TransportInterface;
20+
use Symfony\Contracts\HttpClient\HttpClientInterface;
21+
22+
final class LightSmsTransportTest extends TransportTestCase
23+
{
24+
/**
25+
* @return LightSmsTransport
26+
*/
27+
public function createTransport(?HttpClientInterface $client = null): TransportInterface
28+
{
29+
return new LightSmsTransport('accountSid', 'authToken', 'from', $client ?: $this->createMock(HttpClientInterface::class));
30+
}
31+
32+
public function toStringProvider(): iterable
33+
{
34+
yield ['lightsms://www.lightsms.com?from=from', $this->createTransport()];
35+
}
36+
37+
public function supportedMessagesProvider(): iterable
38+
{
39+
yield [new SmsMessage('0611223344', 'Hello!')];
40+
}
41+
42+
public function unsupportedMessagesProvider(): iterable
43+
{
44+
yield [new ChatMessage('Hello!')];
45+
yield [$this->createMock(MessageInterface::class)];
46+
}
47+
}

0 commit comments

Comments
 (0)
0