From 983914c516a7f35eacfd7266a68a7009d7f5e39d Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:08:56 +0000 Subject: [PATCH 01/18] feat: geosms adapter --- src/Utopia/Messaging/Adapters/SMS/GEOSMS.php | 281 +++++++++++++++++++ tests/e2e/SMS/GEOSMSTest.php | 57 ++++ 2 files changed, 338 insertions(+) create mode 100644 src/Utopia/Messaging/Adapters/SMS/GEOSMS.php create mode 100644 tests/e2e/SMS/GEOSMSTest.php diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php new file mode 100644 index 00000000..49e4e516 --- /dev/null +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php @@ -0,0 +1,281 @@ + 'UK (+44)', + '1' => 'USA (+1)', + '213' => 'Algeria (+213)', + '376' => 'Andorra (+376)', + '244' => 'Angola (+244)', + '1264' => 'Anguilla (+1264)', + '1268' => 'Antigua & Barbuda (+1268)', + '54' => 'Argentina (+54)', + '374' => 'Armenia (+374)', + '297' => 'Aruba (+297)', + '61' => 'Australia (+61)', + '43' => 'Austria (+43)', + '994' => 'Azerbaijan (+994)', + '1242' => 'Bahamas (+1242)', + '973' => 'Bahrain (+973)', + '880' => 'Bangladesh (+880)', + '1246' => 'Barbados (+1246)', + '375' => 'Belarus (+375)', + '32' => 'Belgium (+32)', + '501' => 'Belize (+501)', + '229' => 'Benin (+229)', + '1441' => 'Bermuda (+1441)', + '975' => 'Bhutan (+975)', + '591' => 'Bolivia (+591)', + '387' => 'Bosnia Herzegovina (+387)', + '267' => 'Botswana (+267)', + '55' => 'Brazil (+55)', + '673' => 'Brunei (+673)', + '359' => 'Bulgaria (+359)', + '226' => 'Burkina Faso (+226)', + '257' => 'Burundi (+257)', + '855' => 'Cambodia (+855)', + '237' => 'Cameroon (+237)', + '1' => 'Canada (+1)', + '238' => 'Cape Verde Islands (+238)', + '1345' => 'Cayman Islands (+1345)', + '236' => 'Central African Republic (+236)', + '56' => 'Chile (+56)', + '86' => 'China (+86)', + '57' => 'Colombia (+57)', + '269' => 'Comoros (+269)', + '242' => 'Congo (+242)', + '682' => 'Cook Islands (+682)', + '506' => 'Costa Rica (+506)', + '385' => 'Croatia (+385)', + '53' => 'Cuba (+53)', + '90392' => 'Cyprus North (+90392)', + '357' => 'Cyprus South (+357)', + '42' => 'Czech Republic (+42)', + '45' => 'Denmark (+45)', + '253' => 'Djibouti (+253)', + '1809' => 'Dominica (+1809)', + '1809' => 'Dominican Republic (+1809)', + '593' => 'Ecuador (+593)', + '20' => 'Egypt (+20)', + '503' => 'El Salvador (+503)', + '240' => 'Equatorial Guinea (+240)', + '291' => 'Eritrea (+291)', + '372' => 'Estonia (+372)', + '251' => 'Ethiopia (+251)', + '500' => 'Falkland Islands (+500)', + '298' => 'Faroe Islands (+298)', + '679' => 'Fiji (+679)', + '358' => 'Finland (+358)', + '33' => 'France (+33)', + '594' => 'French Guiana (+594)', + '689' => 'French Polynesia (+689)', + '241' => 'Gabon (+241)', + '220' => 'Gambia (+220)', + '7880' => 'Georgia (+7880)', + '49' => 'Germany (+49)', + '233' => 'Ghana (+233)', + '350' => 'Gibraltar (+350)', + '30' => 'Greece (+30)', + '299' => 'Greenland (+299)', + '1473' => 'Grenada (+1473)', + '590' => 'Guadeloupe (+590)', + '671' => 'Guam (+671)', + '502' => 'Guatemala (+502)', + '224' => 'Guinea (+224)', + '245' => 'Guinea - Bissau (+245)', + '592' => 'Guyana (+592)', + '509' => 'Haiti (+509)', + '504' => 'Honduras (+504)', + '852' => 'Hong Kong (+852)', + '36' => 'Hungary (+36)', + '354' => 'Iceland (+354)', + '91' => 'India (+91)', + '62' => 'Indonesia (+62)', + '98' => 'Iran (+98)', + '964' => 'Iraq (+964)', + '353' => 'Ireland (+353)', + '972' => 'Israel (+972)', + '39' => 'Italy (+39)', + '1876' => 'Jamaica (+1876)', + '81' => 'Japan (+81)', + '962' => 'Jordan (+962)', + '7' => 'Kazakhstan (+7)', + '254' => 'Kenya (+254)', + '686' => 'Kiribati (+686)', + '850' => 'Korea North (+850)', + '82' => 'Korea South (+82)', + '965' => 'Kuwait (+965)', + '996' => 'Kyrgyzstan (+996)', + '856' => 'Laos (+856)', + '371' => 'Latvia (+371)', + '961' => 'Lebanon (+961)', + '266' => 'Lesotho (+266)', + '231' => 'Liberia (+231)', + '218' => 'Libya (+218)', + '417' => 'Liechtenstein (+417)', + '370' => 'Lithuania (+370)', + '352' => 'Luxembourg (+352)', + '853' => 'Macao (+853)', + '389' => 'Macedonia (+389)', + '261' => 'Madagascar (+261)', + '265' => 'Malawi (+265)', + '60' => 'Malaysia (+60)', + '960' => 'Maldives (+960)', + '223' => 'Mali (+223)', + '356' => 'Malta (+356)', + '692' => 'Marshall Islands (+692)', + '596' => 'Martinique (+596)', + '222' => 'Mauritania (+222)', + '269' => 'Mayotte (+269)', + '52' => 'Mexico (+52)', + '691' => 'Micronesia (+691)', + '373' => 'Moldova (+373)', + '377' => 'Monaco (+377)', + '976' => 'Mongolia (+976)', + '1664' => 'Montserrat (+1664)', + '212' => 'Morocco (+212)', + '258' => 'Mozambique (+258)', + '95' => 'Myanmar (+95)', + '264' => 'Namibia (+264)', + '674' => 'Nauru (+674)', + '977' => 'Nepal (+977)', + '31' => 'Netherlands (+31)', + '687' => 'New Caledonia (+687)', + '64' => 'New Zealand (+64)', + '505' => 'Nicaragua (+505)', + '227' => 'Niger (+227)', + '234' => 'Nigeria (+234)', + '683' => 'Niue (+683)', + '672' => 'Norfolk Islands (+672)', + '670' => 'Northern Marianas (+670)', + '47' => 'Norway (+47)', + '968' => 'Oman (+968)', + '680' => 'Palau (+680)', + '507' => 'Panama (+507)', + '675' => 'Papua New Guinea (+675)', + '595' => 'Paraguay (+595)', + '51' => 'Peru (+51)', + '63' => 'Philippines (+63)', + '48' => 'Poland (+48)', + '351' => 'Portugal (+351)', + '1787' => 'Puerto Rico (+1787)', + '974' => 'Qatar (+974)', + '262' => 'Reunion (+262)', + '40' => 'Romania (+40)', + '7' => 'Russia (+7)', + '250' => 'Rwanda (+250)', + '378' => 'San Marino (+378)', + '239' => 'Sao Tome & Principe (+239)', + '966' => 'Saudi Arabia (+966)', + '221' => 'Senegal (+221)', + '381' => 'Serbia (+381)', + '248' => 'Seychelles (+248)', + '232' => 'Sierra Leone (+232)', + '65' => 'Singapore (+65)', + '421' => 'Slovak Republic (+421)', + '386' => 'Slovenia (+386)', + '677' => 'Solomon Islands (+677)', + '252' => 'Somalia (+252)', + '27' => 'South Africa (+27)', + '34' => 'Spain (+34)', + '94' => 'Sri Lanka (+94)', + '290' => 'St. Helena (+290)', + '1869' => 'St. Kitts (+1869)', + '1758' => 'St. Lucia (+1758)', + '249' => 'Sudan (+249)', + '597' => 'Suriname (+597)', + '268' => 'Swaziland (+268)', + '46' => 'Sweden (+46)', + '41' => 'Switzerland (+41)', + '963' => 'Syria (+963)', + '886' => 'Taiwan (+886)', + '7' => 'Tajikstan (+7)', + '66' => 'Thailand (+66)', + '228' => 'Togo (+228)', + '676' => 'Tonga (+676)', + '1868' => 'Trinidad & Tobago (+1868)', + '216' => 'Tunisia (+216)', + '90' => 'Turkey (+90)', + '7' => 'Turkmenistan (+7)', + '993' => 'Turkmenistan (+993)', + '1649' => 'Turks & Caicos Islands (+1649)', + '688' => 'Tuvalu (+688)', + '256' => 'Uganda (+256)', + '380' => 'Ukraine (+380)', + '971' => 'United Arab Emirates (+971)', + '598' => 'Uruguay (+598)', + '7' => 'Uzbekistan (+7)', + '678' => 'Vanuatu (+678)', + '379' => 'Vatican City (+379)', + '58' => 'Venezuela (+58)', + '84' => 'Vietnam (+84)', + '84' => 'Virgin Islands - British (+1284)', + '84' => 'Virgin Islands - US (+1340)', + '681' => 'Wallis & Futuna (+681)', + '969' => 'Yemen (North)(+969)', + '967' => 'Yemen (South)(+967)', + '260' => 'Zambia (+260)', + '263' => 'Zimbabwe (+263)', + ]; + + protected $defaultAdapter; + protected $localAdapters = []; + + public function __construct(SMSAdapter $defaultAdapter) + { + $this->defaultAdapter = $defaultAdapter; + } + + public function getName(): string + { + return 'GEOSMS'; + } + + public function getMaxMessagesPerRequest(): int + { + return $this->defaultAdapter->getMaxMessagesPerRequest(); + } + + public function setLocal(string $prefix, SMSAdapter $adapter): self + { + $this->localAdapters[$prefix] = $adapter; + return $this; + } + + protected function process(SMS $message): string + { + $adapter = $this->getAdapterForMessage($message); + return $adapter->send($message); + } + + protected function getAdapterForMessage(SMS $message): SMSAdapter + { + foreach ($message->getTo() as $recipient) { + $prefix = $this->extractPrefix($recipient); + if (!empty($prefix) && array_key_exists($prefix, $this->localAdapters)) { + return $this->localAdapters[$prefix]; + } + } + + return $this->defaultAdapter; + } + + protected function extractPrefix(string $phoneNumber): string + { + $digits = preg_replace('/\D/', '', $phoneNumber); + foreach ([3, 2, 1] as $length) { + $prefix = substr($digits, 0, $length); + if (isset(self::COUNTRY_CODES[$prefix])) { + return '+' . $prefix; + } + } + return ''; + } +} diff --git a/tests/e2e/SMS/GEOSMSTest.php b/tests/e2e/SMS/GEOSMSTest.php new file mode 100644 index 00000000..b259c9a6 --- /dev/null +++ b/tests/e2e/SMS/GEOSMSTest.php @@ -0,0 +1,57 @@ +createMock(SMSAdapter::class); + $defaultAdapterMock->method('send') + ->willReturn(json_encode(['status' => 'success'])); + + $adapter = new GeoSms($defaultAdapterMock); + + $to = ['+11234567890']; + $from = 'Sender'; + + $message = new SMS( + to: $to, + content: 'Test Content', + from: $from + ); + + $result = json_decode($adapter->send($message)); + + $this->assertEquals('success', $result->status); + } + + public function testSendSMSUsingLocalAdapter() + { + $defaultAdapterMock = $this->createMock(SMSAdapter::class); + $localAdapterMock = $this->createMock(SMSAdapter::class); + $localAdapterMock->method('send') + ->willReturn(json_encode(['status' => 'success', 'adapter' => 'local'])); + + $adapter = new GEOSMS($defaultAdapterMock); + $adapter->setLocal('44', $localAdapterMock); + + $to = ['+441234567890']; + $from = 'Sender'; + + $message = new SMS( + to: $to, + content: 'Test Content', + from: $from + ); + + $result = json_decode($adapter->send($message)); + + $this->assertEquals('success', $result->status); + $this->assertEquals('local', $result->adapter); + } +} From 1284c5bdd92047fac0a42ec309103558029fb179 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:14:32 +0000 Subject: [PATCH 02/18] test: enable msg91 --- tests/e2e/SMS/Msg91Test.php | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/e2e/SMS/Msg91Test.php b/tests/e2e/SMS/Msg91Test.php index df90f4c4..61ec35f0 100644 --- a/tests/e2e/SMS/Msg91Test.php +++ b/tests/e2e/SMS/Msg91Test.php @@ -12,19 +12,17 @@ class Msg91Test extends Base */ public function testSendSMS() { - // $sender = new Msg91(getenv('MSG_91_SENDER_ID'), getenv('MSG_91_AUTH_KEY')); + $sender = new Msg91(getenv('MSG_91_SENDER_ID'), getenv('MSG_91_AUTH_KEY')); - // $message = new SMS( - // to: [getenv('MSG_91_TO')], - // content: 'Test Content', - // from: getenv('MSG_91_FROM') - // ); + $message = new SMS( + to: [getenv('MSG_91_TO')], + content: 'Test Content', + from: getenv('MSG_91_FROM') + ); - // $response = $sender->send($message); - // $result = \json_decode($response, true); + $response = $sender->send($message); + $result = \json_decode($response, true); - // $this->assertEquals('success', $result['type']); - - $this->markTestSkipped('Msg91 requires business verification to use template and SMS api.'); + $this->assertEquals('success', $result['type']); } } From a9e2d22d101db98751c02536e54681cda376148e Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:16:27 +0000 Subject: [PATCH 03/18] chore: fmt --- src/Utopia/Messaging/Adapters/SMS/GEOSMS.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php index 49e4e516..cb153711 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php @@ -5,7 +5,6 @@ use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Messages\SMS; - class GEOSMS extends SMSAdapter { protected const COUNTRY_CODES = [ @@ -226,6 +225,7 @@ class GEOSMS extends SMSAdapter ]; protected $defaultAdapter; + protected $localAdapters = []; public function __construct(SMSAdapter $defaultAdapter) @@ -246,12 +246,14 @@ public function getMaxMessagesPerRequest(): int public function setLocal(string $prefix, SMSAdapter $adapter): self { $this->localAdapters[$prefix] = $adapter; + return $this; } protected function process(SMS $message): string { $adapter = $this->getAdapterForMessage($message); + return $adapter->send($message); } @@ -259,7 +261,7 @@ protected function getAdapterForMessage(SMS $message): SMSAdapter { foreach ($message->getTo() as $recipient) { $prefix = $this->extractPrefix($recipient); - if (!empty($prefix) && array_key_exists($prefix, $this->localAdapters)) { + if (! empty($prefix) && array_key_exists($prefix, $this->localAdapters)) { return $this->localAdapters[$prefix]; } } @@ -273,9 +275,10 @@ protected function extractPrefix(string $phoneNumber): string foreach ([3, 2, 1] as $length) { $prefix = substr($digits, 0, $length); if (isset(self::COUNTRY_CODES[$prefix])) { - return '+' . $prefix; + return '+'.$prefix; } } + return ''; } } From 1c6b1c7875f2bfe0c2440e420f2c3aab449c57ee Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:18:49 +0000 Subject: [PATCH 04/18] fix: geosms namespace --- src/Utopia/Messaging/Adapters/SMS/GEOSMS.php | 6 +++--- tests/e2e/SMS/GEOSMSTest.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php index cb153711..dedc9f22 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php @@ -1,6 +1,6 @@ getTo() as $recipient) { $prefix = $this->extractPrefix($recipient); - if (! empty($prefix) && array_key_exists($prefix, $this->localAdapters)) { + if (!empty($prefix) && array_key_exists($prefix, $this->localAdapters)) { return $this->localAdapters[$prefix]; } } @@ -275,7 +275,7 @@ protected function extractPrefix(string $phoneNumber): string foreach ([3, 2, 1] as $length) { $prefix = substr($digits, 0, $length); if (isset(self::COUNTRY_CODES[$prefix])) { - return '+'.$prefix; + return '+' . $prefix; } } diff --git a/tests/e2e/SMS/GEOSMSTest.php b/tests/e2e/SMS/GEOSMSTest.php index b259c9a6..dbf775dc 100644 --- a/tests/e2e/SMS/GEOSMSTest.php +++ b/tests/e2e/SMS/GEOSMSTest.php @@ -2,7 +2,7 @@ namespace Tests\E2E; -use Utopia\Messaging\Adapters\GEOSMS; +use Utopia\Messaging\Adapters\SMS\GEOSMS; use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Messages\SMS; @@ -14,7 +14,7 @@ public function testSendSMSUsingDefaultAdapter() $defaultAdapterMock->method('send') ->willReturn(json_encode(['status' => 'success'])); - $adapter = new GeoSms($defaultAdapterMock); + $adapter = new GEOSMS($defaultAdapterMock); $to = ['+11234567890']; $from = 'Sender'; From 83641f13b47d6194835ddbfb98f0814396a1499e Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:19:38 +0000 Subject: [PATCH 05/18] chore: fmt --- src/Utopia/Messaging/Adapters/SMS/GEOSMS.php | 4 ++-- tests/e2e/SMS/GEOSMSTest.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php index dedc9f22..c726d872 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php @@ -261,7 +261,7 @@ protected function getAdapterForMessage(SMS $message): SMSAdapter { foreach ($message->getTo() as $recipient) { $prefix = $this->extractPrefix($recipient); - if (!empty($prefix) && array_key_exists($prefix, $this->localAdapters)) { + if (! empty($prefix) && array_key_exists($prefix, $this->localAdapters)) { return $this->localAdapters[$prefix]; } } @@ -275,7 +275,7 @@ protected function extractPrefix(string $phoneNumber): string foreach ([3, 2, 1] as $length) { $prefix = substr($digits, 0, $length); if (isset(self::COUNTRY_CODES[$prefix])) { - return '+' . $prefix; + return '+'.$prefix; } } diff --git a/tests/e2e/SMS/GEOSMSTest.php b/tests/e2e/SMS/GEOSMSTest.php index dbf775dc..c56c95ff 100644 --- a/tests/e2e/SMS/GEOSMSTest.php +++ b/tests/e2e/SMS/GEOSMSTest.php @@ -2,8 +2,8 @@ namespace Tests\E2E; -use Utopia\Messaging\Adapters\SMS\GEOSMS; use Utopia\Messaging\Adapters\SMS as SMSAdapter; +use Utopia\Messaging\Adapters\SMS\GEOSMS; use Utopia\Messaging\Messages\SMS; class GEOSMSTest extends Base From fe65ede70e3430cdb760c04896274ef0f8845d20 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:23:10 +0000 Subject: [PATCH 06/18] fix: geosms mock --- tests/e2e/SMS/GEOSMSTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/e2e/SMS/GEOSMSTest.php b/tests/e2e/SMS/GEOSMSTest.php index c56c95ff..ed39f235 100644 --- a/tests/e2e/SMS/GEOSMSTest.php +++ b/tests/e2e/SMS/GEOSMSTest.php @@ -11,6 +11,8 @@ class GEOSMSTest extends Base public function testSendSMSUsingDefaultAdapter() { $defaultAdapterMock = $this->createMock(SMSAdapter::class); + $defaultAdapterMock->method('getMaxMessagesPerRequest') + ->willReturn(1); $defaultAdapterMock->method('send') ->willReturn(json_encode(['status' => 'success'])); @@ -33,6 +35,8 @@ public function testSendSMSUsingDefaultAdapter() public function testSendSMSUsingLocalAdapter() { $defaultAdapterMock = $this->createMock(SMSAdapter::class); + $defaultAdapterMock->method('getMaxMessagesPerRequest') + ->willReturn(1); $localAdapterMock = $this->createMock(SMSAdapter::class); $localAdapterMock->method('send') ->willReturn(json_encode(['status' => 'success', 'adapter' => 'local'])); From f212fc8dae1751dfeefeedaed92c45bff6bd5650 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:33:42 +0000 Subject: [PATCH 07/18] fix: geosms remove + --- src/Utopia/Messaging/Adapters/SMS/GEOSMS.php | 3 ++- tests/e2e/Email/SendgridTest.php | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php index c726d872..d00b9860 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php @@ -245,6 +245,7 @@ public function getMaxMessagesPerRequest(): int public function setLocal(string $prefix, SMSAdapter $adapter): self { + $prefix = preg_replace('/\+/', '', $prefix); $this->localAdapters[$prefix] = $adapter; return $this; @@ -275,7 +276,7 @@ protected function extractPrefix(string $phoneNumber): string foreach ([3, 2, 1] as $length) { $prefix = substr($digits, 0, $length); if (isset(self::COUNTRY_CODES[$prefix])) { - return '+'.$prefix; + return $prefix; } } diff --git a/tests/e2e/Email/SendgridTest.php b/tests/e2e/Email/SendgridTest.php index 9437b167..ddce65bd 100644 --- a/tests/e2e/Email/SendgridTest.php +++ b/tests/e2e/Email/SendgridTest.php @@ -12,6 +12,7 @@ class SendgridTest extends Base */ public function testSendEmail() { + /* $key = getenv('SENDGRID_API_KEY'); $sender = new Sendgrid($key); @@ -30,5 +31,8 @@ public function testSendEmail() $response = $sender->send($message); $this->assertEquals($response, ''); + */ + + $this->markTestSkipped('Sendgrid: Authenticated user is not authorized to send mail'); } } From e199d58790038c4be05387fb300fa9c753dbcc26 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 7 Nov 2023 15:02:02 +0000 Subject: [PATCH 08/18] feat: return lowest of adapters for getMaxMessagesPerRequest --- src/Utopia/Messaging/Adapters/SMS/GEOSMS.php | 6 +++++- tests/e2e/SMS/GEOSMSTest.php | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php index d00b9860..500077a3 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php @@ -228,9 +228,12 @@ class GEOSMS extends SMSAdapter protected $localAdapters = []; + protected $maxMessagesPerRequest; + public function __construct(SMSAdapter $defaultAdapter) { $this->defaultAdapter = $defaultAdapter; + $this->maxMessagesPerRequest = $defaultAdapter->getMaxMessagesPerRequest(); } public function getName(): string @@ -240,13 +243,14 @@ public function getName(): string public function getMaxMessagesPerRequest(): int { - return $this->defaultAdapter->getMaxMessagesPerRequest(); + return $this->maxMessagesPerRequest; } public function setLocal(string $prefix, SMSAdapter $adapter): self { $prefix = preg_replace('/\+/', '', $prefix); $this->localAdapters[$prefix] = $adapter; + $this->maxMessagesPerRequest = min($this->maxMessagesPerRequest, $adapter->getMaxMessagesPerRequest()); return $this; } diff --git a/tests/e2e/SMS/GEOSMSTest.php b/tests/e2e/SMS/GEOSMSTest.php index ed39f235..255f6601 100644 --- a/tests/e2e/SMS/GEOSMSTest.php +++ b/tests/e2e/SMS/GEOSMSTest.php @@ -38,6 +38,8 @@ public function testSendSMSUsingLocalAdapter() $defaultAdapterMock->method('getMaxMessagesPerRequest') ->willReturn(1); $localAdapterMock = $this->createMock(SMSAdapter::class); + $localAdapterMock->method('getMaxMessagesPerRequest') + ->willReturn(1); $localAdapterMock->method('send') ->willReturn(json_encode(['status' => 'success', 'adapter' => 'local'])); @@ -58,4 +60,19 @@ public function testSendSMSUsingLocalAdapter() $this->assertEquals('success', $result->status); $this->assertEquals('local', $result->adapter); } + + public function testMaxMessagesPerRequestIsLowest() + { + $defaultAdapterMock = $this->createMock(SMSAdapter::class); + $defaultAdapterMock->method('getMaxMessagesPerRequest') + ->willReturn(1000); + $localAdapterMock = $this->createMock(SMSAdapter::class); + $localAdapterMock->method('getMaxMessagesPerRequest') + ->willReturn(2); + + $adapter = new GEOSMS($defaultAdapterMock); + $adapter->setLocal('44', $localAdapterMock); + + $this->assertEquals(2, $adapter->getMaxMessagesPerRequest()); + } } From cb5ffeadd0bf6953c01e995e2b0a6bb42879c963 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:48:44 +0000 Subject: [PATCH 09/18] feat: extract calling code --- src/Utopia/Messaging/Adapters/SMS/GEOSMS.php | 272 ++---------------- .../Adapters/SMS/GEOSMS/CallingCode.php | 219 ++++++++++++++ tests/e2e/SMS/GEOSMS/CallingCodeTest.php | 16 ++ tests/e2e/SMS/GEOSMSTest.php | 18 +- 4 files changed, 261 insertions(+), 264 deletions(-) create mode 100644 src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php create mode 100644 tests/e2e/SMS/GEOSMS/CallingCodeTest.php diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php index 500077a3..a9e1a3ec 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php @@ -2,238 +2,18 @@ namespace Utopia\Messaging\Adapters\SMS; +use Utopia\Messaging\Adapters\SMS\GEOSMS\CallingCode; use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Messages\SMS; class GEOSMS extends SMSAdapter { - protected const COUNTRY_CODES = [ - '44' => 'UK (+44)', - '1' => 'USA (+1)', - '213' => 'Algeria (+213)', - '376' => 'Andorra (+376)', - '244' => 'Angola (+244)', - '1264' => 'Anguilla (+1264)', - '1268' => 'Antigua & Barbuda (+1268)', - '54' => 'Argentina (+54)', - '374' => 'Armenia (+374)', - '297' => 'Aruba (+297)', - '61' => 'Australia (+61)', - '43' => 'Austria (+43)', - '994' => 'Azerbaijan (+994)', - '1242' => 'Bahamas (+1242)', - '973' => 'Bahrain (+973)', - '880' => 'Bangladesh (+880)', - '1246' => 'Barbados (+1246)', - '375' => 'Belarus (+375)', - '32' => 'Belgium (+32)', - '501' => 'Belize (+501)', - '229' => 'Benin (+229)', - '1441' => 'Bermuda (+1441)', - '975' => 'Bhutan (+975)', - '591' => 'Bolivia (+591)', - '387' => 'Bosnia Herzegovina (+387)', - '267' => 'Botswana (+267)', - '55' => 'Brazil (+55)', - '673' => 'Brunei (+673)', - '359' => 'Bulgaria (+359)', - '226' => 'Burkina Faso (+226)', - '257' => 'Burundi (+257)', - '855' => 'Cambodia (+855)', - '237' => 'Cameroon (+237)', - '1' => 'Canada (+1)', - '238' => 'Cape Verde Islands (+238)', - '1345' => 'Cayman Islands (+1345)', - '236' => 'Central African Republic (+236)', - '56' => 'Chile (+56)', - '86' => 'China (+86)', - '57' => 'Colombia (+57)', - '269' => 'Comoros (+269)', - '242' => 'Congo (+242)', - '682' => 'Cook Islands (+682)', - '506' => 'Costa Rica (+506)', - '385' => 'Croatia (+385)', - '53' => 'Cuba (+53)', - '90392' => 'Cyprus North (+90392)', - '357' => 'Cyprus South (+357)', - '42' => 'Czech Republic (+42)', - '45' => 'Denmark (+45)', - '253' => 'Djibouti (+253)', - '1809' => 'Dominica (+1809)', - '1809' => 'Dominican Republic (+1809)', - '593' => 'Ecuador (+593)', - '20' => 'Egypt (+20)', - '503' => 'El Salvador (+503)', - '240' => 'Equatorial Guinea (+240)', - '291' => 'Eritrea (+291)', - '372' => 'Estonia (+372)', - '251' => 'Ethiopia (+251)', - '500' => 'Falkland Islands (+500)', - '298' => 'Faroe Islands (+298)', - '679' => 'Fiji (+679)', - '358' => 'Finland (+358)', - '33' => 'France (+33)', - '594' => 'French Guiana (+594)', - '689' => 'French Polynesia (+689)', - '241' => 'Gabon (+241)', - '220' => 'Gambia (+220)', - '7880' => 'Georgia (+7880)', - '49' => 'Germany (+49)', - '233' => 'Ghana (+233)', - '350' => 'Gibraltar (+350)', - '30' => 'Greece (+30)', - '299' => 'Greenland (+299)', - '1473' => 'Grenada (+1473)', - '590' => 'Guadeloupe (+590)', - '671' => 'Guam (+671)', - '502' => 'Guatemala (+502)', - '224' => 'Guinea (+224)', - '245' => 'Guinea - Bissau (+245)', - '592' => 'Guyana (+592)', - '509' => 'Haiti (+509)', - '504' => 'Honduras (+504)', - '852' => 'Hong Kong (+852)', - '36' => 'Hungary (+36)', - '354' => 'Iceland (+354)', - '91' => 'India (+91)', - '62' => 'Indonesia (+62)', - '98' => 'Iran (+98)', - '964' => 'Iraq (+964)', - '353' => 'Ireland (+353)', - '972' => 'Israel (+972)', - '39' => 'Italy (+39)', - '1876' => 'Jamaica (+1876)', - '81' => 'Japan (+81)', - '962' => 'Jordan (+962)', - '7' => 'Kazakhstan (+7)', - '254' => 'Kenya (+254)', - '686' => 'Kiribati (+686)', - '850' => 'Korea North (+850)', - '82' => 'Korea South (+82)', - '965' => 'Kuwait (+965)', - '996' => 'Kyrgyzstan (+996)', - '856' => 'Laos (+856)', - '371' => 'Latvia (+371)', - '961' => 'Lebanon (+961)', - '266' => 'Lesotho (+266)', - '231' => 'Liberia (+231)', - '218' => 'Libya (+218)', - '417' => 'Liechtenstein (+417)', - '370' => 'Lithuania (+370)', - '352' => 'Luxembourg (+352)', - '853' => 'Macao (+853)', - '389' => 'Macedonia (+389)', - '261' => 'Madagascar (+261)', - '265' => 'Malawi (+265)', - '60' => 'Malaysia (+60)', - '960' => 'Maldives (+960)', - '223' => 'Mali (+223)', - '356' => 'Malta (+356)', - '692' => 'Marshall Islands (+692)', - '596' => 'Martinique (+596)', - '222' => 'Mauritania (+222)', - '269' => 'Mayotte (+269)', - '52' => 'Mexico (+52)', - '691' => 'Micronesia (+691)', - '373' => 'Moldova (+373)', - '377' => 'Monaco (+377)', - '976' => 'Mongolia (+976)', - '1664' => 'Montserrat (+1664)', - '212' => 'Morocco (+212)', - '258' => 'Mozambique (+258)', - '95' => 'Myanmar (+95)', - '264' => 'Namibia (+264)', - '674' => 'Nauru (+674)', - '977' => 'Nepal (+977)', - '31' => 'Netherlands (+31)', - '687' => 'New Caledonia (+687)', - '64' => 'New Zealand (+64)', - '505' => 'Nicaragua (+505)', - '227' => 'Niger (+227)', - '234' => 'Nigeria (+234)', - '683' => 'Niue (+683)', - '672' => 'Norfolk Islands (+672)', - '670' => 'Northern Marianas (+670)', - '47' => 'Norway (+47)', - '968' => 'Oman (+968)', - '680' => 'Palau (+680)', - '507' => 'Panama (+507)', - '675' => 'Papua New Guinea (+675)', - '595' => 'Paraguay (+595)', - '51' => 'Peru (+51)', - '63' => 'Philippines (+63)', - '48' => 'Poland (+48)', - '351' => 'Portugal (+351)', - '1787' => 'Puerto Rico (+1787)', - '974' => 'Qatar (+974)', - '262' => 'Reunion (+262)', - '40' => 'Romania (+40)', - '7' => 'Russia (+7)', - '250' => 'Rwanda (+250)', - '378' => 'San Marino (+378)', - '239' => 'Sao Tome & Principe (+239)', - '966' => 'Saudi Arabia (+966)', - '221' => 'Senegal (+221)', - '381' => 'Serbia (+381)', - '248' => 'Seychelles (+248)', - '232' => 'Sierra Leone (+232)', - '65' => 'Singapore (+65)', - '421' => 'Slovak Republic (+421)', - '386' => 'Slovenia (+386)', - '677' => 'Solomon Islands (+677)', - '252' => 'Somalia (+252)', - '27' => 'South Africa (+27)', - '34' => 'Spain (+34)', - '94' => 'Sri Lanka (+94)', - '290' => 'St. Helena (+290)', - '1869' => 'St. Kitts (+1869)', - '1758' => 'St. Lucia (+1758)', - '249' => 'Sudan (+249)', - '597' => 'Suriname (+597)', - '268' => 'Swaziland (+268)', - '46' => 'Sweden (+46)', - '41' => 'Switzerland (+41)', - '963' => 'Syria (+963)', - '886' => 'Taiwan (+886)', - '7' => 'Tajikstan (+7)', - '66' => 'Thailand (+66)', - '228' => 'Togo (+228)', - '676' => 'Tonga (+676)', - '1868' => 'Trinidad & Tobago (+1868)', - '216' => 'Tunisia (+216)', - '90' => 'Turkey (+90)', - '7' => 'Turkmenistan (+7)', - '993' => 'Turkmenistan (+993)', - '1649' => 'Turks & Caicos Islands (+1649)', - '688' => 'Tuvalu (+688)', - '256' => 'Uganda (+256)', - '380' => 'Ukraine (+380)', - '971' => 'United Arab Emirates (+971)', - '598' => 'Uruguay (+598)', - '7' => 'Uzbekistan (+7)', - '678' => 'Vanuatu (+678)', - '379' => 'Vatican City (+379)', - '58' => 'Venezuela (+58)', - '84' => 'Vietnam (+84)', - '84' => 'Virgin Islands - British (+1284)', - '84' => 'Virgin Islands - US (+1340)', - '681' => 'Wallis & Futuna (+681)', - '969' => 'Yemen (North)(+969)', - '967' => 'Yemen (South)(+967)', - '260' => 'Zambia (+260)', - '263' => 'Zimbabwe (+263)', - ]; - protected $defaultAdapter; - protected $localAdapters = []; - protected $maxMessagesPerRequest; - public function __construct(SMSAdapter $defaultAdapter) { $this->defaultAdapter = $defaultAdapter; - $this->maxMessagesPerRequest = $defaultAdapter->getMaxMessagesPerRequest(); } public function getName(): string @@ -243,47 +23,43 @@ public function getName(): string public function getMaxMessagesPerRequest(): int { - return $this->maxMessagesPerRequest; + return PHP_INT_MAX; } - public function setLocal(string $prefix, SMSAdapter $adapter): self + public function setLocal(CallingCode $callingCode, SMSAdapter $adapter): self { - $prefix = preg_replace('/\+/', '', $prefix); - $this->localAdapters[$prefix] = $adapter; - $this->maxMessagesPerRequest = min($this->maxMessagesPerRequest, $adapter->getMaxMessagesPerRequest()); - + $this->localAdapters[$callingCode->value] = $adapter; return $this; } protected function process(SMS $message): string { - $adapter = $this->getAdapterForMessage($message); - - return $adapter->send($message); - } - - protected function getAdapterForMessage(SMS $message): SMSAdapter - { - foreach ($message->getTo() as $recipient) { - $prefix = $this->extractPrefix($recipient); - if (! empty($prefix) && array_key_exists($prefix, $this->localAdapters)) { - return $this->localAdapters[$prefix]; - } + $recipientsByCallingCode = $this->groupRecipientsByCallingCode($message->getTo()); + $responses = []; + + foreach ($recipientsByCallingCode as $callingCode => $recipients) { + $adapter = isset($this->localAdapters[$callingCode]) ? $this->localAdapters[$callingCode] : $this->defaultAdapter; + + $responses[] = $adapter->send(new SMS( + to: $recipients, + content: $message->getContent(), + from: $message->getFrom(), + attachments: $message->getAttachments() + )); } - return $this->defaultAdapter; + return $responses[0]; } - protected function extractPrefix(string $phoneNumber): string + protected function groupRecipientsByCallingCode(array $recipients): array { - $digits = preg_replace('/\D/', '', $phoneNumber); - foreach ([3, 2, 1] as $length) { - $prefix = substr($digits, 0, $length); - if (isset(self::COUNTRY_CODES[$prefix])) { - return $prefix; - } + $result = []; + + foreach ($recipients as $recipient) { + $callingCode = CallingCode::fromPhoneNumber($recipient); + $result[$callingCode->value][] = $recipient; } - return ''; + return $result; } } diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php new file mode 100644 index 00000000..0e416ef3 --- /dev/null +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php @@ -0,0 +1,219 @@ +assertEquals(CallingCode::USA_AND_CANADA, CallingCode::fromPhoneNumber('+11234567890')); + $this->assertEquals(CallingCode::INDIA, CallingCode::fromPhoneNumber('+911234567890'),); + $this->assertEquals(CallingCode::UNITED_ARAB_EMIRATES, CallingCode::fromPhoneNumber('009711234567890')); + $this->assertEquals(CallingCode::UNITED_KINGDOM, CallingCode::fromPhoneNumber('011441234567890')); + } +} diff --git a/tests/e2e/SMS/GEOSMSTest.php b/tests/e2e/SMS/GEOSMSTest.php index 255f6601..26b0794e 100644 --- a/tests/e2e/SMS/GEOSMSTest.php +++ b/tests/e2e/SMS/GEOSMSTest.php @@ -4,6 +4,7 @@ use Utopia\Messaging\Adapters\SMS as SMSAdapter; use Utopia\Messaging\Adapters\SMS\GEOSMS; +use Utopia\Messaging\Adapters\SMS\GEOSMS\CallingCode; use Utopia\Messaging\Messages\SMS; class GEOSMSTest extends Base @@ -44,7 +45,7 @@ public function testSendSMSUsingLocalAdapter() ->willReturn(json_encode(['status' => 'success', 'adapter' => 'local'])); $adapter = new GEOSMS($defaultAdapterMock); - $adapter->setLocal('44', $localAdapterMock); + $adapter->setLocal(CallingCode::UNITED_KINGDOM, $localAdapterMock); $to = ['+441234567890']; $from = 'Sender'; @@ -60,19 +61,4 @@ public function testSendSMSUsingLocalAdapter() $this->assertEquals('success', $result->status); $this->assertEquals('local', $result->adapter); } - - public function testMaxMessagesPerRequestIsLowest() - { - $defaultAdapterMock = $this->createMock(SMSAdapter::class); - $defaultAdapterMock->method('getMaxMessagesPerRequest') - ->willReturn(1000); - $localAdapterMock = $this->createMock(SMSAdapter::class); - $localAdapterMock->method('getMaxMessagesPerRequest') - ->willReturn(2); - - $adapter = new GEOSMS($defaultAdapterMock); - $adapter->setLocal('44', $localAdapterMock); - - $this->assertEquals(2, $adapter->getMaxMessagesPerRequest()); - } } From 13eaea3e0098bd894149dac4e30abc742118a6cc Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:49:38 +0000 Subject: [PATCH 10/18] chore: rename na code --- src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php | 2 +- tests/e2e/SMS/GEOSMS/CallingCodeTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php index 0e416ef3..5cc38a46 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php @@ -188,7 +188,7 @@ enum CallingCode: string case UNITED_ARAB_EMIRATES = '971'; case UNITED_KINGDOM = '44'; case URUGUAY = '598'; - case USA_AND_CANADA = '1'; + case NORTH_AMERICA = '1'; case VANUATU = '678'; case VENEZUELA = '58'; case VIETNAM = '84'; diff --git a/tests/e2e/SMS/GEOSMS/CallingCodeTest.php b/tests/e2e/SMS/GEOSMS/CallingCodeTest.php index 8feaaa26..50818193 100644 --- a/tests/e2e/SMS/GEOSMS/CallingCodeTest.php +++ b/tests/e2e/SMS/GEOSMS/CallingCodeTest.php @@ -8,7 +8,7 @@ class CallingCodeTest extends Base { public function testFromPhoneNumber() { - $this->assertEquals(CallingCode::USA_AND_CANADA, CallingCode::fromPhoneNumber('+11234567890')); + $this->assertEquals(CallingCode::NORTH_AMERICA, CallingCode::fromPhoneNumber('+11234567890')); $this->assertEquals(CallingCode::INDIA, CallingCode::fromPhoneNumber('+911234567890'),); $this->assertEquals(CallingCode::UNITED_ARAB_EMIRATES, CallingCode::fromPhoneNumber('009711234567890')); $this->assertEquals(CallingCode::UNITED_KINGDOM, CallingCode::fromPhoneNumber('011441234567890')); From 33ccaefdf35e65d253726aaf834dea6f6335dfdf Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:11:49 +0000 Subject: [PATCH 11/18] chore: fmt --- src/Utopia/Messaging/Adapters/SMS/GEOSMS.php | 4 +++- src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php | 7 ++++--- tests/e2e/SMS/GEOSMS/CallingCodeTest.php | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php index a9e1a3ec..bd13018f 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php @@ -2,13 +2,14 @@ namespace Utopia\Messaging\Adapters\SMS; -use Utopia\Messaging\Adapters\SMS\GEOSMS\CallingCode; use Utopia\Messaging\Adapters\SMS as SMSAdapter; +use Utopia\Messaging\Adapters\SMS\GEOSMS\CallingCode; use Utopia\Messaging\Messages\SMS; class GEOSMS extends SMSAdapter { protected $defaultAdapter; + protected $localAdapters = []; public function __construct(SMSAdapter $defaultAdapter) @@ -29,6 +30,7 @@ public function getMaxMessagesPerRequest(): int public function setLocal(CallingCode $callingCode, SMSAdapter $adapter): self { $this->localAdapters[$callingCode->value] = $adapter; + return $this; } diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php index 5cc38a46..38e08ac5 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php @@ -9,7 +9,6 @@ enum CallingCode: string { - case ALGERIA = '213'; case ANDORRA = '376'; case ANGOLA = '244'; @@ -203,7 +202,7 @@ public static function fromPhoneNumber($number): ?CallingCode $digits = str_replace(['+', ' ', '(', ')', '-'], '', $number); // International call prefix is usually 00 or 011 - // https://en.wikipedia.org/wiki/List_of_international_call_prefixes + // https://en.wikipedia.org/wiki/List_of_international_call_prefixes $digits = preg_replace('/^00|^011/', '', $digits); // Prefixes can be 3, 2, or 1 digits long @@ -211,7 +210,9 @@ public static function fromPhoneNumber($number): ?CallingCode foreach ([3, 2, 1] as $length) { $codeScalar = substr($digits, 0, $length); $code = CallingCode::tryFrom($codeScalar); - if ($code) return $code; + if ($code) { + return $code; + } } return null; diff --git a/tests/e2e/SMS/GEOSMS/CallingCodeTest.php b/tests/e2e/SMS/GEOSMS/CallingCodeTest.php index 50818193..74f4a60b 100644 --- a/tests/e2e/SMS/GEOSMS/CallingCodeTest.php +++ b/tests/e2e/SMS/GEOSMS/CallingCodeTest.php @@ -9,7 +9,7 @@ class CallingCodeTest extends Base public function testFromPhoneNumber() { $this->assertEquals(CallingCode::NORTH_AMERICA, CallingCode::fromPhoneNumber('+11234567890')); - $this->assertEquals(CallingCode::INDIA, CallingCode::fromPhoneNumber('+911234567890'),); + $this->assertEquals(CallingCode::INDIA, CallingCode::fromPhoneNumber('+911234567890')); $this->assertEquals(CallingCode::UNITED_ARAB_EMIRATES, CallingCode::fromPhoneNumber('009711234567890')); $this->assertEquals(CallingCode::UNITED_KINGDOM, CallingCode::fromPhoneNumber('011441234567890')); } From 6e2dbcbb0de824b1750ec0d0c2c82a4fef1c596d Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:34:03 +0000 Subject: [PATCH 12/18] feat: use fields instead of enum --- src/Utopia/Messaging/Adapters/SMS/GEOSMS.php | 10 +- .../Adapters/SMS/GEOSMS/CallingCode.php | 761 +++++++++++++----- 2 files changed, 574 insertions(+), 197 deletions(-) diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php index bd13018f..a48b3b91 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php @@ -27,9 +27,9 @@ public function getMaxMessagesPerRequest(): int return PHP_INT_MAX; } - public function setLocal(CallingCode $callingCode, SMSAdapter $adapter): self + public function setLocal(string $callingCode, SMSAdapter $adapter): self { - $this->localAdapters[$callingCode->value] = $adapter; + $this->localAdapters[$callingCode] = $adapter; return $this; } @@ -40,7 +40,9 @@ protected function process(SMS $message): string $responses = []; foreach ($recipientsByCallingCode as $callingCode => $recipients) { - $adapter = isset($this->localAdapters[$callingCode]) ? $this->localAdapters[$callingCode] : $this->defaultAdapter; + $adapter = isset($this->localAdapters[$callingCode]) + ? $this->localAdapters[$callingCode] + : $this->defaultAdapter; $responses[] = $adapter->send(new SMS( to: $recipients, @@ -59,7 +61,7 @@ protected function groupRecipientsByCallingCode(array $recipients): array foreach ($recipients as $recipient) { $callingCode = CallingCode::fromPhoneNumber($recipient); - $result[$callingCode->value][] = $recipient; + $result[$callingCode][] = $recipient; } return $result; diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php index 38e08ac5..b63c079d 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php @@ -7,197 +7,573 @@ * @link https://en.wikipedia.org/wiki/List_of_country_calling_codes */ -enum CallingCode: string +class CallingCode { - case ALGERIA = '213'; - case ANDORRA = '376'; - case ANGOLA = '244'; - case ARGENTINA = '54'; - case ARMENIA = '374'; - case ARUBA = '297'; - case AUSTRALIA = '61'; - case AUSTRIA = '43'; - case AZERBAIJAN = '994'; - case BAHRAIN = '973'; - case BANGLADESH = '880'; - case BELARUS = '375'; - case BELGIUM = '32'; - case BELIZE = '501'; - case BENIN = '229'; - case BHUTAN = '975'; - case BOLIVIA = '591'; - case BOSNIA_HERZEGOVINA = '387'; - case BOTSWANA = '267'; - case BRAZIL = '55'; - case BRUNEI = '673'; - case BULGARIA = '359'; - case BURKINA_FASO = '226'; - case BURUNDI = '257'; - case CAMBODIA = '855'; - case CAMEROON = '237'; - case CAPE_VERDE_ISLANDS = '238'; - case CENTRAL_AFRICAN_REPUBLIC = '236'; - case CHILE = '56'; - case CHINA = '86'; - case COLOMBIA = '57'; - case COMOROS_AND_MAYOTTE = '269'; - case CONGO = '242'; - case COOK_ISLANDS = '682'; - case COSTA_RICA = '506'; - case CROATIA = '385'; - case CUBA = '53'; - case CYPRUS = '357'; - case CZECH_REPUBLIC = '420'; - case DENMARK = '45'; - case DJIBOUTI = '253'; - case ECUADOR = '593'; - case EGYPT = '20'; - case EL_SALVADOR = '503'; - case EQUATORIAL_GUINEA = '240'; - case ERITREA = '291'; - case ESTONIA = '372'; - case ETHIOPIA = '251'; - case FALKLAND_ISLANDS = '500'; - case FAROE_ISLANDS = '298'; - case FIJI = '679'; - case FINLAND = '358'; - case FRANCE = '33'; - case FRENCH_GUIANA = '594'; - case FRENCH_POLYNESIA = '689'; - case GABON = '241'; - case GAMBIA = '220'; - case GEORGIA = '995'; - case GERMANY = '49'; - case GHANA = '233'; - case GIBRALTAR = '350'; - case GREECE = '30'; - case GREENLAND = '299'; - case GUADELOUPE = '590'; - case GUAM = '671'; - case GUATEMALA = '502'; - case GUINEA = '224'; - case GUINEA_BISSAU = '245'; - case GUYANA = '592'; - case HAITI = '509'; - case HONDURAS = '504'; - case HONG_KONG = '852'; - case HUNGARY = '36'; - case ICELAND = '354'; - case INDIA = '91'; - case INDONESIA = '62'; - case IRAN = '98'; - case IRAQ = '964'; - case IRELAND = '353'; - case ISRAEL = '972'; - case ITALY = '39'; - case JAPAN = '81'; - case JORDAN = '962'; - case KENYA = '254'; - case KIRIBATI = '686'; - case NORTH_KOREA = '850'; - case SOUTH_KOREA = '82'; - case KUWAIT = '965'; - case KYRGYZSTAN = '996'; - case LAOS = '856'; - case LATVIA = '371'; - case LEBANON = '961'; - case LESOTHO = '266'; - case LIBERIA = '231'; - case LIBYA = '218'; - case LIECHTENSTEIN = '417'; - case LITHUANIA = '370'; - case LUXEMBOURG = '352'; - case MACAO = '853'; - case MACEDONIA = '389'; - case MADAGASCAR = '261'; - case MALAWI = '265'; - case MALAYSIA = '60'; - case MALDIVES = '960'; - case MALI = '223'; - case MALTA = '356'; - case MARSHALL_ISLANDS = '692'; - case MARTINIQUE = '596'; - case MAURITANIA = '222'; - case MEXICO = '52'; - case MICRONESIA = '691'; - case MOLDOVA = '373'; - case MONACO = '377'; - case MONGOLIA = '976'; - case MOROCCO = '212'; - case MOZAMBIQUE = '258'; - case MYANMAR = '95'; - case NAMIBIA = '264'; - case NAURU = '674'; - case NEPAL = '977'; - case NETHERLANDS = '31'; - case NEW_CALEDONIA = '687'; - case NEW_ZEALAND = '64'; - case NICARAGUA = '505'; - case NIGER = '227'; - case NIGERIA = '234'; - case NIUE = '683'; - case NORFOLK_ISLANDS = '672'; - case NORTHERN_MARIANA_ISLANDS = '670'; - case NORWAY = '47'; - case OMAN = '968'; - case PALAU = '680'; - case PANAMA = '507'; - case PAPUA_NEW_GUINEA = '675'; - case PARAGUAY = '595'; - case PERU = '51'; - case PHILIPPINES = '63'; - case POLAND = '48'; - case PORTUGAL = '351'; - case QATAR = '974'; - case REUNION = '262'; - case ROMANIA = '40'; - case RUSSIA_KAZAKHSTAN_UZBEKISTAN_TURKMENISTAN_AND_TAJIKSTAN = '7'; - case RWANDA = '250'; - case SAN_MARINO = '378'; - case SAO_TOME_AND_PRINCIPE = '239'; - case SAUDI_ARABIA = '966'; - case SENEGAL = '221'; - case SERBIA = '381'; - case SEYCHELLES = '248'; - case SIERRA_LEONE = '232'; - case SINGAPORE = '65'; - case SLOVAK_REPUBLIC = '421'; - case SLOVENIA = '386'; - case SOLOMON_ISLANDS = '677'; - case SOMALIA = '252'; - case SOUTH_AFRICA = '27'; - case SPAIN = '34'; - case SRI_LANKA = '94'; - case ST_HELENA = '290'; - case SUDAN = '249'; - case SURINAME = '597'; - case SWAZILAND = '268'; - case SWEDEN = '46'; - case SWITZERLAND = '41'; - case SYRIA = '963'; - case TAIWAN = '886'; - case THAILAND = '66'; - case TOGO = '228'; - case TONGA = '676'; - case TUNISIA = '216'; - case TURKEY = '90'; - case TUVALU = '688'; - case UGANDA = '256'; - case UKRAINE = '380'; - case UNITED_ARAB_EMIRATES = '971'; - case UNITED_KINGDOM = '44'; - case URUGUAY = '598'; - case NORTH_AMERICA = '1'; - case VANUATU = '678'; - case VENEZUELA = '58'; - case VIETNAM = '84'; - case WALLIS_AND_FUTUNA = '681'; - case YEMEN = '967'; - case ZAMBIA = '260'; - case ZANZIBAR = '255'; - case ZIMBABWE = '263'; - - public static function fromPhoneNumber($number): ?CallingCode + public const ALGERIA = '213'; + + public const ANDORRA = '376'; + + public const ANGOLA = '244'; + + public const ARGENTINA = '54'; + + public const ARMENIA = '374'; + + public const ARUBA = '297'; + + public const AUSTRALIA = '61'; + + public const AUSTRIA = '43'; + + public const AZERBAIJAN = '994'; + + public const BAHRAIN = '973'; + + public const BANGLADESH = '880'; + + public const BELARUS = '375'; + + public const BELGIUM = '32'; + + public const BELIZE = '501'; + + public const BENIN = '229'; + + public const BHUTAN = '975'; + + public const BOLIVIA = '591'; + + public const BOSNIA_HERZEGOVINA = '387'; + + public const BOTSWANA = '267'; + + public const BRAZIL = '55'; + + public const BRUNEI = '673'; + + public const BULGARIA = '359'; + + public const BURKINA_FASO = '226'; + + public const BURUNDI = '257'; + + public const CAMBODIA = '855'; + + public const CAMEROON = '237'; + + public const CAPE_VERDE_ISLANDS = '238'; + + public const CENTRAL_AFRICAN_REPUBLIC = '236'; + + public const CHILE = '56'; + + public const CHINA = '86'; + + public const COLOMBIA = '57'; + + public const COMOROS_AND_MAYOTTE = '269'; + + public const CONGO = '242'; + + public const COOK_ISLANDS = '682'; + + public const COSTA_RICA = '506'; + + public const CROATIA = '385'; + + public const CUBA = '53'; + + public const CYPRUS = '357'; + + public const CZECH_REPUBLIC = '420'; + + public const DENMARK = '45'; + + public const DJIBOUTI = '253'; + + public const ECUADOR = '593'; + + public const EGYPT = '20'; + + public const EL_SALVADOR = '503'; + + public const EQUATORIAL_GUINEA = '240'; + + public const ERITREA = '291'; + + public const ESTONIA = '372'; + + public const ETHIOPIA = '251'; + + public const FALKLAND_ISLANDS = '500'; + + public const FAROE_ISLANDS = '298'; + + public const FIJI = '679'; + + public const FINLAND = '358'; + + public const FRANCE = '33'; + + public const FRENCH_GUIANA = '594'; + + public const FRENCH_POLYNESIA = '689'; + + public const GABON = '241'; + + public const GAMBIA = '220'; + + public const GEORGIA = '995'; + + public const GERMANY = '49'; + + public const GHANA = '233'; + + public const GIBRALTAR = '350'; + + public const GREECE = '30'; + + public const GREENLAND = '299'; + + public const GUADELOUPE = '590'; + + public const GUAM = '671'; + + public const GUATEMALA = '502'; + + public const GUINEA = '224'; + + public const GUINEA_BISSAU = '245'; + + public const GUYANA = '592'; + + public const HAITI = '509'; + + public const HONDURAS = '504'; + + public const HONG_KONG = '852'; + + public const HUNGARY = '36'; + + public const ICELAND = '354'; + + public const INDIA = '91'; + + public const INDONESIA = '62'; + + public const IRAN = '98'; + + public const IRAQ = '964'; + + public const IRELAND = '353'; + + public const ISRAEL = '972'; + + public const ITALY = '39'; + + public const JAPAN = '81'; + + public const JORDAN = '962'; + + public const KENYA = '254'; + + public const KIRIBATI = '686'; + + public const NORTH_KOREA = '850'; + + public const SOUTH_KOREA = '82'; + + public const KUWAIT = '965'; + + public const KYRGYZSTAN = '996'; + + public const LAOS = '856'; + + public const LATVIA = '371'; + + public const LEBANON = '961'; + + public const LESOTHO = '266'; + + public const LIBERIA = '231'; + + public const LIBYA = '218'; + + public const LIECHTENSTEIN = '417'; + + public const LITHUANIA = '370'; + + public const LUXEMBOURG = '352'; + + public const MACAO = '853'; + + public const MACEDONIA = '389'; + + public const MADAGASCAR = '261'; + + public const MALAWI = '265'; + + public const MALAYSIA = '60'; + + public const MALDIVES = '960'; + + public const MALI = '223'; + + public const MALTA = '356'; + + public const MARSHALL_ISLANDS = '692'; + + public const MARTINIQUE = '596'; + + public const MAURITANIA = '222'; + + public const MEXICO = '52'; + + public const MICRONESIA = '691'; + + public const MOLDOVA = '373'; + + public const MONACO = '377'; + + public const MONGOLIA = '976'; + + public const MOROCCO = '212'; + + public const MOZAMBIQUE = '258'; + + public const MYANMAR = '95'; + + public const NAMIBIA = '264'; + + public const NAURU = '674'; + + public const NEPAL = '977'; + + public const NETHERLANDS = '31'; + + public const NEW_CALEDONIA = '687'; + + public const NEW_ZEALAND = '64'; + + public const NICARAGUA = '505'; + + public const NIGER = '227'; + + public const NIGERIA = '234'; + + public const NIUE = '683'; + + public const NORFOLK_ISLANDS = '672'; + + public const NORTHERN_MARIANA_ISLANDS = '670'; + + public const NORWAY = '47'; + + public const OMAN = '968'; + + public const PALAU = '680'; + + public const PANAMA = '507'; + + public const PAPUA_NEW_GUINEA = '675'; + + public const PARAGUAY = '595'; + + public const PERU = '51'; + + public const PHILIPPINES = '63'; + + public const POLAND = '48'; + + public const PORTUGAL = '351'; + + public const QATAR = '974'; + + public const REUNION = '262'; + + public const ROMANIA = '40'; + + public const RUSSIA_KAZAKHSTAN_UZBEKISTAN_TURKMENISTAN_AND_TAJIKSTAN = '7'; + + public const RWANDA = '250'; + + public const SAN_MARINO = '378'; + + public const SAO_TOME_AND_PRINCIPE = '239'; + + public const SAUDI_ARABIA = '966'; + + public const SENEGAL = '221'; + + public const SERBIA = '381'; + + public const SEYCHELLES = '248'; + + public const SIERRA_LEONE = '232'; + + public const SINGAPORE = '65'; + + public const SLOVAK_REPUBLIC = '421'; + + public const SLOVENIA = '386'; + + public const SOLOMON_ISLANDS = '677'; + + public const SOMALIA = '252'; + + public const SOUTH_AFRICA = '27'; + + public const SPAIN = '34'; + + public const SRI_LANKA = '94'; + + public const ST_HELENA = '290'; + + public const SUDAN = '249'; + + public const SURINAME = '597'; + + public const SWAZILAND = '268'; + + public const SWEDEN = '46'; + + public const SWITZERLAND = '41'; + + public const SYRIA = '963'; + + public const TAIWAN = '886'; + + public const THAILAND = '66'; + + public const TOGO = '228'; + + public const TONGA = '676'; + + public const TUNISIA = '216'; + + public const TURKEY = '90'; + + public const TUVALU = '688'; + + public const UGANDA = '256'; + + public const UKRAINE = '380'; + + public const UNITED_ARAB_EMIRATES = '971'; + + public const UNITED_KINGDOM = '44'; + + public const URUGUAY = '598'; + + public const NORTH_AMERICA = '1'; + + public const VANUATU = '678'; + + public const VENEZUELA = '58'; + + public const VIETNAM = '84'; + + public const WALLIS_AND_FUTUNA = '681'; + + public const YEMEN = '967'; + + public const ZAMBIA = '260'; + + public const ZANZIBAR = '255'; + + public const ZIMBABWE = '263'; + + protected const CODES = [ + self::ALGERIA => true, + self::ANDORRA => true, + self::ANGOLA => true, + self::ARGENTINA => true, + self::ARMENIA => true, + self::ARUBA => true, + self::AUSTRALIA => true, + self::AUSTRIA => true, + self::AZERBAIJAN => true, + self::BAHRAIN => true, + self::BANGLADESH => true, + self::BELARUS => true, + self::BELGIUM => true, + self::BELIZE => true, + self::BENIN => true, + self::BHUTAN => true, + self::BOLIVIA => true, + self::BOSNIA_HERZEGOVINA => true, + self::BOTSWANA => true, + self::BRAZIL => true, + self::BRUNEI => true, + self::BULGARIA => true, + self::BURKINA_FASO => true, + self::BURUNDI => true, + self::CAMBODIA => true, + self::CAMEROON => true, + self::CAPE_VERDE_ISLANDS => true, + self::CENTRAL_AFRICAN_REPUBLIC => true, + self::CHILE => true, + self::CHINA => true, + self::COLOMBIA => true, + self::COMOROS_AND_MAYOTTE => true, + self::CONGO => true, + self::COOK_ISLANDS => true, + self::COSTA_RICA => true, + self::CROATIA => true, + self::CUBA => true, + self::CYPRUS => true, + self::CZECH_REPUBLIC => true, + self::DENMARK => true, + self::DJIBOUTI => true, + self::ECUADOR => true, + self::EGYPT => true, + self::EL_SALVADOR => true, + self::EQUATORIAL_GUINEA => true, + self::ERITREA => true, + self::ESTONIA => true, + self::ETHIOPIA => true, + self::FALKLAND_ISLANDS => true, + self::FAROE_ISLANDS => true, + self::FIJI => true, + self::FINLAND => true, + self::FRANCE => true, + self::FRENCH_GUIANA => true, + self::FRENCH_POLYNESIA => true, + self::GABON => true, + self::GAMBIA => true, + self::GEORGIA => true, + self::GERMANY => true, + self::GHANA => true, + self::GIBRALTAR => true, + self::GREECE => true, + self::GREENLAND => true, + self::GUADELOUPE => true, + self::GUAM => true, + self::GUATEMALA => true, + self::GUINEA => true, + self::GUINEA_BISSAU => true, + self::GUYANA => true, + self::HAITI => true, + self::HONDURAS => true, + self::HONG_KONG => true, + self::HUNGARY => true, + self::ICELAND => true, + self::INDIA => true, + self::INDONESIA => true, + self::IRAN => true, + self::IRAQ => true, + self::IRELAND => true, + self::ISRAEL => true, + self::ITALY => true, + self::JAPAN => true, + self::JORDAN => true, + self::KENYA => true, + self::KIRIBATI => true, + self::NORTH_KOREA => true, + self::SOUTH_KOREA => true, + self::KUWAIT => true, + self::KYRGYZSTAN => true, + self::LAOS => true, + self::LATVIA => true, + self::LEBANON => true, + self::LESOTHO => true, + self::LIBERIA => true, + self::LIBYA => true, + self::LIECHTENSTEIN => true, + self::LITHUANIA => true, + self::LUXEMBOURG => true, + self::MACAO => true, + self::MACEDONIA => true, + self::MADAGASCAR => true, + self::MALAWI => true, + self::MALAYSIA => true, + self::MALDIVES => true, + self::MALI => true, + self::MALTA => true, + self::MARSHALL_ISLANDS => true, + self::MARTINIQUE => true, + self::MAURITANIA => true, + self::MEXICO => true, + self::MICRONESIA => true, + self::MOLDOVA => true, + self::MONACO => true, + self::MONGOLIA => true, + self::MOROCCO => true, + self::MOZAMBIQUE => true, + self::MYANMAR => true, + self::NAMIBIA => true, + self::NAURU => true, + self::NEPAL => true, + self::NETHERLANDS => true, + self::NEW_CALEDONIA => true, + self::NEW_ZEALAND => true, + self::NICARAGUA => true, + self::NIGER => true, + self::NIGERIA => true, + self::NIUE => true, + self::NORFOLK_ISLANDS => true, + self::NORTHERN_MARIANA_ISLANDS => true, + self::NORWAY => true, + self::OMAN => true, + self::PALAU => true, + self::PANAMA => true, + self::PAPUA_NEW_GUINEA => true, + self::PARAGUAY => true, + self::PERU => true, + self::PHILIPPINES => true, + self::POLAND => true, + self::PORTUGAL => true, + self::QATAR => true, + self::REUNION => true, + self::ROMANIA => true, + self::RUSSIA_KAZAKHSTAN_UZBEKISTAN_TURKMENISTAN_AND_TAJIKSTAN => true, + self::RWANDA => true, + self::SAN_MARINO => true, + self::SAO_TOME_AND_PRINCIPE => true, + self::SAUDI_ARABIA => true, + self::SENEGAL => true, + self::SERBIA => true, + self::SEYCHELLES => true, + self::SIERRA_LEONE => true, + self::SINGAPORE => true, + self::SLOVAK_REPUBLIC => true, + self::SLOVENIA => true, + self::SOLOMON_ISLANDS => true, + self::SOMALIA => true, + self::SOUTH_AFRICA => true, + self::SPAIN => true, + self::SRI_LANKA => true, + self::ST_HELENA => true, + self::SUDAN => true, + self::SURINAME => true, + self::SWAZILAND => true, + self::SWEDEN => true, + self::SWITZERLAND => true, + self::SYRIA => true, + self::TAIWAN => true, + self::THAILAND => true, + self::TOGO => true, + self::TONGA => true, + self::TUNISIA => true, + self::TURKEY => true, + self::TUVALU => true, + self::UGANDA => true, + self::UKRAINE => true, + self::UNITED_ARAB_EMIRATES => true, + self::UNITED_KINGDOM => true, + self::URUGUAY => true, + self::NORTH_AMERICA => true, + self::VANUATU => true, + self::VENEZUELA => true, + self::VIETNAM => true, + self::WALLIS_AND_FUTUNA => true, + self::YEMEN => true, + self::ZAMBIA => true, + self::ZANZIBAR => true, + self::ZIMBABWE => true, + ]; + + public static function fromPhoneNumber($number): ?string { $digits = str_replace(['+', ' ', '(', ')', '-'], '', $number); @@ -208,9 +584,8 @@ public static function fromPhoneNumber($number): ?CallingCode // Prefixes can be 3, 2, or 1 digits long // Attempt to match the longest first foreach ([3, 2, 1] as $length) { - $codeScalar = substr($digits, 0, $length); - $code = CallingCode::tryFrom($codeScalar); - if ($code) { + $code = substr($digits, 0, $length); + if (isset(self::CODES[$code])) { return $code; } } From 47b612244dd263e390af54b054ed94ed2c70c4c9 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Wed, 8 Nov 2023 16:38:03 +0000 Subject: [PATCH 13/18] feat: exception handling --- src/Utopia/Messaging/Adapters/SMS/GEOSMS.php | 21 +++++++++++++------ .../Adapters/SMS/GEOSMS/CallingCode.php | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php index a48b3b91..190db71a 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php @@ -38,18 +38,27 @@ protected function process(SMS $message): string { $recipientsByCallingCode = $this->groupRecipientsByCallingCode($message->getTo()); $responses = []; + $errors = []; foreach ($recipientsByCallingCode as $callingCode => $recipients) { $adapter = isset($this->localAdapters[$callingCode]) ? $this->localAdapters[$callingCode] : $this->defaultAdapter; - $responses[] = $adapter->send(new SMS( - to: $recipients, - content: $message->getContent(), - from: $message->getFrom(), - attachments: $message->getAttachments() - )); + try { + $responses[] = $adapter->send(new SMS( + to: $recipients, + content: $message->getContent(), + from: $message->getFrom(), + attachments: $message->getAttachments() + )); + } catch (\Exception $e) { + $errors[] = $e; + } + } + + if (count($errors) > 0) { + throw new \Exception('Failed to send SMS to some recipients', 0, $errors[0]); } return $responses[0]; diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php index b63c079d..836264bd 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php @@ -577,7 +577,7 @@ public static function fromPhoneNumber($number): ?string { $digits = str_replace(['+', ' ', '(', ')', '-'], '', $number); - // International call prefix is usually 00 or 011 + // Remove international call prefix, usually `00` or `011` // https://en.wikipedia.org/wiki/List_of_international_call_prefixes $digits = preg_replace('/^00|^011/', '', $digits); From 5e2f0a26b6a4ce611431fb227627a200bb8190a0 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Wed, 8 Nov 2023 19:14:30 +0000 Subject: [PATCH 14/18] test: msg91 --- tests/e2e/SMS/Msg91Test.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/SMS/Msg91Test.php b/tests/e2e/SMS/Msg91Test.php index 61ec35f0..514847d5 100644 --- a/tests/e2e/SMS/Msg91Test.php +++ b/tests/e2e/SMS/Msg91Test.php @@ -24,5 +24,6 @@ public function testSendSMS() $result = \json_decode($response, true); $this->assertEquals('success', $result['type']); + $this->assertEquals('Test Content', $result['message']); } } From 67da6a3f95357f09bfd5222d75c9f064cf5052ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=B7=E5=8D=8E=20=E5=88=98?= Date: Wed, 8 Nov 2023 22:12:26 +0000 Subject: [PATCH 15/18] chore: update tests --- tests/e2e/SMS/Msg91Test.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/SMS/Msg91Test.php b/tests/e2e/SMS/Msg91Test.php index 514847d5..680112f8 100644 --- a/tests/e2e/SMS/Msg91Test.php +++ b/tests/e2e/SMS/Msg91Test.php @@ -22,6 +22,7 @@ public function testSendSMS() $response = $sender->send($message); $result = \json_decode($response, true); + var_dump($response); $this->assertEquals('success', $result['type']); $this->assertEquals('Test Content', $result['message']); From 4ee281401dca91c1070cf899c5bbee6ddb59f4ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=B7=E5=8D=8E=20=E5=88=98?= Date: Wed, 8 Nov 2023 22:52:10 +0000 Subject: [PATCH 16/18] chore: remove checks for message assertion --- tests/e2e/SMS/Msg91Test.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/e2e/SMS/Msg91Test.php b/tests/e2e/SMS/Msg91Test.php index 680112f8..61ec35f0 100644 --- a/tests/e2e/SMS/Msg91Test.php +++ b/tests/e2e/SMS/Msg91Test.php @@ -22,9 +22,7 @@ public function testSendSMS() $response = $sender->send($message); $result = \json_decode($response, true); - var_dump($response); $this->assertEquals('success', $result['type']); - $this->assertEquals('Test Content', $result['message']); } } From faf88d15f8c1548b02007c8820dca2a9e4dc4ff6 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Thu, 9 Nov 2023 11:42:56 +0000 Subject: [PATCH 17/18] feat: group by adapter --- src/Utopia/Messaging/Adapters/SMS/GEOSMS.php | 78 ++++++++++++----- .../Adapters/SMS/GEOSMS/CallingCode.php | 4 +- tests/e2e/SMS/GEOSMS/CallingCodeTest.php | 2 + tests/e2e/SMS/GEOSMSTest.php | 87 ++++++++++++++++--- 4 files changed, 132 insertions(+), 39 deletions(-) diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php index 190db71a..da2e4ed8 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS.php @@ -34,45 +34,77 @@ public function setLocal(string $callingCode, SMSAdapter $adapter): self return $this; } + protected function filterCallingCodesByAdapter(SMSAdapter $adapter): array + { + $result = []; + + foreach ($this->localAdapters as $callingCode => $localAdapter) { + if ($localAdapter === $adapter) { + $result[] = $callingCode; + } + } + + return $result; + } + protected function process(SMS $message): string { - $recipientsByCallingCode = $this->groupRecipientsByCallingCode($message->getTo()); - $responses = []; - $errors = []; + $results = []; + $recipients = $message->getTo(); - foreach ($recipientsByCallingCode as $callingCode => $recipients) { - $adapter = isset($this->localAdapters[$callingCode]) - ? $this->localAdapters[$callingCode] - : $this->defaultAdapter; + do { + [$nextRecipients, $nextAdapter] = $this->getNextRecipientsAndAdapter($recipients); try { - $responses[] = $adapter->send(new SMS( - to: $recipients, - content: $message->getContent(), - from: $message->getFrom(), - attachments: $message->getAttachments() + $results[$nextAdapter->getName()] = json_decode($nextAdapter->send( + new SMS( + to: $nextRecipients, + content: $message->getContent(), + from: $message->getFrom(), + attachments: $message->getAttachments() + ) )); } catch (\Exception $e) { - $errors[] = $e; + $results[$nextAdapter->getName()] = [ + 'type' => 'error', + 'message' => $e->getMessage(), + ]; } - } - if (count($errors) > 0) { - throw new \Exception('Failed to send SMS to some recipients', 0, $errors[0]); - } + $recipients = \array_diff($recipients, $nextRecipients); + } while (count($recipients) > 0); - return $responses[0]; + return \json_encode($results); } - protected function groupRecipientsByCallingCode(array $recipients): array + protected function getNextRecipientsAndAdapter(array $recipients): array { - $result = []; + $nextRecipients = []; + $nextAdapter = null; foreach ($recipients as $recipient) { - $callingCode = CallingCode::fromPhoneNumber($recipient); - $result[$callingCode][] = $recipient; + $adapter = $this->getAdapterByPhoneNumber($recipient); + + if ($nextAdapter === null || $adapter === $nextAdapter) { + $nextAdapter = $adapter; + $nextRecipients[] = $recipient; + } } - return $result; + return [$nextRecipients, $nextAdapter]; + } + + protected function getAdapterByPhoneNumber(?string $phoneNumber): SMSAdapter + { + $callingCode = CallingCode::fromPhoneNumber($phoneNumber); + if ($callingCode === null || empty($callingCode)) { + return $this->defaultAdapter; + } + + if (isset($this->localAdapters[$callingCode])) { + return $this->localAdapters[$callingCode]; + } + + return $this->defaultAdapter; } } diff --git a/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php index 836264bd..141c9250 100644 --- a/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php +++ b/src/Utopia/Messaging/Adapters/SMS/GEOSMS/CallingCode.php @@ -265,6 +265,8 @@ class CallingCode public const NORFOLK_ISLANDS = '672'; + public const NORTH_AMERICA = '1'; + public const NORTHERN_MARIANA_ISLANDS = '670'; public const NORWAY = '47'; @@ -365,8 +367,6 @@ class CallingCode public const URUGUAY = '598'; - public const NORTH_AMERICA = '1'; - public const VANUATU = '678'; public const VENEZUELA = '58'; diff --git a/tests/e2e/SMS/GEOSMS/CallingCodeTest.php b/tests/e2e/SMS/GEOSMS/CallingCodeTest.php index 74f4a60b..7a460d83 100644 --- a/tests/e2e/SMS/GEOSMS/CallingCodeTest.php +++ b/tests/e2e/SMS/GEOSMS/CallingCodeTest.php @@ -10,7 +10,9 @@ public function testFromPhoneNumber() { $this->assertEquals(CallingCode::NORTH_AMERICA, CallingCode::fromPhoneNumber('+11234567890')); $this->assertEquals(CallingCode::INDIA, CallingCode::fromPhoneNumber('+911234567890')); + $this->assertEquals(CallingCode::ISRAEL, CallingCode::fromPhoneNumber('9721234567890')); $this->assertEquals(CallingCode::UNITED_ARAB_EMIRATES, CallingCode::fromPhoneNumber('009711234567890')); $this->assertEquals(CallingCode::UNITED_KINGDOM, CallingCode::fromPhoneNumber('011441234567890')); + $this->assertEquals(null, CallingCode::fromPhoneNumber('2')); } } diff --git a/tests/e2e/SMS/GEOSMSTest.php b/tests/e2e/SMS/GEOSMSTest.php index 26b0794e..d635ca45 100644 --- a/tests/e2e/SMS/GEOSMSTest.php +++ b/tests/e2e/SMS/GEOSMSTest.php @@ -12,8 +12,8 @@ class GEOSMSTest extends Base public function testSendSMSUsingDefaultAdapter() { $defaultAdapterMock = $this->createMock(SMSAdapter::class); - $defaultAdapterMock->method('getMaxMessagesPerRequest') - ->willReturn(1); + $defaultAdapterMock->method('getName') + ->willReturn('default'); $defaultAdapterMock->method('send') ->willReturn(json_encode(['status' => 'success'])); @@ -28,26 +28,85 @@ public function testSendSMSUsingDefaultAdapter() from: $from ); - $result = json_decode($adapter->send($message)); + $result = json_decode($adapter->send($message), true); - $this->assertEquals('success', $result->status); + $this->assertEquals(1, count($result)); + $this->assertEquals('success', $result['default']['status']); } public function testSendSMSUsingLocalAdapter() { $defaultAdapterMock = $this->createMock(SMSAdapter::class); - $defaultAdapterMock->method('getMaxMessagesPerRequest') - ->willReturn(1); $localAdapterMock = $this->createMock(SMSAdapter::class); - $localAdapterMock->method('getMaxMessagesPerRequest') - ->willReturn(1); + $localAdapterMock->method('getName') + ->willReturn('local'); $localAdapterMock->method('send') - ->willReturn(json_encode(['status' => 'success', 'adapter' => 'local'])); + ->willReturn(json_encode(['status' => 'success'])); + + $adapter = new GEOSMS($defaultAdapterMock); + $adapter->setLocal(CallingCode::INDIA, $localAdapterMock); + + $to = ['+911234567890']; + $from = 'Sender'; + + $message = new SMS( + to: $to, + content: 'Test Content', + from: $from + ); + + $result = json_decode($adapter->send($message), true); + + $this->assertEquals(1, count($result)); + $this->assertEquals('success', $result['local']['status']); + } + + public function testSendSMSUsingLocalAdapterAndDefault() + { + $defaultAdapterMock = $this->createMock(SMSAdapter::class); + $defaultAdapterMock->method('getName') + ->willReturn('default'); + $defaultAdapterMock->method('send') + ->willReturn(json_encode(['status' => 'success'])); + $localAdapterMock = $this->createMock(SMSAdapter::class); + $localAdapterMock->method('getName') + ->willReturn('local'); + $localAdapterMock->method('send') + ->willReturn(json_encode(['status' => 'success'])); + + $adapter = new GEOSMS($defaultAdapterMock); + $adapter->setLocal(CallingCode::INDIA, $localAdapterMock); + + $to = ['+911234567890', '+11234567890']; + $from = 'Sender'; + + $message = new SMS( + to: $to, + content: 'Test Content', + from: $from + ); + + $result = json_decode($adapter->send($message), true); + + $this->assertEquals(2, count($result)); + $this->assertEquals('success', $result['local']['status']); + $this->assertEquals('success', $result['default']['status']); + } + + public function testSendSMSUsingGroupedLocalAdapter() + { + $defaultAdapterMock = $this->createMock(SMSAdapter::class); + $localAdapterMock = $this->createMock(SMSAdapter::class); + $localAdapterMock->method('getName') + ->willReturn('local'); + $localAdapterMock->method('send') + ->willReturn(json_encode(['status' => 'success'])); $adapter = new GEOSMS($defaultAdapterMock); - $adapter->setLocal(CallingCode::UNITED_KINGDOM, $localAdapterMock); + $adapter->setLocal(CallingCode::INDIA, $localAdapterMock); + $adapter->setLocal(CallingCode::NORTH_AMERICA, $localAdapterMock); - $to = ['+441234567890']; + $to = ['+911234567890', '+11234567890']; $from = 'Sender'; $message = new SMS( @@ -56,9 +115,9 @@ public function testSendSMSUsingLocalAdapter() from: $from ); - $result = json_decode($adapter->send($message)); + $result = json_decode($adapter->send($message), true); - $this->assertEquals('success', $result->status); - $this->assertEquals('local', $result->adapter); + $this->assertEquals(1, count($result)); + $this->assertEquals('success', $result['local']['status']); } } From 537aab3ae365f37b406a0b885b12fc45afe138b6 Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Thu, 9 Nov 2023 12:13:44 +0000 Subject: [PATCH 18/18] chore: revert msg91 --- tests/e2e/SMS/Msg91Test.php | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/e2e/SMS/Msg91Test.php b/tests/e2e/SMS/Msg91Test.php index 61ec35f0..df90f4c4 100644 --- a/tests/e2e/SMS/Msg91Test.php +++ b/tests/e2e/SMS/Msg91Test.php @@ -12,17 +12,19 @@ class Msg91Test extends Base */ public function testSendSMS() { - $sender = new Msg91(getenv('MSG_91_SENDER_ID'), getenv('MSG_91_AUTH_KEY')); + // $sender = new Msg91(getenv('MSG_91_SENDER_ID'), getenv('MSG_91_AUTH_KEY')); - $message = new SMS( - to: [getenv('MSG_91_TO')], - content: 'Test Content', - from: getenv('MSG_91_FROM') - ); + // $message = new SMS( + // to: [getenv('MSG_91_TO')], + // content: 'Test Content', + // from: getenv('MSG_91_FROM') + // ); - $response = $sender->send($message); - $result = \json_decode($response, true); + // $response = $sender->send($message); + // $result = \json_decode($response, true); - $this->assertEquals('success', $result['type']); + // $this->assertEquals('success', $result['type']); + + $this->markTestSkipped('Msg91 requires business verification to use template and SMS api.'); } }