diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..143d7849 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# 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 +/tests export-ignore \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d13e72b1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/vendor +build +composer.phar +composer.lock +.idea \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..aafbbc81 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + +All notable changes to `Intercom Notification` will be documented in this file + +## 0.0.1 - 2018-09-13 + +- initial release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..4da74e3f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,55 @@ +# Contributing + +Contributions are **welcome** and will be fully **credited**. + +Please read and understand the contribution guide before creating an issue or pull request. + +## Etiquette + +This project is open source, and as such, the maintainers give their free time to build and maintain the source code +held within. They make the code freely available in the hope that it will be of use to other developers. It would be +extremely unfair for them to suffer abuse or anger for their hard work. + +Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the +world that developers are civilized and selfless people. + +It's the duty of the maintainer to ensure that all submissions to the project are of sufficient +quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. + +## Viability + +When requesting or submitting new features, first consider whether it might be useful to others. Open +source projects are used by many developers, who may have entirely different needs to your own. Think about +whether or not your feature is likely to be used by other users of the project. + +## Procedure + +Before filing an issue: + +- Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. +- Check to make sure your feature suggestion isn't already present within the project. +- Check the pull requests tab to ensure that the bug doesn't have a fix in progress. +- Check the pull requests tab to ensure that the feature isn't already in progress. + +Before submitting a pull request: + +- Check the codebase to ensure that your feature doesn't already exist. +- Check the pull requests to ensure that another person hasn't already submitted the feature or fix. + +## Requirements + +If the project maintainer has any additional requirements, you will find them listed here. + +- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). + +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. + +- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. + +- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. + +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. + +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. + +**Happy coding**! diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..85d71d91 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) Andrey Telesh Y. + +> 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 746a917d..6e7e4306 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,130 @@ -# new-channels +# Intercom notifications channel for Laravel 5.6 -Discuss about new channel proposals our share your finished channels in the [proposal issue](https://github.com/laravel-notification-channels/new-channels/issues/6). +[![Latest Version on Packagist](https://img.shields.io/packagist/v/ftw-soft/intercom-notification-channel.svg?style=flat-square)](https://packagist.org/packages/ftw-soft/intercom-notification-channel) +[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md) +[![Build Status](https://img.shields.io/travis/ftw-soft/intercom-notification-channel/master.svg?style=flat-square)](https://travis-ci.org/ftw-soft/intercom-notification-channel) +[![StyleCI](https://styleci.io/repos/148610087/shield)](https://styleci.io/repos/148610087) +[![SensioLabsInsight](https://img.shields.io/sensiolabs/i/ca6db073-da33-40bb-97b0-ddd1d0f5987f.svg?style=flat-square)](https://insight.sensiolabs.com/projects/ca6db073-da33-40bb-97b0-ddd1d0f5987f) +[![Quality Score](https://img.shields.io/scrutinizer/g/ftw-soft/intercom-notification-channel.svg?style=flat-square)](https://scrutinizer-ci.com/g/ftw-soft/intercom-notification-channel) +[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/ftw-soft/intercom-notification-channel/master.svg?style=flat-square)](https://scrutinizer-ci.com/g/ftw-soft/intercom-notification-channel/?branch=master) +[![Total Downloads](https://img.shields.io/packagist/dt/ftw-soft/intercom-notification-channel.svg?style=flat-square)](https://packagist.org/packages/ftw-soft/intercom-notification-channel) -Take a look at our [FAQ](http://laravel-notification-channels.com/) to see our small list of rules, to provide top-notch notification channels. +This package makes it easy to send notifications using [Intercom](https://app.intercom.com) with Laravel 5.6. + +## Contents + +- [Installation](#installation) + - [Setting up the Intercom service](#setting-up-the-intercom-service) +- [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: + +``` bash +composer require ftw-soft/intercom-notification-channel +``` + +### Setting up the Intercom service + +Once installed you need to register the service provider with the application. Open up `config/app.php` and find the `providers` key. + +``` php +'providers' => [ + + \FtwSoft\NotificationChannels\Intercom\IntercomServiceProvider::class, + +] +``` + +Put the followings to your config/services + +``` php +'intercom' => [ + 'token' => env('INTERCOM_API_KEY') +] +``` + +Add your Intercom Token to `.env` + +``` +INTERCOM_API_KEY=xxx +``` + + +## Usage + +Now you can use the channel in your `via()` method inside the notification: + +``` php +use FtwSoft\NotificationChannels\Intercom\Contracts\IntercomNotification; +use FtwSoft\NotificationChannels\Intercom\IntercomChannel; +use FtwSoft\NotificationChannels\Intercom\IntercomMessage; +use Illuminate\Notifications\Notification; + +class TestNotification extends Notification implements IntercomNotification +{ + public function via($notifiable) + { + return ["intercom"]; + } + + public function toIntercom($notifiable): IntercomMessage + { + return IntercomMessage::create("Hey User!") + ->from(123) + ->toUserId(321); + } +} +``` + + +### Available methods + +- `body('')`: Accepts a string value for the Intercom message body +- `email()`: Accepts a string value for the Intercom message type `email` +- `inapp()`: Accepts a string value for the Intercom message type `inapp` (default) +- `subject('')`: Accepts a string value for the Intercom message body (using with `email` type) +- `plain()`: Accepts a string value for the Intercom message plain template +- `personal()`: Accepts a string value for the Intercom message personal template +- `from('123')`: Accepts a string value of the admin's id (sender) +- `to(['type' => 'user', 'id' => '321'])`: Accepts an array value for the recipient data +- `toUserId('')`: Accepts a string value for the Intercom message user by id recipient +- `toUserEmail('')`: Accepts a string value for the Intercom message user by email recipient +- `toContactId('')`: Accepts a string value for the Intercom message contact by id recipient + +More info about fields read in [Intercom API Reference](https://developers.intercom.com/intercom-api-reference/reference#admin-initiated-conversation) + +## 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 android991@gmail.com instead of using the issue tracker. + +## Contributing + +Please see [CONTRIBUTING](CONTRIBUTING.md) for details. + +## Credits + +- [Andrey Telesh](https://github.com/ftw-soft) +- [All Contributors](../../contributors) + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more information. diff --git a/composer.json b/composer.json new file mode 100644 index 00000000..2c2dd24f --- /dev/null +++ b/composer.json @@ -0,0 +1,40 @@ +{ + "name": "ftw-soft/intercom-notification-channel", + "description": "Intercom Notifications Driver", + "type": "library", + "license": "MIT", + "require": { + "php": ">=7.1.3", + "guzzlehttp/guzzle": "^6.3", + "intercom/intercom-php": "^3.2", + "illuminate/notifications": ">=5.5", + "illuminate/support": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "~7.0", + "mockery/mockery": "^1.1" + }, + "autoload": { + "psr-4": { + "FtwSoft\\NotificationChannels\\Intercom\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "FtwSoft\\NotificationChannels\\Intercom\\Tests\\": "tests" + } + }, + "scripts": { + "test": "vendor/bin/phpunit" + }, + "config": { + "sort-packages": true + }, + "extra": { + "laravel": { + "providers": [ + "FtwSoft\\NotificationChannels\\Intercom\\IntercomServiceProvider" + ] + } + } +} diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 00000000..f6c8c51c --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,29 @@ + + + + + tests + + + + + src/ + + + + + + + + + + \ No newline at end of file diff --git a/src/Contracts/IntercomNotification.php b/src/Contracts/IntercomNotification.php new file mode 100644 index 00000000..bd914776 --- /dev/null +++ b/src/Contracts/IntercomNotification.php @@ -0,0 +1,18 @@ + + */ + +namespace FtwSoft\NotificationChannels\Intercom\Exceptions; + + +class IntercomException extends \Exception +{ + +} \ No newline at end of file diff --git a/src/Exceptions/InvalidArgumentException.php b/src/Exceptions/InvalidArgumentException.php new file mode 100644 index 00000000..a4eacae9 --- /dev/null +++ b/src/Exceptions/InvalidArgumentException.php @@ -0,0 +1,18 @@ + + */ + +namespace FtwSoft\NotificationChannels\Intercom\Exceptions; + +use InvalidArgumentException as BaseInvalidArgmentException; + +/** + * @inheritdoc + */ +class InvalidArgumentException extends BaseInvalidArgmentException +{ + +} \ No newline at end of file diff --git a/src/Exceptions/MessageIsNotCompleteException.php b/src/Exceptions/MessageIsNotCompleteException.php new file mode 100644 index 00000000..ce4046d8 --- /dev/null +++ b/src/Exceptions/MessageIsNotCompleteException.php @@ -0,0 +1,49 @@ + + */ + +namespace FtwSoft\NotificationChannels\Intercom\Exceptions; + + +use FtwSoft\NotificationChannels\Intercom\IntercomMessage; +use Throwable; + +class MessageIsNotCompleteException extends IntercomException +{ + /** + * @var IntercomMessage + */ + private $intercomMessage; + + /** + * MessageIsNotCompleteException constructor. + * + * @param IntercomMessage $intercomMessage + * @param string $message + * @param int $code + * @param Throwable|null $previous + */ + public function __construct( + IntercomMessage $intercomMessage, + string $message = "", + int $code = 0, + Throwable $previous = null + ) { + $this->intercomMessage = $intercomMessage; + + parent::__construct($message, $code, $previous); + } + + /** + * @return IntercomMessage + */ + public function getIntercomMessage(): IntercomMessage + { + return $this->intercomMessage; + } + + +} \ No newline at end of file diff --git a/src/Exceptions/RequestException.php b/src/Exceptions/RequestException.php new file mode 100644 index 00000000..a50b39da --- /dev/null +++ b/src/Exceptions/RequestException.php @@ -0,0 +1,43 @@ + + */ + +namespace FtwSoft\NotificationChannels\Intercom\Exceptions; + +use Throwable; +use GuzzleHttp\Exception\RequestException as BaseRequestException; + +class RequestException extends IntercomException +{ + + /** + * @var BaseRequestException + */ + private $baseException; + + /** + * @inheritDoc + */ + public function __construct( + BaseRequestException $baseException, + string $message = "", + int $code = 0, + ?Throwable $previous = null + ) { + $this->baseException = $baseException; + + parent::__construct($message, $code, $previous); + } + + /** + * @return BaseRequestException + */ + public function getBaseException(): BaseRequestException + { + return $this->baseException; + } + +} \ No newline at end of file diff --git a/src/IntercomChannel.php b/src/IntercomChannel.php new file mode 100644 index 00000000..33642d94 --- /dev/null +++ b/src/IntercomChannel.php @@ -0,0 +1,90 @@ + + */ + +namespace FtwSoft\NotificationChannels\Intercom; + +use FtwSoft\NotificationChannels\Intercom\Contracts\IntercomNotification; +use FtwSoft\NotificationChannels\Intercom\Exceptions\InvalidArgumentException; +use FtwSoft\NotificationChannels\Intercom\Exceptions\MessageIsNotCompleteException; +use FtwSoft\NotificationChannels\Intercom\Exceptions\RequestException; +use GuzzleHttp\Exception\BadResponseException; +use Illuminate\Notifications\Notification; +use Intercom\IntercomClient; + +/** + * Class IntercomNotificationChannel + * + * @package FtwSoft\NotificationChannels\Intercom\Notifications + */ +class IntercomChannel +{ + + /** + * @var \Intercom\IntercomClient + */ + private $client; + + /** + * IntercomNotificationChannel constructor. + * + * @param \Intercom\IntercomClient $client + */ + public function __construct(IntercomClient $client) + { + $this->client = $client; + } + + /** + * Send the given notification via Intercom API + * + * @param mixed $notifiable + * @param \Illuminate\Notifications\Notification $notification + * + * @return void + * @throws \FtwSoft\NotificationChannels\Intercom\Exceptions\RequestException When server responses with a bad HTTP + * code + * @throws \FtwSoft\NotificationChannels\Intercom\Exceptions\MessageIsNotCompleteException When message is not + * filled correctly + * @throws \GuzzleHttp\Exception\GuzzleException Other Guzzle uncatched exceptions + * + * @see https://developers.intercom.com/intercom-api-reference/reference#admin-initiated-conversation + */ + public function send($notifiable, Notification $notification): void + { + try { + if (!$notification instanceof IntercomNotification) { + throw new InvalidArgumentException( + sprintf("The notification must implement %s interface", IntercomNotification::class) + ); + } + + $message = $notification->toIntercom($notifiable); + + if (!$message->toIsGiven()) { + if (!$to = $notifiable->routeNotificationFor('intercom')) { + throw new MessageIsNotCompleteException($message, 'Recipient is not provided'); + } + + $message->to($to); + } + + if (!$message->isValid()) { + throw new MessageIsNotCompleteException( + $message, + "The message is not valid. Please check that you have filled required params" + ); + } + + $this->client->messages->create( + $message->toArray() + ); + } catch (BadResponseException $exception) { + throw new RequestException($exception); + } + } + +} \ No newline at end of file diff --git a/src/IntercomMessage.php b/src/IntercomMessage.php new file mode 100644 index 00000000..a37d97c5 --- /dev/null +++ b/src/IntercomMessage.php @@ -0,0 +1,214 @@ + + */ + +namespace FtwSoft\NotificationChannels\Intercom; + +class IntercomMessage +{ + + const TYPE_EMAIL = 'email'; + + const TYPE_INAPP = 'inapp'; + + const TEMPLATE_PLAIN = 'plain'; + + const TEMPLATE_PERSONAL = 'personal'; + + /** + * @param string $body + * + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public static function create(?string $body = null): IntercomMessage + { + return new static($body); + } + + /** + * @var array + */ + public $payload; + + /** + * IntercomMessage constructor. + * + * @param string $body + */ + public function __construct(?string $body = null) + { + if ($body !== null) { + $this->body($body); + } + + $this->inapp(); + } + + /** + * @param string $body + * + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public function body(string $body): IntercomMessage + { + $this->payload['body'] = $body; + + return $this; + } + + /** + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public function email(): IntercomMessage + { + $this->payload['message_type'] = self::TYPE_EMAIL; + + return $this; + } + + /** + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public function inapp(): IntercomMessage + { + $this->payload['message_type'] = self::TYPE_INAPP; + + return $this; + } + + /** + * @param string $value + * + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public function subject(string $value): IntercomMessage + { + $this->payload['subject'] = $value; + + return $this; + } + + /** + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public function plain(): IntercomMessage + { + $this->payload['template'] = self::TEMPLATE_PLAIN; + + return $this; + } + + /** + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public function personal(): IntercomMessage + { + $this->payload['template'] = self::TEMPLATE_PERSONAL; + + return $this; + } + + /** + * @param string $adminId + * + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public function from(string $adminId): IntercomMessage + { + $this->payload['from'] = [ + 'type' => 'admin', + 'id' => $adminId + ]; + + return $this; + } + + /** + * @param array $value + * + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public function to(array $value): IntercomMessage + { + $this->payload['to'] = $value; + + return $this; + } + + /** + * @param string $id + * + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public function toUserId(string $id): IntercomMessage + { + $this->payload['to'] = [ + 'type' => 'user', + 'id' => $id + ]; + + return $this; + } + + /** + * @param string $email + * + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public function toUserEmail(string $email): IntercomMessage + { + $this->payload['to'] = [ + 'type' => 'user', + 'email' => $email + ]; + + return $this; + } + + /** + * @param string $id + * + * @return \FtwSoft\NotificationChannels\Intercom\IntercomMessage + */ + public function toContactId(string $id): IntercomMessage + { + $this->payload['to'] = [ + 'type' => 'contact', + 'id' => $id + ]; + + return $this; + } + + /** + * @return bool + */ + public function isValid(): bool + { + return isset( + $this->payload['body'], + $this->payload['from'], + $this->payload['to'] + ); + } + + /** + * @return bool + */ + public function toIsGiven(): bool + { + return isset($this->payload['to']); + } + + /** + * @return array + */ + public function toArray(): array + { + return $this->payload; + } + +} \ No newline at end of file diff --git a/src/IntercomServiceProvider.php b/src/IntercomServiceProvider.php new file mode 100644 index 00000000..c1a4d57a --- /dev/null +++ b/src/IntercomServiceProvider.php @@ -0,0 +1,43 @@ + + */ + +namespace FtwSoft\NotificationChannels\Intercom; + +use Illuminate\Support\Facades\Config; +use Illuminate\Support\Facades\Notification; +use Illuminate\Support\ServiceProvider; +use Intercom\IntercomClient; +use Illuminate\Contracts\Foundation\Application; + +class IntercomServiceProvider extends ServiceProvider +{ + /** + * Bootstrap the application services. + */ + public function boot() + { + $this->app->when(IntercomChannel::class) + ->needs(IntercomClient::class) + ->give(function () { + /** @var Config $config */ + return new IntercomClient( + Config::get('services.intercom.token'), + null + ); + }); + } + + /** + * Register any package services. + */ + public function register() + { + Notification::extend('intercom', function (Application $app) { + return $app->make(IntercomChannel::class); + }); + } +} \ No newline at end of file diff --git a/tests/IntercomChannelTest.php b/tests/IntercomChannelTest.php new file mode 100644 index 00000000..a7fa30a9 --- /dev/null +++ b/tests/IntercomChannelTest.php @@ -0,0 +1,141 @@ + + */ + +namespace FtwSoft\NotificationChannels\Intercom\Tests; + +use FtwSoft\NotificationChannels\Intercom\Exceptions\InvalidArgumentException; +use FtwSoft\NotificationChannels\Intercom\Exceptions\MessageIsNotCompleteException; +use FtwSoft\NotificationChannels\Intercom\Exceptions\RequestException; +use FtwSoft\NotificationChannels\Intercom\IntercomChannel; +use FtwSoft\NotificationChannels\Intercom\IntercomMessage; +use FtwSoft\NotificationChannels\Intercom\Tests\Mocks\TestNotifiable; +use FtwSoft\NotificationChannels\Intercom\Tests\Mocks\TestNotification; +use GuzzleHttp\Exception\BadResponseException; +use GuzzleHttp\Psr7\Request; +use Illuminate\Notifications\Notification; +use Intercom\IntercomMessages; +use Mockery\Adapter\Phpunit\MockeryTestCase; +use Intercom\IntercomClient; + +class IntercomChannelTest extends MockeryTestCase +{ + + /** + * @var \Intercom\IntercomMessages|\Mockery\Mock + */ + private $intercomMessages; + + /** + * @var \Intercom\IntercomClient + */ + private $intercom; + + /** + * @var \FtwSoft\NotificationChannels\Intercom\IntercomChannel + */ + private $channel; + + protected function setUp() + { + parent::setUp(); + + $this->intercom = new IntercomClient(null, null); + $this->intercomMessages = \Mockery::mock(IntercomMessages::class, $this->intercom); + $this->intercom->messages = $this->intercomMessages; + $this->channel = new IntercomChannel($this->intercom); + } + + public function testItCanSendMessage(): void + { + $notification = new TestNotification( + IntercomMessage::create('Hello World!') + ->from(123) + ->toUserId(321) + ); + + $this->intercomMessages->shouldReceive('create') + ->once() + ->with([ + 'body' => 'Hello World!', + 'message_type' => 'inapp', + 'from' => [ + 'type' => 'admin', + 'id' => '123' + ], + 'to' => [ + 'type' => 'user', + 'id' => '321' + ] + ]); + + $this->channel->send(new TestNotifiable(), $notification); + $this->assertPostConditions(); + } + + public function testInThrowsAnExceptionWhenNotificationIsNotAnIntercomNotification() + { + $notification = new Notification(); + + $this->expectException(InvalidArgumentException::class); + $this->channel->send(new TestNotifiable(), $notification); + } + + public function testItThrowsAnExceptionWhenRecipientIsNotProvided() + { + $notification = new TestNotification( + IntercomMessage::create('Hello World!') + ->from(123) + ); + + $this->expectException(MessageIsNotCompleteException::class); + $this->channel->send(new TestNotifiable(), $notification); + } + + public function testItThrowsAnExceptionSomeOfRequiredParamsAreNotDefined() + { + $notification = new TestNotification( + IntercomMessage::create() + ->from(123) + ->toUserId(321) + ); + + $this->expectException(MessageIsNotCompleteException::class); + $this->channel->send(new TestNotifiable(), $notification); + } + + public function testItThrowsRequestExceptionOnGuzzleBadResponseException(): void + { + $this->intercomMessages->shouldReceive('create') + ->once() + ->andThrow(new BadResponseException('Test case', new Request('post', 'http://foo.bar'))); + + $notification = new TestNotification( + IntercomMessage::create('Hello World!') + ->from(123) + ->toUserId(321) + ); + + $this->expectException(RequestException::class); + + $this->channel->send(new TestNotifiable(), $notification); + } + + public function testItGetsToFromRouteNotificationForIntercomMethod(): void + { + $this->intercomMessages->shouldReceive('create'); + + $message = IntercomMessage::create('Hello World!') + ->from(123); + $notification = new TestNotification($message); + + $expected = ['type' => 'user', 'id' => 321]; + $this->channel->send(new TestNotifiable($expected), $notification); + + $this->assertEquals($expected, $message->payload['to']); + } + +} \ No newline at end of file diff --git a/tests/IntercomMessageTest.php b/tests/IntercomMessageTest.php new file mode 100644 index 00000000..f0c93db7 --- /dev/null +++ b/tests/IntercomMessageTest.php @@ -0,0 +1,213 @@ +assertEquals('inapp', IntercomMessage::TYPE_INAPP); + } + + public function testThatTypeEmailConstantSetCorrectly(): void + { + $this->assertEquals('email', IntercomMessage::TYPE_EMAIL); + } + + public function testThatTemplatePlainConstantSetCorrectly(): void + { + $this->assertEquals('plain', IntercomMessage::TEMPLATE_PLAIN); + } + + public function testThatTemplatePersonalConstantSetCorrectly(): void + { + $this->assertEquals('personal', IntercomMessage::TEMPLATE_PERSONAL); + } + + public function testItAcceptsBodyWhenConstructed(): void + { + $message = new IntercomMessage('Intercom message test'); + $this->assertEquals('Intercom message test', $message->payload['body']); + } + + public function testThatDefaultMessageTypeIsInapp(): void + { + $message = new IntercomMessage(); + $this->assertEquals(IntercomMessage::TYPE_INAPP, $message->payload['message_type']); + } + + public function testThatBodyCanBeSet(): void + { + $message = new IntercomMessage('Intercom message test'); + $message->body('Some other intercom body'); + $this->assertEquals('Some other intercom body', $message->payload['body']); + } + + public function testThatMessageTypeToEmailCanBeSet(): void + { + $message = new IntercomMessage(); + $message->email(); + $this->assertEquals(IntercomMessage::TYPE_EMAIL, $message->payload['message_type']); + } + + public function testThatMessageTypeToInappCanBeSet(): void + { + $message = new IntercomMessage(); + $message->email()->inapp(); + $this->assertEquals(IntercomMessage::TYPE_INAPP, $message->payload['message_type']); + } + + public function testThatSubjectCanBeSet(): void + { + $message = new IntercomMessage(); + $message->subject('Some interesting subject'); + $this->assertEquals('Some interesting subject', $message->payload['subject']); + } + + public function testThatTemplatePlainCanBeSet(): void + { + $message = new IntercomMessage(); + $message->plain(); + $this->assertEquals(IntercomMessage::TEMPLATE_PLAIN, $message->payload['template']); + } + + public function testThatTemplatePersonalCanBeSet(): void + { + $message = new IntercomMessage(); + $message->personal(); + $this->assertEquals(IntercomMessage::TEMPLATE_PERSONAL, $message->payload['template']); + } + + public function testThatSenderCanBeSet(): void + { + $message = new IntercomMessage(); + $message->from(123); + $this->assertEquals( + [ + 'type' => 'admin', + 'id' => 123 + ], + $message->payload['from'] + ); + } + + public function testThatRecipientCanBeSet(): void + { + $message = new IntercomMessage(); + $expected = [ + 'type' => 'user', + 'email' => 'foo@bar.baz' + ]; + $message->to($expected); + + $this->assertEquals($expected, $message->payload['to']); + } + + public function testThatRecipientUserIdCanBeSet(): void + { + $message = new IntercomMessage(); + $message->toUserId(456); + $this->assertEquals( + [ + 'type' => 'user', + 'id' => 456 + ], + $message->payload['to'] + ); + } + + public function testThatRecipientUserEmailCanBeSet(): void + { + $message = new IntercomMessage(); + $message->toUserEmail('foo@bar.com'); + $this->assertEquals( + [ + 'type' => 'user', + 'email' => 'foo@bar.com' + ], + $message->payload['to'] + ); + } + + public function testThatContactIdCanBeSet(): void + { + $message = new IntercomMessage(); + $message->toContactId(789); + $this->assertEquals( + [ + 'type' => 'contact', + 'id' => 789 + ], + $message->payload['to'] + ); + } + + public function testItCanDetermiteIfToIsNotGiven() + { + $message = new IntercomMessage(); + $this->assertFalse($message->toIsGiven()); + + $message->toUserId(123); + $this->assertTrue($message->toIsGiven()); + } + + public function testInCanDetermineWhenRequiredParamsAreNotSet(): void + { + $message = new IntercomMessage(); + $this->assertFalse($message->isValid()); + + $message->body('Some body'); + $this->assertFalse($message->isValid()); + + $message->from(123); + $this->assertFalse($message->isValid()); + + $message->toUserId(321); + $this->assertTrue($message->isValid()); + } + + public function testItCanReturnPayloadAsAnArray(): void + { + $message = new IntercomMessage(); + + $message + ->email() + ->personal() + ->from(123) + ->toUserEmail('recipient@foo.bar') + ->subject('Test case') + ->body('Some message'); + + $expected = [ + 'message_type' => 'email', + 'template' => 'personal', + 'from' => [ + 'type' => 'admin', + 'id' => '123' + ], + 'to' => [ + 'type' => 'user', + 'email' => 'recipient@foo.bar' + ], + 'subject' => 'Test case', + 'body' => 'Some message' + ]; + + $this->assertEquals($expected, $message->toArray()); + } + + public function testThatStaticCreateMethodProvidesBodyToObject(): void + { + $message = IntercomMessage::create(); + $this->assertFalse(isset($message->payload['body'])); + + $message = IntercomMessage::create('Intercom message test'); + $this->assertEquals('Intercom message test', $message->payload['body']); + } + +} \ No newline at end of file diff --git a/tests/MessageIsNotCompleteExceptionTest.php b/tests/MessageIsNotCompleteExceptionTest.php new file mode 100644 index 00000000..07ecb717 --- /dev/null +++ b/tests/MessageIsNotCompleteExceptionTest.php @@ -0,0 +1,25 @@ + + */ + +namespace FtwSoft\NotificationChannels\Intercom\Tests; + + +use FtwSoft\NotificationChannels\Intercom\Exceptions\MessageIsNotCompleteException; +use FtwSoft\NotificationChannels\Intercom\IntercomMessage; +use PHPUnit\Framework\TestCase; + +class MessageIsNotCompleteExceptionTest extends TestCase +{ + + public function testItReturnsMessageProvidedToConstruct(): void + { + $message = IntercomMessage::create('TEST'); + $exception = new MessageIsNotCompleteException($message); + $this->assertEquals($message, $exception->getIntercomMessage()); + } + +} \ No newline at end of file diff --git a/tests/Mocks/TestNotifiable.php b/tests/Mocks/TestNotifiable.php new file mode 100644 index 00000000..216b65bc --- /dev/null +++ b/tests/Mocks/TestNotifiable.php @@ -0,0 +1,39 @@ + + */ + +namespace FtwSoft\NotificationChannels\Intercom\Tests\Mocks; + + +use Illuminate\Notifications\Notifiable; + +class TestNotifiable +{ + use Notifiable; + + /** + * @var bool|array + */ + private $to; + + /** + * TestNotifiable constructor. + * + * @param $to + */ + public function __construct($to = false) + { + $this->to = $to; + } + + /** + * @return array|bool + */ + public function routeNotificationForIntercom() + { + return $this->to; + } +} \ No newline at end of file diff --git a/tests/Mocks/TestNotification.php b/tests/Mocks/TestNotification.php new file mode 100644 index 00000000..1ced2a6e --- /dev/null +++ b/tests/Mocks/TestNotification.php @@ -0,0 +1,41 @@ + + */ + +namespace FtwSoft\NotificationChannels\Intercom\Tests\Mocks; + + +use FtwSoft\NotificationChannels\Intercom\Contracts\IntercomNotification; +use FtwSoft\NotificationChannels\Intercom\IntercomMessage; +use Illuminate\Notifications\Notification; + +class TestNotification extends Notification implements IntercomNotification +{ + + /** + * @var IntercomMessage + */ + private $intercomMessage; + + /** + * TestNotification constructor. + * + * @param \FtwSoft\NotificationChannels\Intercom\IntercomMessage $intercomMessage + */ + public function __construct(IntercomMessage $intercomMessage) + { + $this->intercomMessage = $intercomMessage; + } + + /** + * @inheritdoc + */ + public function toIntercom($notifiable): IntercomMessage + { + return $this->intercomMessage; + } + +} \ No newline at end of file diff --git a/tests/RequestExceptionTest.php b/tests/RequestExceptionTest.php new file mode 100644 index 00000000..28fdd5ab --- /dev/null +++ b/tests/RequestExceptionTest.php @@ -0,0 +1,23 @@ +assertEquals($exception->getBaseException(), $baseException); + } + +} \ No newline at end of file