8000 #37 Slack Webhook by fortkle · Pull Request #109 · owl/owl · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

#37 Slack Webhook #109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Feb 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .env.behat
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,8 @@ MAIL_PORT=587
MAIL_ENCRYPTION=tls

# mail notification flag
NOTIFICATION_ENABLE=true
NOTIFICATION_ENABLE=false

# slack webhook
SLACK_NOTIFICATION_ENABLE=false
SLACK_WEBHOOK_URL=null
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ MAIL_ENCRYPTION=tls

# mail notification flag
NOTIFICATION_ENABLE=false

# slack webhook
SLACK_NOTIFICATION_ENABLE=false
SLACK_WEBHOOK_URL=null
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This software is released under the MIT License, see LICENSE.txt.
- Full Text Search
- Item Publishing Settings (Public, Limited, Only Me)
- Mail Notification
- Slack Notification(webhook)
- Export data as .md files (YAML front matter)

## Requirements
Expand Down
18 changes: 18 additions & 0 deletions app/Events/Item/CreateEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php namespace Owl\Events\Item;

/**
* @copyright (c) owl
*/

use Owl\Events\Item\BaseItemEvent;

/**
* Class CreateEvent
* 記事新規作成のイベントクラス
*
* @package Owl\Events\Item
*/
class CreateEvent extends BaseItemEvent
{
//
}
79 changes: 79 additions & 0 deletions app/Handlers/Events/SlackNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php namespace Owl\Handlers\Events;

/**
* @copyright (c) owl
*/

use Owl\Events\Item\CreateEvent;
use Owl\Events\Item\EditEvent;
use Owl\Services\ItemService;
use Owl\Services\UserService;
use Owl\Libraries\SlackUtils;

/**
* Class SlackNotification
* Slack通知関連のイベントハンドラークラス
*
* @package Owl\Handlers\Events
*/
class SlackNotification
{
/** @var ItemService */
protected $itemService;

/** @var UserService */
protected $userService;

/** @var SlackUtils */
protected $slackUtils;

/**
* @param ItemService $itemService
* @param UserService $userService
* @param SlackUtils $slackUtils
*/
public function __construct(
ItemService $itemService,
UserService $userService,
SlackUtils $slackUtils
) {
$this->itemService = $itemService;
$this->userService = $userService;
$this->slackUtils = $slackUtils;
}

/**
* 各イベントにハンドラーメソッドを登録
*
* @param \Illuminate\Events\Dispatcher $events
*/
public function subscribe($events)
{
$events->listen('Owl\Events\Item\CreateEvent', '\Owl\Handlers\Events\SlackNotification@onItemCreated');
$events->listen('Owl\Events\Item\EditEvent', '\Owl\Handlers\Events\SlackNotification@onItemEdited');
}

/**
* 記事が新規作成された時
*
* @param CreateEvent $event
*/
public function onItemCreated(CreateEvent $event)
{
$item = $this->itemService->getByOpenItemId($event->getId());
$user = $this->userService->getById($event->getUserId());
$this->slackUtils->postCreateMessage($item, $user);
}

/**
* 記事が編集された時
*
* @param EditEvent $event
*/
public function onItemEdited(EditEvent $event)
{
$item = $this->itemService->getByOpenItemId($event->getId());
$user = $this->userService->getById($event->getUserId());
$this->slackUtils->postEditMessage($item, $user);
}
}
10 changes: 9 additions & 1 deletion app/Http/Controllers/ItemController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Owl\Services\TemplateService;
use Owl\Http\Requests\ItemStoreRequest;
use Owl\Http\Requests\ItemUpdateRequest;
use Owl\Events\Item\CreateEvent;
use Owl\Events\Item\EditEvent;

class ItemController extends Controller
Expand Down Expand Up @@ -48,7 +49,7 @@ public function create($templateId = null)
return \View::make('items.create', compact('template', 'user_items'));
}

