Skip to content

Commit

Permalink
Slack Notification Channel (#10)
Browse files Browse the repository at this point in the history
* Added slack notification channel. 

* Updated readme. 

*Added screenshots.
  • Loading branch information
yordadev authored Sep 3, 2022
1 parent c5ff893 commit e7641ba
Show file tree
Hide file tree
Showing 8 changed files with 287 additions and 14 deletions.
31 changes: 18 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ Adjust the configuration file to suite your application.
'enabled' => false, // Do you want discord webhook notifications?
'hook' => env('DISCORD_HOOK', 'please_fill_me_in'),
],
'slack' => [
'enabled' => false, // Do you want Slack webhook notifications?
'hook' => env('SLACK_HOOK', 'please_fill_me_in'),
],
]
]
```
Expand Down Expand Up @@ -112,6 +116,17 @@ applications [broadcast configuration](https://laravel.com/docs/9.x/broadcasting
}
```

### Slack Notification Channel

To utilize Slack Notifications, you will need to [create a webhook](https://api.slack.com/messaging/webhooks#create_a_webhook) for one of your Slack Channels. Once you have your
webhook url, add the following variable to your .env file.

```dotenv
SLACK_HOOK=<hook>
```

Once you have done this, you can enable Slack Notifications in the configuration file.

### Discord Notification Channel

Get a webhook URL from discord in the channel you want to receive your notifications in by
Expand All @@ -124,20 +139,10 @@ DISCORD_HOOK=<hook>

Once you have done this, you can enable Discord Notifications in the configuration file.

### Screenshots

<div align="center">
<a href="https://github.com/YorCreative">
<img src="content/discord_notification_console.png" alt="Logo" width="223" height="300">
</a>
</div>
<br>
<div align="center">
<a href="https://github.com/YorCreative">
<img src="content/discord_notification_request.png" alt="Logo" width="286" height="343">
</a>
</div>
### Wiki Documentation

- [Notification Channels Wiki](https://github.com/YorCreative/Laravel-Query-Watcher/wiki/Notification-Channels)
- [Screenshots](https://github.com/YorCreative/Laravel-Query-Watcher/wiki/Screenshots)
## Testing

```bash
Expand Down
4 changes: 4 additions & 0 deletions config/querywatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@
'enabled' => false,
'hook' => env('DISCORD_HOOK', 'placeholder'),
],
'slack' => [
'enabled' => false,
'hook' => env('SLACK_HOOK', 'placeholder'),
],
],
];
Binary file added content/slack_notification_console.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added content/slack_notification_request.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/Services/ChannelService.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Support\Collection;
use YorCreative\QueryWatcher\Models\QueryModel;
use YorCreative\QueryWatcher\Strategies\NotificationStrategy\Channels\Discord;
use YorCreative\QueryWatcher\Strategies\NotificationStrategy\Channels\Slack;
use YorCreative\QueryWatcher\Strategies\NotificationStrategy\NotificationStrategy;

class ChannelService
Expand Down Expand Up @@ -32,6 +33,7 @@ protected static function getChannels(): Collection
{
return new Collection([
new Discord(),
new Slack(),
]);
}
}
202 changes: 202 additions & 0 deletions src/Strategies/NotificationStrategy/Channels/Slack.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
<?php

namespace YorCreative\QueryWatcher\Strategies\NotificationStrategy\Channels;

use Illuminate\Support\Facades\Http;
use YorCreative\QueryWatcher\Models\QueryModel;
use YorCreative\QueryWatcher\Strategies\NotificationStrategy\NotificationChannelInterface;

class Slack implements NotificationChannelInterface
{
/**
* @return bool
*/
public function isEnabled(): bool
{
return config('querywatcher.channels.slack.enabled');
}

/**
* @param QueryModel $model
*/
public function notify(QueryModel $model): void
{
// Core Base Information
$payload = $this->buildCoreBaseEnrichment($model);

// Contextual Information
if ($model->trigger['action'] == 'Console') {
$payload['blocks'] = $this->buildConsoleEnrichment($payload['blocks']);
} else {
$payload['blocks'] = $this->buildRequestEnrichment($payload['blocks'], $model);
}

// Fire off hook
Http::retry(3)->contentType('application/json')->post(config('querywatcher.channels.slack.hook'), $payload);
}

/**
* @note Slack Block Builder Reference
* https://app.slack.com/block-kit-builder
*
* If you would like to improve your Slack message, see the block kit builder.
*/

/**
* @param QueryModel $model
* @return \array[][]
*/
protected function buildCoreBaseEnrichment(QueryModel $model): array
{
return [
'blocks' => [
[
'type' => 'divider',
],
[
'type' => 'header',
'text' => [
'type' => 'plain_text',
'text' => 'Captured Query',
],
],
[
'type' => 'section',
'text' => [
'type' => 'plain_text',
'text' => $model->sql,
],
],
[
'type' => 'header',
'text' => [
'type' => 'plain_text',
'text' => 'Query Bindings',
],
],
[
'type' => 'section',
'text' => [
'type' => 'plain_text',
'text' => json_encode($model->getBindings()),
],
],
[
'type' => 'header',
'text' => [
'type' => 'plain_text',
'text' => 'Execution Time',
],
],
[
'type' => 'section',
'text' => [
'type' => 'plain_text',
'text' => json_encode($model->time).' ms',
],
],
[
'type' => 'header',
'text' => [
'type' => 'plain_text',
'text' => 'Connection',
],
],
[
'type' => 'section',
'text' => [
'type' => 'plain_text',
'text' => $model->connection,
],
],
],
];
}

/**
* @param array $payload
* @return array
*/
protected function buildConsoleEnrichment(array $payload): array
{
return array_merge($payload, [
[
'type' => 'header',
'text' => [
'type' => 'plain_text',
'text' => 'Contextual Information',
],
],
[
'type' => 'context',
'elements' => [
[
'type' => 'mrkdwn',
'text' => '*Trigger:* Console',
],
],
],
]);
}

/**
* @param array $payload
* @param QueryModel $model
* @return array
*/
protected function buildRequestEnrichment(array $payload, QueryModel $model): array
{
return array_merge($payload, [
[
'type' => 'header',
'text' => [
'type' => 'plain_text',
'text' => 'Contextual Information',
],
],
[
'type' => 'context',
'elements' => [
[
'type' => 'mrkdwn',
'text' => '*Trigger:* '.$model->trigger['action'],
],
],
],
[
'type' => 'context',
'elements' => [
[
'type' => 'mrkdwn',
'text' => '*Method:* '.$model->trigger['context']['method'],
],
],
],
[
'type' => 'context',
'elements' => [
[
'type' => 'mrkdwn',
'text' => '*URL:* '.$model->trigger['context']['url'],
],
],
],
[
'type' => 'context',
'elements' => [
0 => [
'type' => 'mrkdwn',
'text' => '*Request Input:*',
],
],
],
[
'type' => 'section',
'text' => [
'type' => 'mrkdwn',
'text' => json_encode($model->trigger['context']['input']),
],
],
]);
}
}
4 changes: 3 additions & 1 deletion tests/Integration/Services/ChannelServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use ReflectionClass;
use YorCreative\QueryWatcher\Services\ChannelService;
use YorCreative\QueryWatcher\Strategies\NotificationStrategy\Channels\Discord;
use YorCreative\QueryWatcher\Strategies\NotificationStrategy\Channels\Slack;
use YorCreative\QueryWatcher\Tests\TestCase;

class ChannelServiceTest extends TestCase
Expand All @@ -22,11 +23,12 @@ public function it_has_available_channels()

$channels = $protectedMethod->invokeArgs(new ChannelService(), []);

$this->assertCount(1, $channels);
$this->assertCount(2, $channels);

$channels->each(function ($channel) {
$this->assertTrue(in_array($channel, [
new Discord(),
new Slack(),
]));
});
}
Expand Down
58 changes: 58 additions & 0 deletions tests/Unit/Strategies/Channels/SlackTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

namespace YorCreative\QueryWatcher\Tests\Unit\Strategies\Channels;

use Illuminate\Support\Facades\Http;
use YorCreative\QueryWatcher\Strategies\NotificationStrategy\Channels\Slack;
use YorCreative\QueryWatcher\Tests\TestCase;

class SlackTest extends TestCase
{
public Slack $slackChannel;

public function setUp(): void
{
parent::setUp(); // TODO: Change the autogenerated stub

$this->slackChannel = new Slack();
}

/**
* @test
* @group Unit
* @group Channels
* @group Strategies
*/
public function it_can_send_http_request_to_slack()
{
Http::fake();

$this->slackChannel->notify($this->queryModel);

Http::assertSentCount(1);
}

/**
* @test
* @group Unit
* @group Channels
* @group Strategies
*/
public function it_can_determine_that_slack_channel_is_enabled()
{
app()['config']->set('querywatcher.channels.slack.enabled', true);
$this->assertTrue($this->slackChannel->isEnabled());
}

/**
* @test
* @group Unit
* @group Channels
* @group Strategies
*/
public function it_can_determine_that_slack_channel_is_not_enabled()
{
app()['config']->set('querywatcher.channels.slack.enabled', false);
$this->assertFalse($this->slackChannel->isEnabled());
}
}

0 comments on commit e7641ba

Please sign in to comment.