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 * @access public
* @param string $filename * @param string $filename
* @param \Closure $callback Example: function(array $row, $line_number) * @param callable $callback Example: function(array $row, $line_number)
* @return Csv * @return Csv
*/ */
public function read($filename, $callback) public function read($filename, $callback)

View File

@@ -13,7 +13,7 @@ use Pimple\Container;
abstract class NotificationType extends Base abstract class NotificationType extends Base
{ {
/** /**
* Mail transport instances * Container
* *
* @access private * @access private
* @var \Pimple\Container * @var \Pimple\Container
@@ -21,13 +21,21 @@ abstract class NotificationType extends Base
private $classes; private $classes;
/** /**
* Mail transport instances * Notification type labels
* *
* @access private * @access private
* @var array * @var array
*/ */
private $labels = array(); private $labels = array();
/**
* Hidden notification types
*
* @access private
* @var array
*/
private $hiddens = array();
/** /**
* Constructor * Constructor
* *
@@ -47,15 +55,24 @@ abstract class NotificationType extends Base
* @param string $type * @param string $type
* @param string $label * @param string $label
* @param string $class * @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; $container = $this->container;
$this->labels[$type] = $label;
if ($hidden) {
$this->hiddens[] = $type;
} else {
$this->labels[$type] = $label;
}
$this->classes[$type] = function () use ($class, $container) { $this->classes[$type] = function () use ($class, $container) {
return new $class($container); return new $class($container);
}; };
return $this;
} }
/** /**
@@ -80,4 +97,15 @@ abstract class NotificationType extends Base
{ {
return $this->labels; 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(); $tasks = $this->taskFinder->getOverdueTasks();
foreach ($this->groupByColumn($tasks, 'project_id') as $project_id => $project_tasks) { 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); $users = $this->userNotification->getUsersWithNotificationEnabled($project_id);
foreach ($users as $user) { 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\Core\Security;
use Kanboard\Model\Link; 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) function version_91($pdo)
{ {

View File

@@ -6,7 +6,20 @@ use PDO;
use Kanboard\Core\Security; use Kanboard\Core\Security;
use Kanboard\Model\Link; 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) function version_71($pdo)
{ {

View File

@@ -6,7 +6,20 @@ use Kanboard\Core\Security;
use PDO; use PDO;
use Kanboard\Model\Link; 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) function version_86($pdo)
{ {

View File

@@ -2,6 +2,9 @@
namespace Kanboard\ServiceProvider; namespace Kanboard\ServiceProvider;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use League\HTMLToMarkdown\HtmlConverter;
use Kanboard\Core\Plugin\Loader; use Kanboard\Core\Plugin\Loader;
use Kanboard\Core\Mail\Client as EmailClient; use Kanboard\Core\Mail\Client as EmailClient;
use Kanboard\Core\ObjectStorage\FileStorage; use Kanboard\Core\ObjectStorage\FileStorage;
@@ -9,9 +12,7 @@ use Kanboard\Core\Paginator;
use Kanboard\Core\OAuth2; use Kanboard\Core\OAuth2;
use Kanboard\Core\Tool; use Kanboard\Core\Tool;
use Kanboard\Model\UserNotificationType; use Kanboard\Model\UserNotificationType;
use Pimple\Container; use Kanboard\Model\ProjectNotificationType;
use Pimple\ServiceProviderInterface;
use League\HTMLToMarkdown\HtmlConverter;
class ClassProvider implements ServiceProviderInterface class ClassProvider implements ServiceProviderInterface
{ {
@@ -39,6 +40,7 @@ class ClassProvider implements ServiceProviderInterface
'ProjectDailyStats', 'ProjectDailyStats',
'ProjectIntegration', 'ProjectIntegration',
'ProjectPermission', 'ProjectPermission',
'ProjectNotification',
'Subtask', 'Subtask',
'SubtaskExport', 'SubtaskExport',
'SubtaskTimeTracking', 'SubtaskTimeTracking',
@@ -65,7 +67,6 @@ class ClassProvider implements ServiceProviderInterface
'UserNotificationType', 'UserNotificationType',
'UserNotificationFilter', 'UserNotificationFilter',
'UserUnreadNotification', 'UserUnreadNotification',
'Webhook',
), ),
'Formatter' => array( 'Formatter' => array(
'TaskFilterGanttFormatter', 'TaskFilterGanttFormatter',
@@ -135,6 +136,12 @@ class ClassProvider implements ServiceProviderInterface
return $type; 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['pluginLoader'] = new Loader($container);
$container['cspRules'] = array('style-src' => "'self' 'unsafe-inline'", 'img-src' => '* data:'); $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\ProjectActivitySubscriber;
use Kanboard\Subscriber\ProjectDailySummarySubscriber; use Kanboard\Subscriber\ProjectDailySummarySubscriber;
use Kanboard\Subscriber\ProjectModificationDateSubscriber; use Kanboard\Subscriber\ProjectModificationDateSubscriber;
use Kanboard\Subscriber\WebhookSubscriber;
use Kanboard\Subscriber\SubtaskTimeTrackingSubscriber; use Kanboard\Subscriber\SubtaskTimeTrackingSubscriber;
use Kanboard\Subscriber\TaskMovedDateSubscriber; use Kanboard\Subscriber\TaskMovedDateSubscriber;
use Kanboard\Subscriber\TransitionSubscriber; use Kanboard\Subscriber\TransitionSubscriber;
@@ -27,7 +26,6 @@ class EventDispatcherProvider implements ServiceProviderInterface
$container['dispatcher']->addSubscriber(new ProjectActivitySubscriber($container)); $container['dispatcher']->addSubscriber(new ProjectActivitySubscriber($container));
$container['dispatcher']->addSubscriber(new ProjectDailySummarySubscriber($container)); $container['dispatcher']->addSubscriber(new ProjectDailySummarySubscriber($container));
$container['dispatcher']->addSubscriber(new ProjectModificationDateSubscriber($container)); $container['dispatcher']->addSubscriber(new ProjectModificationDateSubscriber($container));
$container['dispatcher']->addSubscriber(new WebhookSubscriber($container));
$container['dispatcher']->addSubscriber(new NotificationSubscriber($container)); $container['dispatcher']->addSubscriber(new NotificationSubscriber($container));
$container['dispatcher']->addSubscriber(new SubtaskTimeTrackingSubscriber($container)); $container['dispatcher']->addSubscriber(new SubtaskTimeTrackingSubscriber($container));
$container['dispatcher']->addSubscriber(new TaskMovedDateSubscriber($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) 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) public function getEventData(GenericEvent $event)
{ {
$values = array(); $values = array();
if (! empty($event['changes'])) {
$values['changes'] = $event['changes'];
}
switch (get_class($event)) { switch (get_class($event)) {
case 'Kanboard\Event\TaskEvent': case 'Kanboard\Event\TaskEvent':
$values['task'] = $this->taskFinder->getDetails($event['task_id']); $values['task'] = $this->taskFinder->getDetails($event['task_id']);
$values['changes'] = isset($event['changes']) ? $event['changes'] : array();
break; break;
case 'Kanboard\Event\SubtaskEvent': case 'Kanboard\Event\SubtaskEvent':
$values['subtask'] = $this->subtask->getById($event['id'], true); $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(); $values['changes'] = isset($event['changes']) ? $event['changes'] : array();
switch (get_class($event)) { switch (get_class($event)) {
case 'Event\SubtaskEvent': case 'Kanboard\Event\SubtaskEvent':
$values['subtask'] = $this->subtask->getById($event['id'], true); $values['subtask'] = $this->subtask->getById($event['id'], true);
break; break;
case 'Event\CommentEvent': case 'Kanboard\Event\CommentEvent':
$values['comment'] = $this->comment->getById($event['id']); $values['comment'] = $this->comment->getById($event['id']);
break; 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);
}
}

View File

@@ -0,0 +1,41 @@
<?php
require_once __DIR__.'/../Base.php';
use Kanboard\Model\Project;
use Kanboard\Model\ProjectNotificationType;
class ProjectNotificationTypeTest extends Base
{
public function testGetTypes()
{
$nt = new ProjectNotificationType($this->container);
$this->assertEmpty($nt->getTypes());
$nt->setType('foo', 'Foo', 'Something1');
$nt->setType('bar', 'Bar', 'Something2');
$nt->setType('baz', 'Baz', 'Something3', true);
$this->assertEquals(array('bar' => 'Bar', 'foo' => 'Foo'), $nt->getTypes());
$this->assertEquals(array('baz'), $nt->getHiddenTypes());
}
public function testGetSelectedTypes()
{
$nt = new ProjectNotificationType($this->container);
$p = new Project($this->container);
$this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
// No type defined
$this->assertEmpty($nt->getSelectedTypes(1));
// Hidden type
$nt->setType('baz', 'Baz', 'Something3', true);
$this->assertEquals(array('baz'), $nt->getSelectedTypes(1));
// User defined types
$this->assertTrue($nt->saveSelectedTypes(1, array('foo', 'bar')));
$this->assertEquals(array('baz', 'bar', 'foo'), $nt->getSelectedTypes(1));
}
}

View File

@@ -16,7 +16,7 @@ class UserNotificationTypeTest extends Base
$this->assertEquals(array('email' => 'Email', 'web' => 'Web'), $nt->getTypes()); $this->assertEquals(array('email' => 'Email', 'web' => 'Web'), $nt->getTypes());
} }
public function testGetUserNotificationTypes() public function testGetSelectedTypes()
{ {
$nt = new UserNotificationType($this->container); $nt = new UserNotificationType($this->container);
$types = $nt->getSelectedTypes(1); $types = $nt->getSelectedTypes(1);

View File

@@ -8,7 +8,7 @@ use Kanboard\Model\TaskCreation;
use Kanboard\Model\TaskModification; use Kanboard\Model\TaskModification;
use Kanboard\Model\Project; use Kanboard\Model\Project;
use Kanboard\Model\Comment; use Kanboard\Model\Comment;
use Kanboard\Subscriber\WebhookSubscriber; use Kanboard\Subscriber\NotificationSubscriber;
class WebhookTest extends Base class WebhookTest extends Base
{ {
@@ -17,7 +17,7 @@ class WebhookTest extends Base
$c = new Config($this->container); $c = new Config($this->container);
$p = new Project($this->container); $p = new Project($this->container);
$tc = new TaskCreation($this->container); $tc = new TaskCreation($this->container);
$this->container['dispatcher']->addSubscriber(new WebhookSubscriber($this->container)); $this->container['dispatcher']->addSubscriber(new NotificationSubscriber($this->container));
$c->save(array('webhook_url' => 'http://localhost/?task-creation')); $c->save(array('webhook_url' => 'http://localhost/?task-creation'));
@@ -33,16 +33,16 @@ class WebhookTest extends Base
$this->assertEquals('task.create', $event['event_name']); $this->assertEquals('task.create', $event['event_name']);
$this->assertNotEmpty($event['event_data']); $this->assertNotEmpty($event['event_data']);
$this->assertArrayHasKey('project_id', $event['event_data']); $this->assertArrayHasKey('project_id', $event['event_data']['task']);
$this->assertArrayHasKey('task_id', $event['event_data']); $this->assertArrayHasKey('id', $event['event_data']['task']);
$this->assertArrayHasKey('title', $event['event_data']); $this->assertArrayHasKey('title', $event['event_data']['task']);
$this->assertArrayHasKey('column_id', $event['event_data']); $this->assertArrayHasKey('column_id', $event['event_data']['task']);
$this->assertArrayHasKey('color_id', $event['event_data']); $this->assertArrayHasKey('color_id', $event['event_data']['task']);
$this->assertArrayHasKey('swimlane_id', $event['event_data']); $this->assertArrayHasKey('swimlane_id', $event['event_data']['task']);
$this->assertArrayHasKey('date_creation', $event['event_data']); $this->assertArrayHasKey('date_creation', $event['event_data']['task']);
$this->assertArrayHasKey('date_modification', $event['event_data']); $this->assertArrayHasKey('date_modification', $event['event_data']['task']);
$this->assertArrayHasKey('date_moved', $event['event_data']); $this->assertArrayHasKey('date_moved', $event['event_data']['task']);
$this->assertArrayHasKey('position', $event['event_data']); $this->assertArrayHasKey('position', $event['event_data']['task']);
} }
public function testTaskModification() public function testTaskModification()
@@ -51,7 +51,7 @@ class WebhookTest extends Base
$p = new Project($this->container); $p = new Project($this->container);
$tc = new TaskCreation($this->container); $tc = new TaskCreation($this->container);
$tm = new TaskModification($this->container); $tm = new TaskModification($this->container);
$this->container['dispatcher']->addSubscriber(new WebhookSubscriber($this->container)); $this->container['dispatcher']->addSubscriber(new NotificationSubscriber($this->container));
$c->save(array('webhook_url' => 'http://localhost/modif/')); $c->save(array('webhook_url' => 'http://localhost/modif/'));
@@ -68,16 +68,16 @@ class WebhookTest extends Base
$this->assertEquals('task.update', $event['event_name']); $this->assertEquals('task.update', $event['event_name']);
$this->assertNotEmpty($event['event_data']); $this->assertNotEmpty($event['event_data']);
$this->assertArrayHasKey('project_id', $event['event_data']); $this->assertArrayHasKey('project_id', $event['event_data']['task']);
$this->assertArrayHasKey('task_id', $event['event_data']); $this->assertArrayHasKey('id', $event['event_data']['task']);
$this->assertArrayHasKey('title', $event['event_data']); $this->assertArrayHasKey('title', $event['event_data']['task']);
$this->assertArrayHasKey('column_id', $event['event_data']); $this->assertArrayHasKey('column_id', $event['event_data']['task']);
$this->assertArrayHasKey('color_id', $event['event_data']); $this->assertArrayHasKey('color_id', $event['event_data']['task']);
$this->assertArrayHasKey('swimlane_id', $event['event_data']); $this->assertArrayHasKey('swimlane_id', $event['event_data']['task']);
$this->assertArrayHasKey('date_creation', $event['event_data']); $this->assertArrayHasKey('date_creation', $event['event_data']['task']);
$this->assertArrayHasKey('date_modification', $event['event_data']); $this->assertArrayHasKey('date_modification', $event['event_data']['task']);
$this->assertArrayHasKey('date_moved', $event['event_data']); $this->assertArrayHasKey('date_moved', $event['event_data']['task']);
$this->assertArrayHasKey('position', $event['event_data']); $this->assertArrayHasKey('position', $event['event_data']['task']);
} }
public function testCommentCreation() public function testCommentCreation()
@@ -86,7 +86,7 @@ class WebhookTest extends Base
$p = new Project($this->container); $p = new Project($this->container);
$tc = new TaskCreation($this->container); $tc = new TaskCreation($this->container);
$cm = new Comment($this->container); $cm = new Comment($this->container);
$this->container['dispatcher']->addSubscriber(new WebhookSubscriber($this->container)); $this->container['dispatcher']->addSubscriber(new NotificationSubscriber($this->container));
$c->save(array('webhook_url' => 'http://localhost/comment')); $c->save(array('webhook_url' => 'http://localhost/comment'));
@@ -103,10 +103,10 @@ class WebhookTest extends Base
$this->assertEquals('comment.create', $event['event_name']); $this->assertEquals('comment.create', $event['event_name']);
$this->assertNotEmpty($event['event_data']); $this->assertNotEmpty($event['event_data']);
$this->assertArrayHasKey('task_id', $event['event_data']); $this->assertArrayHasKey('task_id', $event['event_data']['comment']);
$this->assertArrayHasKey('user_id', $event['event_data']); $this->assertArrayHasKey('user_id', $event['event_data']['comment']);
$this->assertArrayHasKey('comment', $event['event_data']); $this->assertArrayHasKey('comment', $event['event_data']['comment']);
$this->assertArrayHasKey('id', $event['event_data']); $this->assertArrayHasKey('id', $event['event_data']['comment']);
$this->assertEquals('test comment', $event['event_data']['comment']); $this->assertEquals('test comment', $event['event_data']['comment']['comment']);
} }
} }