Move webhook to project notification type

This commit is contained in:
Frederic Guillot
2015-10-17 12:30:05 -04:00
parent 3543f45c2d
commit 472f94efee
18 changed files with 311 additions and 129 deletions

View File

@@ -131,7 +131,7 @@ class Csv
*
* @access public
* @param string $filename
* @param \Closure $callback Example: function(array $row, $line_number)
* @param callable $callback Example: function(array $row, $line_number)
* @return Csv
*/
public function read($filename, $callback)

View File

@@ -13,7 +13,7 @@ use Pimple\Container;
abstract class NotificationType extends Base
{
/**
* Mail transport instances
* Container
*
* @access private
* @var \Pimple\Container
@@ -21,13 +21,21 @@ abstract class NotificationType extends Base
private $classes;
/**
* Mail transport instances
* Notification type labels
*
* @access private
* @var array
*/
private $labels = array();
/**
* Hidden notification types
*
* @access private
* @var array
*/
private $hiddens = array();
/**
* Constructor
*
@@ -47,15 +55,24 @@ abstract class NotificationType extends Base
* @param string $type
* @param string $label
* @param string $class
* @param boolean $hidden
* @return NotificationType
*/
public function setType($type, $label, $class)
public function setType($type, $label, $class, $hidden = false)
{
$container = $this->container;
$this->labels[$type] = $label;
if ($hidden) {
$this->hiddens[] = $type;
} else {
$this->labels[$type] = $label;
}
$this->classes[$type] = function () use ($class, $container) {
return new $class($container);
};
return $this;
}
/**
@@ -80,4 +97,15 @@ abstract class NotificationType extends Base
{
return $this->labels;
}
/**
* Get all hidden notification types
*
* @access public
* @return array
*/
public function getHiddenTypes()
{
return $this->hiddens;
}
}

View File

