├── LICENSE.md ├── composer.json ├── config └── smsapi.php └── src ├── Exceptions └── ExceptionFactory.php ├── SmsapiChannel.php ├── SmsapiClient.php ├── SmsapiMessage.php ├── SmsapiMmsMessage.php ├── SmsapiServiceProvider.php ├── SmsapiSmsMessage.php └── SmsapiVmsMessage.php /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) Mateusz Drost 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel-notification-channels/smsapi", 3 | "description": "Smsapi Notifications Channel for Laravel", 4 | "homepage": "https://github.com/laravel-notification-channels/smsapi", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Mateusz Drost", 9 | "email": "mat.drost@gmail.com", 10 | "homepage": "https://github.com/mdrost", 11 | "role": "Developer" 12 | } 13 | ], 14 | "require": { 15 | "php": ">=7.2", 16 | "illuminate/notifications": "~6.0 || ~7.0 || ~8.0 || ~9.0 || ~10.0 || ^11.0 || ^12.0", 17 | "illuminate/support": "~6.0 || ~7.0 || ~8.0 || ~9.0 || ~10.0 || ^11.0 || ^12.0", 18 | "smsapi/php-client": "^1.8 || ^3.0" 19 | }, 20 | "require-dev": { 21 | "mockery/mockery": "^1.0", 22 | "phpunit/phpunit": "^8.0 || ^10.5" 23 | }, 24 | "autoload": { 25 | "psr-4": { 26 | "NotificationChannels\\Smsapi\\": "src" 27 | } 28 | }, 29 | "autoload-dev": { 30 | "psr-4": { 31 | "NotificationChannels\\Smsapi\\Tests\\": "tests" 32 | } 33 | }, 34 | "scripts": { 35 | "test": "vendor/bin/phpunit" 36 | }, 37 | "config": { 38 | "sort-packages": true 39 | }, 40 | "extra": { 41 | "laravel": { 42 | "providers": [ 43 | "NotificationChannels\\Smsapi\\SmsapiServiceProvider" 44 | ] 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /config/smsapi.php: -------------------------------------------------------------------------------- 1 | [ 7 | /* 8 | |---------------------------------------------------------------------- 9 | | Authentication methods 10 | |---------------------------------------------------------------------- 11 | | 12 | | Supported: "token", "password". 13 | | 14 | */ 15 | 'method' => 'token', 16 | 17 | 'credentials' => [ 18 | 'token' => env('SMSAPI_AUTH_TOKEN'), 19 | 20 | // 'username' => env('SMSAPI_AUTH_USERNAME'), 21 | // 'password' => env('SMSAPI_AUTH_PASSWORD'), // Hashed by MD5 22 | ], 23 | 24 | /* 25 | |---------------------------------------------------------------------- 26 | | SMSAPI service type 27 | |---------------------------------------------------------------------- 28 | | SMSAPI runs a polish service on smsapi.pl and a international service 29 | | on smsapi.com. This option will set which version will be used. 30 | | 31 | | Supported: "SmsapiClient::SERVICE_PL", "SmsapiClient::SERVICE_COM". 32 | | 33 | */ 34 | 'service' => SmsapiClient::SERVICE_PL, 35 | ], 36 | 37 | /* 38 | |-------------------------------------------------------------------------- 39 | | Default options 40 | |-------------------------------------------------------------------------- 41 | | 42 | | These options will be set if user does not provide their own in code. 43 | | 44 | */ 45 | 'defaults' => [ 46 | /* 47 | |---------------------------------------------------------------------- 48 | | Common default options 49 | |---------------------------------------------------------------------- 50 | | 51 | | Setting options here will take precedence 52 | | over those set in dashboard. 53 | | 54 | | Common supported options: "notify_url", "partner", "test". 55 | | 56 | */ 57 | 'common' => [ 58 | // 'notify_url' => env('SMSAPI_NOTIFY_URL'), 59 | // 'partner' => env('SMSAPI_PARTNER'), 60 | // 'test' => env('SMSAPI_TEST', true), 61 | ], 62 | 63 | /* 64 | |---------------------------------------------------------------------- 65 | | SMS default options 66 | |---------------------------------------------------------------------- 67 | | 68 | | Setting common options here will take precedence 69 | | over those set in common section. 70 | | 71 | | SMS only supported options: "from", "fast", "flash", "encoding", 72 | | "normalize", "nounicode", "single". 73 | | 74 | */ 75 | 'sms' => [ 76 | // 'from' => env('SMSAPI_FROM'), 77 | // 'fast' => false, 78 | // 'flash' => false, 79 | // 'encoding' => 'utf-8', 80 | // 'normalize' => false, 81 | // 'nounicode' => false, 82 | // 'single' => false, 83 | ], 84 | 85 | /* 86 | |---------------------------------------------------------------------- 87 | | MMS default options 88 | |---------------------------------------------------------------------- 89 | | 90 | | Setting common options here will take precedence 91 | | over those set in common section. 92 | | 93 | */ 94 | 'mms' => [ 95 | ], 96 | 97 | /* 98 | |---------------------------------------------------------------------- 99 | | VMS default options 100 | |---------------------------------------------------------------------- 101 | | 102 | | Setting common options here will take precedence 103 | | over those set in common section. 104 | | 105 | | VMS only supported options: "from", "tries", "interval", "tts_lector", 106 | | "skip_gsm". 107 | | 108 | */ 109 | 'vms' => [ 110 | // 'from' => env('SMSAPI_FROM'), 111 | // 'tries' => 2, 112 | // 'interval' => 300, 113 | // 'tts_lector' => 'Agnieszka', 114 | // 'skip_gsm' => false, 115 | ], 116 | ], 117 | 118 | /* 119 | |-------------------------------------------------------------------------- 120 | | Extra options 121 | |-------------------------------------------------------------------------- 122 | | 123 | | For future compatibility feel free to provide here your own options. 124 | | 125 | */ 126 | 'extra' => [ 127 | ], 128 | ]; 129 | -------------------------------------------------------------------------------- /src/Exceptions/ExceptionFactory.php: -------------------------------------------------------------------------------- 1 | client = $client; 21 | } 22 | 23 | /** 24 | * Send the given notification. 25 | * 26 | * @param mixed $notifiable 27 | * @param Notification $notification 28 | * @return StatusResponse 29 | */ 30 | public function send($notifiable, Notification $notification) 31 | { 32 | $message = $notification->toSmsapi($notifiable); 33 | if (is_string($message)) { 34 | $message = new SmsapiSmsMessage($message); 35 | } 36 | 37 | if ($to = $notifiable->routeNotificationFor('smsapi')) { 38 | $message->to($to); 39 | } elseif ($group = $notifiable->routeNotificationFor('smsapi_group')) { 40 | $message->group($group); 41 | } 42 | 43 | return $this->client->send($message); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/SmsapiClient.php: -------------------------------------------------------------------------------- 1 | client = $client; 41 | $this->defaults = $defaults; 42 | $this->proxy = $proxy; 43 | } 44 | 45 | /** 46 | * @param SmsapiMessage $message 47 | * @return Response 48 | */ 49 | public function send(SmsapiMessage $message) 50 | { 51 | if ($message instanceof SmsapiSmsMessage) { 52 | return $this->sendSms($message); 53 | } elseif ($message instanceof SmsapiMmsMessage) { 54 | return $this->sendMms($message); 55 | } elseif ($message instanceof SmsapiVmsMessage) { 56 | return $this->sendVms($message); 57 | } 58 | } 59 | 60 | /** 61 | * @param SmsapiSmsMessage $message 62 | * @return Response 63 | */ 64 | public function sendSms(SmsapiSmsMessage $message) 65 | { 66 | $data = $this->mergeDefaults($message->data, 'sms'); 67 | 68 | $sms = (new SmsFactory($this->proxy, $this->client))->actionSend(); 69 | if (isset($data['content'])) { 70 | $sms->setText($data['content']); 71 | } 72 | if (isset($data['template'])) { 73 | $sms->setTemplate($data['template']); 74 | } 75 | if (isset($data['to'])) { 76 | $sms->setTo($data['to']); 77 | } 78 | if (isset($data['group'])) { 79 | $sms->setGroup($data['group']); 80 | } 81 | if (isset($data['from'])) { 82 | $sms->setSender($data['from']); 83 | } 84 | if (isset($data['fast'])) { 85 | $sms->setFast($data['fast']); 86 | } 87 | if (isset($data['flash'])) { 88 | $sms->setFlash($data['flash']); 89 | } 90 | if (isset($data['encoding'])) { 91 | $sms->setEncoding($data['encoding']); 92 | } 93 | if (isset($data['normalize'])) { 94 | $sms->setNormalize($data['normalize']); 95 | } 96 | if (isset($data['nounicode'])) { 97 | $sms->setNoUnicode($data['nounicode']); 98 | } 99 | if (isset($data['single'])) { 100 | $sms->setSingle($data['single']); 101 | } 102 | if (isset($data['date'])) { 103 | $sms->setDateSent($data['date']); 104 | } 105 | if (isset($data['notify_url'])) { 106 | $sms->setNotifyUrl($data['notify_url']); 107 | } 108 | if (isset($data['partner'])) { 109 | $sms->setPartner($data['partner']); 110 | } 111 | if (isset($data['test'])) { 112 | $sms->setTest($data['test']); 113 | } 114 | 115 | return $sms->execute(); 116 | } 117 | 118 | /** 119 | * @param SmsapiMmsMessage $message 120 | * @return Response 121 | */ 122 | public function sendMms(SmsapiMmsMessage $message) 123 | { 124 | $data = $this->mergeDefaults($message->data, 'mms'); 125 | 126 | $mms = (new MmsFactory($this->proxy, $this->client))->actionSend(); 127 | $mms->setSubject($data['subject']); 128 | $mms->setSmil($data['smil']); 129 | if (isset($data['to'])) { 130 | $mms->setTo($data['to']); 131 | } 132 | if (isset($data['group'])) { 133 | $mms->setGroup($data['group']); 134 | } 135 | if (isset($data['date'])) { 136 | $mms->setDateSent($data['date']); 137 | } 138 | if (isset($data['notify_url'])) { 139 | $mms->setNotifyUrl($data['notify_url']); 140 | } 141 | if (isset($data['partner'])) { 142 | $mms->setPartner($data['partner']); 143 | } 144 | if (isset($data['test'])) { 145 | $mms->setTest($data['test']); 146 | } 147 | 148 | return $mms->execute(); 149 | } 150 | 151 | /** 152 | * @param SmsapiVmsMessage $message 153 | * @return Response 154 | */ 155 | public function sendVms(SmsapiVmsMessage $message) 156 | { 157 | $data = $this->mergeDefaults($message->data, 'vms'); 158 | 159 | $vms = (new VmsFactory($this->proxy, $this->client))->actionSend(); 160 | if (isset($data['file'])) { 161 | $vms->setFile($data['file']); 162 | } 163 | if (isset($data['tts'])) { 164 | $vms->setTts($data['tts']); 165 | if (isset($data['tts_lector'])) { 166 | $vms->setTtsLector($data['tts_lector']); 167 | } 168 | } 169 | if (isset($data['to'])) { 170 | $vms->setTo($data['to']); 171 | } 172 | if (isset($data['group'])) { 173 | $vms->setGroup($data['group']); 174 | } 175 | if (isset($data['from'])) { 176 | $vms->setFrom($data['from']); 177 | } 178 | if (isset($data['tries'])) { 179 | $vms->setTry($data['tries']); 180 | } 181 | if (isset($data['interval'])) { 182 | $vms->setInterval($data['interval']); 183 | } 184 | if (isset($data['date'])) { 185 | $vms->setDateSent($data['date']); 186 | } 187 | if (isset($data['notify_url'])) { 188 | $vms->setNotifyUrl($data['notify_url']); 189 | } 190 | if (isset($data['partner'])) { 191 | $vms->setPartner($data['partner']); 192 | } 193 | if (isset($data['test'])) { 194 | $vms->setTest($data['test']); 195 | } 196 | 197 | return $vms->execute(); 198 | } 199 | 200 | /** 201 | * Merge defaults into message data. 202 | * 203 | * @param array $data message data 204 | * @param string $type sms, mms, vms 205 | * @return array defaults merged with message data 206 | */ 207 | private function mergeDefaults(array $data, string $type) 208 | { 209 | if (array_key_exists($type, $this->defaults)) { 210 | $data += $this->defaults['sms']; 211 | } 212 | 213 | return $data; 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/SmsapiMessage.php: -------------------------------------------------------------------------------- 1 | data['to'] = $to; 23 | 24 | return $this; 25 | } 26 | 27 | /** 28 | * @param string $group 29 | * @return self 30 | */ 31 | public function group($group) 32 | { 33 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'string', $group); 34 | $this->data['group'] = $group; 35 | 36 | return $this; 37 | } 38 | 39 | /** 40 | * @param int|string $date 41 | * @return self 42 | */ 43 | public function date($date) 44 | { 45 | ExceptionFactory::assertArgumentTypes(1, __METHOD__, ['integer', 'string'], $date); 46 | $this->data['date'] = $date; 47 | 48 | return $this; 49 | } 50 | 51 | /** 52 | * @param string $notifyUrl 53 | * @return self 54 | */ 55 | public function notifyUrl($notifyUrl) 56 | { 57 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'string', $notifyUrl); 58 | $this->data['notify_url'] = $notifyUrl; 59 | 60 | return $this; 61 | } 62 | 63 | /** 64 | * @param string $partner 65 | * @return self 66 | */ 67 | public function partner($partner) 68 | { 69 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'string', $partner); 70 | $this->data['partner'] = $partner; 71 | 72 | return $this; 73 | } 74 | 75 | /** 76 | * @param bool $test 77 | * @return self 78 | */ 79 | public function test($test = true) 80 | { 81 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'boolean', $test); 82 | $this->data['test'] = $test; 83 | 84 | return $this; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/SmsapiMmsMessage.php: -------------------------------------------------------------------------------- 1 | data['subject'] = $subject; 17 | 18 | return $this; 19 | } 20 | 21 | /** 22 | * @param string $smil 23 | * @return self 24 | */ 25 | public function smil($smil) 26 | { 27 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'string', $smil); 28 | $this->data['smil'] = $smil; 29 | 30 | return $this; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/SmsapiServiceProvider.php: -------------------------------------------------------------------------------- 1 | app->when(SmsapiChannel::class) 18 | ->needs(SmsapiClient::class) 19 | ->give(function () { 20 | $config = config('smsapi'); 21 | $auth = $config['auth'] + ['service' => SmsapiClient::SERVICE_PL]; 22 | if ($auth['method'] === 'token') { 23 | $client = Client::createFromToken($auth['credentials']['token']); 24 | } elseif ($auth['method'] === 'password') { 25 | $client = new Client($auth['credentials']['username']); 26 | $client->setPasswordHash($auth['credentials']['password']); 27 | } 28 | $defaults = $config['defaults'] + ['sms' => [], 'mms' => [], 'vms' => []]; 29 | 30 | $defaults['sms'] = Arr::only($defaults['sms'], [ 31 | 'from', 'fast', 'flash', 'encoding', 'normalize', 'nounicode', 'single', 32 | ]); 33 | 34 | $defaults['mms'] = Arr::only($defaults['mms'], [ 35 | ]); 36 | 37 | $defaults['vms'] = Arr::only($defaults['vms'], [ 38 | 'from', 'tries', 'interval', 'tts_lector', 'skip_gsm', 39 | ]); 40 | 41 | if (! empty($defaults['common'])) { 42 | $defaults['common'] = Arr::only($defaults['common'], [ 43 | 'notify_url', 'partner', 'test', 44 | ]); 45 | 46 | $defaults['sms'] += $defaults['common']; 47 | $defaults['mms'] += $defaults['common']; 48 | $defaults['vms'] += $defaults['common']; 49 | } 50 | 51 | $defaults = Arr::only($defaults, ['sms', 'mms', 'vms']); 52 | $defaults = array_map(function (array $defaults) { 53 | return array_filter($defaults, function ($value) { 54 | return $value !== null; 55 | }); 56 | }, $defaults); 57 | 58 | $proxy = new Native($auth['service']); 59 | 60 | return new SmsapiClient($client, $defaults, $proxy); 61 | }); 62 | 63 | if ($this->app->runningInConsole()) { 64 | $this->publishes([ 65 | __DIR__.'/../config/smsapi.php' => config_path('smsapi.php'), 66 | ], 'config'); 67 | } 68 | } 69 | 70 | /** 71 | * Register the application services. 72 | */ 73 | public function register() 74 | { 75 | $this->mergeConfigFrom(__DIR__.'/../config/smsapi.php', 'smsapi'); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/SmsapiSmsMessage.php: -------------------------------------------------------------------------------- 1 | data['content'] = $content; 17 | } 18 | } 19 | 20 | /** 21 | * @param string $content 22 | * @return self 23 | */ 24 | public function content($content) 25 | { 26 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'string', $content); 27 | $this->data['content'] = $content; 28 | 29 | return $this; 30 | } 31 | 32 | /** 33 | * @param string $template 34 | * @return self 35 | */ 36 | public function template($template) 37 | { 38 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'string', $template); 39 | $this->data['template'] = $template; 40 | 41 | return $this; 42 | } 43 | 44 | /** 45 | * @param string $from 46 | * @return self 47 | */ 48 | public function from($from) 49 | { 50 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'string', $from); 51 | $this->data['from'] = $from; 52 | 53 | return $this; 54 | } 55 | 56 | /** 57 | * @param bool $fast 58 | * @return self 59 | */ 60 | public function fast($fast = true) 61 | { 62 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'boolean', $fast); 63 | $this->data['fast'] = $fast; 64 | 65 | return $this; 66 | } 67 | 68 | /** 69 | * @param bool $flash 70 | * @return self 71 | */ 72 | public function flash($flash = true) 73 | { 74 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'boolean', $flash); 75 | $this->data['flash'] = $flash; 76 | 77 | return $this; 78 | } 79 | 80 | /** 81 | * @param string $encoding 82 | * @return self 83 | */ 84 | public function encoding($encoding) 85 | { 86 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'string', $encoding); 87 | $this->data['encoding'] = $encoding; 88 | 89 | return $this; 90 | } 91 | 92 | /** 93 | * @param bool $normalize 94 | * @return self 95 | */ 96 | public function normalize($normalize = true) 97 | { 98 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'boolean', $normalize); 99 | $this->data['normalize'] = $normalize; 100 | 101 | return $this; 102 | } 103 | 104 | /** 105 | * @param bool $nounicode 106 | * @return self 107 | */ 108 | public function nounicode($nounicode = true) 109 | { 110 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'boolean', $nounicode); 111 | $this->data['nounicode'] = $nounicode; 112 | 113 | return $this; 114 | } 115 | 116 | /** 117 | * @param bool $single 118 | * @return self 119 | */ 120 | public function single($single = true) 121 | { 122 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'boolean', $single); 123 | $this->data['single'] = $single; 124 | 125 | return $this; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/SmsapiVmsMessage.php: -------------------------------------------------------------------------------- 1 | data['file'] = $file; 17 | 18 | return $this; 19 | } 20 | 21 | /** 22 | * @param string $tts 23 | * @return self 24 | */ 25 | public function tts($tts) 26 | { 27 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'string', $tts); 28 | $this->data['tts'] = $tts; 29 | 30 | return $this; 31 | } 32 | 33 | /** 34 | * @param string $ttsLector 35 | * @return self 36 | */ 37 | public function ttsLector($ttsLector) 38 | { 39 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'string', $ttsLector); 40 | $this->data['tts_lector'] = $ttsLector; 41 | 42 | return $this; 43 | } 44 | 45 | /** 46 | * @param string $from 47 | * @return self 48 | */ 49 | public function from($from) 50 | { 51 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'string', $from); 52 | $this->data['from'] = $from; 53 | 54 | return $this; 55 | } 56 | 57 | /** 58 | * @param int $tries 59 | * @return self 60 | */ 61 | public function tries($tries) 62 | { 63 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'integer', $tries); 64 | $this->data['tries'] = $tries; 65 | 66 | return $this; 67 | } 68 | 69 | /** 70 | * @param int $interval 71 | * @return self 72 | */ 73 | public function interval($interval) 74 | { 75 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'integer', $interval); 76 | $this->data['interval'] = $interval; 77 | 78 | return $this; 79 | } 80 | 81 | /** 82 | * @param bool $skipGsm 83 | * @return self 84 | */ 85 | public function skipGsm($skipGsm = true) 86 | { 87 | ExceptionFactory::assertArgumentType(1, __METHOD__, 'boolean', $skipGsm); 88 | $this->data['skip_gsm'] = $skipGsm; 89 | 90 | return $this; 91 | } 92 | } 93 | --------------------------------------------------------------------------------