From 77737dec173f88f6fd96341bf73cc1b40726ef0a Mon Sep 17 00:00:00 2001 From: Marcel Pociot Date: Thu, 11 Aug 2016 09:44:03 +0200 Subject: [PATCH 01/54] Initial commit --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..aa64d01 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# new-channels +Submit pull requests here for new notification channels From 3e13385e83c2408347d86b13a18ac599deb3cb2c Mon Sep 17 00:00:00 2001 From: Cody Scott Date: Tue, 16 Aug 2016 14:51:07 -0700 Subject: [PATCH 02/54] Add Discord channel --- .editorconfig | 15 ++ .gitattributes | 10 ++ .gitignore | 4 + .scrutinizer.yml | 21 +++ .styleci.yml | 3 + .travis.yml | 22 +++ CHANGELOG.md | 7 + CONTRIBUTING.md | 55 +++++++ LICENSE.md | 21 +++ README.md | 165 +++++++++++++++++++- composer.json | 47 ++++++ phpunit.xml.dist | 29 ++++ src/Commands/SetupCommand.php | 81 ++++++++++ src/Discord.php | 87 +++++++++++ src/DiscordChannel.php | 44 ++++++ src/DiscordMessage.php | 36 +++++ src/DiscordServiceProvider.php | 26 +++ src/Exceptions/CouldNotSendNotification.php | 43 +++++ tests/DiscordChannelTest.php | 90 +++++++++++ tests/DiscordMessageTest.php | 26 +++ 20 files changed, 830 insertions(+), 2 deletions(-) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .scrutinizer.yml create mode 100644 .styleci.yml create mode 100644 .travis.yml create mode 100755 CHANGELOG.md create mode 100755 CONTRIBUTING.md create mode 100644 LICENSE.md create mode 100644 composer.json create mode 100644 phpunit.xml.dist create mode 100644 src/Commands/SetupCommand.php create mode 100644 src/Discord.php create mode 100644 src/DiscordChannel.php create mode 100644 src/DiscordMessage.php create mode 100644 src/DiscordServiceProvider.php create mode 100644 src/Exceptions/CouldNotSendNotification.php create mode 100644 tests/DiscordChannelTest.php create mode 100644 tests/DiscordMessageTest.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..cd8eb86 --- /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/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b263871 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +# Path-based git attributes +# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html + +# Ignore all test and documentation with "export-ignore". +/.gitattributes export-ignore +/.gitignore export-ignore +/.travis.yml export-ignore +/phpunit.xml.dist export-ignore +/.scrutinizer.yml export-ignore +/tests export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f0a634 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/vendor +build +composer.phar +composer.lock diff --git a/.scrutinizer.yml b/.scrutinizer.yml new file mode 100644 index 0000000..6fad5be --- /dev/null +++ b/.scrutinizer.yml @@ -0,0 +1,21 @@ +filter: + excluded_paths: [tests/*] + +checks: + php: + remove_extra_empty_lines: true + remove_php_closing_tag: true + remove_trailing_whitespace: true + fix_use_statements: + remove_unused: true + preserve_multiple: false + preserve_blanklines: true + order_alphabetically: true + fix_php_opening_tag: true + fix_linefeed: true + fix_line_ending: true + fix_identation_4spaces: true + fix_doc_comments: true + +tools: + external_code_coverage: true diff --git a/.styleci.yml b/.styleci.yml new file mode 100644 index 0000000..916d27e --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,3 @@ +preset: laravel + +linting: true diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..ff42c2c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,22 @@ +language: php + +php: + - 5.6 + - 7.0 + - 7.1 + +env: + matrix: + - COMPOSER_FLAGS="--prefer-lowest" + - COMPOSER_FLAGS="" + +before_script: + - travis_retry composer self-update + - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-source + +script: + - phpunit --coverage-text --coverage-clover=coverage.clover + +after_script: + - wget https://scrutinizer-ci.com/ocular.phar + - php ocular.phar code-coverage:upload --format=php-clover coverage.clover diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100755 index 0000000..10483be --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All Notable changes to `discord` will be documented in this file + +## 1.0.0 - 201X-XX-XX + +- initial release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100755 index 0000000..4da74e3 --- /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 0000000..52f52a8 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) Cody Scott + +> 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 index aa64d01..a09f00d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,163 @@ -# new-channels -Submit pull requests here for new notification channels +# Discord notification channel for Laravel 5.3 [WIP] + +[![Latest Version on Packagist](https://img.shields.io/packagist/v/laravel-notification-channels/discord.svg?style=flat-square)](https://packagist.org/packages/laravel-notification-channels/discord) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) +[![Build Status](https://img.shields.io/travis/laravel-notification-channels/discord/master.svg?style=flat-square)](https://travis-ci.org/laravel-notification-channels/discord) +[![StyleCI](https://styleci.io/repos/:style_ci_id/shield)](https://styleci.io/repos/:style_ci_id) +[![SensioLabsInsight](https://img.shields.io/sensiolabs/i/:sensio_labs_id.svg?style=flat-square)](https://insight.sensiolabs.com/projects/:sensio_labs_id) +[![Quality Score](https://img.shields.io/scrutinizer/g/laravel-notification-channels/discord.svg?style=flat-square)](https://scrutinizer-ci.com/g/laravel-notification-channels/discord) +[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/laravel-notification-channels/discord/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/laravel-notification-channels/discord/?branch=master) +[![Total Downloads](https://img.shields.io/packagist/dt/laravel-notification-channels/discord.svg?style=flat-square)](https://packagist.org/packages/laravel-notification-channels/discord) + +This package makes it easy to send notifications using the [Discord bot API](https://discordapp.com/developers/docs/intro) with Laravel 5.3. + +## Contents + +- [Installation](#installation) + - [Setting up your Discord bot](#setting-up-your-discord-bot) +- [Usage](#usage) + - [Available Message methods](#available-message-methods) +- [Changelog](#changelog) +- [Testing](#testing) +- [Security](#security) +- [Contributing](#contributing) +- [Credits](#credits) +- [License](#license) + + +## Installation + +You can install the package via composer: + +`composer require laravel-notification-channels/discord` + +Next, you must load the service provider: + +```php +// config/app.php +'providers' => [ + // ... + NotificationChannels\Discord\DiscordServiceProvider::class, +] +``` + +### Setting up your Discord bot + +1. [Create a Discord application.](https://discordapp.com/developers/applications/me/create) +2. Click the `Create a Bot User` button on your Discord application. +3. Paste your bot's API token, found under `App Bot User`, in your `services.php` config file: + + ```php + // config/services.php + 'discord' => [ + 'token' => 'YOUR_API_TOKEN', + ], + ``` + +4. Add the bot to your server and identify it by running the artisan command: + + ```shell + php artisan discord:setup + ``` + +## Usage + +In every model you wish to be notifiable via Discord, you must add a channel ID property to that model accessible through a `routeNotificationForDiscord` method: + +```php +class Guild extends Eloquent +{ + use Notifiable; + + public function routeNotificationForPushover() + { + return $this->discord_channel; + } +} +``` + +> **NOTE**: Discord handles direct messages as though they are a regular channel. If you wish to allow users to receive direct messages from your bot, you will need to create a private channel with that user. +> An example workflow may look like the following: +> +> 1. Your `users` table has two discord columns: `discord_user` and `discord_channel` +> 2. When a user updates their Discord user ID (`discord_user`), generate and save a channel ID (`discord_channel`) +> 3. Return the user's `discord_channel` in the `routeNotificationForDiscord` method on the User model +> +> You can generate direct message channels by using the `getPrivateChannel` method in `NotificationChannels\Discord\Discord`: +> +> ```php +> use NotificationChannels\Discord\Discord; +> // ... +> +> class UserDiscordSettingsController +> { +> public function store(Request $request) +> { +> $user = $request->input('discord_user'); +> $channel = app(Discord::class)->getPrivateChannel($user); +> +> Auth::user()->update([ +> 'discord_user' => $user, +> 'discord_channel' => $channel, +> ]); +> } +> } +> ``` + +You may now tell Laravel to send notifications to Discord channels in the `via` method: + +```php +class GameChallengeNotification extends Notification +{ + public $channelger; + + public $game; + + public function __construct(Guild $challenger, Game $game) + { + $this->challenger = $challenger; + $this->game = $game; + } + public function via($notifiable) + { + return [DiscordChannel::class]; + } + + public function toDiscord($notifiable) + { + return (new DiscordMessage) + ->body("You have been challenged to a game of *{$this->game->name}* by **{$this->channelger->name}**!"); + } +} +``` + +### Available Message methods + +* `body(string)`: Set the content of the message. ([Supports basic markdown](https://support.discordapp.com/hc/en-us/articles/210298617-Markdown-Text-101-Chat-Formatting-Bold-Italic-Underline-)) + +## 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 cs475x@icloud.com instead of using the issue tracker. + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## Credits + +- [Cody Scott](https://github.com/cs475x) +- [All Contributors](../../contributors) + +## License + +The MIT License (MIT). Please see [LICENSE](LICENSE.md) for more information. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..fcbd487 --- /dev/null +++ b/composer.json @@ -0,0 +1,47 @@ +{ + "name": "laravel-notification-channels/discord", + "description": "Laravel notification driver for Discord.", + "keywords": [ + "laravel", + "notification", + "driver", + "channel", + "discord" + ], + "homepage": "https://github.com/laravel-notification-channels/discord", + "license": "MIT", + "authors": [ + { + "name": "Cody Scott", + "email": "cs475x@icloud.com", + "role": "Developer" + } + ], + "require": { + "php": ">=5.6.4", + "guzzlehttp/guzzle": "^6.2", + "illuminate/console": "^5.3@dev", + "illuminate/notifications": "^5.3@dev", + "illuminate/queue": "^5.3@dev", + "illuminate/support": "^5.3@dev", + "textalk/websocket": "1.0.*" + }, + "require-dev": { + "mockery/mockery": "^0.9.5", + "phpunit/phpunit": "4.*" + }, + "autoload": { + "psr-4": { + "NotificationChannels\\Discord\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "NotificationChannels\\Discord\\Test\\": "tests" + } + }, + "config": { + "sort-packages": true + }, + "minimum-stability": "dev" +} diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..974d92a --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + tests + + + + + src/ + + + + + + + + + + diff --git a/src/Commands/SetupCommand.php b/src/Commands/SetupCommand.php new file mode 100644 index 0000000..9019def --- /dev/null +++ b/src/Commands/SetupCommand.php @@ -0,0 +1,81 @@ +error('You must paste your Discord token (App Bot User token) into your `services.php` config file.'); + $this->error('View the README for more info: https://github.com/laravel-notification-channels/discord#installation'); + + return -1; + } + + if (! $this->confirm('Is the bot already added to your server?')) { + $clientId = $this->ask('What is your Discord app client ID?'); + + $this->warn('Add the bot to your server by visiting this link: https://discordapp.com/oauth2/authorize?&client_id='.$clientId.'&scope=bot&permissions=0'); + } + + $this->warn("Attempting to identify the bot with Discord's WebScoket gateway..."); + + $gateway = 'wss://gateway.discord.gg'; + + try { + $response = (new HttpClient)->get('https://discordapp.com/api/gateway', [ + 'headers' => [ + 'Authorization' => 'Bot '.$token, + ], + ]); + + $gateway = Arr::get(json_decode($response->getBody(), true), 'url', $gateway); + } catch (\Excetion $e) { + $this->warn("Could not get a WebSocket gateway address, defaulting to '$gateway'."); + } + + $this->warn("Connecting to '$gateway'..."); + + $client = new Client($gateway); + + // Discord requires all bots to connect via a WebSocket connection and + // identify at least once before any HTTP API requests are allowed. + // https://discordapp.com/developers/docs/topics/gateway#gateway-identify + $client->send(json_encode([ + 'op' => 2, + 'd' => [ + 'token' => $token, + 'v' => 3, + 'compress' => false, + 'properties' => [ + '$os' => PHP_OS, + '$browser' => 'laravel-notification-channels-discord', + '$device' => 'laravel-notification-channels-discord', + '$referrer' => '', + '$referring_domain' => '' + ] + ] + ])); + + $response = $client->receive(); + $identified = Arr::get(json_decode($response, true), 't') === 'READY'; + + if (! $identified) { + $this->error("Discord responded with an error while trying to identify the bot: $response"); + + return -1; + } + + $this->info('Your bot has been identified by Discord and can now send API requests!'); + } +} diff --git a/src/Discord.php b/src/Discord.php new file mode 100644 index 0000000..d409284 --- /dev/null +++ b/src/Discord.php @@ -0,0 +1,87 @@ +http = $http; + $this->token = $token; + } + + /** + * @param string $channel + * @param array $data + * @return \Psr\Http\Message\ResponseInterface + */ + public function send($channel, array $data) + { + return $this->request('POST', 'channels/'.$channel.'/messages', $data); + } + + /** + * @param mixed $user + * @return string + */ + public function getPrivateChannel($user) + { + return $this->request('POST', 'users/@me/channels', ['recipient_id' => $user])['id']; + } + + /** + * @param string $endpoint + * @param array $data + * @return array + * @throws \NotificationChannels\Discord\Exceptions\CouldNotSendNotification + */ + protected function request($verb, $endpoint, array $data) + { + $url = rtrim($this->baseUrl, '/').'/'.ltrim($endpoint, '/'); + + try { + $response = $this->http->request($verb, $url, [ + 'headers' => [ + 'Authorization' => 'Bot '.$this->token, + ], + 'json' => $data, + ]); + } catch (RequestException $e) { + throw CouldNotSendNotification::serviceRespondedWithAnHttpError($e->getResponse()); + } catch (\Exception $e) { + throw CouldNotSendNotification::serviceCommunicationError($e); + } + + $body = json_decode($response->getBody(), true); + + if (Arr::get($body, 'code', 0) > 0) { + throw CouldNotSendNotification::serviceRespondedWithAnApiError($body); + } + + return $body; + } +} diff --git a/src/DiscordChannel.php b/src/DiscordChannel.php new file mode 100644 index 0000000..548156f --- /dev/null +++ b/src/DiscordChannel.php @@ -0,0 +1,44 @@ +discord = $discord; + } + + /** + * Send the given notification. + * + * @param mixed $notifiable + * @param \Illuminate\Notifications\Notification $notification + * @throws \NotificationChannels\Discord\Exceptions\CouldNotSendNotification + */ + public function send($notifiable, Notification $notification) + { + if (! $channel = $notifiable->routeNotificationFor('discord')) { + return; + } + + $message = $notification->toDiscord($notifiable); + + $this->discord->send($channel, [ + 'content' => $message->body, + ]); + } +} diff --git a/src/DiscordMessage.php b/src/DiscordMessage.php new file mode 100644 index 0000000..387eca2 --- /dev/null +++ b/src/DiscordMessage.php @@ -0,0 +1,36 @@ +body = $body; + } + + /** + * Set the text content of the message. + * + * @param string $body + * @return $this + */ + public function body($body) + { + $this->body = $body; + + return $this; + } +} diff --git a/src/DiscordServiceProvider.php b/src/DiscordServiceProvider.php new file mode 100644 index 0000000..ed2706c --- /dev/null +++ b/src/DiscordServiceProvider.php @@ -0,0 +1,26 @@ +app->bind('command.discord:setup', SetupCommand::class); + + $this->commands([ + 'command.discord:setup', + ]); + } + + public function boot() + { + $this->app->when(Discord::class) + ->needs('$token') + ->give($this->app['config']->get('services.discord.token')); + } +} diff --git a/src/Exceptions/CouldNotSendNotification.php b/src/Exceptions/CouldNotSendNotification.php new file mode 100644 index 0000000..2e95ac8 --- /dev/null +++ b/src/Exceptions/CouldNotSendNotification.php @@ -0,0 +1,43 @@ +getStatusCode()}"; + + if ($error = Arr::get(json_decode($response->getBody(), true), 'message')) { + $message .= ": $error"; + } + + return new static($message); + } + + /** + * @param array $response + * @return static + */ + public static function serviceRespondedWithAnApiError($response) + { + return new static("Discord responded with an API error: {$response['code']}: {$response['message']}"); + } + + /** + * @param \Exception $e + * @return static + */ + public static function serviceCommunicationError(Exception $e) + { + return new static("Communication with Discord failed: {$e->getCode()}: {$e->getMessage()}"); + } +} diff --git a/tests/DiscordChannelTest.php b/tests/DiscordChannelTest.php new file mode 100644 index 0000000..7235cf4 --- /dev/null +++ b/tests/DiscordChannelTest.php @@ -0,0 +1,90 @@ +shouldReceive('request') + ->once() + ->with('POST', 'https://discordapp.com/api/channels/0123456789/messages', [ + 'headers' => [ + 'Authorization' => 'Bot super-secret', + ], + 'json' => ['content' => 'Hello, Discord!'], + ]) + ->andReturn(new Response(200)); + + $discord = new Discord($http, 'super-secret'); + $channel = new DiscordChannel($discord); + + $channel->send(new TestNotifiable, new TestNotification); + } + + /** @test */ + public function it_throws_an_exception_when_it_could_not_send_the_notification() + { + $this->setExpectedException(CouldNotSendNotification::class); + + $http = Mockery::mock(HttpClient::class); + $http->shouldReceive('request') + ->once() + ->andThrow(\Exception::class); + + $discord = new Discord($http, 'super-secret'); + $channel = new DiscordChannel($discord); + + $channel->send(new TestNotifiable, new TestNotification); + } + + /** @test */ + public function it_throws_an_exception_when_an_api_error_is_returned() + { + $this->setExpectedException(CouldNotSendNotification::class); + + $response = Mockery::mock(Response::class); + $response->shouldReceive('getBody') + ->once() + ->andReturn('{"code": 10003, "message": "Unknown Channel"}'); + + $http = Mockery::mock(HttpClient::class); + $http->shouldReceive('post') + ->once() + ->andReturn($response); + + $discord = new Discord($http, 'super-secret'); + $channel = new DiscordChannel($discord); + + $channel->send(new TestNotifiable, new TestNotification); + } +} + +class TestNotifiable +{ + use \Illuminate\Notifications\Notifiable; + + public function routeNotificationForDiscord() + { + return '0123456789'; + } +} + +class TestNotification extends \Illuminate\Notifications\Notification +{ + public function toDiscord() + { + return (new DiscordMessage) + ->body('Hello, Discord!'); + } +} diff --git a/tests/DiscordMessageTest.php b/tests/DiscordMessageTest.php new file mode 100644 index 0000000..d239e58 --- /dev/null +++ b/tests/DiscordMessageTest.php @@ -0,0 +1,26 @@ +assertEquals('a message', $message->body); + } + + /** @test */ + public function it_can_set_the_body() + { + $message = new DiscordMessage; + + $message->body('a message'); + + $this->assertEquals('a message', $message->body); + } +} From f77b0137d825cccb09383c1c3e679e036b9879c6 Mon Sep 17 00:00:00 2001 From: Freek Van der Herten Date: Tue, 16 Aug 2016 23:52:35 +0200 Subject: [PATCH 03/54] Revert "Add Discord channel" (#14) --- .editorconfig | 15 -- .gitattributes | 10 -- .gitignore | 4 - .scrutinizer.yml | 21 --- .styleci.yml | 3 - .travis.yml | 22 --- CHANGELOG.md | 7 - CONTRIBUTING.md | 55 ------- LICENSE.md | 21 --- README.md | 165 +------------------- composer.json | 47 ------ phpunit.xml.dist | 29 ---- src/Commands/SetupCommand.php | 81 ---------- src/Discord.php | 87 ----------- src/DiscordChannel.php | 44 ------ src/DiscordMessage.php | 36 ----- src/DiscordServiceProvider.php | 26 --- src/Exceptions/CouldNotSendNotification.php | 43 ----- tests/DiscordChannelTest.php | 90 ----------- tests/DiscordMessageTest.php | 26 --- 20 files changed, 2 insertions(+), 830 deletions(-) delete mode 100644 .editorconfig delete mode 100644 .gitattributes delete mode 100644 .gitignore delete mode 100644 .scrutinizer.yml delete mode 100644 .styleci.yml delete mode 100644 .travis.yml delete mode 100755 CHANGELOG.md delete mode 100755 CONTRIBUTING.md delete mode 100644 LICENSE.md delete mode 100644 composer.json delete mode 100644 phpunit.xml.dist delete mode 100644 src/Commands/SetupCommand.php delete mode 100644 src/Discord.php delete mode 100644 src/DiscordChannel.php delete mode 100644 src/DiscordMessage.php delete mode 100644 src/DiscordServiceProvider.php delete mode 100644 src/Exceptions/CouldNotSendNotification.php delete mode 100644 tests/DiscordChannelTest.php delete mode 100644 tests/DiscordMessageTest.php diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index cd8eb86..0000000 --- a/.editorconfig +++ /dev/null @@ -1,15 +0,0 @@ -; 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/.gitattributes b/.gitattributes deleted file mode 100644 index b263871..0000000 --- a/.gitattributes +++ /dev/null @@ -1,10 +0,0 @@ -# Path-based git attributes -# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html - -# Ignore all test and documentation with "export-ignore". -/.gitattributes export-ignore -/.gitignore export-ignore -/.travis.yml export-ignore -/phpunit.xml.dist export-ignore -/.scrutinizer.yml export-ignore -/tests export-ignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 3f0a634..0000000 --- a/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/vendor -build -composer.phar -composer.lock diff --git a/.scrutinizer.yml b/.scrutinizer.yml deleted file mode 100644 index 6fad5be..0000000 --- a/.scrutinizer.yml +++ /dev/null @@ -1,21 +0,0 @@ -filter: - excluded_paths: [tests/*] - -checks: - php: - remove_extra_empty_lines: true - remove_php_closing_tag: true - remove_trailing_whitespace: true - fix_use_statements: - remove_unused: true - preserve_multiple: false - preserve_blanklines: true - order_alphabetically: true - fix_php_opening_tag: true - fix_linefeed: true - fix_line_ending: true - fix_identation_4spaces: true - fix_doc_comments: true - -tools: - external_code_coverage: true diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index 916d27e..0000000 --- a/.styleci.yml +++ /dev/null @@ -1,3 +0,0 @@ -preset: laravel - -linting: true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ff42c2c..0000000 --- a/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: php - -php: - - 5.6 - - 7.0 - - 7.1 - -env: - matrix: - - COMPOSER_FLAGS="--prefer-lowest" - - COMPOSER_FLAGS="" - -before_script: - - travis_retry composer self-update - - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-source - -script: - - phpunit --coverage-text --coverage-clover=coverage.clover - -after_script: - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover coverage.clover diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100755 index 10483be..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -# Changelog - -All Notable changes to `discord` will be documented in this file - -## 1.0.0 - 201X-XX-XX - -- initial release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100755 index 4da74e3..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,55 +0,0 @@ -# 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 deleted file mode 100644 index 52f52a8..0000000 --- a/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -# The MIT License (MIT) - -Copyright (c) Cody Scott - -> 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 index a09f00d..aa64d01 100644 --- a/README.md +++ b/README.md @@ -1,163 +1,2 @@ -# Discord notification channel for Laravel 5.3 [WIP] - -[![Latest Version on Packagist](https://img.shields.io/packagist/v/laravel-notification-channels/discord.svg?style=flat-square)](https://packagist.org/packages/laravel-notification-channels/discord) -[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) -[![Build Status](https://img.shields.io/travis/laravel-notification-channels/discord/master.svg?style=flat-square)](https://travis-ci.org/laravel-notification-channels/discord) -[![StyleCI](https://styleci.io/repos/:style_ci_id/shield)](https://styleci.io/repos/:style_ci_id) -[![SensioLabsInsight](https://img.shields.io/sensiolabs/i/:sensio_labs_id.svg?style=flat-square)](https://insight.sensiolabs.com/projects/:sensio_labs_id) -[![Quality Score](https://img.shields.io/scrutinizer/g/laravel-notification-channels/discord.svg?style=flat-square)](https://scrutinizer-ci.com/g/laravel-notification-channels/discord) -[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/laravel-notification-channels/discord/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/laravel-notification-channels/discord/?branch=master) -[![Total Downloads](https://img.shields.io/packagist/dt/laravel-notification-channels/discord.svg?style=flat-square)](https://packagist.org/packages/laravel-notification-channels/discord) - -This package makes it easy to send notifications using the [Discord bot API](https://discordapp.com/developers/docs/intro) with Laravel 5.3. - -## Contents - -- [Installation](#installation) - - [Setting up your Discord bot](#setting-up-your-discord-bot) -- [Usage](#usage) - - [Available Message methods](#available-message-methods) -- [Changelog](#changelog) -- [Testing](#testing) -- [Security](#security) -- [Contributing](#contributing) -- [Credits](#credits) -- [License](#license) - - -## Installation - -You can install the package via composer: - -`composer require laravel-notification-channels/discord` - -Next, you must load the service provider: - -```php -// config/app.php -'providers' => [ - // ... - NotificationChannels\Discord\DiscordServiceProvider::class, -] -``` - -### Setting up your Discord bot - -1. [Create a Discord application.](https://discordapp.com/developers/applications/me/create) -2. Click the `Create a Bot User` button on your Discord application. -3. Paste your bot's API token, found under `App Bot User`, in your `services.php` config file: - - ```php - // config/services.php - 'discord' => [ - 'token' => 'YOUR_API_TOKEN', - ], - ``` - -4. Add the bot to your server and identify it by running the artisan command: - - ```shell - php artisan discord:setup - ``` - -## Usage - -In every model you wish to be notifiable via Discord, you must add a channel ID property to that model accessible through a `routeNotificationForDiscord` method: - -```php -class Guild extends Eloquent -{ - use Notifiable; - - public function routeNotificationForPushover() - { - return $this->discord_channel; - } -} -``` - -> **NOTE**: Discord handles direct messages as though they are a regular channel. If you wish to allow users to receive direct messages from your bot, you will need to create a private channel with that user. -> An example workflow may look like the following: -> -> 1. Your `users` table has two discord columns: `discord_user` and `discord_channel` -> 2. When a user updates their Discord user ID (`discord_user`), generate and save a channel ID (`discord_channel`) -> 3. Return the user's `discord_channel` in the `routeNotificationForDiscord` method on the User model -> -> You can generate direct message channels by using the `getPrivateChannel` method in `NotificationChannels\Discord\Discord`: -> -> ```php -> use NotificationChannels\Discord\Discord; -> // ... -> -> class UserDiscordSettingsController -> { -> public function store(Request $request) -> { -> $user = $request->input('discord_user'); -> $channel = app(Discord::class)->getPrivateChannel($user); -> -> Auth::user()->update([ -> 'discord_user' => $user, -> 'discord_channel' => $channel, -> ]); -> } -> } -> ``` - -You may now tell Laravel to send notifications to Discord channels in the `via` method: - -```php -class GameChallengeNotification extends Notification -{ - public $channelger; - - public $game; - - public function __construct(Guild $challenger, Game $game) - { - $this->challenger = $challenger; - $this->game = $game; - } - public function via($notifiable) - { - return [DiscordChannel::class]; - } - - public function toDiscord($notifiable) - { - return (new DiscordMessage) - ->body("You have been challenged to a game of *{$this->game->name}* by **{$this->channelger->name}**!"); - } -} -``` - -### Available Message methods - -* `body(string)`: Set the content of the message. ([Supports basic markdown](https://support.discordapp.com/hc/en-us/articles/210298617-Markdown-Text-101-Chat-Formatting-Bold-Italic-Underline-)) - -## 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 cs475x@icloud.com instead of using the issue tracker. - -## Contributing - -Please see [CONTRIBUTING](CONTRIBUTING.md) for details. - -## Credits - -- [Cody Scott](https://github.com/cs475x) -- [All Contributors](../../contributors) - -## License - -The MIT License (MIT). Please see [LICENSE](LICENSE.md) for more information. +# new-channels +Submit pull requests here for new notification channels diff --git a/composer.json b/composer.json deleted file mode 100644 index fcbd487..0000000 --- a/composer.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "laravel-notification-channels/discord", - "description": "Laravel notification driver for Discord.", - "keywords": [ - "laravel", - "notification", - "driver", - "channel", - "discord" - ], - "homepage": "https://github.com/laravel-notification-channels/discord", - "license": "MIT", - "authors": [ - { - "name": "Cody Scott", - "email": "cs475x@icloud.com", - "role": "Developer" - } - ], - "require": { - "php": ">=5.6.4", - "guzzlehttp/guzzle": "^6.2", - "illuminate/console": "^5.3@dev", - "illuminate/notifications": "^5.3@dev", - "illuminate/queue": "^5.3@dev", - "illuminate/support": "^5.3@dev", - "textalk/websocket": "1.0.*" - }, - "require-dev": { - "mockery/mockery": "^0.9.5", - "phpunit/phpunit": "4.*" - }, - "autoload": { - "psr-4": { - "NotificationChannels\\Discord\\": "src" - } - }, - "autoload-dev": { - "psr-4": { - "NotificationChannels\\Discord\\Test\\": "tests" - } - }, - "config": { - "sort-packages": true - }, - "minimum-stability": "dev" -} diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index 974d92a..0000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,29 +0,0 @@ - - - - - tests - - - - - src/ - - - - - - - - - - diff --git a/src/Commands/SetupCommand.php b/src/Commands/SetupCommand.php deleted file mode 100644 index 9019def..0000000 --- a/src/Commands/SetupCommand.php +++ /dev/null @@ -1,81 +0,0 @@ -error('You must paste your Discord token (App Bot User token) into your `services.php` config file.'); - $this->error('View the README for more info: https://github.com/laravel-notification-channels/discord#installation'); - - return -1; - } - - if (! $this->confirm('Is the bot already added to your server?')) { - $clientId = $this->ask('What is your Discord app client ID?'); - - $this->warn('Add the bot to your server by visiting this link: https://discordapp.com/oauth2/authorize?&client_id='.$clientId.'&scope=bot&permissions=0'); - } - - $this->warn("Attempting to identify the bot with Discord's WebScoket gateway..."); - - $gateway = 'wss://gateway.discord.gg'; - - try { - $response = (new HttpClient)->get('https://discordapp.com/api/gateway', [ - 'headers' => [ - 'Authorization' => 'Bot '.$token, - ], - ]); - - $gateway = Arr::get(json_decode($response->getBody(), true), 'url', $gateway); - } catch (\Excetion $e) { - $this->warn("Could not get a WebSocket gateway address, defaulting to '$gateway'."); - } - - $this->warn("Connecting to '$gateway'..."); - - $client = new Client($gateway); - - // Discord requires all bots to connect via a WebSocket connection and - // identify at least once before any HTTP API requests are allowed. - // https://discordapp.com/developers/docs/topics/gateway#gateway-identify - $client->send(json_encode([ - 'op' => 2, - 'd' => [ - 'token' => $token, - 'v' => 3, - 'compress' => false, - 'properties' => [ - '$os' => PHP_OS, - '$browser' => 'laravel-notification-channels-discord', - '$device' => 'laravel-notification-channels-discord', - '$referrer' => '', - '$referring_domain' => '' - ] - ] - ])); - - $response = $client->receive(); - $identified = Arr::get(json_decode($response, true), 't') === 'READY'; - - if (! $identified) { - $this->error("Discord responded with an error while trying to identify the bot: $response"); - - return -1; - } - - $this->info('Your bot has been identified by Discord and can now send API requests!'); - } -} diff --git a/src/Discord.php b/src/Discord.php deleted file mode 100644 index d409284..0000000 --- a/src/Discord.php +++ /dev/null @@ -1,87 +0,0 @@ -http = $http; - $this->token = $token; - } - - /** - * @param string $channel - * @param array $data - * @return \Psr\Http\Message\ResponseInterface - */ - public function send($channel, array $data) - { - return $this->request('POST', 'channels/'.$channel.'/messages', $data); - } - - /** - * @param mixed $user - * @return string - */ - public function getPrivateChannel($user) - { - return $this->request('POST', 'users/@me/channels', ['recipient_id' => $user])['id']; - } - - /** - * @param string $endpoint - * @param array $data - * @return array - * @throws \NotificationChannels\Discord\Exceptions\CouldNotSendNotification - */ - protected function request($verb, $endpoint, array $data) - { - $url = rtrim($this->baseUrl, '/').'/'.ltrim($endpoint, '/'); - - try { - $response = $this->http->request($verb, $url, [ - 'headers' => [ - 'Authorization' => 'Bot '.$this->token, - ], - 'json' => $data, - ]); - } catch (RequestException $e) { - throw CouldNotSendNotification::serviceRespondedWithAnHttpError($e->getResponse()); - } catch (\Exception $e) { - throw CouldNotSendNotification::serviceCommunicationError($e); - } - - $body = json_decode($response->getBody(), true); - - if (Arr::get($body, 'code', 0) > 0) { - throw CouldNotSendNotification::serviceRespondedWithAnApiError($body); - } - - return $body; - } -} diff --git a/src/DiscordChannel.php b/src/DiscordChannel.php deleted file mode 100644 index 548156f..0000000 --- a/src/DiscordChannel.php +++ /dev/null @@ -1,44 +0,0 @@ -discord = $discord; - } - - /** - * Send the given notification. - * - * @param mixed $notifiable - * @param \Illuminate\Notifications\Notification $notification - * @throws \NotificationChannels\Discord\Exceptions\CouldNotSendNotification - */ - public function send($notifiable, Notification $notification) - { - if (! $channel = $notifiable->routeNotificationFor('discord')) { - return; - } - - $message = $notification->toDiscord($notifiable); - - $this->discord->send($channel, [ - 'content' => $message->body, - ]); - } -} diff --git a/src/DiscordMessage.php b/src/DiscordMessage.php deleted file mode 100644 index 387eca2..0000000 --- a/src/DiscordMessage.php +++ /dev/null @@ -1,36 +0,0 @@ -body = $body; - } - - /** - * Set the text content of the message. - * - * @param string $body - * @return $this - */ - public function body($body) - { - $this->body = $body; - - return $this; - } -} diff --git a/src/DiscordServiceProvider.php b/src/DiscordServiceProvider.php deleted file mode 100644 index ed2706c..0000000 --- a/src/DiscordServiceProvider.php +++ /dev/null @@ -1,26 +0,0 @@ -app->bind('command.discord:setup', SetupCommand::class); - - $this->commands([ - 'command.discord:setup', - ]); - } - - public function boot() - { - $this->app->when(Discord::class) - ->needs('$token') - ->give($this->app['config']->get('services.discord.token')); - } -} diff --git a/src/Exceptions/CouldNotSendNotification.php b/src/Exceptions/CouldNotSendNotification.php deleted file mode 100644 index 2e95ac8..0000000 --- a/src/Exceptions/CouldNotSendNotification.php +++ /dev/null @@ -1,43 +0,0 @@ -getStatusCode()}"; - - if ($error = Arr::get(json_decode($response->getBody(), true), 'message')) { - $message .= ": $error"; - } - - return new static($message); - } - - /** - * @param array $response - * @return static - */ - public static function serviceRespondedWithAnApiError($response) - { - return new static("Discord responded with an API error: {$response['code']}: {$response['message']}"); - } - - /** - * @param \Exception $e - * @return static - */ - public static function serviceCommunicationError(Exception $e) - { - return new static("Communication with Discord failed: {$e->getCode()}: {$e->getMessage()}"); - } -} diff --git a/tests/DiscordChannelTest.php b/tests/DiscordChannelTest.php deleted file mode 100644 index 7235cf4..0000000 --- a/tests/DiscordChannelTest.php +++ /dev/null @@ -1,90 +0,0 @@ -shouldReceive('request') - ->once() - ->with('POST', 'https://discordapp.com/api/channels/0123456789/messages', [ - 'headers' => [ - 'Authorization' => 'Bot super-secret', - ], - 'json' => ['content' => 'Hello, Discord!'], - ]) - ->andReturn(new Response(200)); - - $discord = new Discord($http, 'super-secret'); - $channel = new DiscordChannel($discord); - - $channel->send(new TestNotifiable, new TestNotification); - } - - /** @test */ - public function it_throws_an_exception_when_it_could_not_send_the_notification() - { - $this->setExpectedException(CouldNotSendNotification::class); - - $http = Mockery::mock(HttpClient::class); - $http->shouldReceive('request') - ->once() - ->andThrow(\Exception::class); - - $discord = new Discord($http, 'super-secret'); - $channel = new DiscordChannel($discord); - - $channel->send(new TestNotifiable, new TestNotification); - } - - /** @test */ - public function it_throws_an_exception_when_an_api_error_is_returned() - { - $this->setExpectedException(CouldNotSendNotification::class); - - $response = Mockery::mock(Response::class); - $response->shouldReceive('getBody') - ->once() - ->andReturn('{"code": 10003, "message": "Unknown Channel"}'); - - $http = Mockery::mock(HttpClient::class); - $http->shouldReceive('post') - ->once() - ->andReturn($response); - - $discord = new Discord($http, 'super-secret'); - $channel = new DiscordChannel($discord); - - $channel->send(new TestNotifiable, new TestNotification); - } -} - -class TestNotifiable -{ - use \Illuminate\Notifications\Notifiable; - - public function routeNotificationForDiscord() - { - return '0123456789'; - } -} - -class TestNotification extends \Illuminate\Notifications\Notification -{ - public function toDiscord() - { - return (new DiscordMessage) - ->body('Hello, Discord!'); - } -} diff --git a/tests/DiscordMessageTest.php b/tests/DiscordMessageTest.php deleted file mode 100644 index d239e58..0000000 --- a/tests/DiscordMessageTest.php +++ /dev/null @@ -1,26 +0,0 @@ -assertEquals('a message', $message->body); - } - - /** @test */ - public function it_can_set_the_body() - { - $message = new DiscordMessage; - - $message->body('a message'); - - $this->assertEquals('a message', $message->body); - } -} From 7c85b2161b16983fe66cdd8e8bb6f7a6da099e5a Mon Sep 17 00:00:00 2001 From: Marcel Pociot Date: Thu, 18 Aug 2016 16:03:19 +0200 Subject: [PATCH 04/54] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aa64d01..746a917 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # new-channels -Submit pull requests here for new notification channels + +Discuss about new channel proposals our share your finished channels in the [proposal issue](https://github.com/laravel-notification-channels/new-channels/issues/6). + +Take a look at our [FAQ](http://laravel-notification-channels.com/) to see our small list of rules, to provide top-notch notification channels. From 16f56847850bca740096bb56d02c1b5d8d1aa798 Mon Sep 17 00:00:00 2001 From: Manash Jyoti Sonowal Date: Mon, 7 Aug 2017 15:14:54 +0530 Subject: [PATCH 05/54] Add Textlocal Channel Which provides the ability to send SMS via textlocal.in API --- CHANGELOG.md | 7 + CONTRIBUTING.md | 55 ++ LICENSE.md | 21 + README.md | 94 ++- composer.json | 39 + phpunit.xml.dist | 29 + src/Exceptions/CouldNotSendNotification.php | 11 + src/Textlocal.php | 825 ++++++++++++++++++++ src/TextlocalChannel.php | 58 ++ src/TextlocalServiceProvider.php | 36 + tests/ExampleTest.php | 12 + 11 files changed, 1184 insertions(+), 3 deletions(-) create mode 100755 CHANGELOG.md create mode 100755 CONTRIBUTING.md create mode 100644 LICENSE.md create mode 100644 composer.json create mode 100644 phpunit.xml.dist create mode 100644 src/Exceptions/CouldNotSendNotification.php create mode 100644 src/Textlocal.php create mode 100644 src/TextlocalChannel.php create mode 100644 src/TextlocalServiceProvider.php create mode 100644 tests/ExampleTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100755 index 0000000..ce1e1d2 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All notable changes to `Textlocal` will be documented in this file + +## 0.0.1 - 2017-08-07 + +- initial release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100755 index 0000000..4da74e3 --- /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 0000000..e65b3a7 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) Manash Jyoti Sonowal + +> 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 index 746a917..1ba7e1c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,93 @@ -# new-channels +This package allows to send SMS using Textlocal API using laravel notifications -Discuss about new channel proposals our share your finished channels in the [proposal issue](https://github.com/laravel-notification-channels/new-channels/issues/6). +Here's the latest documentation on Laravel 5.4 Notifications System: -Take a look at our [FAQ](http://laravel-notification-channels.com/) to see our small list of rules, to provide top-notch notification channels. +https://laravel.com/docs/5.4/notifications + +# Found any bugs or improvement open an issue or send me a PR + +[![Latest Version on Packagist](https://img.shields.io/packagist/v/laravel-notification-channels/textlocal.svg?style=flat-square)](https://packagist.org/packages/laravel-notification-channels/textlocal) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) +[![Build Status](https://img.shields.io/travis/laravel-notification-channels/textlocal/master.svg?style=flat-square)](https://travis-ci.org/laravel-notification-channels/textlocal) +[![StyleCI](https://styleci.io/repos/:style_ci_id/shield)](https://styleci.io/repos/:style_ci_id) +[![SensioLabsInsight](https://img.shields.io/sensiolabs/i/:sensio_labs_id.svg?style=flat-square)](https://insight.sensiolabs.com/projects/:sensio_labs_id) +[![Quality Score](https://img.shields.io/scrutinizer/g/laravel-notification-channels/textlocal.svg?style=flat-square)](https://scrutinizer-ci.com/g/laravel-notification-channels/textlocal) +[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/laravel-notification-channels/textlocal/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/laravel-notification-channels/textlocal/?branch=master) +[![Total Downloads](https://img.shields.io/packagist/dt/laravel-notification-channels/textlocal.svg?style=flat-square)](https://packagist.org/packages/laravel-notification-channels/textlocal) + +This package makes it easy to send notifications using [textlocal](https://www.textlocal.in/) with Laravel 5.3.+ + + + +## Contents + +- [Installation](#installation) + - [Setting up the textlocal service](#setting-up-the-textlocal-service) +- [Usage](#usage) + - [Available Message methods](#available-message-methods) +- [Changelog](#changelog) +- [Testing](#testing) +- [Security](#security) +- [Contributing](#contributing) +- [Credits](#credits) +- [License](#license) + + +## Installation + +Create an account in textlocal then create an API key or hash(password). + +`composer require laravel-notification-channels/textlocal` + +### Setting up the textlocal service + +put the followings and to your config/services +``` +'sms' => [ + 'textlocal' => [ + 'username' => env('TEXTLOCAL_USERNAME'), + 'hash' => env('TEXTLOCAL_HASH'), + 'sender' => env('TEXTLOCAL_SENDER'), +] +``` + + +## Usage +textlocal +implement this method `routeNotificationForSms()` in your notifiable class/model which will return array of mobile numbers +and lastly implement `toSms()` method in the notification class which will return the (string) sms or template that is defined in textlocal account that needs to be send. + +### Available Message methods + +A list of all available options + +## 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 manash149@gmail.com instead of using the issue tracker. + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## Credits + +- [Manash Jyoti Sonowal](https://github.com/msonowal) +- [All Contributors](../../contributors) + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. + +## TODO +Need to convert to Guzzle Http as a Client in core +add tests diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..55d8703 --- /dev/null +++ b/composer.json @@ -0,0 +1,39 @@ +{ + "name": "laravel-notification-channels/textlocal", + "description": "This package helps to send SMS via Textlocal API in laravel way", + "homepage": "https://github.com/laravel-notification-channels/textlocal", + "license": "MIT", + "authors": [ + { + "name": "Manash Jyoti Sonowal", + "email": "manash149@gmail.com", + "homepage": "https://github.com/msonowal", + "role": "Developer" + } + ], + "require": { + "php": ">=5.6.4", + "illuminate/notifications": "^5.3|^5.4", + "illuminate/support": "^5.1|^5.2|^5.3|^5.4" + }, + "require-dev": { + "mockery/mockery": "^0.9.5", + "phpunit/phpunit": "4.*" + }, + "autoload": { + "psr-4": { + "NotificationChannels\\Textlocal\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "NotificationChannels\\Textlocal\\Test\\": "tests" + } + }, + "scripts": { + "test": "vendor/bin/phpunit" + }, + "config": { + "sort-packages": true + } +} diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..f9e8249 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + tests + + + + + src/ + + + + + + + + + + diff --git a/src/Exceptions/CouldNotSendNotification.php b/src/Exceptions/CouldNotSendNotification.php new file mode 100644 index 0000000..f9dc566 --- /dev/null +++ b/src/Exceptions/CouldNotSendNotification.php @@ -0,0 +1,11 @@ + + * @version 1.4-IN + * @const REQUEST_URL URL to make the request to + * @const REQUEST_TIMEOUT Timeout in seconds for the HTTP request + * @const REQUEST_HANDLER Handler to use when making the HTTP request (for future use) + */ +class Textlocal +{ + const REQUEST_URL = 'https://api.textlocal.in/'; + const REQUEST_TIMEOUT = 60; + const REQUEST_HANDLER = 'curl'; + + private $username; + private $hash; + private $apiKey; + + private $errorReporting = false; + + public $errors = array(); + public $warnings = array(); + + public $lastRequest = array(); + + /** + * Instantiate the object + * + * @param $username + * @param $hash + */ + function __construct($username, $hash, $apiKey = false) + { + $this->username = $username; + $this->hash = $hash; + if ($apiKey) { + $this->apiKey = $apiKey; + } + + } + + /** + * Private function to construct and send the request and handle the response + * + * @param $command + * @param array $params + * @return array|mixed + * @throws Exception + * @todo Add additional request handlers - eg fopen, file_get_contacts + */ + private function _sendRequest($command, $params = array()) + { + if ($this->apiKey && !empty($this->apiKey)) { + $params['apiKey'] = $this->apiKey; + + } else { + $params['hash'] = $this->hash; + } + // Create request string + $params['username'] = $this->username; + + $this->lastRequest = $params; + + if (self::REQUEST_HANDLER == 'curl') { + $rawResponse = $this->_sendRequestCurl($command, $params); + } else { throw new Exception('Invalid request handler.'); + } + + $result = json_decode($rawResponse); + if (isset($result->errors)) { + if (count($result->errors) > 0) { + foreach ($result->errors as $error) { + switch ($error->code) { + default: + throw new Exception($error->message); + } + } + } + } + + return $result; + } + + /** + * Curl request handler + * + * @param $command + * @param $params + * @return mixed + * @throws Exception + */ + private function _sendRequestCurl($command, $params) + { + + $url = self::REQUEST_URL . $command . '/'; + + // Initialize handle + $ch = curl_init($url); + curl_setopt_array( + $ch, array( + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $params, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_TIMEOUT => self::REQUEST_TIMEOUT + ) + ); + + $rawResponse = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $error = curl_error($ch); + curl_close($ch); + + if ($rawResponse === false) { + throw new Exception('Failed to connect to the Textlocal service: ' . $error); + } elseif ($httpCode != 200) { + throw new Exception('Bad response from the Textlocal service: HTTP code ' . $httpCode); + } + + return $rawResponse; + } + + /** + * fopen() request handler + * + * @param $command + * @param $params + * @throws Exception + */ + private function _sendRequestFopen($command, $params) + { + throw new Exception('Unsupported transfer method'); + } + + /** + * Get last request's parameters + * + * @return array + */ + public function getLastRequest() + { + return $this->lastRequest; + } + + /** + * Send an SMS to one or more comma separated numbers + * + * @param $numbers + * @param $message + * @param $sender + * @param null $sched + * @param false $test + * @param null $receiptURL + * @param numm $custom + * @param false $optouts + * @param false $simpleReplyService + * @return array|mixed + * @throws Exception + */ + + public function sendSms($numbers, $message, $sender, $sched = null, $test = false, $receiptURL = null, $custom = null, $optouts = false, $simpleReplyService = false) + { + + if (!is_array($numbers)) { + throw new Exception('Invalid $numbers format. Must be an array'); + } + if (empty($message)) { + throw new Exception('Empty message'); + } + if (empty($sender)) { + throw new Exception('Empty sender name'); + } + if (!is_null($sched) && !is_numeric($sched)) { + throw new Exception('Invalid date format. Use numeric epoch format'); + } + + $params = array( + 'message' => rawurlencode($message), + 'numbers' => implode(',', $numbers), + 'sender' => rawurlencode($sender), + 'schedule_time' => $sched, + 'test' => $test, + 'receipt_url' => $receiptURL, + 'custom' => $custom, + 'optouts' => $optouts, + 'simple_reply' => $simpleReplyService + ); + + return $this->_sendRequest('send', $params); + } + + + /** + * Send an SMS to a Group of contacts - group IDs can be retrieved from getGroups() + * + * @param $groupId + * @param $message + * @param null $sender + * @param false $test + * @param null $receiptURL + * @param numm $custom + * @param false $optouts + * @param false $simpleReplyService + * @return array|mixed + * @throws Exception + */ + public function sendSmsGroup($groupId, $message, $sender = null, $sched = null, $test = false, $receiptURL = null, $custom = null, $optouts = false, $simpleReplyService = false) + { + + if (!is_numeric($groupId)) { + throw new Exception('Invalid $groupId format. Must be a numeric group ID'); + } + if (empty($message)) { + throw new Exception('Empty message'); + } + if (empty($sender)) { + throw new Exception('Empty sender name'); + } + if (!is_null($sched) && !is_numeric($sched)) { + throw new Exception('Invalid date format. Use numeric epoch format'); + } + + $params = array( + 'message' => rawurlencode($message), + 'group_id' => $groupId, + 'sender' => rawurlencode($sender), + 'schedule_time' => $sched, + 'test' => $test, + 'receipt_url' => $receiptURL, + 'custom' => $custom, + 'optouts' => $optouts, + 'simple_reply' => $simpleReplyService + ); + + return $this->_sendRequest('send', $params); + } + + + /** + * Send an MMS to a one or more comma separated contacts + * + * @param $numbers + * @param $fileSource - either an absolute or relative path, or http url to a file. + * @param $message + * @param null $sched + * @param false $test + * @param false $optouts + * @return array|mixed + * @throws Exception + */ + public function sendMms($numbers, $fileSource, $message, $sched = null, $test = false, $optouts = false) + { + + if (!is_array($numbers)) { + throw new Exception('Invalid $numbers format. Must be an array'); + } + if (empty($message)) { + throw new Exception('Empty message'); + } + if (empty($fileSource)) { + throw new Exception('Empty file source'); + } + if (!is_null($sched) && !is_numeric($sched)) { + throw new Exception('Invalid date format. Use numeric epoch format'); + } + + $params = array( + 'message' => rawurlencode($message), + 'numbers' => implode(',', $numbers), + 'schedule_time' => $sched, + 'test' => $test, + 'optouts' => $optouts + ); + + /** + * Local file. POST to service +*/ + if (is_readable($fileSource)) { + $params['file'] = '@' . $fileSource; + } else { $params['url'] = $fileSource; + } + + return $this->_sendRequest('send_mms', $params); + } + + /** + * Send an MMS to a group - group IDs can be + * + * @param $groupId + * @param $fileSource + * @param $message + * @param null $sched + * @param false $test + * @param false $optouts + * @return array|mixed + * @throws Exception + */ + public function sendMmsGroup($groupId, $fileSource, $message, $sched = null, $test = false, $optouts = false) + { + + if (!is_numeric($groupId)) { + throw new Exception('Invalid $groupId format. Must be a numeric group ID'); + } + if (empty($message)) { + throw new Exception('Empty message'); + } + if (empty($fileSource)) { + throw new Exception('Empty file source'); + } + if (!is_null($sched) && !is_numeric($sched)) { + throw new Exception('Invalid date format. Use numeric epoch format'); + } + + $params = array( + 'message' => rawurlencode($message), + 'group_id' => $groupId, + 'schedule_time' => $sched, + 'test' => $test, + 'optouts' => $optouts + ); + + /** + * Local file. POST to service +*/ + if (is_readable($fileSource)) { + $params['file'] = '@' . $fileSource; + } else { $params['url'] = $fileSource; + } + + return $this->_sendRequest('send_mms', $params); + } + + /** + * Returns reseller customer's ID's + * + * @return array + **/ + + public function getUsers() + { + return $this->_sendRequest('get_users'); + } + + /** + * Transfer credits to a reseller's customer + * + * @param $user - can be ID or Email + * @param $credits + * @return array|mixed + * @throws Exception + **/ + + public function transferCredits($user, $credits) + { + + if (!is_numeric($credits)) { + throw new Exception('Invalid credits format'); + } + if (!is_numeric($user)) { + throw new Exception('Invalid user'); + } + if (empty($user)) { + throw new Exception('No user specified'); + } + if (empty($credits)) { + throw new Exception('No credits specified'); + } + + if (is_int($user)) { + $params = array( + 'user_id' => $user, + 'credits' => $credits + ); + } else { + $params = array( + 'user_email' => rawurlencode($user), + 'credits' => $credits + ); + } + + return $this->_sendRequest('transfer_credits', $params); + } + + /**Get templates from an account **/ + + public function getTemplates() + { + return $this->_sendRequest('get_templates'); + } + + /** + * Check the availability of a keyword + * + * @param $keyword + * return array|mixed + */ + public function checkKeyword($keyword) + { + + $params = array('keyword' => $keyword); + return $this->_sendRequest('check_keyword', $params); + } + + /** + * Create a new contact group + * + * @param $name + * @return array|mixed + */ + public function createGroup($name) + { + $params = array('name' => $name); + return $this->_sendRequest('create_group', $params); + } + + /** + * Get contacts from a group - Group IDs can be retrieved with the getGroups() function + * + * @param $groupId + * @param $limit + * @param int $startPos + * @return array|mixed + * @throws Exception + */ + public function getContacts($groupId, $limit, $startPos = 0) + { + + if (!is_numeric($groupId)) { + throw new Exception('Invalid $groupId format. Must be a numeric group ID'); + } + if (!is_numeric($startPos) || $startPos < 0) { + throw new Exception('Invalid $startPos format. Must be a numeric start position, 0 or above'); + } + if (!is_numeric($limit) || $limit < 1) { + throw new Exception('Invalid $limit format. Must be a numeric limit value, 1 or above'); + } + + $params = array( + 'group_id' => $groupId, + 'start' => $startPos, + 'limit' => $limit + ); + return $this->_sendRequest('get_contacts', $params); + } + + /** + * Create one or more number-only contacts in a specific group, defaults to 'My Contacts' + * + * @param $numbers + * @param string $groupid + * @return array|mixed + */ + public function createContacts($numbers, $groupid = '5') + { + $params = array("group_id" => $groupid); + + if (is_array($numbers)) { + $params['numbers'] = implode(',', $numbers); + } else { + $params['numbers'] = $numbers; + } + + return $this->_sendRequest('create_contacts', $params); + } + + /** + * Create bulk contacts - with name and custom information from an array of: + * [first_name] [last_name] [number] [custom1] [custom2] [custom3] + * + * @param array $contacts + * @param string $groupid + * @return array|mixed + */ + function createContactsBulk($contacts, $groupid = '5') + { + // JSON & URL-encode array + $contacts = rawurlencode(json_encode($contacts)); + + $params = array + ("group_id" => $groupid, "contacts" => $contacts); + return $this->_sendRequest('create_contacts_bulk', $params); + } + + /** + * Get a list of groups and group IDs + * + * @return array|mixed + */ + public function getGroups() + { + return $this->_sendRequest('get_groups'); + } + + /** + * Get the status of a message based on the Message ID - this can be taken from sendSMS or from a history report + * + * @param $messageid + * @return array|mixed + */ + public function getMessageStatus($messageid) + { + $params = array("message_id" => $messageid); + return $this->_sendRequest('status_message', $params); + } + + /** + * Get the status of a message based on the Batch ID - this can be taken from sendSMS or from a history report + * + * @param $batchid + * @return array|mixed + */ + public function getBatchStatus($batchid) + { + $params = array("batch_id" => $batchid); + return $this->_sendRequest('status_batch', $params); + } + + /** + * Get sender names + * + * @return array|mixed + */ + public function getSenderNames() + { + return $this->_sendRequest('get_sender_names'); + } + + /** + * Get inboxes available on the account + * + * @return array|mixed + */ + public function getInboxes() + { + return $this->_sendRequest('get_inboxes'); + } + + /** + * Get Credit Balances + * + * @return array + */ + public function getBalance() + { + $result = $this->_sendRequest('balance'); + return array('sms' => $result->balance->sms, 'mms' => $result->balance->mms); + } + + /** + * Get messages from an inbox - The ID can ge retrieved from getInboxes() + * + * @param $inbox + * @return array|bool|mixed + */ + public function getMessages($inbox) + { + if (!isset($inbox)) { return false; + } + $options = array('inbox_id' => $inbox); + return $this->_sendRequest('get_messages', $options); + } + + /** + * Cancel a scheduled message based on a message ID from getScheduledMessages() + * + * @param $id + * @return array|bool|mixed + */ + public function cancelScheduledMessage($id) + { + if (!isset($id)) { return false; + } + $options = array('sent_id' => $id); + return $this->_sendRequest('cancel_scheduled', $options); + } + + /** + * Get Scheduled Message information + * + * @return array|mixed + */ + public function getScheduledMessages() + { + return $this->_sendRequest('get_scheduled'); + } + + /** + * Delete a contact based on telephone number from a group + * + * @param $number + * @param int $groupid + * @return array|bool|mixed + */ + public function deleteContact($number, $groupid = 5) + { + if (!isset($number)) { return false; + } + $options = array('number' => $number, 'group_id' => $groupid); + return $this->_sendRequest('delete_contact', $options); + } + + /** + * Delete a group - Be careful, we can not recover any data deleted by mistake + * + * @param $groupid + * @return array|mixed + */ + public function deleteGroup($groupid) + { + $options = array('group_id' => $groupid); + return $this->_sendRequest('delete_group', $options); + } + + + /** + * Get single SMS history (single numbers, comma seperated numbers when sending) + * + * @param $start + * @param $limit + * @param $min_time Unix timestamp + * @param $max_time Unix timestamp + * @return array|bool|mixed + */ + public function getSingleMessageHistory($start, $limit, $min_time, $max_time) + { + return $this->getHistory('get_history_single', $start, $limit, $min_time, $max_time); + } + + /** + * Get API SMS Message history + * + * @param $start + * @param $limit + * @param $min_time Unix timestamp + * @param $max_time Unix timestamp + * @return array|bool|mixed + */ + public function getAPIMessageHistory($start, $limit, $min_time, $max_time) + { + return $this->getHistory('get_history_api', $start, $limit, $min_time, $max_time); + } + + /** + * Get Email to SMS History + * + * @param $start + * @param $limit + * @param $min_time Unix timestamp + * @param $max_time Unix timestamp + * @return array|bool|mixed + */ + public function getEmailToSMSHistory($start, $limit, $min_time, $max_time) + { + return $this->getHistory('get_history_email', $start, $limit, $min_time, $max_time); + } + + /** + * Get group SMS history + * + * @param $start + * @param $limit + * @param $min_time Unix timestamp + * @param $max_time Unix timestamp + * @return array|bool|mixed + */ + public function getGroupMessageHistory($start, $limit, $min_time, $max_time) + { + return $this->getHistory('get_history_group', $start, $limit, $min_time, $max_time); + } + + /** + * Generic function to provide validation and the request method for getting all types of history + * + * @param $type + * @param $start + * @param $limit + * @param $min_time + * @param $max_time + * @return array|bool|mixed + */ + private function getHistory($type, $start, $limit, $min_time, $max_time) + { + if (!isset($start) || !isset($limit) || !isset($min_time) || !isset($max_time)) { return false; + } + $options = array('start' => $start, 'limit' => $limit, 'min_time' => $min_time, 'max_time' => $max_time); + return $this->_sendRequest($type, $options); + } + + /** + * Get a list of surveys + * + * @return array|mixed + */ + public function getSurveys() + { + return $this->_sendRequest('get_surveys'); + } + + /** + * Get a deatils of a survey + * + * @return array|mixed + */ + public function getSurveyDetails() + { + $options = array('survey_id' => $surveyid); + return $this->_sendRequest('get_survey_details'); + } + + /** + * Get a the results of a given survey + * + * @return array|mixed + */ + public function getSurveyResults($surveyid, $start, $end) + { + $options = array('survey_id' => $surveyid, 'start_date' => $start, 'end_date' => $end); + return $this->_sendRequest('get_surveys', $options); + } + + /** + * Get all account optouts + * + * @return array|mixed + */ + + public function getOptouts($time = null) + { + return $this->_sendRequest('get_optouts'); + } +} + +; + +class Contact +{ + var $number; + var $first_name; + var $last_name; + var $custom1; + var $custom2; + var $custom3; + + var $groupID; + + /** + * Structure of a contact object + * + * @param $number + * @param string $firstname + * @param string $lastname + * @param string $custom1 + * @param string $custom2 + * @param string $custom3 + */ + function __construct($number, $firstname = '', $lastname = '', $custom1 = '', $custom2 = '', $custom3 = '') + { + $this->number = $number; + $this->first_name = $firstname; + $this->last_name = $lastname; + $this->custom1 = $custom1; + $this->custom2 = $custom2; + $this->custom3 = $custom3; + } +} + +; + +/** + * If the json_encode function does not exist, then create it.. + */ + +if (!function_exists('json_encode')) { + function json_encode($a = false) + { + if (is_null($a)) { return 'null'; + } + if ($a === false) { return 'false'; + } + if ($a === true) { return 'true'; + } + if (is_scalar($a)) { + if (is_float($a)) { + // Always use "." for floats. + return floatval(str_replace(",", ".", strval($a))); + } + + if (is_string($a)) { + static $jsonReplaces = array(array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"')); + return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $a) . '"'; + } else { + return $a; + } + } + $isList = true; + for ($i = 0, reset($a); $i < count($a); $i++, next($a)) { + if (key($a) !== $i) { + $isList = false; + break; + } + } + $result = array(); + if ($isList) { + foreach ($a as $v) { $result[] = json_encode($v); + } + return '[' . join(',', $result) . ']'; + } else { + foreach ($a as $k => $v) { $result[] = json_encode($k) . ':' . json_encode($v); + } + return '{' . join(',', $result) . '}'; + } + } +} + + diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php new file mode 100644 index 0000000..683dde5 --- /dev/null +++ b/src/TextlocalChannel.php @@ -0,0 +1,58 @@ +client = $client; + $this->sender = config('services.sms.textlocal.sender'); + } + + /** + * Send the given notification. + * + * @param mixed $notifiable + * @param \Illuminate\Notifications\Notification $notification + * + * @throws \NotificationChannels\Textlocal\Exceptions\CouldNotSendNotification + */ + public function send($notifiable, Notification $notification) + { + // Get the mobile number/s from the model + $numbers = (array) $notifiable->routeNotificationForSms(); + + if (empty($numbers)) { + return; + } + + if (!is_array($numbers) ) { + $numbers = array($numbers); + } + + // Get the message from the notification class + $message = (string) $notification->toSms($notifiable); + + if (empty($message)) { + return; + } + + try { + $response = $this->client->sendSms($numbers, $message, $this->sender); + return json_decode(json_encode($response), true); + + } catch (\Exception $exception) { + throw CouldNotSendNotification::serviceRespondedWithAnError($exception); + } + } +} diff --git a/src/TextlocalServiceProvider.php b/src/TextlocalServiceProvider.php new file mode 100644 index 0000000..53d2335 --- /dev/null +++ b/src/TextlocalServiceProvider.php @@ -0,0 +1,36 @@ +app->when(TextlocalChannel::class) + ->needs(Textlocal::class) + ->give( + function () { + $textlocalConfig = config('services.sms.textlocal'); + + return new Textlocal( + $textlocalConfig['username'], + $textlocalConfig['hash'] + ); + } + ); + } + + /** + * Register the application services. + */ + public function register() + { + } +} diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php new file mode 100644 index 0000000..c6d9b11 --- /dev/null +++ b/tests/ExampleTest.php @@ -0,0 +1,12 @@ +assertTrue(true); + } +} From 0feceaa9ccc6e55f444ddda98fd7ed2cb735f2c3 Mon Sep 17 00:00:00 2001 From: Manash Jyoti Sonowal Date: Mon, 7 Aug 2017 15:23:58 +0530 Subject: [PATCH 06/54] Exception handling --- src/Exceptions/CouldNotSendNotification.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Exceptions/CouldNotSendNotification.php b/src/Exceptions/CouldNotSendNotification.php index f9dc566..b89deae 100644 --- a/src/Exceptions/CouldNotSendNotification.php +++ b/src/Exceptions/CouldNotSendNotification.php @@ -1,11 +1,11 @@ getMessage()); } } From ccf2195d1c50c4263c4538c2b5fe78c7a20e8779 Mon Sep 17 00:00:00 2001 From: Manash Jyoti Sonowal Date: Mon, 7 Aug 2017 15:34:53 +0530 Subject: [PATCH 07/54] Apply Patch from CI --- src/Exceptions/CouldNotSendNotification.php | 2 +- src/Textlocal.php | 382 +++++++++++--------- src/TextlocalChannel.php | 14 +- 3 files changed, 216 insertions(+), 182 deletions(-) diff --git a/src/Exceptions/CouldNotSendNotification.php b/src/Exceptions/CouldNotSendNotification.php index b89deae..a2c90b3 100644 --- a/src/Exceptions/CouldNotSendNotification.php +++ b/src/Exceptions/CouldNotSendNotification.php @@ -6,6 +6,6 @@ class CouldNotSendNotification extends \Exception { public static function serviceRespondedWithAnError($exception) { - return new static("Could Not Send SMS to TEXTLOCAL ." . $exception->getMessage()); + return new static('Could Not Send SMS to TEXTLOCAL .'.$exception->getMessage()); } } diff --git a/src/Textlocal.php b/src/Textlocal.php index feb1a35..1944e99 100644 --- a/src/Textlocal.php +++ b/src/Textlocal.php @@ -3,14 +3,13 @@ namespace NotificationChannels\Textlocal; /** - * Textlocal API2 Wrapper Class + * Textlocal API2 Wrapper Class. * * This class is used to interface with the Textlocal API2 to send messages, manage contacts, retrieve messages from * inboxes, track message delivery statuses, access history reports * - * @package Textlocal - * @subpackage API * @author Andy Dixon + * * @version 1.4-IN * @const REQUEST_URL URL to make the request to * @const REQUEST_TIMEOUT Timeout in seconds for the HTTP request @@ -28,41 +27,42 @@ class Textlocal private $errorReporting = false; - public $errors = array(); - public $warnings = array(); + public $errors = []; + public $warnings = []; - public $lastRequest = array(); + public $lastRequest = []; /** - * Instantiate the object + * Instantiate the object. * * @param $username * @param $hash */ - function __construct($username, $hash, $apiKey = false) + public function __construct($username, $hash, $apiKey = false) { $this->username = $username; $this->hash = $hash; if ($apiKey) { $this->apiKey = $apiKey; } - } /** - * Private function to construct and send the request and handle the response + * Private function to construct and send the request and handle the response. * * @param $command - * @param array $params - * @return array|mixed + * @param array $params + * * @throws Exception + * + * @return array|mixed + * * @todo Add additional request handlers - eg fopen, file_get_contacts */ - private function _sendRequest($command, $params = array()) + private function _sendRequest($command, $params = []) { if ($this->apiKey && !empty($this->apiKey)) { $params['apiKey'] = $this->apiKey; - } else { $params['hash'] = $this->hash; } @@ -73,7 +73,8 @@ private function _sendRequest($command, $params = array()) if (self::REQUEST_HANDLER == 'curl') { $rawResponse = $this->_sendRequestCurl($command, $params); - } else { throw new Exception('Invalid request handler.'); + } else { + throw new Exception('Invalid request handler.'); } $result = json_decode($rawResponse); @@ -92,28 +93,29 @@ private function _sendRequest($command, $params = array()) } /** - * Curl request handler + * Curl request handler. * * @param $command * @param $params - * @return mixed + * * @throws Exception + * + * @return mixed */ private function _sendRequestCurl($command, $params) { - - $url = self::REQUEST_URL . $command . '/'; + $url = self::REQUEST_URL.$command.'/'; // Initialize handle $ch = curl_init($url); curl_setopt_array( - $ch, array( + $ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => $params, CURLOPT_RETURNTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, - CURLOPT_TIMEOUT => self::REQUEST_TIMEOUT - ) + CURLOPT_TIMEOUT => self::REQUEST_TIMEOUT, + ] ); $rawResponse = curl_exec($ch); @@ -122,19 +124,20 @@ private function _sendRequestCurl($command, $params) curl_close($ch); if ($rawResponse === false) { - throw new Exception('Failed to connect to the Textlocal service: ' . $error); + throw new Exception('Failed to connect to the Textlocal service: '.$error); } elseif ($httpCode != 200) { - throw new Exception('Bad response from the Textlocal service: HTTP code ' . $httpCode); + throw new Exception('Bad response from the Textlocal service: HTTP code '.$httpCode); } return $rawResponse; } /** - * fopen() request handler + * fopen() request handler. * * @param $command * @param $params + * * @throws Exception */ private function _sendRequestFopen($command, $params) @@ -143,7 +146,7 @@ private function _sendRequestFopen($command, $params) } /** - * Get last request's parameters + * Get last request's parameters. * * @return array */ @@ -153,24 +156,24 @@ public function getLastRequest() } /** - * Send an SMS to one or more comma separated numbers + * Send an SMS to one or more comma separated numbers. * * @param $numbers * @param $message * @param $sender - * @param null $sched - * @param false $test - * @param null $receiptURL - * @param numm $custom - * @param false $optouts - * @param false $simpleReplyService - * @return array|mixed + * @param null $sched + * @param false $test + * @param null $receiptURL + * @param numm $custom + * @param false $optouts + * @param false $simpleReplyService + * * @throws Exception + * + * @return array|mixed */ - public function sendSms($numbers, $message, $sender, $sched = null, $test = false, $receiptURL = null, $custom = null, $optouts = false, $simpleReplyService = false) { - if (!is_array($numbers)) { throw new Exception('Invalid $numbers format. Must be an array'); } @@ -184,7 +187,7 @@ public function sendSms($numbers, $message, $sender, $sched = null, $test = fals throw new Exception('Invalid date format. Use numeric epoch format'); } - $params = array( + $params = [ 'message' => rawurlencode($message), 'numbers' => implode(',', $numbers), 'sender' => rawurlencode($sender), @@ -193,30 +196,30 @@ public function sendSms($numbers, $message, $sender, $sched = null, $test = fals 'receipt_url' => $receiptURL, 'custom' => $custom, 'optouts' => $optouts, - 'simple_reply' => $simpleReplyService - ); + 'simple_reply' => $simpleReplyService, + ]; return $this->_sendRequest('send', $params); } - /** - * Send an SMS to a Group of contacts - group IDs can be retrieved from getGroups() + * Send an SMS to a Group of contacts - group IDs can be retrieved from getGroups(). * * @param $groupId * @param $message - * @param null $sender - * @param false $test - * @param null $receiptURL - * @param numm $custom - * @param false $optouts - * @param false $simpleReplyService - * @return array|mixed + * @param null $sender + * @param false $test + * @param null $receiptURL + * @param numm $custom + * @param false $optouts + * @param false $simpleReplyService + * * @throws Exception + * + * @return array|mixed */ public function sendSmsGroup($groupId, $message, $sender = null, $sched = null, $test = false, $receiptURL = null, $custom = null, $optouts = false, $simpleReplyService = false) { - if (!is_numeric($groupId)) { throw new Exception('Invalid $groupId format. Must be a numeric group ID'); } @@ -230,7 +233,7 @@ public function sendSmsGroup($groupId, $message, $sender = null, $sched = null, throw new Exception('Invalid date format. Use numeric epoch format'); } - $params = array( + $params = [ 'message' => rawurlencode($message), 'group_id' => $groupId, 'sender' => rawurlencode($sender), @@ -239,28 +242,28 @@ public function sendSmsGroup($groupId, $message, $sender = null, $sched = null, 'receipt_url' => $receiptURL, 'custom' => $custom, 'optouts' => $optouts, - 'simple_reply' => $simpleReplyService - ); + 'simple_reply' => $simpleReplyService, + ]; return $this->_sendRequest('send', $params); } - /** - * Send an MMS to a one or more comma separated contacts + * Send an MMS to a one or more comma separated contacts. * * @param $numbers * @param $fileSource - either an absolute or relative path, or http url to a file. * @param $message - * @param null $sched - * @param false $test - * @param false $optouts - * @return array|mixed + * @param null $sched + * @param false $test + * @param false $optouts + * * @throws Exception + * + * @return array|mixed */ public function sendMms($numbers, $fileSource, $message, $sched = null, $test = false, $optouts = false) { - if (!is_array($numbers)) { throw new Exception('Invalid $numbers format. Must be an array'); } @@ -274,40 +277,42 @@ public function sendMms($numbers, $fileSource, $message, $sched = null, $test = throw new Exception('Invalid date format. Use numeric epoch format'); } - $params = array( + $params = [ 'message' => rawurlencode($message), 'numbers' => implode(',', $numbers), 'schedule_time' => $sched, 'test' => $test, - 'optouts' => $optouts - ); + 'optouts' => $optouts, + ]; - /** + /* * Local file. POST to service */ if (is_readable($fileSource)) { - $params['file'] = '@' . $fileSource; - } else { $params['url'] = $fileSource; + $params['file'] = '@'.$fileSource; + } else { + $params['url'] = $fileSource; } return $this->_sendRequest('send_mms', $params); } /** - * Send an MMS to a group - group IDs can be + * Send an MMS to a group - group IDs can be. * * @param $groupId * @param $fileSource * @param $message - * @param null $sched - * @param false $test - * @param false $optouts - * @return array|mixed + * @param null $sched + * @param false $test + * @param false $optouts + * * @throws Exception + * + * @return array|mixed */ public function sendMmsGroup($groupId, $fileSource, $message, $sched = null, $test = false, $optouts = false) { - if (!is_numeric($groupId)) { throw new Exception('Invalid $groupId format. Must be a numeric group ID'); } @@ -321,48 +326,48 @@ public function sendMmsGroup($groupId, $fileSource, $message, $sched = null, $te throw new Exception('Invalid date format. Use numeric epoch format'); } - $params = array( + $params = [ 'message' => rawurlencode($message), 'group_id' => $groupId, 'schedule_time' => $sched, 'test' => $test, - 'optouts' => $optouts - ); + 'optouts' => $optouts, + ]; - /** + /* * Local file. POST to service */ if (is_readable($fileSource)) { - $params['file'] = '@' . $fileSource; - } else { $params['url'] = $fileSource; + $params['file'] = '@'.$fileSource; + } else { + $params['url'] = $fileSource; } return $this->_sendRequest('send_mms', $params); } /** - * Returns reseller customer's ID's + * Returns reseller customer's ID's. * * @return array **/ - public function getUsers() { return $this->_sendRequest('get_users'); } /** - * Transfer credits to a reseller's customer + * Transfer credits to a reseller's customer. * * @param $user - can be ID or Email * @param $credits - * @return array|mixed + * * @throws Exception + * + * @return array|mixed **/ - public function transferCredits($user, $credits) { - if (!is_numeric($credits)) { throw new Exception('Invalid credits format'); } @@ -377,15 +382,15 @@ public function transferCredits($user, $credits) } if (is_int($user)) { - $params = array( + $params = [ 'user_id' => $user, - 'credits' => $credits - ); + 'credits' => $credits, + ]; } else { - $params = array( + $params = [ 'user_email' => rawurlencode($user), - 'credits' => $credits - ); + 'credits' => $credits, + ]; } return $this->_sendRequest('transfer_credits', $params); @@ -399,42 +404,45 @@ public function getTemplates() } /** - * Check the availability of a keyword + * Check the availability of a keyword. * * @param $keyword * return array|mixed */ public function checkKeyword($keyword) { + $params = ['keyword' => $keyword]; - $params = array('keyword' => $keyword); return $this->_sendRequest('check_keyword', $params); } /** - * Create a new contact group + * Create a new contact group. * * @param $name + * * @return array|mixed */ public function createGroup($name) { - $params = array('name' => $name); + $params = ['name' => $name]; + return $this->_sendRequest('create_group', $params); } /** - * Get contacts from a group - Group IDs can be retrieved with the getGroups() function + * Get contacts from a group - Group IDs can be retrieved with the getGroups() function. * * @param $groupId * @param $limit - * @param int $startPos - * @return array|mixed + * @param int $startPos + * * @throws Exception + * + * @return array|mixed */ public function getContacts($groupId, $limit, $startPos = 0) { - if (!is_numeric($groupId)) { throw new Exception('Invalid $groupId format. Must be a numeric group ID'); } @@ -445,24 +453,26 @@ public function getContacts($groupId, $limit, $startPos = 0) throw new Exception('Invalid $limit format. Must be a numeric limit value, 1 or above'); } - $params = array( + $params = [ 'group_id' => $groupId, 'start' => $startPos, - 'limit' => $limit - ); + 'limit' => $limit, + ]; + return $this->_sendRequest('get_contacts', $params); } /** - * Create one or more number-only contacts in a specific group, defaults to 'My Contacts' + * Create one or more number-only contacts in a specific group, defaults to 'My Contacts'. * * @param $numbers - * @param string $groupid + * @param string $groupid + * * @return array|mixed */ public function createContacts($numbers, $groupid = '5') { - $params = array("group_id" => $groupid); + $params = ['group_id' => $groupid]; if (is_array($numbers)) { $params['numbers'] = implode(',', $numbers); @@ -475,24 +485,25 @@ public function createContacts($numbers, $groupid = '5') /** * Create bulk contacts - with name and custom information from an array of: - * [first_name] [last_name] [number] [custom1] [custom2] [custom3] + * [first_name] [last_name] [number] [custom1] [custom2] [custom3]. + * + * @param array $contacts + * @param string $groupid * - * @param array $contacts - * @param string $groupid * @return array|mixed */ - function createContactsBulk($contacts, $groupid = '5') + public function createContactsBulk($contacts, $groupid = '5') { // JSON & URL-encode array $contacts = rawurlencode(json_encode($contacts)); - $params = array - ("group_id" => $groupid, "contacts" => $contacts); + $params = ['group_id' => $groupid, 'contacts' => $contacts]; + return $this->_sendRequest('create_contacts_bulk', $params); } /** - * Get a list of groups and group IDs + * Get a list of groups and group IDs. * * @return array|mixed */ @@ -502,31 +513,35 @@ public function getGroups() } /** - * Get the status of a message based on the Message ID - this can be taken from sendSMS or from a history report + * Get the status of a message based on the Message ID - this can be taken from sendSMS or from a history report. * * @param $messageid + * * @return array|mixed */ public function getMessageStatus($messageid) { - $params = array("message_id" => $messageid); + $params = ['message_id' => $messageid]; + return $this->_sendRequest('status_message', $params); } /** - * Get the status of a message based on the Batch ID - this can be taken from sendSMS or from a history report + * Get the status of a message based on the Batch ID - this can be taken from sendSMS or from a history report. * * @param $batchid + * * @return array|mixed */ public function getBatchStatus($batchid) { - $params = array("batch_id" => $batchid); + $params = ['batch_id' => $batchid]; + return $this->_sendRequest('status_batch', $params); } /** - * Get sender names + * Get sender names. * * @return array|mixed */ @@ -536,7 +551,7 @@ public function getSenderNames() } /** - * Get inboxes available on the account + * Get inboxes available on the account. * * @return array|mixed */ @@ -546,46 +561,53 @@ public function getInboxes() } /** - * Get Credit Balances + * Get Credit Balances. * * @return array */ public function getBalance() { $result = $this->_sendRequest('balance'); - return array('sms' => $result->balance->sms, 'mms' => $result->balance->mms); + + return ['sms' => $result->balance->sms, 'mms' => $result->balance->mms]; } /** - * Get messages from an inbox - The ID can ge retrieved from getInboxes() + * Get messages from an inbox - The ID can ge retrieved from getInboxes(). * * @param $inbox + * * @return array|bool|mixed */ public function getMessages($inbox) { - if (!isset($inbox)) { return false; + if (!isset($inbox)) { + return false; } - $options = array('inbox_id' => $inbox); + $options = ['inbox_id' => $inbox]; + return $this->_sendRequest('get_messages', $options); } /** - * Cancel a scheduled message based on a message ID from getScheduledMessages() + * Cancel a scheduled message based on a message ID from getScheduledMessages(). * * @param $id + * * @return array|bool|mixed */ public function cancelScheduledMessage($id) { - if (!isset($id)) { return false; + if (!isset($id)) { + return false; } - $options = array('sent_id' => $id); + $options = ['sent_id' => $id]; + return $this->_sendRequest('cancel_scheduled', $options); } /** - * Get Scheduled Message information + * Get Scheduled Message information. * * @return array|mixed */ @@ -595,40 +617,45 @@ public function getScheduledMessages() } /** - * Delete a contact based on telephone number from a group + * Delete a contact based on telephone number from a group. * * @param $number - * @param int $groupid + * @param int $groupid + * * @return array|bool|mixed */ public function deleteContact($number, $groupid = 5) { - if (!isset($number)) { return false; + if (!isset($number)) { + return false; } - $options = array('number' => $number, 'group_id' => $groupid); + $options = ['number' => $number, 'group_id' => $groupid]; + return $this->_sendRequest('delete_contact', $options); } /** - * Delete a group - Be careful, we can not recover any data deleted by mistake + * Delete a group - Be careful, we can not recover any data deleted by mistake. * * @param $groupid + * * @return array|mixed */ public function deleteGroup($groupid) { - $options = array('group_id' => $groupid); + $options = ['group_id' => $groupid]; + return $this->_sendRequest('delete_group', $options); } - /** - * Get single SMS history (single numbers, comma seperated numbers when sending) + * Get single SMS history (single numbers, comma seperated numbers when sending). * * @param $start * @param $limit * @param $min_time Unix timestamp * @param $max_time Unix timestamp + * * @return array|bool|mixed */ public function getSingleMessageHistory($start, $limit, $min_time, $max_time) @@ -637,12 +664,13 @@ public function getSingleMessageHistory($start, $limit, $min_time, $max_time) } /** - * Get API SMS Message history + * Get API SMS Message history. * * @param $start * @param $limit * @param $min_time Unix timestamp * @param $max_time Unix timestamp + * * @return array|bool|mixed */ public function getAPIMessageHistory($start, $limit, $min_time, $max_time) @@ -651,12 +679,13 @@ public function getAPIMessageHistory($start, $limit, $min_time, $max_time) } /** - * Get Email to SMS History + * Get Email to SMS History. * * @param $start * @param $limit * @param $min_time Unix timestamp * @param $max_time Unix timestamp + * * @return array|bool|mixed */ public function getEmailToSMSHistory($start, $limit, $min_time, $max_time) @@ -665,12 +694,13 @@ public function getEmailToSMSHistory($start, $limit, $min_time, $max_time) } /** - * Get group SMS history + * Get group SMS history. * * @param $start * @param $limit * @param $min_time Unix timestamp * @param $max_time Unix timestamp + * * @return array|bool|mixed */ public function getGroupMessageHistory($start, $limit, $min_time, $max_time) @@ -679,25 +709,28 @@ public function getGroupMessageHistory($start, $limit, $min_time, $max_time) } /** - * Generic function to provide validation and the request method for getting all types of history + * Generic function to provide validation and the request method for getting all types of history. * * @param $type * @param $start * @param $limit * @param $min_time * @param $max_time + * * @return array|bool|mixed */ private function getHistory($type, $start, $limit, $min_time, $max_time) { - if (!isset($start) || !isset($limit) || !isset($min_time) || !isset($max_time)) { return false; + if (!isset($start) || !isset($limit) || !isset($min_time) || !isset($max_time)) { + return false; } - $options = array('start' => $start, 'limit' => $limit, 'min_time' => $min_time, 'max_time' => $max_time); + $options = ['start' => $start, 'limit' => $limit, 'min_time' => $min_time, 'max_time' => $max_time]; + return $this->_sendRequest($type, $options); } /** - * Get a list of surveys + * Get a list of surveys. * * @return array|mixed */ @@ -707,54 +740,53 @@ public function getSurveys() } /** - * Get a deatils of a survey + * Get a deatils of a survey. * * @return array|mixed */ public function getSurveyDetails() { - $options = array('survey_id' => $surveyid); + $options = ['survey_id' => $surveyid]; + return $this->_sendRequest('get_survey_details'); } /** - * Get a the results of a given survey + * Get a the results of a given survey. * * @return array|mixed */ public function getSurveyResults($surveyid, $start, $end) { - $options = array('survey_id' => $surveyid, 'start_date' => $start, 'end_date' => $end); + $options = ['survey_id' => $surveyid, 'start_date' => $start, 'end_date' => $end]; + return $this->_sendRequest('get_surveys', $options); } /** - * Get all account optouts + * Get all account optouts. * * @return array|mixed */ - public function getOptouts($time = null) { return $this->_sendRequest('get_optouts'); } } -; - class Contact { - var $number; - var $first_name; - var $last_name; - var $custom1; - var $custom2; - var $custom3; + public $number; + public $first_name; + public $last_name; + public $custom1; + public $custom2; + public $custom3; - var $groupID; + public $groupID; /** - * Structure of a contact object + * Structure of a contact object. * * @param $number * @param string $firstname @@ -763,7 +795,7 @@ class Contact * @param string $custom2 * @param string $custom3 */ - function __construct($number, $firstname = '', $lastname = '', $custom1 = '', $custom2 = '', $custom3 = '') + public function __construct($number, $firstname = '', $lastname = '', $custom1 = '', $custom2 = '', $custom3 = '') { $this->number = $number; $this->first_name = $firstname; @@ -774,30 +806,32 @@ function __construct($number, $firstname = '', $lastname = '', $custom1 = '', $c } } -; - -/** +/* * If the json_encode function does not exist, then create it.. */ if (!function_exists('json_encode')) { function json_encode($a = false) { - if (is_null($a)) { return 'null'; + if (is_null($a)) { + return 'null'; } - if ($a === false) { return 'false'; + if ($a === false) { + return 'false'; } - if ($a === true) { return 'true'; + if ($a === true) { + return 'true'; } if (is_scalar($a)) { if (is_float($a)) { // Always use "." for floats. - return floatval(str_replace(",", ".", strval($a))); + return floatval(str_replace(',', '.', strval($a))); } if (is_string($a)) { - static $jsonReplaces = array(array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"')); - return '"' . str_replace($jsonReplaces[0], $jsonReplaces[1], $a) . '"'; + static $jsonReplaces = [['\\', '/', "\n", "\t", "\r", "\b", "\f", '"'], ['\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"']]; + + return '"'.str_replace($jsonReplaces[0], $jsonReplaces[1], $a).'"'; } else { return $a; } @@ -809,17 +843,19 @@ function json_encode($a = false) break; } } - $result = array(); + $result = []; if ($isList) { - foreach ($a as $v) { $result[] = json_encode($v); + foreach ($a as $v) { + $result[] = json_encode($v); } - return '[' . join(',', $result) . ']'; + + return '['.implode(',', $result).']'; } else { - foreach ($a as $k => $v) { $result[] = json_encode($k) . ':' . json_encode($v); + foreach ($a as $k => $v) { + $result[] = json_encode($k).':'.json_encode($v); } - return '{' . join(',', $result) . '}'; + + return '{'.implode(',', $result).'}'; } } } - - diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index 683dde5..1bc821b 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -2,10 +2,8 @@ namespace NotificationChannels\Textlocal; -use NotificationChannels\Textlocal\Exceptions\CouldNotSendNotification; -use NotificationChannels\Textlocal\Events\MessageWasSent; -use NotificationChannels\Textlocal\Events\SendingMessage; use Illuminate\Notifications\Notification; +use NotificationChannels\Textlocal\Exceptions\CouldNotSendNotification; class TextlocalChannel { @@ -15,8 +13,8 @@ class TextlocalChannel public function __construct(Textlocal $client) { // Initialisation code here - $this->client = $client; - $this->sender = config('services.sms.textlocal.sender'); + $this->client = $client; + $this->sender = config('services.sms.textlocal.sender'); } /** @@ -36,8 +34,8 @@ public function send($notifiable, Notification $notification) return; } - if (!is_array($numbers) ) { - $numbers = array($numbers); + if (!is_array($numbers)) { + $numbers = [$numbers]; } // Get the message from the notification class @@ -49,8 +47,8 @@ public function send($notifiable, Notification $notification) try { $response = $this->client->sendSms($numbers, $message, $this->sender); - return json_decode(json_encode($response), true); + return json_decode(json_encode($response), true); } catch (\Exception $exception) { throw CouldNotSendNotification::serviceRespondedWithAnError($exception); } From 9ea8b72ed7135d810b4f775af868f55c7b108971 Mon Sep 17 00:00:00 2001 From: Manash Jyoti Sonowal Date: Mon, 7 Aug 2017 15:39:50 +0530 Subject: [PATCH 08/54] modified default case namespace --- tests/ExampleTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php index c6d9b11..b2cb7d5 100644 --- a/tests/ExampleTest.php +++ b/tests/ExampleTest.php @@ -1,6 +1,6 @@ Date: Wed, 9 Aug 2017 13:05:56 +0530 Subject: [PATCH 09/54] updated exception import which was incorrect previously --- src/Exceptions/CouldNotSendNotification.php | 2 +- src/Textlocal.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Exceptions/CouldNotSendNotification.php b/src/Exceptions/CouldNotSendNotification.php index a2c90b3..38e61cc 100644 --- a/src/Exceptions/CouldNotSendNotification.php +++ b/src/Exceptions/CouldNotSendNotification.php @@ -6,6 +6,6 @@ class CouldNotSendNotification extends \Exception { public static function serviceRespondedWithAnError($exception) { - return new static('Could Not Send SMS to TEXTLOCAL .'.$exception->getMessage()); + return new static('Could Not Send SMS Error: '.$exception->getMessage()); } } diff --git a/src/Textlocal.php b/src/Textlocal.php index 1944e99..c4fb479 100644 --- a/src/Textlocal.php +++ b/src/Textlocal.php @@ -2,6 +2,8 @@ namespace NotificationChannels\Textlocal; +use \Exception; + /** * Textlocal API2 Wrapper Class. * From 519cd6206bd6f1fae30c2baa12c8ab2ff37e0dc9 Mon Sep 17 00:00:00 2001 From: Manash Jyoti Sonowal Date: Wed, 9 Aug 2017 13:10:42 +0530 Subject: [PATCH 10/54] apply fixes from styleci --- src/Exceptions/CouldNotSendNotification.php | 2 +- src/Textlocal.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Exceptions/CouldNotSendNotification.php b/src/Exceptions/CouldNotSendNotification.php index 38e61cc..947a81b 100644 --- a/src/Exceptions/CouldNotSendNotification.php +++ b/src/Exceptions/CouldNotSendNotification.php @@ -6,6 +6,6 @@ class CouldNotSendNotification extends \Exception { public static function serviceRespondedWithAnError($exception) { - return new static('Could Not Send SMS Error: '.$exception->getMessage()); + return new static('Could Not Send SMS : '.$exception->getMessage()); } } diff --git a/src/Textlocal.php b/src/Textlocal.php index c4fb479..2ff875e 100644 --- a/src/Textlocal.php +++ b/src/Textlocal.php @@ -2,7 +2,7 @@ namespace NotificationChannels\Textlocal; -use \Exception; +use Exception; /** * Textlocal API2 Wrapper Class. From 30ec260389c631a53241d02c8bb5cb57de0b2be2 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Sat, 25 Nov 2017 14:00:02 +0530 Subject: [PATCH 11/54] Update composer.json --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 55d8703..00adbc1 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { - "name": "laravel-notification-channels/textlocal", - "description": "This package helps to send SMS via Textlocal API in laravel way", + "name": "msonowal/laravel-notification-channel-textlocal", + "description": "This Driver for textlocal sms to send SMS via Textlocal API through laravel notification", "homepage": "https://github.com/laravel-notification-channels/textlocal", "license": "MIT", "authors": [ @@ -13,8 +13,8 @@ ], "require": { "php": ">=5.6.4", - "illuminate/notifications": "^5.3|^5.4", - "illuminate/support": "^5.1|^5.2|^5.3|^5.4" + "illuminate/notifications": "^5.3|^5.4|^5.5", + "illuminate/support": "^5.1|^5.2|^5.3|^5.4|^5.5" }, "require-dev": { "mockery/mockery": "^0.9.5", From e51d5ac800e7fb01f4c02f5918c3d6121b41da22 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Sat, 25 Nov 2017 14:04:34 +0530 Subject: [PATCH 12/54] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ba7e1c..3fa110e 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ This package makes it easy to send notifications using [textlocal](https://www.t Create an account in textlocal then create an API key or hash(password). -`composer require laravel-notification-channels/textlocal` +`composer require msonowal/laravel-notification-channel-textlocal` ### Setting up the textlocal service From 83e3f76fa8436ee2fe7b6519ca33718142571fbc Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Sat, 25 Nov 2017 14:38:52 +0530 Subject: [PATCH 13/54] Update TextlocalChannel.php --- src/TextlocalChannel.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index 1bc821b..61d6079 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -37,6 +37,10 @@ public function send($notifiable, Notification $notification) if (!is_array($numbers)) { $numbers = [$numbers]; } + + if (! array_filter($numbers, 'is_int')) { + return; + } // Get the message from the notification class $message = (string) $notification->toSms($notifiable); From b37a6726c266643fe29294a9e3e4228f5a97086b Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Sat, 25 Nov 2017 14:45:58 +0530 Subject: [PATCH 14/54] Update README.md --- README.md | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 3fa110e..90c5ba4 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,9 @@ https://laravel.com/docs/5.4/notifications # Found any bugs or improvement open an issue or send me a PR -[![Latest Version on Packagist](https://img.shields.io/packagist/v/laravel-notification-channels/textlocal.svg?style=flat-square)](https://packagist.org/packages/laravel-notification-channels/textlocal) -[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) -[![Build Status](https://img.shields.io/travis/laravel-notification-channels/textlocal/master.svg?style=flat-square)](https://travis-ci.org/laravel-notification-channels/textlocal) -[![StyleCI](https://styleci.io/repos/:style_ci_id/shield)](https://styleci.io/repos/:style_ci_id) -[![SensioLabsInsight](https://img.shields.io/sensiolabs/i/:sensio_labs_id.svg?style=flat-square)](https://insight.sensiolabs.com/projects/:sensio_labs_id) -[![Quality Score](https://img.shields.io/scrutinizer/g/laravel-notification-channels/textlocal.svg?style=flat-square)](https://scrutinizer-ci.com/g/laravel-notification-channels/textlocal) -[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/laravel-notification-channels/textlocal/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/laravel-notification-channels/textlocal/?branch=master) -[![Total Downloads](https://img.shields.io/packagist/dt/laravel-notification-channels/textlocal.svg?style=flat-square)](https://packagist.org/packages/laravel-notification-channels/textlocal) +[![Latest Stable Version](https://poser.pugx.org/msonowal/laravel-notification-channel-textlocal/v/stable)](https://packagist.org/packages/msonowal/laravel-notification-channel-textlocal) +[![License](https://poser.pugx.org/msonowal/laravel-notification-channel-textlocal/license)](https://packagist.org/packages/msonowal/laravel-notification-channel-textlocal) +[![Total Downloads](https://poser.pugx.org/msonowal/laravel-notification-channel-textlocal/downloads)](https://packagist.org/packages/msonowal/laravel-notification-channel-textlocal) This package makes it easy to send notifications using [textlocal](https://www.textlocal.in/) with Laravel 5.3.+ @@ -44,10 +39,11 @@ Create an account in textlocal then create an API key or hash(password). put the followings and to your config/services ``` 'sms' => [ - 'textlocal' => [ - 'username' => env('TEXTLOCAL_USERNAME'), - 'hash' => env('TEXTLOCAL_HASH'), - 'sender' => env('TEXTLOCAL_SENDER'), + 'textlocal' => [ + 'username' => env('TEXTLOCAL_USERNAME'), + 'hash' => env('TEXTLOCAL_HASH'), + 'sender' => env('TEXTLOCAL_SENDER'), + ] ] ``` From 5e0e269047e03fe7e3e9687e40f351a744d15bf4 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Sat, 2 Dec 2017 20:57:25 +0530 Subject: [PATCH 15/54] Update TextlocalChannel.php --- src/TextlocalChannel.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index 61d6079..fb9a4a9 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -38,9 +38,7 @@ public function send($notifiable, Notification $notification) $numbers = [$numbers]; } - if (! array_filter($numbers, 'is_int')) { - return; - } + //TODO check if numbers are correct // Get the message from the notification class $message = (string) $notification->toSms($notifiable); From 0b5230f51cc17136b06b13a097869c5b72f3a163 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 4 Apr 2018 11:36:21 +0530 Subject: [PATCH 16/54] Update TextlocalChannel.php --- src/TextlocalChannel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index fb9a4a9..073d05d 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -52,7 +52,7 @@ public function send($notifiable, Notification $notification) return json_decode(json_encode($response), true); } catch (\Exception $exception) { - throw CouldNotSendNotification::serviceRespondedWithAnError($exception); + throw CouldNotSendNotification::serviceRespondedWithAnError($exception, $message); } } } From e7906c6abdee28de33f32551eadd53440f994302 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 4 Apr 2018 11:37:12 +0530 Subject: [PATCH 17/54] Update CouldNotSendNotification.php --- src/Exceptions/CouldNotSendNotification.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Exceptions/CouldNotSendNotification.php b/src/Exceptions/CouldNotSendNotification.php index 947a81b..466ecc6 100644 --- a/src/Exceptions/CouldNotSendNotification.php +++ b/src/Exceptions/CouldNotSendNotification.php @@ -4,8 +4,8 @@ class CouldNotSendNotification extends \Exception { - public static function serviceRespondedWithAnError($exception) + public static function serviceRespondedWithAnError($exception, $message = null) { - return new static('Could Not Send SMS : '.$exception->getMessage()); + return new static('Could Not Send SMS : '.$exception->getMessage() . ' message: ' . $message); } } From 1792aea2d6a77d5a609aefbdddeff699534c14ba Mon Sep 17 00:00:00 2001 From: Manash Jyoti Sonowal Date: Fri, 19 Oct 2018 14:42:00 +0530 Subject: [PATCH 18/54] Added Multiple region textlocal config --- README.md | 15 ++++++++-- scrutinizer.yml | 21 +++++++++++++ src/Textlocal.php | 51 ++++++++++++++++++-------------- src/TextlocalServiceProvider.php | 6 +++- src/config/textlocal.php | 9 ++++++ styleci.yml | 1 + travis.yml | 22 ++++++++++++++ 7 files changed, 98 insertions(+), 27 deletions(-) create mode 100644 scrutinizer.yml create mode 100644 src/config/textlocal.php create mode 100644 styleci.yml create mode 100644 travis.yml diff --git a/README.md b/README.md index 90c5ba4..4937623 100644 --- a/README.md +++ b/README.md @@ -46,12 +46,19 @@ put the followings and to your config/services ] ] ``` +### Configuring .env +``` + TEXTLOCAL_USERNAME=Your email id or api key + TEXTLOCAL_HASH=get it from url '/docs/' under your API KEYS section + TEXTLOCAL_SENDER=Name of the Sender that will be displayed to the recipient (max 6 Characters). + TEXTLOCAL_COUNTRY=Your Two letter(ISO-3166-alpha-2) Country Code. It should be the Country of the TEXTLOCAL account. +``` +Currently, only textlocal of two country is supported IN(India) and UK(United Kingdom). ## Usage -textlocal -implement this method `routeNotificationForSms()` in your notifiable class/model which will return array of mobile numbers -and lastly implement `toSms()` method in the notification class which will return the (string) sms or template that is defined in textlocal account that needs to be send. + +Implement this method `routeNotificationForSms()` in your notifiable class/model which will return array of mobile numbers. Please make sure the mobile number contains the dial code as well (e.g +91 for India). And lastly implement `toSms()` method in the notification class which will return the (string) sms or template that is defined in textlocal account that needs to be send. ### Available Message methods @@ -78,6 +85,7 @@ Please see [CONTRIBUTING](CONTRIBUTING.md) for details. ## Credits - [Manash Jyoti Sonowal](https://github.com/msonowal) +- [Manash Jyoti Sonowal](https://github.com/tomonsoejang) - [All Contributors](../../contributors) ## License @@ -86,4 +94,5 @@ The MIT License (MIT). Please see [License File](LICENSE.md) for more informatio ## TODO Need to convert to Guzzle Http as a Client in core +Add more countries add tests diff --git a/scrutinizer.yml b/scrutinizer.yml new file mode 100644 index 0000000..6fad5be --- /dev/null +++ b/scrutinizer.yml @@ -0,0 +1,21 @@ +filter: + excluded_paths: [tests/*] + +checks: + php: + remove_extra_empty_lines: true + remove_php_closing_tag: true + remove_trailing_whitespace: true + fix_use_statements: + remove_unused: true + preserve_multiple: false + preserve_blanklines: true + order_alphabetically: true + fix_php_opening_tag: true + fix_linefeed: true + fix_line_ending: true + fix_identation_4spaces: true + fix_doc_comments: true + +tools: + external_code_coverage: true diff --git a/src/Textlocal.php b/src/Textlocal.php index 2ff875e..2d874cf 100644 --- a/src/Textlocal.php +++ b/src/Textlocal.php @@ -13,16 +13,18 @@ * @author Andy Dixon * * @version 1.4-IN - * @const REQUEST_URL URL to make the request to + * @string $request_url URL to make the request to * @const REQUEST_TIMEOUT Timeout in seconds for the HTTP request * @const REQUEST_HANDLER Handler to use when making the HTTP request (for future use) */ class Textlocal { - const REQUEST_URL = 'https://api.textlocal.in/'; const REQUEST_TIMEOUT = 60; const REQUEST_HANDLER = 'curl'; + private $request_url; + private $country; + private $username; private $hash; private $apiKey; @@ -47,6 +49,9 @@ public function __construct($username, $hash, $apiKey = false) if ($apiKey) { $this->apiKey = $apiKey; } + + $this->country = config('textlocal.country'); + $this->request_url = config('textlocal.request_urls')[$this->country]; } /** @@ -63,7 +68,7 @@ public function __construct($username, $hash, $apiKey = false) */ private function _sendRequest($command, $params = []) { - if ($this->apiKey && !empty($this->apiKey)) { + if ($this->apiKey && ! empty($this->apiKey)) { $params['apiKey'] = $this->apiKey; } else { $params['hash'] = $this->hash; @@ -106,7 +111,7 @@ private function _sendRequest($command, $params = []) */ private function _sendRequestCurl($command, $params) { - $url = self::REQUEST_URL.$command.'/'; + $url = $this->request_url.$command.'/'; // Initialize handle $ch = curl_init($url); @@ -176,7 +181,7 @@ public function getLastRequest() */ public function sendSms($numbers, $message, $sender, $sched = null, $test = false, $receiptURL = null, $custom = null, $optouts = false, $simpleReplyService = false) { - if (!is_array($numbers)) { + if (! is_array($numbers)) { throw new Exception('Invalid $numbers format. Must be an array'); } if (empty($message)) { @@ -185,7 +190,7 @@ public function sendSms($numbers, $message, $sender, $sched = null, $test = fals if (empty($sender)) { throw new Exception('Empty sender name'); } - if (!is_null($sched) && !is_numeric($sched)) { + if (! is_null($sched) && ! is_numeric($sched)) { throw new Exception('Invalid date format. Use numeric epoch format'); } @@ -222,7 +227,7 @@ public function sendSms($numbers, $message, $sender, $sched = null, $test = fals */ public function sendSmsGroup($groupId, $message, $sender = null, $sched = null, $test = false, $receiptURL = null, $custom = null, $optouts = false, $simpleReplyService = false) { - if (!is_numeric($groupId)) { + if (! is_numeric($groupId)) { throw new Exception('Invalid $groupId format. Must be a numeric group ID'); } if (empty($message)) { @@ -231,7 +236,7 @@ public function sendSmsGroup($groupId, $message, $sender = null, $sched = null, if (empty($sender)) { throw new Exception('Empty sender name'); } - if (!is_null($sched) && !is_numeric($sched)) { + if (! is_null($sched) && ! is_numeric($sched)) { throw new Exception('Invalid date format. Use numeric epoch format'); } @@ -266,7 +271,7 @@ public function sendSmsGroup($groupId, $message, $sender = null, $sched = null, */ public function sendMms($numbers, $fileSource, $message, $sched = null, $test = false, $optouts = false) { - if (!is_array($numbers)) { + if (! is_array($numbers)) { throw new Exception('Invalid $numbers format. Must be an array'); } if (empty($message)) { @@ -275,7 +280,7 @@ public function sendMms($numbers, $fileSource, $message, $sched = null, $test = if (empty($fileSource)) { throw new Exception('Empty file source'); } - if (!is_null($sched) && !is_numeric($sched)) { + if (! is_null($sched) && ! is_numeric($sched)) { throw new Exception('Invalid date format. Use numeric epoch format'); } @@ -315,7 +320,7 @@ public function sendMms($numbers, $fileSource, $message, $sched = null, $test = */ public function sendMmsGroup($groupId, $fileSource, $message, $sched = null, $test = false, $optouts = false) { - if (!is_numeric($groupId)) { + if (! is_numeric($groupId)) { throw new Exception('Invalid $groupId format. Must be a numeric group ID'); } if (empty($message)) { @@ -324,7 +329,7 @@ public function sendMmsGroup($groupId, $fileSource, $message, $sched = null, $te if (empty($fileSource)) { throw new Exception('Empty file source'); } - if (!is_null($sched) && !is_numeric($sched)) { + if (! is_null($sched) && ! is_numeric($sched)) { throw new Exception('Invalid date format. Use numeric epoch format'); } @@ -370,10 +375,10 @@ public function getUsers() **/ public function transferCredits($user, $credits) { - if (!is_numeric($credits)) { + if (! is_numeric($credits)) { throw new Exception('Invalid credits format'); } - if (!is_numeric($user)) { + if (! is_numeric($user)) { throw new Exception('Invalid user'); } if (empty($user)) { @@ -445,13 +450,13 @@ public function createGroup($name) */ public function getContacts($groupId, $limit, $startPos = 0) { - if (!is_numeric($groupId)) { + if (! is_numeric($groupId)) { throw new Exception('Invalid $groupId format. Must be a numeric group ID'); } - if (!is_numeric($startPos) || $startPos < 0) { + if (! is_numeric($startPos) || $startPos < 0) { throw new Exception('Invalid $startPos format. Must be a numeric start position, 0 or above'); } - if (!is_numeric($limit) || $limit < 1) { + if (! is_numeric($limit) || $limit < 1) { throw new Exception('Invalid $limit format. Must be a numeric limit value, 1 or above'); } @@ -583,7 +588,7 @@ public function getBalance() */ public function getMessages($inbox) { - if (!isset($inbox)) { + if (! isset($inbox)) { return false; } $options = ['inbox_id' => $inbox]; @@ -600,7 +605,7 @@ public function getMessages($inbox) */ public function cancelScheduledMessage($id) { - if (!isset($id)) { + if (! isset($id)) { return false; } $options = ['sent_id' => $id]; @@ -628,7 +633,7 @@ public function getScheduledMessages() */ public function deleteContact($number, $groupid = 5) { - if (!isset($number)) { + if (! isset($number)) { return false; } $options = ['number' => $number, 'group_id' => $groupid]; @@ -723,7 +728,7 @@ public function getGroupMessageHistory($start, $limit, $min_time, $max_time) */ private function getHistory($type, $start, $limit, $min_time, $max_time) { - if (!isset($start) || !isset($limit) || !isset($min_time) || !isset($max_time)) { + if (! isset($start) || ! isset($limit) || ! isset($min_time) || ! isset($max_time)) { return false; } $options = ['start' => $start, 'limit' => $limit, 'min_time' => $min_time, 'max_time' => $max_time]; @@ -812,7 +817,7 @@ public function __construct($number, $firstname = '', $lastname = '', $custom1 = * If the json_encode function does not exist, then create it.. */ -if (!function_exists('json_encode')) { +if (! function_exists('json_encode')) { function json_encode($a = false) { if (is_null($a)) { @@ -860,4 +865,4 @@ function json_encode($a = false) return '{'.implode(',', $result).'}'; } } -} +} \ No newline at end of file diff --git a/src/TextlocalServiceProvider.php b/src/TextlocalServiceProvider.php index 53d2335..b9d3c22 100644 --- a/src/TextlocalServiceProvider.php +++ b/src/TextlocalServiceProvider.php @@ -25,6 +25,10 @@ function () { ); } ); + + $this->publishes([ + __DIR__.'/../config/textlocal.php' => config_path('textlocal.php'), + ], 'textlocal'); } /** @@ -33,4 +37,4 @@ function () { public function register() { } -} +} \ No newline at end of file diff --git a/src/config/textlocal.php b/src/config/textlocal.php new file mode 100644 index 0000000..4213454 --- /dev/null +++ b/src/config/textlocal.php @@ -0,0 +1,9 @@ + [ + 'IN' => 'https://api.textlocal.in/', + 'UK' => 'https://api.txtlocal.com/' + ], + 'country' => env('TEXTLOCAL_COUNTRY', 'IN'), +]; \ No newline at end of file diff --git a/styleci.yml b/styleci.yml new file mode 100644 index 0000000..0285f17 --- /dev/null +++ b/styleci.yml @@ -0,0 +1 @@ +preset: laravel diff --git a/travis.yml b/travis.yml new file mode 100644 index 0000000..ff42c2c --- /dev/null +++ b/travis.yml @@ -0,0 +1,22 @@ +language: php + +php: + - 5.6 + - 7.0 + - 7.1 + +env: + matrix: + - COMPOSER_FLAGS="--prefer-lowest" + - COMPOSER_FLAGS="" + +before_script: + - travis_retry composer self-update + - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-source + +script: + - phpunit --coverage-text --coverage-clover=coverage.clover + +after_script: + - wget https://scrutinizer-ci.com/ocular.phar + - php ocular.phar code-coverage:upload --format=php-clover coverage.clover From 3e2438f2d96cfaff1eb4e341f3b43f6a7b39c752 Mon Sep 17 00:00:00 2001 From: Manash Jyoti Sonowal Date: Fri, 19 Oct 2018 15:36:38 +0530 Subject: [PATCH 19/54] moved config dir --- README.md | 11 ++++++++--- {src/config => config}/textlocal.php | 0 2 files changed, 8 insertions(+), 3 deletions(-) rename {src/config => config}/textlocal.php (100%) diff --git a/README.md b/README.md index 4937623..177c782 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,9 @@ put the followings and to your config/services ``` 'sms' => [ 'textlocal' => [ - 'username' => env('TEXTLOCAL_USERNAME'), - 'hash' => env('TEXTLOCAL_HASH'), - 'sender' => env('TEXTLOCAL_SENDER'), + 'username' => env('TEXTLOCAL_USERNAME'), + 'hash' => env('TEXTLOCAL_HASH'), + 'sender' => env('TEXTLOCAL_SENDER'), ] ] ``` @@ -54,6 +54,11 @@ put the followings and to your config/services TEXTLOCAL_COUNTRY=Your Two letter(ISO-3166-alpha-2) Country Code. It should be the Country of the TEXTLOCAL account. ``` +### Publish Config +``` + php artisan vendor:publish --tag=textlocal +``` + Currently, only textlocal of two country is supported IN(India) and UK(United Kingdom). ## Usage diff --git a/src/config/textlocal.php b/config/textlocal.php similarity index 100% rename from src/config/textlocal.php rename to config/textlocal.php From c4c56044e12475cbb7f0583c52d1f2828282aaee Mon Sep 17 00:00:00 2001 From: Manash Jyoti Sonowal Date: Fri, 19 Oct 2018 15:37:58 +0530 Subject: [PATCH 20/54] updated contributors name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 177c782..c279d9d 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Please see [CONTRIBUTING](CONTRIBUTING.md) for details. ## Credits - [Manash Jyoti Sonowal](https://github.com/msonowal) -- [Manash Jyoti Sonowal](https://github.com/tomonsoejang) +- [Mr Ejang](https://github.com/tomonsoejang) - [All Contributors](../../contributors) ## License From 964f1bd17d06aca9277237f53b98ae1a6d808b86 Mon Sep 17 00:00:00 2001 From: Manash Jyoti Sonowal Date: Wed, 24 Oct 2018 22:37:59 +0530 Subject: [PATCH 21/54] Fixed a bug which occurs when textlocal config is not published and hence no URL is set so resulting in unable to connect to host Now it merges the configurations with default fallback added notification channel for on demand support --- src/TextlocalChannel.php | 5 ++++- src/TextlocalServiceProvider.php | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index 073d05d..7955bee 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -28,7 +28,10 @@ public function __construct(Textlocal $client) public function send($notifiable, Notification $notification) { // Get the mobile number/s from the model - $numbers = (array) $notifiable->routeNotificationForSms(); + if (! $numbers = $notifiable->routeNotificationFor('textlocal')) { + return; + } + //$numbers = (array) $notifiable->routeNotificationForSms(); if (empty($numbers)) { return; diff --git a/src/TextlocalServiceProvider.php b/src/TextlocalServiceProvider.php index b9d3c22..e4e3a55 100644 --- a/src/TextlocalServiceProvider.php +++ b/src/TextlocalServiceProvider.php @@ -26,9 +26,7 @@ function () { } ); - $this->publishes([ - __DIR__.'/../config/textlocal.php' => config_path('textlocal.php'), - ], 'textlocal'); + $this->publishConfiguration(); } /** @@ -36,5 +34,17 @@ function () { */ public function register() { + $config = __DIR__ . '/../config/textlocal.php'; + + $this->mergeConfigFrom($config, 'textlocal'); + } + + public function publishConfiguration() + { + $path = realpath(__DIR__.'/../config/textlocal.php'); + + $this->publishes([ + $path => config_path('textlocal.php') + ], 'textlocal'); } } \ No newline at end of file From 09f53ab1a8f638a9fda2af142ca55b795f851feb Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Mon, 29 Oct 2018 22:42:11 +0530 Subject: [PATCH 22/54] Update TextlocalChannel.php --- src/TextlocalChannel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index 7955bee..a3f505e 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -28,7 +28,7 @@ public function __construct(Textlocal $client) public function send($notifiable, Notification $notification) { // Get the mobile number/s from the model - if (! $numbers = $notifiable->routeNotificationFor('textlocal')) { + if (! $numbers = $notifiable->routeNotificationFor('sms')) { return; } //$numbers = (array) $notifiable->routeNotificationForSms(); From e14ddd6c2172b09bfaf81ea673232626be898aa3 Mon Sep 17 00:00:00 2001 From: nikugogoi <95nikass@gmail.com> Date: Fri, 5 Apr 2019 20:49:14 +0530 Subject: [PATCH 23/54] auto package discovery for newer laravel versions need to check if working --- composer.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/composer.json b/composer.json index 00adbc1..be3cce9 100644 --- a/composer.json +++ b/composer.json @@ -30,6 +30,13 @@ "NotificationChannels\\Textlocal\\Test\\": "tests" } }, + "extra": { + "laravel": { + "providers": [ + "NotificationChannels\\Textlocal\\TextlocalServiceProvider" + ] + } + }, "scripts": { "test": "vendor/bin/phpunit" }, From e3b5ef94cd16e1e373ebe3d9f54432675860c7fd Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Mon, 29 Jul 2019 15:11:44 +0530 Subject: [PATCH 24/54] updated to use api_key from config updated api_key in constructor which was previously only taking hash --- src/TextlocalServiceProvider.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/TextlocalServiceProvider.php b/src/TextlocalServiceProvider.php index e4e3a55..3a7a7d9 100644 --- a/src/TextlocalServiceProvider.php +++ b/src/TextlocalServiceProvider.php @@ -21,7 +21,8 @@ function () { return new Textlocal( $textlocalConfig['username'], - $textlocalConfig['hash'] + $textlocalConfig['hash'], + $textlocalConfig['api_key'], ); } ); @@ -47,4 +48,4 @@ public function publishConfiguration() $path => config_path('textlocal.php') ], 'textlocal'); } -} \ No newline at end of file +} From 244e5fbef7033762754e0080f2b067b98488dd38 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Mon, 29 Jul 2019 15:13:33 +0530 Subject: [PATCH 25/54] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c279d9d..daea08b 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,9 @@ put the followings and to your config/services 'sms' => [ 'textlocal' => [ 'username' => env('TEXTLOCAL_USERNAME'), + 'password' => env('TEXTLOCAL_PASSWORD'), 'hash' => env('TEXTLOCAL_HASH'), + 'api_key' => env('TEXTLOCAL_API_KEY'), 'sender' => env('TEXTLOCAL_SENDER'), ] ] @@ -50,6 +52,7 @@ put the followings and to your config/services ``` TEXTLOCAL_USERNAME=Your email id or api key TEXTLOCAL_HASH=get it from url '/docs/' under your API KEYS section + TEXTLOCAL_API_KEY get it from url '/docs/' under your API KEYS section TEXTLOCAL_SENDER=Name of the Sender that will be displayed to the recipient (max 6 Characters). TEXTLOCAL_COUNTRY=Your Two letter(ISO-3166-alpha-2) Country Code. It should be the Country of the TEXTLOCAL account. ``` From 34d77ac693f9a69fdc180a8a38a63a99e48d7395 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Mon, 29 Jul 2019 18:14:00 +0530 Subject: [PATCH 26/54] Update TextlocalServiceProvider.php --- src/TextlocalServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TextlocalServiceProvider.php b/src/TextlocalServiceProvider.php index 3a7a7d9..e9b46a6 100644 --- a/src/TextlocalServiceProvider.php +++ b/src/TextlocalServiceProvider.php @@ -22,7 +22,7 @@ function () { return new Textlocal( $textlocalConfig['username'], $textlocalConfig['hash'], - $textlocalConfig['api_key'], + $textlocalConfig['api_key'] ); } ); From 0db29099836b19d2fd53337e10bfd0c74aff8d93 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Thu, 12 Sep 2019 12:36:14 +0530 Subject: [PATCH 27/54] Added Laravel 6 support --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index be3cce9..1ece52d 100644 --- a/composer.json +++ b/composer.json @@ -13,12 +13,12 @@ ], "require": { "php": ">=5.6.4", - "illuminate/notifications": "^5.3|^5.4|^5.5", - "illuminate/support": "^5.1|^5.2|^5.3|^5.4|^5.5" + "illuminate/notifications": "^5.3|^5.4|^5.5|^5.6|^5.7|^5.8|^6.0", + "illuminate/support": "^5.1|^5.2|^5.3|^5.4|^5.5|^5.6|^5.7|^5.8|^6.0" }, "require-dev": { - "mockery/mockery": "^0.9.5", - "phpunit/phpunit": "4.*" + "mockery/mockery": "^0.9.5|^1.0", + "phpunit/phpunit": "4.*|^8.0" }, "autoload": { "psr-4": { From b4d67d8a4495bf6cf55d839f7857563ce78fe308 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Thu, 12 Sep 2019 12:37:07 +0530 Subject: [PATCH 28/54] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index daea08b..2d96136 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ This package allows to send SMS using Textlocal API using laravel notifications -Here's the latest documentation on Laravel 5.4 Notifications System: - -https://laravel.com/docs/5.4/notifications +Supports Laravel 5.x to 6.x # Found any bugs or improvement open an issue or send me a PR From 56bf3c932e625e6d7bb98532448a8ee34556d089 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Fri, 13 Sep 2019 11:05:38 +0530 Subject: [PATCH 29/54] Update composer.json Co-Authored-By: atymic <50683531+atymic@users.noreply.github.com> --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1ece52d..20a85d6 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "require": { "php": ">=5.6.4", "illuminate/notifications": "^5.3|^5.4|^5.5|^5.6|^5.7|^5.8|^6.0", - "illuminate/support": "^5.1|^5.2|^5.3|^5.4|^5.5|^5.6|^5.7|^5.8|^6.0" + "illuminate/support": "~5.5||~6.0" }, "require-dev": { "mockery/mockery": "^0.9.5|^1.0", From 9ad75cfb531923dfc657d33ccf532ee8b5de170f Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Fri, 13 Sep 2019 11:05:46 +0530 Subject: [PATCH 30/54] Update composer.json Co-Authored-By: atymic <50683531+atymic@users.noreply.github.com> --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 20a85d6..59eda5b 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ }, "require-dev": { "mockery/mockery": "^0.9.5|^1.0", - "phpunit/phpunit": "4.*|^8.0" + "phpunit/phpunit": "~5|^8.0" }, "autoload": { "psr-4": { From 2b94219a1fbe13b2efe8e70baa1789196c2d66dc Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Fri, 13 Sep 2019 11:06:01 +0530 Subject: [PATCH 31/54] Update phpunit.xml.dist Co-Authored-By: atymic <50683531+atymic@users.noreply.github.com> --- phpunit.xml.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f9e8249..7042c52 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -22,7 +22,7 @@ - + From 6e7607fc70279b5ef95f8bc5c661a41cf2cc4eea Mon Sep 17 00:00:00 2001 From: Shankar Akunuri Date: Tue, 29 Oct 2019 22:17:03 +0530 Subject: [PATCH 32/54] Adding unicode support to SMS. (#8) * Update Textlocal.php Adding unicode SMS support. * Update TextlocalChannel.php Adding unicode SMS support. --- src/Textlocal.php | 36 +++++++++++++++++++++++++----------- src/TextlocalChannel.php | 9 ++++++++- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/Textlocal.php b/src/Textlocal.php index 2d874cf..0713e61 100644 --- a/src/Textlocal.php +++ b/src/Textlocal.php @@ -35,6 +35,7 @@ class Textlocal public $warnings = []; public $lastRequest = []; + public $treatAsUnicode = 0; /** * Instantiate the object. @@ -171,7 +172,7 @@ public function getLastRequest() * @param null $sched * @param false $test * @param null $receiptURL - * @param numm $custom + * @param null $custom * @param false $optouts * @param false $simpleReplyService * @@ -195,15 +196,16 @@ public function sendSms($numbers, $message, $sender, $sched = null, $test = fals } $params = [ - 'message' => rawurlencode($message), - 'numbers' => implode(',', $numbers), - 'sender' => rawurlencode($sender), - 'schedule_time' => $sched, - 'test' => $test, - 'receipt_url' => $receiptURL, - 'custom' => $custom, - 'optouts' => $optouts, - 'simple_reply' => $simpleReplyService, + 'message' => rawurlencode($message), + 'numbers' => implode(',', $numbers), + 'sender' => rawurlencode($sender), + 'schedule_time' => $sched, + 'test' => $test, + 'receipt_url' => $receiptURL, + 'custom' => $custom, + 'optouts' => $optouts, + 'simple_reply' => $simpleReplyService, + 'unicode' => $this->treatAsUnicode, ]; return $this->_sendRequest('send', $params); @@ -779,6 +781,18 @@ public function getOptouts($time = null) { return $this->_sendRequest('get_optouts'); } + + /** + * Set unicode mode + * + * @param bool $mode + * @return \NotificationChannels\Textlocal\Textlocal + */ + public function setUnicodeMode(bool $mode) + { + $this->treatAsUnicode = (int) $mode; + return $this; + } } class Contact @@ -865,4 +879,4 @@ function json_encode($a = false) return '{'.implode(',', $result).'}'; } } -} \ No newline at end of file +} diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index a3f505e..50db586 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -50,8 +50,15 @@ public function send($notifiable, Notification $notification) return; } + // Get unicode parameter from notification class + $unicode = false; + if (method_exists($notification, 'getUnicodeMode')) { + $unicode = $notification->getUnicodeMode(); + } + try { - $response = $this->client->sendSms($numbers, $message, $this->sender); + $response = $this->client->setUnicodeMode($unicode) + ->sendSms($numbers, $message, $this->sender); return json_decode(json_encode($response), true); } catch (\Exception $exception) { From d24268bde7e8183f343cfc287cea01c8535fdc5d Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:15:20 +0530 Subject: [PATCH 33/54] updated minimum php version to 7.0 --- composer.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 59eda5b..e2a97e3 100644 --- a/composer.json +++ b/composer.json @@ -12,9 +12,9 @@ } ], "require": { - "php": ">=5.6.4", - "illuminate/notifications": "^5.3|^5.4|^5.5|^5.6|^5.7|^5.8|^6.0", - "illuminate/support": "~5.5||~6.0" + "php": ">=7.0", + "illuminate/notifications": "~5.5|~6.0", + "illuminate/support": "~5.5|~6.0" }, "require-dev": { "mockery/mockery": "^0.9.5|^1.0", From ffebe51db76f754ab6e5ccf319d064e948fe4c86 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:21:45 +0530 Subject: [PATCH 34/54] Update TextlocalChannel.php --- src/TextlocalChannel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index 50db586..a124c25 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -58,9 +58,9 @@ public function send($notifiable, Notification $notification) try { $response = $this->client->setUnicodeMode($unicode) - ->sendSms($numbers, $message, $this->sender); + ->sendSms($numbers, $message, $this->sender); - return json_decode(json_encode($response), true); + return $response; } catch (\Exception $exception) { throw CouldNotSendNotification::serviceRespondedWithAnError($exception, $message); } From 5c0f0da15dbb60a4da02261cb12a5e517778d28b Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:22:43 +0530 Subject: [PATCH 35/54] Update travis.yml --- travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/travis.yml b/travis.yml index ff42c2c..1ca768d 100644 --- a/travis.yml +++ b/travis.yml @@ -1,9 +1,11 @@ language: php php: - - 5.6 - 7.0 - 7.1 + - 7.2 + - 7.3 + - 7.4 env: matrix: From 620d6a41e99c432fcda06103819b55540035d219 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:24:56 +0530 Subject: [PATCH 36/54] Update textlocal.php --- config/textlocal.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/textlocal.php b/config/textlocal.php index 4213454..5649547 100644 --- a/config/textlocal.php +++ b/config/textlocal.php @@ -6,4 +6,4 @@ 'UK' => 'https://api.txtlocal.com/' ], 'country' => env('TEXTLOCAL_COUNTRY', 'IN'), -]; \ No newline at end of file +]; From 8c62761901b9d192b4017261c250915def7ff920 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:26:38 +0530 Subject: [PATCH 37/54] Update TextlocalServiceProvider.php --- src/TextlocalServiceProvider.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/TextlocalServiceProvider.php b/src/TextlocalServiceProvider.php index e9b46a6..0410131 100644 --- a/src/TextlocalServiceProvider.php +++ b/src/TextlocalServiceProvider.php @@ -17,12 +17,12 @@ public function boot() ->needs(Textlocal::class) ->give( function () { - $textlocalConfig = config('services.sms.textlocal'); + $config = config('textlocal'); return new Textlocal( - $textlocalConfig['username'], - $textlocalConfig['hash'], - $textlocalConfig['api_key'] + $config['username'], + $config['hash'], + $config['api_key'] ); } ); From 00fb886cc5036402c558d0e171dc11c45861357e Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:29:47 +0530 Subject: [PATCH 38/54] Update Textlocal.php --- src/Textlocal.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Textlocal.php b/src/Textlocal.php index 0713e61..989b0b6 100644 --- a/src/Textlocal.php +++ b/src/Textlocal.php @@ -42,12 +42,13 @@ class Textlocal * * @param $username * @param $hash + * @param string|null $apiKey */ - public function __construct($username, $hash, $apiKey = false) + public function __construct($username, $hash, $apiKey = null) { $this->username = $username; $this->hash = $hash; - if ($apiKey) { + if (! is_null($apiKey)) { $this->apiKey = $apiKey; } @@ -170,7 +171,7 @@ public function getLastRequest() * @param $message * @param $sender * @param null $sched - * @param false $test + * @param bool $test * @param null $receiptURL * @param null $custom * @param false $optouts @@ -180,7 +181,7 @@ public function getLastRequest() * * @return array|mixed */ - public function sendSms($numbers, $message, $sender, $sched = null, $test = false, $receiptURL = null, $custom = null, $optouts = false, $simpleReplyService = false) + public function sendSms($numbers, $message, $sender, $sched = null, bool $test = false, $receiptURL = null, $custom = null, $optouts = false, $simpleReplyService = false) { if (! is_array($numbers)) { throw new Exception('Invalid $numbers format. Must be an array'); From 4495ca3edf32b7d5d9d4e33749e0313dd947bd41 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:32:55 +0530 Subject: [PATCH 39/54] Update Textlocal.php --- src/Textlocal.php | 54 ----------------------------------------------- 1 file changed, 54 deletions(-) diff --git a/src/Textlocal.php b/src/Textlocal.php index 989b0b6..e8fc1f6 100644 --- a/src/Textlocal.php +++ b/src/Textlocal.php @@ -827,57 +827,3 @@ public function __construct($number, $firstname = '', $lastname = '', $custom1 = $this->custom3 = $custom3; } } - -/* - * If the json_encode function does not exist, then create it.. - */ - -if (! function_exists('json_encode')) { - function json_encode($a = false) - { - if (is_null($a)) { - return 'null'; - } - if ($a === false) { - return 'false'; - } - if ($a === true) { - return 'true'; - } - if (is_scalar($a)) { - if (is_float($a)) { - // Always use "." for floats. - return floatval(str_replace(',', '.', strval($a))); - } - - if (is_string($a)) { - static $jsonReplaces = [['\\', '/', "\n", "\t", "\r", "\b", "\f", '"'], ['\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"']]; - - return '"'.str_replace($jsonReplaces[0], $jsonReplaces[1], $a).'"'; - } else { - return $a; - } - } - $isList = true; - for ($i = 0, reset($a); $i < count($a); $i++, next($a)) { - if (key($a) !== $i) { - $isList = false; - break; - } - } - $result = []; - if ($isList) { - foreach ($a as $v) { - $result[] = json_encode($v); - } - - return '['.implode(',', $result).']'; - } else { - foreach ($a as $k => $v) { - $result[] = json_encode($k).':'.json_encode($v); - } - - return '{'.implode(',', $result).'}'; - } - } -} From 4c981b0c42982ba6375c124682a6e5159d04c66a Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:34:28 +0530 Subject: [PATCH 40/54] Update composer.json --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index e2a97e3..157818d 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,7 @@ ], "require": { "php": ">=7.0", + "ext-json": "*", "illuminate/notifications": "~5.5|~6.0", "illuminate/support": "~5.5|~6.0" }, From 203efc289424c04bba0c572169f685dd4fbbee43 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:35:40 +0530 Subject: [PATCH 41/54] Update TextlocalChannel.php --- src/TextlocalChannel.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index a124c25..a72face 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -12,9 +12,8 @@ class TextlocalChannel public function __construct(Textlocal $client) { - // Initialisation code here $this->client = $client; - $this->sender = config('services.sms.textlocal.sender'); + $this->sender = config('textlocal.sender'); } /** From 8bb470156559213dff0251aa6d3d24f3698f26ee Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:39:18 +0530 Subject: [PATCH 42/54] Update TextlocalChannel.php --- src/TextlocalChannel.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index a72face..8d6ddf4 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -5,11 +5,21 @@ use Illuminate\Notifications\Notification; use NotificationChannels\Textlocal\Exceptions\CouldNotSendNotification; +/** + * Textlocal channel class which is used to interact with core + * textlocal sdk and faciliate to send sms via + * laravel notification system + */ class TextlocalChannel { private $client; private $sender; + /** + * creates a textlocal channel object by using the configs + * + * @param Textlocal $client + */ public function __construct(Textlocal $client) { $this->client = $client; @@ -56,7 +66,8 @@ public function send($notifiable, Notification $notification) } try { - $response = $this->client->setUnicodeMode($unicode) + $response = $this->client + ->setUnicodeMode($unicode) ->sendSms($numbers, $message, $this->sender); return $response; From 56795f2efe7f384d1f20bd6f42c678a5ca093124 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:40:02 +0530 Subject: [PATCH 43/54] Update TextlocalChannel.php --- src/TextlocalChannel.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index 8d6ddf4..aca54ef 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -40,7 +40,6 @@ public function send($notifiable, Notification $notification) if (! $numbers = $notifiable->routeNotificationFor('sms')) { return; } - //$numbers = (array) $notifiable->routeNotificationForSms(); if (empty($numbers)) { return; From 8deb52c6ae8b3dd08a870dd8d450321cb73148d1 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:42:40 +0530 Subject: [PATCH 44/54] Update TextlocalChannel.php --- src/TextlocalChannel.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index aca54ef..4482c43 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -48,8 +48,6 @@ public function send($notifiable, Notification $notification) if (!is_array($numbers)) { $numbers = [$numbers]; } - - //TODO check if numbers are correct // Get the message from the notification class $message = (string) $notification->toSms($notifiable); From 03788690d943b05a4fff18e1127d160018a64613 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:51:56 +0530 Subject: [PATCH 45/54] updated method routeNotificationFor('sms') to routeNotificationFor('Textlocal') updated method routeNotificationFor('sms') to routeNotificationFor('Textlocal') instead of generic --- src/TextlocalChannel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index 4482c43..a622657 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -37,7 +37,7 @@ public function __construct(Textlocal $client) public function send($notifiable, Notification $notification) { // Get the mobile number/s from the model - if (! $numbers = $notifiable->routeNotificationFor('sms')) { + if (! $numbers = $notifiable->routeNotificationFor('Textlocal')) { return; } From 610ba8292a7b4de9c968a2bf7b5196faa4b94b91 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:54:40 +0530 Subject: [PATCH 46/54] Update textlocal.php --- config/textlocal.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/textlocal.php b/config/textlocal.php index 5649547..95f9986 100644 --- a/config/textlocal.php +++ b/config/textlocal.php @@ -1,6 +1,11 @@ env('TEXTLOCAL_USERNAME'), + 'password' => env('TEXTLOCAL_PASSWORD'), + 'hash' => env('TEXTLOCAL_HASH'), + 'api_key' => env('TEXTLOCAL_API_KEY'), + 'sender' => env('TEXTLOCAL_SENDER'), 'request_urls' => [ 'IN' => 'https://api.textlocal.in/', 'UK' => 'https://api.txtlocal.com/' From 8a6196e17433ad0acab1370eb424efd5a08538d4 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:56:01 +0530 Subject: [PATCH 47/54] Update README.md --- README.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 2d96136..9933c82 100644 --- a/README.md +++ b/README.md @@ -34,17 +34,20 @@ Create an account in textlocal then create an API key or hash(password). ### Setting up the textlocal service -put the followings and to your config/services +default textlocal config update as desired ``` -'sms' => [ - 'textlocal' => [ - 'username' => env('TEXTLOCAL_USERNAME'), - 'password' => env('TEXTLOCAL_PASSWORD'), - 'hash' => env('TEXTLOCAL_HASH'), - 'api_key' => env('TEXTLOCAL_API_KEY'), - 'sender' => env('TEXTLOCAL_SENDER'), - ] -] +return [ + 'username' => env('TEXTLOCAL_USERNAME'), + 'password' => env('TEXTLOCAL_PASSWORD'), + 'hash' => env('TEXTLOCAL_HASH'), + 'api_key' => env('TEXTLOCAL_API_KEY'), + 'sender' => env('TEXTLOCAL_SENDER'), + 'request_urls' => [ + 'IN' => 'https://api.textlocal.in/', + 'UK' => 'https://api.txtlocal.com/' + ], + 'country' => env('TEXTLOCAL_COUNTRY', 'IN'), +]; ``` ### Configuring .env ``` @@ -64,7 +67,7 @@ Currently, only textlocal of two country is supported IN(India) and UK(United Ki ## Usage -Implement this method `routeNotificationForSms()` in your notifiable class/model which will return array of mobile numbers. Please make sure the mobile number contains the dial code as well (e.g +91 for India). And lastly implement `toSms()` method in the notification class which will return the (string) sms or template that is defined in textlocal account that needs to be send. +Implement this method `routeNotificationForTextlocal()` in your notifiable class/model which will return array of mobile numbers. Please make sure the mobile number contains the dial code as well (e.g +91 for India). And lastly implement `toSms()` method in the notification class which will return the (string) sms or template that is defined in textlocal account that needs to be send. ### Available Message methods From 4881869c56f23b05bdc64e0bb0e6b54e7841321f Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 30 Oct 2019 11:57:05 +0530 Subject: [PATCH 48/54] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9933c82..57f8694 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,11 @@ return [ 'hash' => env('TEXTLOCAL_HASH'), 'api_key' => env('TEXTLOCAL_API_KEY'), 'sender' => env('TEXTLOCAL_SENDER'), - 'request_urls' => [ - 'IN' => 'https://api.textlocal.in/', - 'UK' => 'https://api.txtlocal.com/' - ], - 'country' => env('TEXTLOCAL_COUNTRY', 'IN'), + 'request_urls' => [ + 'IN' => 'https://api.textlocal.in/', + 'UK' => 'https://api.txtlocal.com/' + ], + 'country' => env('TEXTLOCAL_COUNTRY', 'IN'), ]; ``` ### Configuring .env From ee8e7e5cc0e7d728d9254b6f71e6b1c2b716a091 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Tue, 5 Nov 2019 12:45:08 +0530 Subject: [PATCH 49/54] Update composer.json Co-Authored-By: atymic --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 157818d..4b1c489 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "msonowal/laravel-notification-channel-textlocal", - "description": "This Driver for textlocal sms to send SMS via Textlocal API through laravel notification", + "description": "Textlocal Notifications Channel for Laravel", "homepage": "https://github.com/laravel-notification-channels/textlocal", "license": "MIT", "authors": [ From 610c6e823902f8b742693e951112c4ad0ab06649 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Tue, 5 Nov 2019 12:45:31 +0530 Subject: [PATCH 50/54] Update README.md Co-Authored-By: atymic --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57f8694..3873e7d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ This package allows to send SMS using Textlocal API using laravel notifications -Supports Laravel 5.x to 6.x +Supports Laravel 5.5 to 6.x # Found any bugs or improvement open an issue or send me a PR From 37ad61364940cf45f1264b907fc28c0c66d24bd1 Mon Sep 17 00:00:00 2001 From: tsainadh <56969292+tsainadh@users.noreply.github.com> Date: Mon, 9 Dec 2019 22:00:56 +0530 Subject: [PATCH 51/54] Update TextlocalChannel.php (#12) set sender id from notification if having multiple sender id's to manage. --- src/TextlocalChannel.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index a622657..0637ade 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -62,6 +62,10 @@ public function send($notifiable, Notification $notification) $unicode = $notification->getUnicodeMode(); } + if (method_exists($notification, 'getSenderId')) { + $this->sender = $notification->getSenderId(); + } + try { $response = $this->client ->setUnicodeMode($unicode) From 5fc9ae9b12cebb8f5cabef87b092e0647d07e1d3 Mon Sep 17 00:00:00 2001 From: Manash Sonowal Date: Wed, 29 Apr 2020 02:04:16 +0530 Subject: [PATCH 52/54] added laravel 7 support added test work in progress --- .gitignore | 7 ++ README.md | 27 +++++--- composer.json | 11 +++- phpunit.xml.dist | 4 +- src/Textlocal.php | 27 ++++---- src/TextlocalChannel.php | 5 +- src/TextlocalServiceProvider.php | 4 ++ tests/ExampleTest.php | 12 ---- tests/TextlocalNotificationTest.php | 99 +++++++++++++++++++++++++++++ 9 files changed, 158 insertions(+), 38 deletions(-) create mode 100644 .gitignore delete mode 100644 tests/ExampleTest.php create mode 100644 tests/TextlocalNotificationTest.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..909768d --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +/vendor +build +composer.phar +composer.lock +.DS_Store +.phpunit.result.cache +.vscode \ No newline at end of file diff --git a/README.md b/README.md index 3873e7d..ce5cf31 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# Textlocal SMS Notifications Channel for Laravel + This package allows to send SMS using Textlocal API using laravel notifications Supports Laravel 5.5 to 6.x @@ -8,7 +10,7 @@ Supports Laravel 5.5 to 6.x [![License](https://poser.pugx.org/msonowal/laravel-notification-channel-textlocal/license)](https://packagist.org/packages/msonowal/laravel-notification-channel-textlocal) [![Total Downloads](https://poser.pugx.org/msonowal/laravel-notification-channel-textlocal/downloads)](https://packagist.org/packages/msonowal/laravel-notification-channel-textlocal) -This package makes it easy to send notifications using [textlocal](https://www.textlocal.in/) with Laravel 5.3.+ +This package makes it easy to send notifications using [textlocal](https://www.textlocal.in/) the Laravel way @@ -17,7 +19,6 @@ This package makes it easy to send notifications using [textlocal](https://www.t - [Installation](#installation) - [Setting up the textlocal service](#setting-up-the-textlocal-service) - [Usage](#usage) - - [Available Message methods](#available-message-methods) - [Changelog](#changelog) - [Testing](#testing) - [Security](#security) @@ -32,7 +33,7 @@ Create an account in textlocal then create an API key or hash(password). `composer require msonowal/laravel-notification-channel-textlocal` -### Setting up the textlocal service +### Setting up the Textlocal service default textlocal config update as desired ``` @@ -52,10 +53,10 @@ return [ ### Configuring .env ``` TEXTLOCAL_USERNAME=Your email id or api key - TEXTLOCAL_HASH=get it from url '/docs/' under your API KEYS section - TEXTLOCAL_API_KEY get it from url '/docs/' under your API KEYS section + TEXTLOCAL_HASH=get it from url '/docs/' under your API KEYS section of textlocal + TEXTLOCAL_API_KEY get it from url '/docs/' under your API KEYS section of textlocal TEXTLOCAL_SENDER=Name of the Sender that will be displayed to the recipient (max 6 Characters). - TEXTLOCAL_COUNTRY=Your Two letter(ISO-3166-alpha-2) Country Code. It should be the Country of the TEXTLOCAL account. + TEXTLOCAL_COUNTRY=Your Two letter(ISO-3166-alpha-2) Country Code. It should be the Country of the TEXTLOCAL account. defaulted to IN ``` ### Publish Config @@ -69,9 +70,19 @@ Currently, only textlocal of two country is supported IN(India) and UK(United Ki Implement this method `routeNotificationForTextlocal()` in your notifiable class/model which will return array of mobile numbers. Please make sure the mobile number contains the dial code as well (e.g +91 for India). And lastly implement `toSms()` method in the notification class which will return the (string) sms or template that is defined in textlocal account that needs to be send. -### Available Message methods +And if you want to have a specific sender based on Notification, e.g. like you are sending promotional notification using one and another for transaction then you can just define this method in your notification class which will return your sender id for that notification only +``` +public function getUnicodeMode() +{ + return 'YOUR_SENDER_ID'; +} +``` -A list of all available options +Unicode support +If you want to send the notification content to have unicode support set define this method in your notification which will return boolean based on which the sms will set the unicode mode in textlocal API +``` +getUnicodeMode +``` ## Changelog diff --git a/composer.json b/composer.json index 4b1c489..e841a7d 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,13 @@ { "name": "msonowal/laravel-notification-channel-textlocal", "description": "Textlocal Notifications Channel for Laravel", + "keywords": [ + "laravel", + "notifications", + "textlocal", + "sms", + "india" + ], "homepage": "https://github.com/laravel-notification-channels/textlocal", "license": "MIT", "authors": [ @@ -14,8 +21,8 @@ "require": { "php": ">=7.0", "ext-json": "*", - "illuminate/notifications": "~5.5|~6.0", - "illuminate/support": "~5.5|~6.0" + "illuminate/notifications": "~5.5|^6.0|^7.0", + "illuminate/support": "~5.5|^6.0|^7.0" }, "require-dev": { "mockery/mockery": "^0.9.5|^1.0", diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7042c52..66778ad 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -10,7 +10,7 @@ processIsolation="false" stopOnFailure="false"> - + tests @@ -26,4 +26,4 @@ - + \ No newline at end of file diff --git a/src/Textlocal.php b/src/Textlocal.php index e8fc1f6..f1afcfb 100644 --- a/src/Textlocal.php +++ b/src/Textlocal.php @@ -23,7 +23,6 @@ class Textlocal const REQUEST_HANDLER = 'curl'; private $request_url; - private $country; private $username; private $hash; @@ -37,6 +36,8 @@ class Textlocal public $lastRequest = []; public $treatAsUnicode = 0; + public $defaultSender; + /** * Instantiate the object. * @@ -44,16 +45,17 @@ class Textlocal * @param $hash * @param string|null $apiKey */ - public function __construct($username, $hash, $apiKey = null) + public function __construct(string $sender, string $requestUrl, $username, $hash, $apiKey = null) { + $this->defaultSender = $sender; + $this->username = $username; $this->hash = $hash; if (! is_null($apiKey)) { $this->apiKey = $apiKey; } - $this->country = config('textlocal.country'); - $this->request_url = config('textlocal.request_urls')[$this->country]; + $this->request_url = $requestUrl; } /** @@ -118,7 +120,8 @@ private function _sendRequestCurl($command, $params) // Initialize handle $ch = curl_init($url); curl_setopt_array( - $ch, [ + $ch, + [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => $params, CURLOPT_RETURNTRANSFER => true, @@ -181,7 +184,7 @@ public function getLastRequest() * * @return array|mixed */ - public function sendSms($numbers, $message, $sender, $sched = null, bool $test = false, $receiptURL = null, $custom = null, $optouts = false, $simpleReplyService = false) + public function sendSms($numbers, $message, $sender = null, $sched = null, bool $test = false, $receiptURL = null, $custom = null, $optouts = false, $simpleReplyService = false) { if (! is_array($numbers)) { throw new Exception('Invalid $numbers format. Must be an array'); @@ -189,8 +192,9 @@ public function sendSms($numbers, $message, $sender, $sched = null, bool $test = if (empty($message)) { throw new Exception('Empty message'); } - if (empty($sender)) { - throw new Exception('Empty sender name'); + if (empty($sender) || is_null($sender)) { + $sender = $this->defaultSender; + //throw new Exception('Empty sender name'); } if (! is_null($sched) && ! is_numeric($sched)) { throw new Exception('Invalid date format. Use numeric epoch format'); @@ -236,8 +240,9 @@ public function sendSmsGroup($groupId, $message, $sender = null, $sched = null, if (empty($message)) { throw new Exception('Empty message'); } - if (empty($sender)) { - throw new Exception('Empty sender name'); + if (empty($sender) || is_null($sender)) { + $sender = $this->defaultSender; + //throw new Exception('Empty sender name'); } if (! is_null($sched) && ! is_numeric($sched)) { throw new Exception('Invalid date format. Use numeric epoch format'); @@ -785,7 +790,7 @@ public function getOptouts($time = null) /** * Set unicode mode - * + * * @param bool $mode * @return \NotificationChannels\Textlocal\Textlocal */ diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index 0637ade..ad61081 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -13,7 +13,7 @@ class TextlocalChannel { private $client; - private $sender; + private $sender = null; /** * creates a textlocal channel object by using the configs @@ -23,7 +23,6 @@ class TextlocalChannel public function __construct(Textlocal $client) { $this->client = $client; - $this->sender = config('textlocal.sender'); } /** @@ -59,7 +58,7 @@ public function send($notifiable, Notification $notification) // Get unicode parameter from notification class $unicode = false; if (method_exists($notification, 'getUnicodeMode')) { - $unicode = $notification->getUnicodeMode(); + $unicode = (bool) $notification->getUnicodeMode(); } if (method_exists($notification, 'getSenderId')) { diff --git a/src/TextlocalServiceProvider.php b/src/TextlocalServiceProvider.php index 0410131..e7bb8d8 100644 --- a/src/TextlocalServiceProvider.php +++ b/src/TextlocalServiceProvider.php @@ -19,7 +19,11 @@ public function boot() function () { $config = config('textlocal'); + $requestUrl = $config['request_urls'][$config['country']]; + return new Textlocal( + $config['sender'], + $requestUrl, $config['username'], $config['hash'], $config['api_key'] diff --git a/tests/ExampleTest.php b/tests/ExampleTest.php deleted file mode 100644 index b2cb7d5..0000000 --- a/tests/ExampleTest.php +++ /dev/null @@ -1,12 +0,0 @@ -assertTrue(true); - } -} diff --git a/tests/TextlocalNotificationTest.php b/tests/TextlocalNotificationTest.php new file mode 100644 index 0000000..2fc2d4f --- /dev/null +++ b/tests/TextlocalNotificationTest.php @@ -0,0 +1,99 @@ +sms = M::mock(Textlocal::class, 'username', 'hash'); + + $this->channel = new TextlocalChannel($this->sms); + } + + public function tearDown(): void + { + M::close(); + } + + public function test_it_can_send_a_notification(): void + { + $this->sms->shouldReceive('setUnicodeMode') + // ->once() + ->with(false) + ->andReturn($this->sms); + + $this->sms->shouldReceive('sendSms') + // ->once() + ->with('+1234567890', 'test-template', null); + + + $this->channel->send(new TestNotifiable(), new TestNotification()); + } + + public function test_it_can_send_a_notification_to_multiple_phones(): void + { + $this->sms->shouldReceive('send') + ->once() + ->with( + ['+1234567890', '+0987654321', '+1234554321'], + 'hello', + 'John_Doe', + ); + + $this->channel->send(new TestNotifiableWithManyPhones(), new TestNotification()); + } +} + +class TestNotifiable +{ + use Notifiable; + + // Laravel v5.6+ passes the notification instance here + // So we need to add `Notification $notification` argument to check it when this project stops supporting < 5.6 + public function routeNotificationForTextlocal() + { + return '+1234567890'; + } +} + +class TestNotifiableWithoutRouteNotificationForTextlocal extends TestNotifiable +{ + public function routeNotificationForTextlocal() + { + return false; + } +} + +class TestNotifiableWithManyPhones extends TestNotifiable +{ + public function routeNotificationForsmsru() + { + return ['+1234567890', '+919706353416', '+1234554321']; + } +} + +class TestNotification extends Notification +{ + public function toSms() + { + return 'test-template'; + } +} From 6c364dbefa486c587d99735d36dc0ecd6f314e4e Mon Sep 17 00:00:00 2001 From: msonowal Date: Tue, 18 May 2021 13:02:17 +0530 Subject: [PATCH 53/54] updated some static analyzed code fixes --- src/Textlocal.php | 4 ++-- src/TextlocalChannel.php | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Textlocal.php b/src/Textlocal.php index f1afcfb..a3fc4c7 100644 --- a/src/Textlocal.php +++ b/src/Textlocal.php @@ -759,11 +759,11 @@ public function getSurveys() * * @return array|mixed */ - public function getSurveyDetails() + public function getSurveyDetails($surveyid) { $options = ['survey_id' => $surveyid]; - return $this->_sendRequest('get_survey_details'); + return $this->_sendRequest('get_survey_details', $options); } /** diff --git a/src/TextlocalChannel.php b/src/TextlocalChannel.php index ad61081..b8cfc17 100644 --- a/src/TextlocalChannel.php +++ b/src/TextlocalChannel.php @@ -6,10 +6,15 @@ use NotificationChannels\Textlocal\Exceptions\CouldNotSendNotification; /** - * Textlocal channel class which is used to interact with core + * Textlocal channel class which is used to interact with core. + * * textlocal sdk and faciliate to send sms via * laravel notification system + * + * @author Manash Sonowal + * */ + class TextlocalChannel { private $client; From 68a140338283352a04b386c39111def3d1512434 Mon Sep 17 00:00:00 2001 From: msonowal Date: Tue, 18 May 2021 13:14:56 +0530 Subject: [PATCH 54/54] updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eeb7dd9..b2a13cd 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ This package makes it easy to send notifications using [textlocal](https://www.t Create an account in textlocal then create an API key or hash(password). -`composer require msonowal/laravel-notification-channel-textlocal` +`composer require laravel-notification-channels/textlocal` ### Setting up the Textlocal service