@@ -20,8 +20,6 @@ class OverdueNotification extends Base
$tasks = $this->taskFinder->getOverdueTasks();
foreach ($this->groupByColumn($tasks, 'project_id') as $project_id => $project_tasks) {
// Get the list of users that should receive notifications for each projects
$users = $this->userNotification->getUsersWithNotificationEnabled($project_id);
foreach ($users as $user) {

View File

@@ -0,0 +1,29 @@
<?php
namespace Kanboard\Model;
/**
* Project Notification
*
* @package model
* @author Frederic Guillot
*/
class ProjectNotification extends Base
{
/**
* Send notifications
*
* @access public
* @param integer $project_id
* @param string $event_name
* @param array $event_data
*/
public function sendNotifications($project_id, $event_name, array $event_data)
{
$project = $this->project->getById($project_id);
foreach ($this->projectNotificationType->getSelectedTypes($project_id) as $type) {
$this->projectNotificationType->getType($type)->notifyProject($project, $event_name, $event_data);
}
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace Kanboard\Model;
/**
* Project Notification Type
*
* @package model
* @author Frederic Guillot
*/
class ProjectNotificationType extends NotificationType
{
/**
* SQL table name
*
* @var string
*/
const TABLE = 'project_has_notification_types';
/**
* Get selected notification types for a given project
*
* @access public
* @param integer $project_id
* @return array
*/
public function getSelectedTypes($project_id)
{
$selectedTypes = $this->db
->table(self::TABLE)
->eq('project_id', $project_id)
->asc('notification_type')
->findAllByColumn('notification_type');
return array_merge($this->getHiddenTypes(), $selectedTypes);
}
/**
* Save notification types for a given project
*
* @access public
* @param integer $project_id
* @param string[] $types
* @return boolean
*/
public function saveSelectedTypes($project_id, array $types)
{
$results = array();
$this->db->table(self::TABLE)->eq('project_id', $project_id)->remove();
foreach ($types as $type) {
$results[] = $this->db->table(self::TABLE)->insert(array('project_id' => $project_id, 'notification_type' => $type));
}
return ! in_array(false, $results);
}
}

View File

@@ -1,34 +0,0 @@
<?php
namespace Kanboard\Model;
/**
* Webhook model
*
* @package model
* @author Frederic Guillot
*/
class Webhook extends Base
{
/**
* Call the external URL
*
* @access public
* @param array $values Event payload
*/
public function notify(array $values)
{
$url = $this->config->get('webhook_url');
$token = $this->config->get('webhook_token');
if (! empty($url)) {
if (strpos($url, '?') !== false) {
$url .= '&token='.$token;
} else {
$url .= '?token='.$token;
}
return $this->httpClient->postJson($url, $values);
}
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Kanboard\Notification;
use Kanboard\Core\Base;
/**
* Webhook Notification
*
* @package notification
* @author Frederic Guillot
*/
class Webhook extends Base implements NotificationInterface
{
/**
* Send notification to a user
*
* @access public
* @param array $user
* @param string $event_name
* @param array $event_data
*/
public function notifyUser(array $user, $event_name, array $event_data)
{
}
/**
* Send notification to a project
*
* @access public
* @param array $project
* @param string $event_name
* @param array $event_data
*/
public function notifyProject(array $project, $event_name, array $event_data)
{
$url = $this->config->get('webhook_url');
$token = $this->config->get('webhook_token');
if (! empty($url)) {
if (strpos($url, '?') !== false) {
$url .= '&token='.$token;
} else {
$url .= '?token='.$token;
}
$payload = array(
'event_name' => $event_name,
'event_data' => $event_data,
);
return $this->httpClient->postJson($url, $payload);
}
}
}

View File

@@ -6,7 +6,21 @@ use PDO;
use Kanboard\Core\Security;
use Kanboard\Model\Link;
const VERSION = 91;
const VERSION = 92;
function version_92($pdo)
{
$pdo->exec("
CREATE TABLE project_has_notification_types (
id INT NOT NULL AUTO_INCREMENT,
project_id INT NOT NULL,
notification_type VARCHAR(50),
PRIMARY KEY(id),
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
UNIQUE(project_id, notification_type),
) ENGINE=InnoDB CHARSET=utf8
");
}
function version_91($pdo)
{

View File

@@ -6,7 +6,20 @@ use PDO;
use Kanboard\Core\Security;
use Kanboard\Model\Link;
const VERSION = 71;
const VERSION = 72;
function version_72($pdo)
{
$pdo->exec("
CREATE TABLE project_has_notification_types (
id SERIAL PRIMARY KEY,
project_id INTEGER NOT NULL,
notification_type VARCHAR(50),
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
UNIQUE(project_id, notification_type)
)
");
}
function version_71($pdo)
{

View File

@@ -6,7 +6,20 @@ use Kanboard\Core\Security;
use PDO;
use Kanboard\Model\Link;
const VERSION = 86;
const VERSION = 87;
function version_87($pdo)
{
$pdo->exec("
CREATE TABLE project_has_notification_types (
id INTEGER PRIMARY KEY,
project_id INTEGER NOT NULL,
notification_type TEXT,
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE,
UNIQUE(project_id, notification_type)
)
");
}
function version_86($pdo)
{

View File

@@ -2,6 +2,9 @@
namespace Kanboard\ServiceProvider;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use League\HTMLToMarkdown\HtmlConverter;
use Kanboard\Core\Plugin\Loader;
use Kanboard\Core\Mail\Client as EmailClient;
use Kanboard\Core\ObjectStorage\FileStorage;
@@ -9,9 +12,7 @@ use Kanboard\Core\Paginator;
use Kanboard\Core\OAuth2;
use Kanboard\Core\Tool;
use Kanboard\Model\UserNotificationType;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use League\HTMLToMarkdown\HtmlConverter;
use Kanboard\Model\ProjectNotificationType;
class ClassProvider implements ServiceProviderInterface
{
@@ -39,6 +40,7 @@ class ClassProvider implements ServiceProviderInterface
'ProjectDailyStats',
'ProjectIntegration',
'ProjectPermission',
'ProjectNotification',
'Subtask',
'SubtaskExport',
'SubtaskTimeTracking',
@@ -65,7 +67,6 @@ class ClassProvider implements ServiceProviderInterface
'UserNotificationType',
'UserNotificationFilter',
'UserUnreadNotification',
'Webhook',
),
'Formatter' => array(
'TaskFilterGanttFormatter',
@@ -135,6 +136,12 @@ class ClassProvider implements ServiceProviderInterface
return $type;
};
$container['projectNotificationType'] = function ($container) {
$type = new ProjectNotificationType($container);
$type->setType('webhook', t('Webhook'), '\Kanboard\Notification\Webhook', true);
return $type;
};
$container['pluginLoader'] = new Loader($container);
$container['cspRules'] = array('style-src' => "'self' 'unsafe-inline'", 'img-src' => '* data:');

View File

@@ -11,7 +11,6 @@ use Kanboard\Subscriber\NotificationSubscriber;
use Kanboard\Subscriber\ProjectActivitySubscriber;
use Kanboard\Subscriber\ProjectDailySummarySubscriber;
use Kanboard\Subscriber\ProjectModificationDateSubscriber;
use Kanboard\Subscriber\WebhookSubscriber;
use Kanboard\Subscriber\SubtaskTimeTrackingSubscriber;
use Kanboard\Subscriber\TaskMovedDateSubscriber;
use Kanboard\Subscriber\TransitionSubscriber;
@@ -27,7 +26,6 @@ class EventDispatcherProvider implements ServiceProviderInterface
$container['dispatcher']->addSubscriber(new ProjectActivitySubscriber($container));
$container['dispatcher']->addSubscriber(new ProjectDailySummarySubscriber($container));
$container['dispatcher']->addSubscriber(new ProjectModificationDateSubscriber($container));
$container['dispatcher']->addSubscriber(new WebhookSubscriber($container));
$container['dispatcher']->addSubscriber(new NotificationSubscriber($container));
$container['dispatcher']->addSubscriber(new SubtaskTimeTrackingSubscriber($container));
$container['dispatcher']->addSubscriber(new TaskMovedDateSubscriber($container));

View File

@@ -32,17 +32,25 @@ class NotificationSubscriber extends \Kanboard\Core\Base implements EventSubscri
public function execute(GenericEvent $event, $event_name)
{
$this->userNotification->sendNotifications($event_name, $this->getEventData($event));
$event_data = $this->getEventData($event);
if (! empty($event_data)) {
$this->userNotification->sendNotifications($event_name, $event_data);
$this->projectNotification->sendNotifications($event_data['task']['project_id'], $event_name, $event_data);
}
}
public function getEventData(GenericEvent $event)
{
$values = array();
if (! empty($event['changes'])) {
$values['changes'] = $event['changes'];
}
switch (get_class($event)) {
case 'Kanboard\Event\TaskEvent':
$values['task'] = $this->taskFinder->getDetails($event['task_id']);
$values['changes'] = isset($event['changes']) ? $event['changes'] : array();
break;
case 'Kanboard\Event\SubtaskEvent':
$values['subtask'] = $this->subtask->getById($event['id'], true);

View File

@@ -61,10 +61,10 @@ class ProjectActivitySubscriber extends \Kanboard\Core\Base implements EventSubs
$values['changes'] = isset($event['changes']) ? $event['changes'] : array();
switch (get_class($event)) {
case 'Event\SubtaskEvent':
case 'Kanboard\Event\SubtaskEvent':
$values['subtask'] = $this->subtask->getById($event['id'], true);
break;
case 'Event\CommentEvent':
case 'Kanboard\Event\CommentEvent':
$values['comment'] = $this->comment->getById($event['id']);
break;
}

View File

@@ -1,45 +0,0 @@
<?php
namespace Kanboard\Subscriber;
use Kanboard\Event\CommentEvent;
use Kanboard\Event\GenericEvent;
use Kanboard\Event\TaskEvent;
use Kanboard\Model\Comment;
use Kanboard\Model\Task;
use Kanboard\Model\File;
use Kanboard\Model\Subtask;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class WebhookSubscriber extends \Kanboard\Core\Base implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
Task::EVENT_CREATE => array('execute', 0),
Task::EVENT_UPDATE => array('execute', 0),
Task::EVENT_CLOSE => array('execute', 0),
Task::EVENT_OPEN => array('execute', 0),
Task::EVENT_MOVE_COLUMN => array('execute', 0),
Task::EVENT_MOVE_POSITION => array('execute', 0),
Task::EVENT_ASSIGNEE_CHANGE => array('execute', 0),
Task::EVENT_MOVE_PROJECT => array('execute', 0),
Task::EVENT_MOVE_SWIMLANE => array('execute', 0),
Comment::EVENT_CREATE => array('execute', 0),
Comment::EVENT_UPDATE => array('execute', 0),
File::EVENT_CREATE => array('execute', 0),
Subtask::EVENT_CREATE => array('execute', 0),
Subtask::EVENT_UPDATE => array('execute', 0),
);
}
public function execute(GenericEvent $event, $event_name)
{
$payload = array(
'event_name' => $event_name,
'event_data' => $event->getAll(),
);
$this->webhook->notify($payload);
}
}