public function store(ItemStoreRequest $request)
public function store(ItemStoreRequest $request, Dispatcher $event)
{
$user = $this->userService->getCurrentUser();

Expand All @@ -70,6 +71,13 @@ public function store(ItemStoreRequest $request)
$this->tagService->syncTags($item, $tag_ids);
}

// fire CreateEvent
// TODO: do not create instance in controller method
$event->fire(new CreateEvent(
$object->open_item_id,
(int) $user->id
));

return \Redirect::route('items.show', [$item->open_item_id]);
}

Expand Down
110 changes: 110 additions & 0 deletions app/Libraries/SlackUtils.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php namespace Owl\Libraries;

use Illuminate\Contracts\Config\Repository as Config;

class SlackUtils
{
/** enable */
public $is_enabled = false;

/** Slack webhook url */
public $webhook_url = '';

/** Bot icon url */
public $icon_url = 'https://raw.githubusercontent.com/wiki/owl/owl/images/owl_webhook_logo.png';

/** Bot user name */
public $username = 'owl';

public function __construct(Config $config)
{
$this->is_enabled = $config->get('notification.slack.enabled');
$this->webhook_url = $config->get('notification.slack.webhook_url');
}

public function postMessage($params)
{
if (! $this->is_enabled) {
return false;
}

return $this->request($this->createOptions($this->formatParams($params)));
}

public function postCreateMessage($item, $user)
{
$params = [];
$params['fallback'] = "新しい投稿がありました。( " . \Request::root() . '/items/' . $item->open_item_id . " )";
$params['pretext'] = \Request::root() . '/items/' . $item->open_item_id;
$params['author_name'] = $user->username;
$params['author_link'] = \Request::root() . '/' . $user->username;
$params['author_icon'] = \HTML::gravator($user->email, 16, 'mm', 'g', false);
$params['title'] = $item->title;
$params['title_link'] = \Request::root() . '/items/' . $item->open_item_id;
$params['text'] = mb_strimwidth($item->body, 0, 200, "...");
return $this->postMessage($params);
}

public function postEditMessage($item, $user)
{
$params = [];
$params['fallback'] = "記事が編集されました。( " . \Request::root() . '/items/' . $item->open_item_id . " )";
$params['pretext'] = \Request::root() . '/items/' . $item->open_item_id;
$params['author_name'] = $user->username;
$params['author_link'] = \Request::root() . '/' . $user->username;
$params['author_icon'] = \HTML::gravator($user->email, 16, 'mm&# F438 39;, 'g', false);
$params['title'] = $item->title;
$params['title_link'] = \Request::root() . '/items/' . $item->open_item_id;
$params['text'] = mb_strimwidth($item->body, 0, 200, "...");
return $this->postMessage($params);
}

protected function formatParams($params)
{
return [
'url' => $this->webhook_url,
'body' => [
'payload' => json_encode([
'username' => $this->username,
'icon_url' => $this->icon_url,
'attachments' => [[
'fallback' => $params['fallback'] ?: '',
'author_name' => $params['author_name'] ?: '',
'author_link' => $params['author_link'] ?: '',
'author_icon' => $params['author_icon'] ?: '',
'title' => $params['title'] ?: '',
'title_link' => $params['title_link'] ?: '',
'text' => $params['text'] ?: '',
]]
]),
],
];
}

protected function createOptions($params)
{
return [
CURLOPT_URL => $params['url'],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $params['body'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
];
}

protected function request($options)
{
$ch = curl_init();
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($result, 0, $header_size);
$result = substr($result, $header_size);
curl_close($ch);

return [
'Header' => $header,
'Result' => $result,
];
}
}
5 changes: 5 additions & 0 deletions app/Providers/EventServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,10 @@ protected function registerSubscriber()
if (config('notification.enabled')) {
\Event::subscribe('\Owl\Handlers\Events\EmailNotification');
}
// Slack通知イベントハンドラー
$slack_webhook_url = config('notification.slack.webhook_url'); // for PHP <= 5.4
if (config('notification.slack.enabled') && !empty($slack_webhook_url)) {
\Event::subscribe('\Owl\Handlers\Events\SlackNotification');
}
}
}
8 changes: 8 additions & 0 deletions config/notification.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,12 @@
* メールによるアクション通知機能を有効にする場合はtrueを設定する
*/
'enabled' => env('NOTIFICATION_ENABLE', false),

