From 2af107911d3fbd0c2dc94de9b75158da9fbd44b6 Mon Sep 17 00:00:00 2001 From: Robert Wayne Date: Thu, 26 Jan 2023 14:54:57 -0800 Subject: [PATCH 1/3] initial commit --- .editorconfig | 15 + .github/workflows/tests.yml | 32 ++ .gitignore | 6 + .lando.yml | 5 + .styleci.yml | 1 + CHANGELOG.md | 7 + CONTRIBUTING.md | 55 ++++ LICENSE.md | 21 ++ README.md | 125 ++++++++ build/report.junit.xml | 26 ++ composer.json | 53 ++++ config/clicksend.php | 36 +++ phpunit.xml.dist | 32 ++ src/ClickSend.php | 90 ++++++ src/ClickSendChannel.php | 78 +++++ src/ClickSendMessage.php | 106 +++++++ src/ClickSendServiceProvider.php | 63 ++++ src/Exceptions/CouldNotSendNotification.php | 15 + src/Facades/ClickSend.php | 19 ++ tests/Feature/ClientAPICredentialsTest.php | 22 ++ .../Feature/ClientAccountCredentialsTest.php | 22 ++ tests/Feature/FeatureTestCase.php | 20 ++ .../Feature/NoClickSendConfigurationTest.php | 22 ++ .../Unit/Channels/ClickSendSmsChannelTest.php | 274 ++++++++++++++++++ 24 files changed, 1145 insertions(+) create mode 100644 .editorconfig create mode 100644 .github/workflows/tests.yml create mode 100644 .gitignore create mode 100644 .lando.yml create mode 100644 .styleci.yml create mode 100755 CHANGELOG.md create mode 100755 CONTRIBUTING.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 build/report.junit.xml create mode 100644 composer.json create mode 100644 config/clicksend.php create mode 100644 phpunit.xml.dist create mode 100644 src/ClickSend.php create mode 100644 src/ClickSendChannel.php create mode 100644 src/ClickSendMessage.php create mode 100644 src/ClickSendServiceProvider.php create mode 100644 src/Exceptions/CouldNotSendNotification.php create mode 100644 src/Facades/ClickSend.php create mode 100644 tests/Feature/ClientAPICredentialsTest.php create mode 100644 tests/Feature/ClientAccountCredentialsTest.php create mode 100644 tests/Feature/FeatureTestCase.php create mode 100644 tests/Feature/NoClickSendConfigurationTest.php create mode 100644 tests/Unit/Channels/ClickSendSmsChannelTest.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..cd8eb86e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +; This file is for unifying the coding style for different editors and IDEs. +; More information at http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_size = 4 +indent_style = space +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000..f9ff88d2 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,32 @@ +name: PHPUnit tests + +on: + - push + - pull_request + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + php: [7.2, 7.3, 7.4, 8.0] + + name: Tests on PHP ${{ matrix.php }} - ${{ matrix.stability }} + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: composer:v2 + coverage: none + + - name: Install dependencies + run: composer update --prefer-source --no-interaction --no-progress + + - name: Execute tests + run: vendor/bin/phpunit --verbose diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..9bf84788 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +**/.DS_Store +/vendor +composer.lock +/phpunit.xml +.phpunit.result.cache +/.idea diff --git a/.lando.yml b/.lando.yml new file mode 100644 index 00000000..298012b9 --- /dev/null +++ b/.lando.yml @@ -0,0 +1,5 @@ +name: clicksend-channel +recipe: lamp +config: + webroot: src + php: '8.1' diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 00000000..0285f179 --- /dev/null +++ b/.styleci.yml @@ -0,0 +1 @@ +preset: laravel diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100755 index 00000000..dc56a0b5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All notable changes to `clicksend` will be documented in this file + +## 1.0.0 - 2023-01-26 + +- initial release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100755 index 00000000..4da74e3f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing + +Contributions are **welcome** and will be fully **credited**. + +Please read and understand the contribution guide before creating an issue or pull request. + +## Etiquette + +This project is open source, and as such, the maintainers give their free time to build and maintain the source code +held within. They make the code freely available in the hope that it will be of use to other developers. It would be +extremely unfair for them to suffer abuse or anger for their hard work. + +Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the +world that developers are civilized and selfless people. + +It's the duty of the maintainer to ensure that all submissions to the project are of sufficient +quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. + +## Viability + +When requesting or submitting new features, first consider whether it might be useful to others. Open +source projects are used by many developers, who may have entirely different needs to your own. Think about +whether or not your feature is likely to be used by other users of the project. + +## Procedure + +Before filing an issue: + +- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. +- Check to make sure your feature suggestion isn't already present within the project. +- Check the pull requests tab to ensure that the bug doesn't have a fix in progress. +- Check the pull requests tab to ensure that the feature isn't already in progress. + +Before submitting a pull request: + +- Check the codebase to ensure that your feature doesn't already exist. +- Check the pull requests to ensure that another person hasn't already submitted the feature or fix. + +## Requirements + +If the project maintainer has any additional requirements, you will find them listed here. + +- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). + +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. + +- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. + +- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. + +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. + +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. + +**Happy coding**! diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..d536433d --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) Robert Wayne + +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +> THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..f4b132dc --- /dev/null +++ b/README.md @@ -0,0 +1,125 @@ +# ClickSend notifications channel for Laravel + +This package makes it easy to send notification via [SMS using ClickSend API](https://developers.clicksend.com/docs/rest/v3/?php) with Laravel 5.5+, 6.x, 7.x, 8.x & 9.x + +## Contents + +- [Installation](#installation) + - [Setting up a ClickSend account](#set-up-a-clicksend-account) + - [Install the package via composer](#install-the-package-via-composer) + - [Configuration env](#configuration-env) +- [Usage](#usage) + - [Available Message methods](#available-message-methods) +- [Changelog](#changelog) +- [Testing](#testing) +- [Security](#security) +- [Contributing](#contributing) +- [Credits](#credits) +- [License](#license) + + +## Installation + +### Set up a ClickSend account + +You'll need a ClickSend account. Head over to their [website](https://clicksend.com/) and create or login to your account. + +From the dashboard, in the sidebar... `Developers` then `API Credentials` to find your API credentials. + +### Install the package via composer + +```bash +composer require laravel-notification-channels/clicksend +``` +### Configuration env +Add your ClickSend API credentials to your .env file: + +```php +CLICK_SEND_USERNAME=test@tester.com +CLICK_SEND_KEY=YOUR-API-KEY-FROM-CLICKSEND +CLICK_SEND_FROM=8885551212 +``` +OR, use your ClickSend account credentials... +```php +CLICK_SEND_ACCOUNT_USERNAME=test@tester.com +CLICK_SEND_ACCOUNT_PASSWORD=your_clicksend_account_password +CLICK_SEND_FROM=8885551212 +``` + +## Usage + +You can use the channel in your `via()` method inside the notification: + +```php +use Illuminate\Notifications\Notification; +use \NotificationChannels\ClickSend\ClickSendMessage; +use \NotificationChannels\ClickSend\ClickSendChannel; + +class AccountApproved extends Notification +{ + public function via($notifiable) + { + return [ClickSendChannel::class]; + } + + public function toClickSend($notifiable) + { + return (new ClickSendMessage) + ->content("{$notifiable->name}, your account was approved!"); + } +} +``` +In your notifiable model, make sure to include a `routeNotificationForClickSend()` method, +provide the number in [international format](https://help.clicksend.com/article/hpkm4oco32-what-format-does-the-recipient-phone-number-need-to-be-in) +or ClickSend with automatically format it using your accounts [default country](https://dashboard.clicksend.com/messaging-settings/sms/general). + +```php +public function routeNotificationForClickSend() +{ + return $this->phone; // 6142345678 +} +``` + +### Available methods + +`from('')`: Accepts your sender id (ClickSend from number) + +`content('')`: Accepts a string value for the notification body. + +`reference('')`: Accepts a reference string, it's a [custom_string used in ClickSend](https://help.clicksend.com/article/qj7wj57leq-what-is-the-custom-string-used-for) delivery reports. + +## Changelog + +Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. + +## Testing + +``` bash +$ composer test +``` + +## Security + +If you discover any security related issues, please email webrobert@gmail.com instead of using the issue tracker. + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## Credits + +- [Robert Wayne](https://github.com/webrobert) +- [All Contributors](../../contributors) + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. diff --git a/build/report.junit.xml b/build/report.junit.xml new file mode 100644 index 00000000..4aac1420 --- /dev/null +++ b/build/report.junit.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..afa0051b --- /dev/null +++ b/composer.json @@ -0,0 +1,53 @@ +{ + "name": "laravel-notification-channels/clicksend", + "description": "Provides ClickSend SMS notification channel for Laravel.", + "homepage": "https://github.com/laravel-notification-channels/clicksend", + "license": "MIT", + "authors": [ + { + "name": "Robert Wayne", + "email": "webrobert@gmail.com", + "homepage": "https://github.com/webrobert", + "role": "Developer" + } + ], + "require": { + "php": ">=7.2", + "illuminate/notifications": "~6.0 || ~7.0 || ~8.0", + "illuminate/support": "~6.0 || ~7.0 || ~8.0", + "clicksend/clicksend-php": "^5.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^9.0", + "orchestra/testbench": "^6.0|^7.0|^8.0" + }, + "autoload": { + "psr-4": { + "NotificationChannels\\ClickSend\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "NotificationChannels\\ClickSend\\Test\\": "tests" + } + }, + "scripts": { + "test": "vendor/bin/phpunit", + "test:unit": "phpunit --verbose --testsuite Unit", + "test:integration": "phpunit --verbose --testsuite Integration" + }, + "extra": { + "laravel": { + "providers": [ + "NotificationChannels\\ClickSend\\ClickSendServiceProvider" + ], + "aliases": { + "ClickSend": "NotificationChannels\\ClickSend\\Facades\\ClickSend" + } + } + }, + "config": { + "sort-packages": true + } +} diff --git a/config/clicksend.php b/config/clicksend.php new file mode 100644 index 00000000..ece0d347 --- /dev/null +++ b/config/clicksend.php @@ -0,0 +1,36 @@ + env('CLICK_SEND_FROM'), + + /* + |-------------------------------------------------------------------------- + | API Credentials + |-------------------------------------------------------------------------- + | + | The following configuration options contain your API credentials, which + | may be accessed from your ClickSend dashboard. These credentials may be + | used to authenticate with the ClickSend API to allow sending messages. + | + */ + + 'api_username' => env('CLICK_SEND_USERNAME'), + 'api_key' => env('CLICK_SEND_KEY'), + + // OR + + 'account_username' => env('CLICK_SEND_ACCOUNT_USERNAME'), + 'account_password' => env('CLICK_SEND_ACCOUNT_PASSWORD'), + +]; diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 00000000..e93aef52 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,32 @@ + + + + + ./tests/Unit + + + ./tests/Feature + + + + + src/ + + + + + + + + + + diff --git a/src/ClickSend.php b/src/ClickSend.php new file mode 100644 index 00000000..a3f520b1 --- /dev/null +++ b/src/ClickSend.php @@ -0,0 +1,90 @@ +config = $config; + $this->client = $client; + } + + /** + * Create a new ClickSend instance. + * + * @param array $config + * @param ClientInterface|null $client + * + * @return static + */ + public static function make(array $config, ?ClientInterface $client = null) + { + return new static($config, $client); + } + + /** + * Create a new ClickSend Client. + * + * @return Client + * + * @throws \RuntimeException + */ + public function client() : Client + { + [$username, $password] = $this->firstComboOrFail([ + 'apiCredentials' => [ + $this->config['api_username'], $this->config['api_key'] + ], + 'accountCredentials' => [ + $this->config['account_username'], $this->config['account_password'] + ] + ]); + + $credentials = Configuration::getDefaultConfiguration() + ->setUsername($username) + ->setPassword($password); + + return new Client($this->client, $credentials); + } + + private function firstComboOrFail(array $combos) + { + $credentials = collect($combos) + ->first( function($pair) { return ! in_array(null, $pair,true); }); + + if(! $credentials) { + throw new RuntimeException('Please provide your ClickSend API credentials. + Possible combinations: api_username + api_key OR account_username + account_password.'); + } + + return $credentials; + } +} diff --git a/src/ClickSendChannel.php b/src/ClickSendChannel.php new file mode 100644 index 00000000..5677723e --- /dev/null +++ b/src/ClickSendChannel.php @@ -0,0 +1,78 @@ +from = $from; + $this->client = $client; + } + + /** + * Send the given notification. + * + * @param mixed $notifiable + * @param Notification $notification + * @return mixed + */ + public function send($notifiable, Notification $notification): void + { + if (! $to = $notifiable->routeNotificationFor('ClickSend', $notification)) { + return; + } + + $message = $notification->toClickSend($notifiable); + + if (is_string($message)) { + $message = new ClickSendMessage($message); + } + + $sms_messages = (new SmsMessageCollection())->setMessages([ + new SmsMessage([ + 'to' => $to, + 'body' => trim($message->content), + 'from' => $message->from ?: $this->from, + 'source' => 'laravel', + 'custom_string' => $message->reference + ]) + ]); + + try { + ( $message->client ?? $this->client )->smsSendPost( $sms_messages ); + } + catch (ApiException $e) { + throw CouldNotSendNotification::ClickSendApiException($e); + }; + } +} diff --git a/src/ClickSendMessage.php b/src/ClickSendMessage.php new file mode 100644 index 00000000..fcc966fc --- /dev/null +++ b/src/ClickSendMessage.php @@ -0,0 +1,106 @@ +content = $content; + } + + /** + * Set the message content. + * + * @param string $content + * @return ClickSendMessage + */ + public function content($content) + { + $this->content = $content; + + return $this; + } + + /** + * Set the phone number the message should be sent from. + * + * @param string $from + * @return $this + */ + public function from($from) + { + $this->from = $from; + + return $this; + } + + /** + * Set the client reference (up to 40 characters). + * + * @param string $string + * @return $this + */ + public function reference($string) + { + $this->reference = $string; + + return $this; + } + + + /** + * Set the ClickSend SMS client instance. + * + * @param SMSApi $client + * @return $this + */ + public function usingClient($client) + { + $this->client = $client; + + return $this; + }} diff --git a/src/ClickSendServiceProvider.php b/src/ClickSendServiceProvider.php new file mode 100644 index 00000000..95f6ed6d --- /dev/null +++ b/src/ClickSendServiceProvider.php @@ -0,0 +1,63 @@ +mergeConfigFrom(__DIR__.'/../config/clicksend.php', 'clicksend'); + + $this->app->singleton(Client::class, function ($app) { + $config = $app['config']['clicksend']; + + if ($httpClient = $config['http_client'] ?? null) { + $httpClient = $app->make($httpClient); + } elseif (! class_exists('GuzzleHttp\Client')) { + throw new RuntimeException( + 'The ClickSend client requires a "psr/http-client-implementation" class such as Guzzle.' + ); + } + + return ClickSend::make($app['config']['clicksend'], $httpClient)->client(); + }); + + $this->app->bind(ClickSendChannel::class, function ($app) { + return new ClickSendChannel( + $app->make(Client::class), + $app['config']['clicksend.sms_from'] + ); + }); + + Notification::resolved(function (ChannelManager $service) { + $service->extend('clicksend', function ($app) { + return $app->make(ClickSendChannel::class); + }); + }); + } + + /** + * Bootstrap the application services. + * + * @return void + */ + public function boot() + { + if ($this->app->runningInConsole()) { + $this->publishes([ + __DIR__.'/../config/clicksend.php' => $this->app->configPath('clicksend.php'), + ], 'clicksend'); + } + } +} diff --git a/src/Exceptions/CouldNotSendNotification.php b/src/Exceptions/CouldNotSendNotification.php new file mode 100644 index 00000000..da9e634a --- /dev/null +++ b/src/Exceptions/CouldNotSendNotification.php @@ -0,0 +1,15 @@ +set('clicksend.api_username', 'my_username'); + $app['config']->set('clicksend.api_key', 'my_api_key'); + } + + public function testClientCreatedWithBasicAPICredentials() + { + $credentials = $this->app->make(Client::class)->getConfig(); + + $this->assertEquals([ 'my_username', 'my_api_key' ], + [ $credentials->getUsername(), $credentials->getPassword() ]); + } +} diff --git a/tests/Feature/ClientAccountCredentialsTest.php b/tests/Feature/ClientAccountCredentialsTest.php new file mode 100644 index 00000000..ec3e0bab --- /dev/null +++ b/tests/Feature/ClientAccountCredentialsTest.php @@ -0,0 +1,22 @@ +set('clicksend.account_username', 'my_username'); + $app['config']->set('clicksend.account_password', 'my_account_password'); + } + + public function testClientCreatedWithBasicAPICredentials() + { + $credentials = $this->app->make(Client::class)->getConfig(); + + $this->assertEquals([ 'my_username', 'my_account_password' ], + [ $credentials->getUsername(), $credentials->getPassword() ]); + } +} diff --git a/tests/Feature/FeatureTestCase.php b/tests/Feature/FeatureTestCase.php new file mode 100644 index 00000000..dd4bad5c --- /dev/null +++ b/tests/Feature/FeatureTestCase.php @@ -0,0 +1,20 @@ +set('clicksend.api_key', 'my_api_key'); + } + + public function testWhenNoConfigurationIsGivenExceptionIsRaised() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage( 'Please provide your ClickSend API credentials. + Possible combinations: api_username + api_key OR account_username + account_password.'); + app(Client::class); + } +} diff --git a/tests/Unit/Channels/ClickSendSmsChannelTest.php b/tests/Unit/Channels/ClickSendSmsChannelTest.php new file mode 100644 index 00000000..ace9c425 --- /dev/null +++ b/tests/Unit/Channels/ClickSendSmsChannelTest.php @@ -0,0 +1,274 @@ +setMessages([ + new SMS([ + 'to' => '5555555555', + 'from' =>'4444444444', + 'body' => 'this is my message', + 'source' => 'laravel' + ]) + ]); + + $clickSend->shouldReceive('smsSendPost') + ->with(IsEqual::equalTo($mockSms)) + ->once(); + + $channel->send($notifiable, $notification); + } + + public function testSmsIsSentViaClickSendWithCustomClient() + { + $sms_messages = (new SmsMessageCollection())->setMessages([ + new SMS([ + 'to' => '5555555555', + 'from' =>'4444444444', + 'body' => 'this is my message', + 'source' => 'laravel' + ]) + ]); + + $customClickSend = m::mock(Client::class); + $customClickSend->shouldReceive('smsSendPost') + ->with(IsEqual::equalTo($sms_messages)) + ->once(); + + $notification = new NotificationClickSendSmsChannelTestCustomClientNotification($customClickSend); + $notifiable = new NotificationClickSendSmsChannelTestNotifiable; + + $channel = new ClickSendChannel( + $clickSend = m::mock(Client::class), '4444444444' + ); + + $clickSend->shouldNotReceive('smsSendPost'); + + $channel->send($notifiable, $notification); + } + + public function testSmsIsSentViaClickSendWithCustomFrom() + { + $notification = new NotificationClickSendSmsChannelTestCustomFromNotification; + $notifiable = new NotificationClickSendSmsChannelTestNotifiable; + + $channel = new ClickSendChannel( + $clickSend = m::mock(Client::class), '4444444444' + ); + + $mockSms = (new SmsMessageCollection())->setMessages([ + new SMS([ + 'to' => '5555555555', + 'from' =>'5554443333', + 'body' => 'this is my message', + 'source' => 'laravel' + ]) + ]); + + $clickSend->shouldReceive('smsSendPost') + ->with(IsEqual::equalTo($mockSms)) + ->once(); + + $channel->send($notifiable, $notification); + } + + public function testSmsIsSentViaClickSendWithCustomFromAndClient() + { + $customClickSend = m::mock(Client::class); + + $mockSms = (new SmsMessageCollection())->setMessages([ + new SMS([ + 'to' => '5555555555', + 'from' =>'5554443333', + 'body' => 'this is my message', + 'source' => 'laravel' + ]) + ]); + + $customClickSend->shouldReceive('smsSendPost') + ->with(IsEqual::equalTo($mockSms)) + ->once(); + + $notification = new NotificationClickSendSmsChannelTestCustomFromAndClientNotification($customClickSend); + $notifiable = new NotificationClickSendSmsChannelTestNotifiable; + + $channel = new ClickSendChannel( + $clickSend = m::mock(Client::class), '4444444444' + ); + + $clickSend->shouldNotReceive('smsSendPost'); + + $channel->send($notifiable, $notification); + } + + public function testSmsIsSentViaClickSendWithCustomFromAndCustomString() + { + $notification = new NotificationClickSendSmsChannelTestCustomFromAndClientRefNotification; + $notifiable = new NotificationClickSendSmsChannelTestNotifiable; + + $channel = new ClickSendChannel( + $clickSend = m::mock(Client::class), '4444444444' + ); + + $mockSms = (new SmsMessageCollection())->setMessages([ + new SMS([ + 'to' => '5555555555', + 'from' =>'5554443333', + 'body' => 'this is my message', + 'source' => 'laravel', + 'custom_string' => '11' + ]) + ]); + + $clickSend->shouldReceive('smsSendPost') + ->with(IsEqual::equalTo($mockSms)) + ->once(); + + $channel->send($notifiable, $notification); + } + + public function testSmsIsSentViaClickSendWithCustomClientFromAndClientRef() + { + $customClickSend = m::mock(Client::class); + + $mockSms = (new SmsMessageCollection())->setMessages([ + new SMS([ + 'to' => '5555555555', + 'from' =>'5554443333', + 'body' => 'this is my message', + 'source' => 'laravel', + 'custom_string' => '11' + ]) + ]); + + $customClickSend->shouldReceive('smsSendPost') + ->with(IsEqual::equalTo($mockSms)) + ->once(); + + $notification = new NotificationClickSendSmsChannelTestCustomClientFromAndClientRefNotification($customClickSend); + $notifiable = new NotificationClickSendSmsChannelTestNotifiable; + + $channel = new ClickSendChannel( + $clickSend = m::mock(Client::class), '4444444444' + ); + + $clickSend->shouldNotReceive('smsSendPost'); + + $channel->send($notifiable, $notification); + } +} + +class NotificationClickSendSmsChannelTestNotifiable +{ + use Notifiable; + + public $phone_number = '5555555555'; + + public function routeNotificationForClickSend($notification) + { + return $this->phone_number; + } +} + +class NotificationClickSendSmsChannelTestNotification extends Notification +{ + public function toClickSend($notifiable) + { + return new ClickSendMessage('this is my message'); + } +} + +class NotificationClickSendSmsChannelTestCustomClientNotification extends Notification +{ + private $client; + + public function __construct(Client $client) + { + $this->client = $client; + } + + public function toClickSend($notifiable) + { + return (new ClickSendMessage('this is my message')) + ->usingClient($this->client); + } +} + +class NotificationClickSendSmsChannelTestCustomFromNotification extends Notification +{ + public function toClickSend($notifiable) + { + return (new ClickSendMessage('this is my message')) + ->from('5554443333'); + } +} + +class NotificationClickSendSmsChannelTestCustomFromAndClientNotification extends Notification +{ + private $client; + + public function __construct(Client $client) + { + $this->client = $client; + } + + public function toClickSend($notifiable) + { + return (new ClickSendMessage('this is my message')) + ->from('5554443333') + ->usingClient($this->client); + } +} + +class NotificationClickSendSmsChannelTestCustomFromAndClientRefNotification extends Notification +{ + public function toClickSend($notifiable) + { + return (new ClickSendMessage('this is my message')) + ->from('5554443333') + ->reference('11'); + } +} + +class NotificationClickSendSmsChannelTestCustomClientFromAndClientRefNotification extends Notification +{ + private $client; + + public function __construct(Client $client) + { + $this->client = $client; + } + + public function toClickSend($notifiable) + { + return (new ClickSendMessage('this is my message')) + ->from('5554443333') + ->reference('11') + ->usingClient($this->client); + } +} From 0791a8cc4f2daa876e5109a9e4eac8c88c3426e4 Mon Sep 17 00:00:00 2001 From: Robert Wayne Date: Thu, 26 Jan 2023 15:42:09 -0800 Subject: [PATCH 2/3] removed 7.2 php from test.yml --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f9ff88d2..30423590 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: true matrix: - php: [7.2, 7.3, 7.4, 8.0] + php: [7.3, 7.4, 8.0] name: Tests on PHP ${{ matrix.php }} - ${{ matrix.stability }} From 7c7c76e7e0b4cfa5eb5e694b84b58eafa09b5f23 Mon Sep 17 00:00:00 2001 From: Robert Wayne Date: Sat, 28 Jan 2023 12:23:02 -0800 Subject: [PATCH 3/3] styleci fixes --- build/report.junit.xml | 32 +++++++-------- src/ClickSend.php | 22 +++++------ src/ClickSendChannel.php | 26 ++++++------- src/ClickSendMessage.php | 14 +++---- src/ClickSendServiceProvider.php | 2 +- src/Exceptions/CouldNotSendNotification.php | 2 +- src/Facades/ClickSend.php | 2 +- tests/Feature/ClientAPICredentialsTest.php | 4 +- .../Feature/ClientAccountCredentialsTest.php | 4 +- .../Feature/NoClickSendConfigurationTest.php | 2 +- .../Unit/Channels/ClickSendSmsChannelTest.php | 39 +++++++++---------- 11 files changed, 73 insertions(+), 76 deletions(-) diff --git a/build/report.junit.xml b/build/report.junit.xml index 4aac1420..85e99530 100644 --- a/build/report.junit.xml +++ b/build/report.junit.xml @@ -1,25 +1,25 @@ - - - - - - - - - + + + + + + + + + - - - + + + - - + + - - + + diff --git a/src/ClickSend.php b/src/ClickSend.php index a3f520b1..e98172f2 100644 --- a/src/ClickSend.php +++ b/src/ClickSend.php @@ -2,9 +2,9 @@ namespace NotificationChannels\ClickSend; -use Psr\Http\Client\ClientInterface; use ClickSend\Api\SMSApi as Client; use ClickSend\Configuration; +use Psr\Http\Client\ClientInterface; use RuntimeException; class ClickSend @@ -27,8 +27,7 @@ class ClickSend * Create a new ClickSend instance. * * @param array $config - * @param ClientInterface|null $client - * + * @param ClientInterface|null $client * @return void */ public function __construct(array $config = [], ?ClientInterface $client = null) @@ -41,8 +40,7 @@ public function __construct(array $config = [], ?ClientInterface $client = null) * Create a new ClickSend instance. * * @param array $config - * @param ClientInterface|null $client - * + * @param ClientInterface|null $client * @return static */ public static function make(array $config, ?ClientInterface $client = null) @@ -57,15 +55,15 @@ public static function make(array $config, ?ClientInterface $client = null) * * @throws \RuntimeException */ - public function client() : Client + public function client(): Client { [$username, $password] = $this->firstComboOrFail([ 'apiCredentials' => [ - $this->config['api_username'], $this->config['api_key'] + $this->config['api_username'], $this->config['api_key'], ], 'accountCredentials' => [ - $this->config['account_username'], $this->config['account_password'] - ] + $this->config['account_username'], $this->config['account_password'], + ], ]); $credentials = Configuration::getDefaultConfiguration() @@ -78,9 +76,11 @@ public function client() : Client private function firstComboOrFail(array $combos) { $credentials = collect($combos) - ->first( function($pair) { return ! in_array(null, $pair,true); }); + ->first(function ($pair) { + return ! in_array(null, $pair, true); + }); - if(! $credentials) { + if (! $credentials) { throw new RuntimeException('Please provide your ClickSend API credentials. Possible combinations: api_username + api_key OR account_username + account_password.'); } diff --git a/src/ClickSendChannel.php b/src/ClickSendChannel.php index 5677723e..5fc88b8c 100644 --- a/src/ClickSendChannel.php +++ b/src/ClickSendChannel.php @@ -2,12 +2,12 @@ namespace NotificationChannels\ClickSend; -use NotificationChannels\ClickSend\Exceptions\CouldNotSendNotification; use ClickSend\Api\SMSApi as ClickSendClient; -use Illuminate\Notifications\Notification; -use ClickSend\Model\SmsMessageCollection; -use ClickSend\Model\SmsMessage; use ClickSend\ApiException; +use ClickSend\Model\SmsMessage; +use ClickSend\Model\SmsMessageCollection; +use Illuminate\Notifications\Notification; +use NotificationChannels\ClickSend\Exceptions\CouldNotSendNotification; class ClickSendChannel { @@ -28,9 +28,8 @@ class ClickSendChannel /** * Create a new ClickSend channel instance. * - * @param ClickSendClient $client - * @param string $from - * + * @param ClickSendClient $client + * @param string $from * @return void */ public function __construct(ClickSendClient $client, $from) @@ -43,7 +42,7 @@ public function __construct(ClickSendClient $client, $from) * Send the given notification. * * @param mixed $notifiable - * @param Notification $notification + * @param Notification $notification * @return mixed */ public function send($notifiable, Notification $notification): void @@ -64,15 +63,14 @@ public function send($notifiable, Notification $notification): void 'body' => trim($message->content), 'from' => $message->from ?: $this->from, 'source' => 'laravel', - 'custom_string' => $message->reference - ]) + 'custom_string' => $message->reference, + ]), ]); try { - ( $message->client ?? $this->client )->smsSendPost( $sms_messages ); - } - catch (ApiException $e) { + ($message->client ?? $this->client)->smsSendPost($sms_messages); + } catch (ApiException $e) { throw CouldNotSendNotification::ClickSendApiException($e); - }; + } } } diff --git a/src/ClickSendMessage.php b/src/ClickSendMessage.php index fcc966fc..175e7bf8 100644 --- a/src/ClickSendMessage.php +++ b/src/ClickSendMessage.php @@ -44,7 +44,7 @@ class ClickSendMessage /** * Create a new message instance. * - * @param string $content + * @param string $content * @return void */ public function __construct($content = '') @@ -55,7 +55,7 @@ public function __construct($content = '') /** * Set the message content. * - * @param string $content + * @param string $content * @return ClickSendMessage */ public function content($content) @@ -68,7 +68,7 @@ public function content($content) /** * Set the phone number the message should be sent from. * - * @param string $from + * @param string $from * @return $this */ public function from($from) @@ -81,7 +81,7 @@ public function from($from) /** * Set the client reference (up to 40 characters). * - * @param string $string + * @param string $string * @return $this */ public function reference($string) @@ -91,11 +91,10 @@ public function reference($string) return $this; } - /** * Set the ClickSend SMS client instance. * - * @param SMSApi $client + * @param SMSApi $client * @return $this */ public function usingClient($client) @@ -103,4 +102,5 @@ public function usingClient($client) $this->client = $client; return $this; - }} + } +} diff --git a/src/ClickSendServiceProvider.php b/src/ClickSendServiceProvider.php index 95f6ed6d..22331417 100644 --- a/src/ClickSendServiceProvider.php +++ b/src/ClickSendServiceProvider.php @@ -2,10 +2,10 @@ namespace NotificationChannels\ClickSend; +use ClickSend\Api\SMSApi as Client; use Illuminate\Notifications\ChannelManager; use Illuminate\Support\Facades\Notification; use Illuminate\Support\ServiceProvider; -use ClickSend\Api\SMSApi as Client; use RuntimeException; class ClickSendServiceProvider extends ServiceProvider diff --git a/src/Exceptions/CouldNotSendNotification.php b/src/Exceptions/CouldNotSendNotification.php index da9e634a..77b9de7c 100644 --- a/src/Exceptions/CouldNotSendNotification.php +++ b/src/Exceptions/CouldNotSendNotification.php @@ -9,7 +9,7 @@ class CouldNotSendNotification extends \Exception public static function ClickSendApiException(ApiException $exception): self { return new static( - "ClickSend could not send and responded with an error.", null, $exception + 'ClickSend could not send and responded with an error.', null, $exception ); } } diff --git a/src/Facades/ClickSend.php b/src/Facades/ClickSend.php index 86f738e9..fa923c1c 100644 --- a/src/Facades/ClickSend.php +++ b/src/Facades/ClickSend.php @@ -12,7 +12,7 @@ class ClickSend extends Facade * * @return string */ - protected static function getFacadeAccessor() : string + protected static function getFacadeAccessor(): string { return Client::class; } diff --git a/tests/Feature/ClientAPICredentialsTest.php b/tests/Feature/ClientAPICredentialsTest.php index 3654962a..61ddf745 100644 --- a/tests/Feature/ClientAPICredentialsTest.php +++ b/tests/Feature/ClientAPICredentialsTest.php @@ -16,7 +16,7 @@ public function testClientCreatedWithBasicAPICredentials() { $credentials = $this->app->make(Client::class)->getConfig(); - $this->assertEquals([ 'my_username', 'my_api_key' ], - [ $credentials->getUsername(), $credentials->getPassword() ]); + $this->assertEquals(['my_username', 'my_api_key'], + [$credentials->getUsername(), $credentials->getPassword()]); } } diff --git a/tests/Feature/ClientAccountCredentialsTest.php b/tests/Feature/ClientAccountCredentialsTest.php index ec3e0bab..fb75e594 100644 --- a/tests/Feature/ClientAccountCredentialsTest.php +++ b/tests/Feature/ClientAccountCredentialsTest.php @@ -16,7 +16,7 @@ public function testClientCreatedWithBasicAPICredentials() { $credentials = $this->app->make(Client::class)->getConfig(); - $this->assertEquals([ 'my_username', 'my_account_password' ], - [ $credentials->getUsername(), $credentials->getPassword() ]); + $this->assertEquals(['my_username', 'my_account_password'], + [$credentials->getUsername(), $credentials->getPassword()]); } } diff --git a/tests/Feature/NoClickSendConfigurationTest.php b/tests/Feature/NoClickSendConfigurationTest.php index b6bb657f..95a57788 100644 --- a/tests/Feature/NoClickSendConfigurationTest.php +++ b/tests/Feature/NoClickSendConfigurationTest.php @@ -15,7 +15,7 @@ protected function getEnvironmentSetUp($app) public function testWhenNoConfigurationIsGivenExceptionIsRaised() { $this->expectException(RuntimeException::class); - $this->expectExceptionMessage( 'Please provide your ClickSend API credentials. + $this->expectExceptionMessage('Please provide your ClickSend API credentials. Possible combinations: api_username + api_key OR account_username + account_password.'); app(Client::class); } diff --git a/tests/Unit/Channels/ClickSendSmsChannelTest.php b/tests/Unit/Channels/ClickSendSmsChannelTest.php index ace9c425..8ae4a07a 100644 --- a/tests/Unit/Channels/ClickSendSmsChannelTest.php +++ b/tests/Unit/Channels/ClickSendSmsChannelTest.php @@ -2,18 +2,17 @@ namespace NotificationChannels\ClickSend\Test\Unit\Channels; -use ClickSend\Api\SMSApi; +use ClickSend\Api\SMSApi as Client; +use ClickSend\Model\SmsMessage as SMS; +use ClickSend\Model\SmsMessageCollection; +use Hamcrest\Core\IsEqual; +use Illuminate\Notifications\Notifiable; +use Illuminate\Notifications\Notification; use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration; +use Mockery as m; use NotificationChannels\ClickSend\ClickSendChannel; use NotificationChannels\ClickSend\ClickSendMessage; -use Illuminate\Notifications\Notification; -use ClickSend\Model\SmsMessageCollection; -use Illuminate\Notifications\Notifiable; -use ClickSend\Model\SmsMessage as SMS; -use ClickSend\Api\SMSApi as Client; use PHPUnit\Framework\TestCase; -use Hamcrest\Core\IsEqual; -use Mockery as m; class ClickSendSmsChannelTest extends TestCase { @@ -33,8 +32,8 @@ public function testSmsIsSentViaClickSend() 'to' => '5555555555', 'from' =>'4444444444', 'body' => 'this is my message', - 'source' => 'laravel' - ]) + 'source' => 'laravel', + ]), ]); $clickSend->shouldReceive('smsSendPost') @@ -51,8 +50,8 @@ public function testSmsIsSentViaClickSendWithCustomClient() 'to' => '5555555555', 'from' =>'4444444444', 'body' => 'this is my message', - 'source' => 'laravel' - ]) + 'source' => 'laravel', + ]), ]); $customClickSend = m::mock(Client::class); @@ -86,8 +85,8 @@ public function testSmsIsSentViaClickSendWithCustomFrom() 'to' => '5555555555', 'from' =>'5554443333', 'body' => 'this is my message', - 'source' => 'laravel' - ]) + 'source' => 'laravel', + ]), ]); $clickSend->shouldReceive('smsSendPost') @@ -106,8 +105,8 @@ public function testSmsIsSentViaClickSendWithCustomFromAndClient() 'to' => '5555555555', 'from' =>'5554443333', 'body' => 'this is my message', - 'source' => 'laravel' - ]) + 'source' => 'laravel', + ]), ]); $customClickSend->shouldReceive('smsSendPost') @@ -141,8 +140,8 @@ public function testSmsIsSentViaClickSendWithCustomFromAndCustomString() 'from' =>'5554443333', 'body' => 'this is my message', 'source' => 'laravel', - 'custom_string' => '11' - ]) + 'custom_string' => '11', + ]), ]); $clickSend->shouldReceive('smsSendPost') @@ -162,8 +161,8 @@ public function testSmsIsSentViaClickSendWithCustomClientFromAndClientRef() 'from' =>'5554443333', 'body' => 'this is my message', 'source' => 'laravel', - 'custom_string' => '11' - ]) + 'custom_string' => '11', + ]), ]); $customClickSend->shouldReceive('smsSendPost')