/**
* Slack webhookを有効にする場合はURLを設定する
*/
'slack' => [
'enabled' => env('SLACK_NOTIFICATION_ENABLE', null),
'webhook_url' => env('SLACK_WEBHOOK_URL', null),
]
];
Binary file added storage/database.sqlite_bk
Binary file not shown.
12 changes: 12 additions & 0 deletions tests/Events/CreateEventTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

use Owl\Events\Item\CreateEvent;

class CreateEventTest extends \TestCase
{
public function testValidInstance()
{
$event = new CreateEvent('itemId', 'userId');
$this->assertInstanceOf('Owl\Events\Item\CreateEvent', $event);
}
}
83 changes: 83 additions & 0 deletions tests/Handlers/SlackNotificationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

use Mockery as m;
use MockeryInterface as i;
use Owl\Handlers\Events\SlackNotification;
use Owl\Events\Item\CreateEvent;
use Owl\Events\Item\EditEvent;
use Owl\Libraries\SlackUtils;

class SlackNotificationTest extends \TestCase
{
/** @var string */
protected $handlerName = 'Owl\Handlers\Events\SlackNotification';

public function setUp()
{
parent::setUp();

// mock data
$this->dummyItem = (object) [
'open_item_id' => 'open_item_id',
'title' => 'title',
'user_id' => 'user_id',
];
$this->dummyUser = (object) [
'id' => 'sender_id',
'username' => 'sender',
];
// mock class
$this->itemRepo = m::mock($this->itemRepoName);
$this->userRepo = m::mock($this->userRepoName);
}

public function testValidInstance()
{
$handler = $this->app->make($this->handlerName);
$this->assertInstanceOf($this->handlerName, $handler);
}

public function testShouldItemCreateNotify()
{
$this->itemRepo->shouldReceive('getByOpenItemId')->andReturn($this->dummyItem);
$this->userRepo->shouldReceive('getById')->andReturn($this->dummyUser);

$slackUtilMock = m::mock('Owl\Libraries\SlackUtils');
$slackUtilMock->shouldReceive('postCreateMessage')->andReturn(true);
$this->app->bind('Owl\Libraries\SlackUtils', function ($app) use ($slackUtilMock) {
return $slackUtilMock;
});
$this->bindReposHelper($this->itemRepo, $this->userRepo);
$handler = $this->app->make($this->handlerName);

$createEvent = new CreateEvent('itemId', 'userId');
$handler->onItemCreated($createEvent);
}

public function testShouldItemEditNotify()
{
$this->itemRepo->shouldReceive('getByOpenItemId')->andReturn($this->dummyItem);
$this->userRepo->shouldReceive('getById')->andReturn($this->dummyUser);

$slackUtilMock = m::mock('Owl\Libraries\SlackUtils');
$slackUtilMock->shouldReceive('postEditMessage')->andReturn(true);
$this->app->bind('Owl\Libraries\SlackUtils', function ($app) use ($slackUtilMock) {
return $slackUtilMock;
});
$this->bindReposHelper($this->itemRepo, $this->userRepo);
$handler = $this->app->make($this->handlerName);

$editEvent = new EditEvent('itemId', 'userId');
$handler->onItemEdited($editEvent);
}

protected function bindReposHelper($itemRepo, $userRepo)
{
$this->app->bind($this->itemRepoName, function ($app) use ($itemRepo) {
return $itemRepo;
});
$this->app->bind($this->userRepoName, function ($app) use ($userRepo) {
return $userRepo;
});
}
}
0