diff options
author | Frederic Guillot <fred@kanboard.net> | 2015-06-07 20:06:31 -0400 |
---|---|---|
committer | Frederic Guillot <fred@kanboard.net> | 2015-06-07 20:06:31 -0400 |
commit | 4f32352fe62e47ad5ea760eb00493bdc061b2407 (patch) | |
tree | 8d5f087907dd5cba196dbfc06e626b3146659e1f | |
parent | 9d9e3afba2054bfa23ba6f019b7c8885c2d8415e (diff) |
Add user filter/condition for notifications
-rw-r--r-- | app/Console/TaskOverdueNotification.php | 20 | ||||
-rw-r--r-- | app/Controller/User.php | 6 | ||||
-rw-r--r-- | app/Model/Base.php | 19 | ||||
-rw-r--r-- | app/Model/Notification.php | 335 | ||||
-rw-r--r-- | app/Model/SubtaskTimeTracking.php | 3 | ||||
-rw-r--r-- | app/Model/Task.php | 1 | ||||
-rw-r--r-- | app/Model/TaskFinder.php | 2 | ||||
-rw-r--r-- | app/Schema/Mysql.php | 7 | ||||
-rw-r--r-- | app/Schema/Postgres.php | 7 | ||||
-rw-r--r-- | app/Schema/Sqlite.php | 7 | ||||
-rw-r--r-- | app/Subscriber/NotificationSubscriber.php | 27 | ||||
-rw-r--r-- | app/Template/notification/task_overdue.php (renamed from app/Template/notification/task_due.php) | 4 | ||||
-rw-r--r-- | app/Template/user/notifications.php | 16 | ||||
-rw-r--r-- | tests/units/Base.php | 17 | ||||
-rw-r--r-- | tests/units/NotificationTest.php | 272 |
15 files changed, 538 insertions, 205 deletions
diff --git a/app/Console/TaskOverdueNotification.php b/app/Console/TaskOverdueNotification.php index 86a7d1b9..3d254ae4 100644 --- a/app/Console/TaskOverdueNotification.php +++ b/app/Console/TaskOverdueNotification.php @@ -19,25 +19,7 @@ class TaskOverdueNotification extends Base protected function execute(InputInterface $input, OutputInterface $output) { - $projects = array(); - $tasks = $this->taskFinder->getOverdueTasks(); - - // Group tasks by project - foreach ($tasks as $task) { - $projects[$task['project_id']][] = $task; - } - - // Send notifications for each project - foreach ($projects as $project_id => $project_tasks) { - - $users = $this->notification->getUsersList($project_id); - - $this->notification->sendEmails( - 'task_due', - $users, - array('tasks' => $project_tasks, 'project' => $project_tasks[0]['project_name']) - ); - } + $tasks = $this->notification->sendOverdueTaskNotifications(); if ($input->getOption('show')) { $this->showTable($output, $tasks); diff --git a/app/Controller/User.php b/app/Controller/User.php index b049c926..4cea06b1 100644 --- a/app/Controller/User.php +++ b/app/Controller/User.php @@ -105,9 +105,11 @@ class User extends Base if ($valid) { - if ($this->user->create($values)) { + $user_id = $this->user->create($values); + + if ($user_id !== false) { $this->session->flash(t('User created successfully.')); - $this->response->redirect('?controller=user'); + $this->response->redirect($this->helper->url->to('user', 'show', array('user_id' => $user_id))); } else { $this->session->flashError(t('Unable to create your user.')); diff --git a/app/Model/Base.php b/app/Model/Base.php index 784545fe..51ae782d 100644 --- a/app/Model/Base.php +++ b/app/Model/Base.php @@ -143,4 +143,23 @@ abstract class Base extends \Core\Base 'url' => $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])), ); } + + /** + * Group a collection of records by a column + * + * @access public + * @param array $collection + * @param string $column + * @return array + */ + public function groupByColumn(array $collection, $column) + { + $result = array(); + + foreach ($collection as $item) { + $result[$item[$column]][] = $item; + } + + return $result; + } } diff --git a/app/Model/Notification.php b/app/Model/Notification.php index 0c2a5d24..7255a414 100644 --- a/app/Model/Notification.php +++ b/app/Model/Notification.php @@ -21,186 +21,326 @@ class Notification extends Base const TABLE = 'user_has_notifications'; /** - * Get a list of people with notifications enabled + * User filters + * + * @var integer + */ + const FILTER_NONE = 1; + const FILTER_ASSIGNEE = 2; + const FILTER_CREATOR = 3; + const FILTER_BOTH = 4; + + /** + * Send overdue tasks * * @access public - * @param integer $project_id Project id - * @param array $exclude_users List of user_id to exclude - * @return array */ - public function getUsersWithNotification($project_id, array $exclude_users = array()) + public function sendOverdueTaskNotifications() { - if ($this->projectPermission->isEverybodyAllowed($project_id)) { + $tasks = $this->taskFinder->getOverdueTasks(); + $projects = array(); - return $this->db - ->table(User::TABLE) - ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', User::TABLE.'.email', User::TABLE.'.language') - ->eq('notifications_enabled', '1') - ->neq('email', '') - ->notin(User::TABLE.'.id', $exclude_users) - ->findAll(); + 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->notification->getUsersWithNotificationEnabled($project_id); + + foreach ($users as $user) { + $this->sendUserOverdueTaskNotifications($user, $project_tasks); + } } - return $this->db - ->table(ProjectPermission::TABLE) - ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', User::TABLE.'.email', User::TABLE.'.language') - ->join(User::TABLE, 'id', 'user_id') - ->eq('project_id', $project_id) - ->eq('notifications_enabled', '1') - ->neq('email', '') - ->notin(User::TABLE.'.id', $exclude_users) - ->findAll(); + return $tasks; } /** - * Get the list of users to send the notification for a given project + * Send overdue tasks for a given user * * @access public - * @param integer $project_id Project id - * @param array $exclude_users List of user_id to exclude - * @return array + * @param array $user + * @param array $tasks */ - public function getUsersList($project_id, array $exclude_users = array()) + public function sendUserOverdueTaskNotifications(array $user, array $tasks) { - // Exclude the connected user - if (Session::isOpen() && $this->userSession->isLogged()) { - $exclude_users[] = $this->userSession->getId(); + $user_tasks = array(); + + foreach ($tasks as $task) { + if ($this->notification->shouldReceiveNotification($user, array('task' => $task))) { + $user_tasks[] = $task; + } } - $users = $this->getUsersWithNotification($project_id, $exclude_users); + if (! empty($user_tasks)) { + $this->sendEmailNotification( + $user, + Task::EVENT_OVERDUE, + array('tasks' => $user_tasks, 'project_name' => $tasks[0]['project_name']) + ); + } + } - foreach ($users as $index => $user) { + /** + * Send notifications to people + * + * @access public + * @param string $event_name + * @param array $event_data + */ + public function sendNotifications($event_name, array $event_data) + { + $logged_user_id = $this->userSession->isLogged() ? $this->userSession->getId() : 0; + $users = $this->notification->getUsersWithNotificationEnabled($event_data['task']['project_id'], $logged_user_id); - $projects = $this->db->table(self::TABLE) - ->eq('user_id', $user['id']) - ->findAllByColumn('project_id'); + foreach ($users as $user) { + if ($this->shouldReceiveNotification($user, $event_data)) { + $this->sendEmailNotification($user, $event_name, $event_data); + } + } - // The user have selected only some projects - if (! empty($projects)) { + // Restore locales + $this->config->setupTranslations(); + } - // If the user didn't select this project we remove that guy from the list - if (! in_array($project_id, $projects)) { - unset($users[$index]); - } - } + /** + * Send email notification to someone + * + * @access public + * @param array $user User + * @param string $event_name + * @param array $event_data + */ + public function sendEmailNotification(array $user, $event_name, array $event_data) + { + // Use the user language otherwise use the application language (do not use the session language) + if (! empty($user['language'])) { + Translator::load($user['language']); + } + else { + Translator::load($this->config->get('application_language', 'en_US')); } - return $users; + $this->emailClient->send( + $user['email'], + $user['name'] ?: $user['username'], + $this->getMailSubject($event_name, $event_data), + $this->getMailContent($event_name, $event_data) + ); } /** - * Send the email notifications + * Return true if the user should receive notification * * @access public - * @param string $template Template name - * @param array $users List of users - * @param array $data Template data + * @param array $user + * @param array $event_data + * @return boolean */ - public function sendEmails($template, array $users, array $data) + public function shouldReceiveNotification(array $user, array $event_data) { - foreach ($users as $user) { + $filters = array( + 'filterNone', + 'filterAssignee', + 'filterCreator', + 'filterBoth', + ); - // Use the user language otherwise use the application language (do not use the session language) - if (! empty($user['language'])) { - Translator::load($user['language']); - } - else { - Translator::load($this->config->get('application_language', 'en_US')); + foreach ($filters as $filter) { + if ($this->$filter($user, $event_data)) { + return $this->filterProject($user, $event_data); } + } - $this->emailClient->send( - $user['email'], - $user['name'] ?: $user['username'], - $this->getMailSubject($template, $data), - $this->getMailContent($template, $data) - ); + return false; + } + + /** + * Return true if the user will receive all notifications + * + * @access public + * @param array $user + * @param array $event_data + * @return boolean + */ + public function filterNone(array $user, array $event_data) + { + return $user['notifications_filter'] == self::FILTER_NONE; + } + + /** + * Return true if the user is the assignee and selected the filter "assignee" + * + * @access public + * @param array $user + * @param array $event_data + * @return boolean + */ + public function filterAssignee(array $user, array $event_data) + { + return $user['notifications_filter'] == self::FILTER_ASSIGNEE && $event_data['task']['owner_id'] == $user['id']; + } + + /** + * Return true if the user is the creator and enabled the filter "creator" + * + * @access public + * @param array $user + * @param array $event_data + * @return boolean + */ + public function filterCreator(array $user, array $event_data) + { + return $user['notifications_filter'] == self::FILTER_CREATOR && $event_data['task']['creator_id'] == $user['id']; + } + + /** + * Return true if the user is the assignee or the creator and selected the filter "both" + * + * @access public + * @param array $user + * @param array $event_data + * @return boolean + */ + public function filterBoth(array $user, array $event_data) + { + return $user['notifications_filter'] == self::FILTER_BOTH && + ($event_data['task']['creator_id'] == $user['id'] || $event_data['task']['owner_id'] == $user['id']); + } + + /** + * Return true if the user want to receive notification for the selected project + * + * @access public + * @param array $user + * @param array $event_data + * @return boolean + */ + public function filterProject(array $user, array $event_data) + { + $projects = $this->db->table(self::TABLE)->eq('user_id', $user['id'])->findAllByColumn('project_id'); + + if (! empty($projects)) { + return in_array($event_data['task']['project_id'], $projects); } - // Restore locales - $this->config->setupTranslations(); + return true; } /** - * Get the mail subject for a given label + * Get a list of people with notifications enabled * - * @access private - * @param string $label Label - * @param array $data Template data + * @access public + * @param integer $project_id Project id + * @param array $exclude_user_id User id to exclude + * @return array */ - private function getStandardMailSubject($label, array $data) + public function getUsersWithNotificationEnabled($project_id, $exclude_user_id = 0) { - return sprintf('[%s][%s] %s (#%d)', $data['task']['project_name'], $label, $data['task']['title'], $data['task']['id']); + if ($this->projectPermission->isEverybodyAllowed($project_id)) { + + return $this->db + ->table(User::TABLE) + ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', User::TABLE.'.email', User::TABLE.'.language', User::TABLE.'.notifications_filter') + ->eq('notifications_enabled', '1') + ->neq('email', '') + ->neq(User::TABLE.'.id', $exclude_user_id) + ->findAll(); + } + + return $this->db + ->table(ProjectPermission::TABLE) + ->columns(User::TABLE.'.id', User::TABLE.'.username', User::TABLE.'.name', User::TABLE.'.email', User::TABLE.'.language', User::TABLE.'.notifications_filter') + ->join(User::TABLE, 'id', 'user_id') + ->eq('project_id', $project_id) + ->eq('notifications_enabled', '1') + ->neq('email', '') + ->neq(User::TABLE.'.id', $exclude_user_id) + ->findAll(); + } + + /** + * Get the mail content for a given template name + * + * @access public + * @param string $event_name Event name + * @param array $event_data Event data + * @return string + */ + public function getMailContent($event_name, array $event_data) + { + return $this->template->render( + 'notification/'.str_replace('.', '_', $event_name), + $event_data + array('application_url' => $this->config->get('application_url')) + ); } /** * Get the mail subject for a given template name * * @access public - * @param string $template Template name - * @param array $data Template data + * @param string $event_name Event name + * @param array $event_data Event data + * @return string */ public function getMailSubject($template, array $data) { switch ($template) { - case 'file_creation': + case Task::EVENT_CREATE: $subject = $this->getStandardMailSubject(e('New attachment'), $data); break; - case 'comment_creation': + case Comment::EVENT_CREATE: $subject = $this->getStandardMailSubject(e('New comment'), $data); break; - case 'comment_update': + case Comment::EVENT_UPDATE: $subject = $this->getStandardMailSubject(e('Comment updated'), $data); break; - case 'subtask_creation': + case Subtask::EVENT_CREATE: $subject = $this->getStandardMailSubject(e('New subtask'), $data); break; - case 'subtask_update': + case Subtask::EVENT_UPDATE: $subject = $this->getStandardMailSubject(e('Subtask updated'), $data); break; - case 'task_creation': + case Task::EVENT_CREATE: $subject = $this->getStandardMailSubject(e('New task'), $data); break; - case 'task_update': + case Task::EVENT_UPDATE: $subject = $this->getStandardMailSubject(e('Task updated'), $data); break; - case 'task_close': + case Task::EVENT_CLOSE: $subject = $this->getStandardMailSubject(e('Task closed'), $data); break; - case 'task_open': + case Task::EVENT_OPEN: $subject = $this->getStandardMailSubject(e('Task opened'), $data); break; - case 'task_move_column': + case Task::EVENT_MOVE_COLUMN: $subject = $this->getStandardMailSubject(e('Column Change'), $data); break; - case 'task_move_position': + case Task::EVENT_MOVE_POSITION: $subject = $this->getStandardMailSubject(e('Position Change'), $data); break; - case 'task_assignee_change': + case Task::EVENT_ASSIGNEE_CHANGE: $subject = $this->getStandardMailSubject(e('Assignee Change'), $data); break; - case 'task_due': - $subject = e('[%s][Due tasks]', $data['project']); + case Task::EVENT_OVERDUE: + $subject = e('[%s] Overdue tasks', $data['project_name']); break; default: - $subject = e('[Kanboard] Notification'); + $subject = e('Notification'); } return $subject; } /** - * Get the mail content for a given template name + * Get the mail subject for a given label * - * @access public - * @param string $template Template name + * @access private + * @param string $label Label * @param array $data Template data + * @return string */ - public function getMailContent($template, array $data) + private function getStandardMailSubject($label, array $data) { - return $this->template->render( - 'notification/'.$template, - $data + array('application_url' => $this->config->get('application_url')) - ); + return sprintf('[%s][%s] %s (#%d)', $data['task']['project_name'], $label, $data['task']['title'], $data['task']['id']); } /** @@ -219,7 +359,8 @@ class Notification extends Base // Activate notifications $this->db->table(User::TABLE)->eq('id', $user_id)->update(array( - 'notifications_enabled' => '1' + 'notifications_enabled' => '1', + 'notifications_filter' => empty($values['notifications_filter']) ? self::FILTER_BOTH : $values['notifications_filter'], )); // Save selected projects @@ -251,9 +392,7 @@ class Notification extends Base */ public function readSettings($user_id) { - $values = array(); - $values['notifications_enabled'] = $this->db->table(User::TABLE)->eq('id', $user_id)->findOneColumn('notifications_enabled'); - + $values = $this->db->table(User::TABLE)->eq('id', $user_id)->columns('notifications_enabled', 'notifications_filter')->findOne(); $projects = $this->db->table(self::TABLE)->eq('user_id', $user_id)->findAllByColumn('project_id'); foreach ($projects as $project_id) { diff --git a/app/Model/SubtaskTimeTracking.php b/app/Model/SubtaskTimeTracking.php index d4edf660..93a698b6 100644 --- a/app/Model/SubtaskTimeTracking.php +++ b/app/Model/SubtaskTimeTracking.php @@ -105,7 +105,8 @@ class SubtaskTimeTracking extends Base ->join(Subtask::TABLE, 'id', 'subtask_id') ->join(Task::TABLE, 'id', 'task_id', Subtask::TABLE) ->join(User::TABLE, 'id', 'user_id', self::TABLE) - ->eq(Task::TABLE.'.project_id', $project_id); + ->eq(Task::TABLE.'.project_id', $project_id) + ->asc(self::TABLE.'.id'); } /** diff --git a/app/Model/Task.php b/app/Model/Task.php index abd787ad..71d973a4 100644 --- a/app/Model/Task.php +++ b/app/Model/Task.php @@ -40,6 +40,7 @@ class Task extends Base const EVENT_OPEN = 'task.open'; const EVENT_CREATE_UPDATE = 'task.create_update'; const EVENT_ASSIGNEE_CHANGE = 'task.assignee_change'; + const EVENT_OVERDUE = 'task.overdue'; /** * Recurrence: status diff --git a/app/Model/TaskFinder.php b/app/Model/TaskFinder.php index 6f53249a..5a1d33c6 100644 --- a/app/Model/TaskFinder.php +++ b/app/Model/TaskFinder.php @@ -168,6 +168,8 @@ class TaskFinder extends Base Task::TABLE.'.title', Task::TABLE.'.date_due', Task::TABLE.'.project_id', + Task::TABLE.'.creator_id', + Task::TABLE.'.owner_id', Project::TABLE.'.name AS project_name', User::TABLE.'.username AS assignee_username', User::TABLE.'.name AS assignee_name' diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php index a65525c8..bcb365bd 100644 --- a/app/Schema/Mysql.php +++ b/app/Schema/Mysql.php @@ -6,7 +6,12 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 72; +const VERSION = 73; + +function version_73($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN notifications_filter INT DEFAULT 4"); +} function version_72($pdo) { diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php index 0afcd26a..65a9c9bf 100644 --- a/app/Schema/Postgres.php +++ b/app/Schema/Postgres.php @@ -6,7 +6,12 @@ use PDO; use Core\Security; use Model\Link; -const VERSION = 52; +const VERSION = 53; + +function version_53($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN notifications_filter INTEGER DEFAULT 4"); +} function version_52($pdo) { diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php index 43fb136e..ceb3028c 100644 --- a/app/Schema/Sqlite.php +++ b/app/Schema/Sqlite.php @@ -6,7 +6,12 @@ use Core\Security; use PDO; use Model\Link; -const VERSION = 70; +const VERSION = 71; + +function version_71($pdo) +{ + $pdo->exec("ALTER TABLE users ADD COLUMN notifications_filter INTEGER DEFAULT 4"); +} function version_70($pdo) { diff --git a/app/Subscriber/NotificationSubscriber.php b/app/Subscriber/NotificationSubscriber.php index 92d46754..41fd6aef 100644 --- a/app/Subscriber/NotificationSubscriber.php +++ b/app/Subscriber/NotificationSubscriber.php @@ -11,21 +11,6 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; class NotificationSubscriber extends \Core\Base implements EventSubscriberInterface { - private $templates = array( - Task::EVENT_CREATE => 'task_creation', - Task::EVENT_UPDATE => 'task_update', - Task::EVENT_CLOSE => 'task_close', - Task::EVENT_OPEN => 'task_open', - Task::EVENT_MOVE_COLUMN => 'task_move_column', - Task::EVENT_MOVE_POSITION => 'task_move_position', - Task::EVENT_ASSIGNEE_CHANGE => 'task_assignee_change', - Subtask::EVENT_CREATE => 'subtask_creation', - Subtask::EVENT_UPDATE => 'subtask_update', - Comment::EVENT_CREATE => 'comment_creation', - Comment::EVENT_UPDATE => 'comment_update', - File::EVENT_CREATE => 'file_creation', - ); - public static function getSubscribedEvents() { return array( @@ -46,18 +31,10 @@ class NotificationSubscriber extends \Core\Base implements EventSubscriberInterf public function execute(GenericEvent $event, $event_name) { - $values = $this->getTemplateData($event); - - if (isset($values['task']['project_id'])) { - $users = $this->notification->getUsersList($values['task']['project_id']); - - if (! empty($users)) { - $this->notification->sendEmails($this->templates[$event_name], $users, $values); - } - } + $this->notification->sendNotifications($event_name, $this->getEventData($event)); } - public function getTemplateData(GenericEvent $event) + public function getEventData(GenericEvent $event) { $values = array(); diff --git a/app/Template/notification/task_due.php b/app/Template/notification/task_overdue.php index 7482424a..dc2659dc 100644 --- a/app/Template/notification/task_due.php +++ b/app/Template/notification/task_overdue.php @@ -1,4 +1,4 @@ -<h2><?= t('List of due tasks for the project "%s"', $project) ?></h2> +<h2><?= t('Overdue tasks for the project "%s"', $project_name) ?></h2> <ul> <?php foreach ($tasks as $task): ?> @@ -16,5 +16,3 @@ </li> <?php endforeach ?> </ul> - -<?= $this->render('notification/footer', array('task' => $task)) ?> diff --git a/app/Template/user/notifications.php b/app/Template/user/notifications.php index df5cbb9b..a425705d 100644 --- a/app/Template/user/notifications.php +++ b/app/Template/user/notifications.php @@ -5,15 +5,27 @@ <form method="post" action="<?= $this->url->href('user', 'notifications', array('user_id' => $user['id'])) ?>" autocomplete="off"> <?= $this->form->csrf() ?> + <?= $this->form->checkbox('notifications_enabled', t('Enable email notifications'), '1', $notifications['notifications_enabled'] == 1) ?><br> - <?= $this->form->checkbox('notifications_enabled', t('Enable email notifications'), '1', $notifications['notifications_enabled'] == 1) ?><br/> + <hr> + + <?= t('I want to receive notifications for:') ?> + + <?= $this->form->radios('notifications_filter', array( + \Model\Notification::FILTER_NONE => t('All tasks'), + \Model\Notification::FILTER_ASSIGNEE => t('Only for tasks assigned to me'), + \Model\Notification::FILTER_CREATOR => t('Only for tasks created by me'), + \Model\Notification::FILTER_BOTH => t('Only for tasks created by me and assigned to me'), + ), $notifications) ?><br> + + <hr> <?php if (! empty($projects)): ?> <p><?= t('I want to receive notifications only for those projects:') ?><br/><br/></p> <div class="form-checkbox-group"> <?php foreach ($projects as $project_id => $project_name): ?> - <?= $this->form->checkbox('projects['.$project_id.']', $project_name, '1', isset($notifications['project_'.$project_id])) ?><br/> + <?= $this->form->checkbox('projects['.$project_id.']', $project_name, '1', isset($notifications['project_'.$project_id])) ?><br> <?php endforeach ?> </div> <?php endif ?> diff --git a/tests/units/Base.php b/tests/units/Base.php index d5fea977..a90987ab 100644 --- a/tests/units/Base.php +++ b/tests/units/Base.php @@ -11,6 +11,22 @@ use SimpleLogger\File; date_default_timezone_set('UTC'); +class FakeEmailClient +{ + public $email; + public $name; + public $subject; + public $html; + + public function send($email, $name, $subject, $html) + { + $this->email = $email; + $this->name = $name; + $this->subject = $subject; + $this->html = $html; + } +} + class FakeHttpClient { private $url = ''; @@ -79,6 +95,7 @@ abstract class Base extends PHPUnit_Framework_TestCase $this->container['logger'] = new Logger; $this->container['logger']->setLogger(new File('/dev/null')); $this->container['httpClient'] = new FakeHttpClient; + $this->container['emailClient'] = new FakeEmailClient; } public function tearDown() diff --git a/tests/units/NotificationTest.php b/tests/units/NotificationTest.php index 37285212..4421fd47 100644 --- a/tests/units/NotificationTest.php +++ b/tests/units/NotificationTest.php @@ -9,7 +9,155 @@ use Model\Notification; class NotificationTest extends Base { - public function testGetUsersWithNotification() + public function testFilterNone() + { + $u = new User($this->container); + $n = new Notification($this->container); + + $this->assertEquals(2, $u->create(array('username' => 'user1', 'notifications_filter' => Notification::FILTER_NONE))); + $this->assertTrue($n->filterNone($u->getById(2), array())); + + $this->assertEquals(3, $u->create(array('username' => 'user2', 'notifications_filter' => Notification::FILTER_BOTH))); + $this->assertFalse($n->filterNone($u->getById(3), array())); + } + + public function testFilterCreator() + { + $u = new User($this->container); + $n = new Notification($this->container); + + $this->assertEquals(2, $u->create(array('username' => 'user1', 'notifications_filter' => Notification::FILTER_CREATOR))); + $this->assertTrue($n->filterCreator($u->getById(2), array('task' => array('creator_id' => 2)))); + + $this->assertEquals(3, $u->create(array('username' => 'user2', 'notifications_filter' => Notification::FILTER_CREATOR))); + $this->assertFalse($n->filterCreator($u->getById(3), array('task' => array('creator_id' => 1)))); + + $this->assertEquals(4, $u->create(array('username' => 'user3', 'notifications_filter' => Notification::FILTER_NONE))); + $this->assertFalse($n->filterCreator($u->getById(4), array('task' => array('creator_id' => 2)))); + } + + public function testFilterAssignee() + { + $u = new User($this->container); + $n = new Notification($this->container); + + $this->assertEquals(2, $u->create(array('username' => 'user1', 'notifications_filter' => Notification::FILTER_ASSIGNEE))); + $this->assertTrue($n->filterAssignee($u->getById(2), array('task' => array('owner_id' => 2)))); + + $this->assertEquals(3, $u->create(array('username' => 'user2', 'notifications_filter' => Notification::FILTER_ASSIGNEE))); + $this->assertFalse($n->filterAssignee($u->getById(3), array('task' => array('owner_id' => 1)))); + + $this->assertEquals(4, $u->create(array('username' => 'user3', 'notifications_filter' => Notification::FILTER_NONE))); + $this->assertFalse($n->filterAssignee($u->getById(4), array('task' => array('owner_id' => 2)))); + } + + public function testFilterBoth() + { + $u = new User($this->container); + $n = new Notification($this->container); + + $this->assertEquals(2, $u->create(array('username' => 'user1', 'notifications_filter' => Notification::FILTER_BOTH))); + $this->assertTrue($n->filterBoth($u->getById(2), array('task' => array('owner_id' => 2, 'creator_id' => 1)))); + $this->assertTrue($n->filterBoth($u->getById(2), array('task' => array('owner_id' => 0, 'creator_id' => 2)))); + + $this->assertEquals(3, $u->create(array('username' => 'user2', 'notifications_filter' => Notification::FILTER_BOTH))); + $this->assertFalse($n->filterBoth($u->getById(3), array('task' => array('owner_id' => 1, 'creator_id' => 1)))); + $this->assertFalse($n->filterBoth($u->getById(3), array('task' => array('owner_id' => 2, 'creator_id' => 1)))); + + $this->assertEquals(4, $u->create(array('username' => 'user3', 'notifications_filter' => Notification::FILTER_NONE))); + $this->assertFalse($n->filterBoth($u->getById(4), array('task' => array('owner_id' => 2, 'creator_id' => 1)))); + } + + public function testFilterProject() + { + $u = new User($this->container); + $n = new Notification($this->container); + $p = new Project($this->container); + + $this->assertEquals(1, $p->create(array('name' => 'UnitTest1'))); + $this->assertEquals(2, $p->create(array('name' => 'UnitTest2'))); + + // No project selected + $this->assertTrue($n->filterProject($u->getById(1), array())); + + // User that select only some projects + $this->assertEquals(2, $u->create(array('username' => 'user2', 'notifications_filter' => Notification::FILTER_NONE))); + $n->saveSettings(2, array('notifications_enabled' => 1, 'projects' => array(2 => true))); + + $this->assertFalse($n->filterProject($u->getById(2), array('task' => array('project_id' => 1)))); + $this->assertTrue($n->filterProject($u->getById(2), array('task' => array('project_id' => 2)))); + } + + public function testFilterUserWithNoFilter() + { + $u = new User($this->container); + $n = new Notification($this->container); + $p = new Project($this->container); + + $this->assertEquals(2, $u->create(array('username' => 'user2', 'notifications_filter' => Notification::FILTER_NONE))); + + $this->assertTrue($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 1)))); + } + + public function testFilterUserWithAssigneeFilter() + { + $u = new User($this->container); + $n = new Notification($this->container); + $p = new Project($this->container); + + $this->assertEquals(2, $u->create(array('username' => 'user2', 'notifications_filter' => Notification::FILTER_ASSIGNEE))); + + $this->assertTrue($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 1, 'owner_id' => 2)))); + $this->assertFalse($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 1, 'owner_id' => 1)))); + } + + public function testFilterUserWithCreatorFilter() + { + $u = new User($this->container); + $n = new Notification($this->container); + $p = new Project($this->container); + + $this->assertEquals(2, $u->create(array('username' => 'user2', 'notifications_filter' => Notification::FILTER_CREATOR))); + + $this->assertTrue($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 1, 'creator_id' => 2)))); + $this->assertFalse($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 1, 'creator_id' => 1)))); + } + + public function testFilterUserWithBothFilter() + { + $u = new User($this->container); + $n = new Notification($this->container); + $p = new Project($this->container); + + $this->assertEquals(2, $u->create(array('username' => 'user2', 'notifications_filter' => Notification::FILTER_BOTH))); + + $this->assertTrue($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 1, 'creator_id' => 2, 'owner_id' => 3)))); + $this->assertTrue($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 1, 'creator_id' => 0, 'owner_id' => 2)))); + $this->assertFalse($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 1, 'creator_id' => 4, 'owner_id' => 1)))); + $this->assertFalse($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 1, 'creator_id' => 5, 'owner_id' => 0)))); + } + + public function testFilterUserWithBothFilterAndProjectSelected() + { + $u = new User($this->container); + $n = new Notification($this->container); + $p = new Project($this->container); + + $this->assertEquals(1, $p->create(array('name' => 'UnitTest1'))); + $this->assertEquals(2, $p->create(array('name' => 'UnitTest2'))); + + $this->assertEquals(2, $u->create(array('username' => 'user2', 'notifications_filter' => Notification::FILTER_BOTH))); + + $n->saveSettings(2, array('notifications_enabled' => 1, 'projects' => array(2 => true))); + + $this->assertFalse($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 1, 'creator_id' => 2, 'owner_id' => 3)))); + $this->assertFalse($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 1, 'creator_id' => 0, 'owner_id' => 2)))); + + $this->assertTrue($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 2, 'creator_id' => 2, 'owner_id' => 3)))); + $this->assertTrue($n->shouldReceiveNotification($u->getById(2), array('task' => array('project_id' => 2, 'creator_id' => 0, 'owner_id' => 2)))); + } + + public function testGetProjectMembersWithNotifications() { $u = new User($this->container); $p = new Project($this->container); @@ -32,7 +180,7 @@ class NotificationTest extends Base // Nobody is member of any projects $this->assertEmpty($pp->getMembers(1)); - $this->assertEmpty($n->getUsersWithNotification(1)); + $this->assertEmpty($n->getUsersWithNotificationEnabled(1)); // We allow all users to be member of our projects $this->assertTrue($pp->addMember(1, 1)); @@ -41,7 +189,7 @@ class NotificationTest extends Base $this->assertTrue($pp->addMember(1, 4)); $this->assertNotEmpty($pp->getMembers(1)); - $users = $n->getUsersWithNotification(1); + $users = $n->getUsersWithNotificationEnabled(1); $this->assertNotEmpty($users); $this->assertEquals(2, count($users)); @@ -49,16 +197,15 @@ class NotificationTest extends Base $this->assertEquals('user3@here', $users[1]['email']); } - public function testGetUserList() + public function testGetUsersWithNotificationsWhenEverybodyAllowed() { $u = new User($this->container); $p = new Project($this->container); - $pp = new ProjectPermission($this->container); $n = new Notification($this->container); + $pp = new ProjectPermission($this->container); - $this->assertEquals(1, $p->create(array('name' => 'UnitTest1'))); - $this->assertEquals(2, $p->create(array('name' => 'UnitTest2'))); - $this->assertEquals(3, $p->create(array('name' => 'UnitTest3', 'is_everybody_allowed' => 1))); + $this->assertEquals(1, $p->create(array('name' => 'UnitTest1', 'is_everybody_allowed' => 1))); + $this->assertTrue($pp->isEverybodyAllowed(1)); // Email + Notifications enabled $this->assertNotFalse($u->create(array('username' => 'user1', 'email' => 'user1@here', 'notifications_enabled' => 1))); @@ -72,62 +219,83 @@ class NotificationTest extends Base // No email + notifications disabled $this->assertNotFalse($u->create(array('username' => 'user4'))); - // We allow all users to be member of our projects - $this->assertTrue($pp->addMember(1, 1)); - $this->assertTrue($pp->addMember(1, 2)); - $this->assertTrue($pp->addMember(1, 3)); - $this->assertTrue($pp->addMember(1, 4)); - - $this->assertTrue($pp->addMember(2, 1)); - $this->assertTrue($pp->addMember(2, 2)); - $this->assertTrue($pp->addMember(2, 3)); - $this->assertTrue($pp->addMember(2, 4)); + $users = $n->getUsersWithNotificationEnabled(1); - $users = $n->getUsersList(1); $this->assertNotEmpty($users); $this->assertEquals(2, count($users)); $this->assertEquals('user1@here', $users[0]['email']); $this->assertEquals('user3@here', $users[1]['email']); + } - $users = $n->getUsersList(2); - $this->assertNotEmpty($users); - $this->assertEquals(2, count($users)); - $this->assertEquals('user1@here', $users[0]['email']); - $this->assertEquals('user3@here', $users[1]['email']); + public function testGetMailContent() + { + $n = new Notification($this->container); + $this->assertNotEmpty($n->getMailContent('task.open', array('task' => array('id' => 2, 'title' => 'blah')))); + } - // User 3 choose to receive notification only for project 2 - $n->saveSettings(4, array('notifications_enabled' => 1, 'projects' => array(2 => true))); + public function testGetEmailSubject() + { + $n = new Notification($this->container); - $users = $n->getUsersList(1); - $this->assertNotEmpty($users); - $this->assertEquals(1, count($users)); - $this->assertEquals('user1@here', $users[0]['email']); + $this->assertEquals( + '[test][Task opened] blah (#2)', + $n->getMailSubject('task.open', array('task' => array('id' => 2, 'title' => 'blah', 'project_name' => 'test'))) + ); + } - $users = $n->getUsersList(2); - $this->assertNotEmpty($users); - $this->assertEquals(2, count($users)); - $this->assertEquals('user1@here', $users[0]['email']); - $this->assertEquals('user3@here', $users[1]['email']); + public function testSendNotificationsToCreator() + { + $u = new User($this->container); + $p = new Project($this->container); + $n = new Notification($this->container); + $pp = new ProjectPermission($this->container); - // User 1 excluded - $users = $n->getUsersList(1, array(2)); - $this->assertEmpty($users); + $this->assertEquals(1, $p->create(array('name' => 'UnitTest1'))); + $this->assertEquals(2, $u->create(array('username' => 'user1', 'email' => 'user1@here', 'notifications_enabled' => 1))); + $this->assertTrue($pp->addMember(1, 2)); - $users = $n->getUsersList(2, array(2)); - $this->assertNotEmpty($users); - $this->assertEquals(1, count($users)); - $this->assertEquals('user3@here', $users[0]['email']); + $n->sendNotifications('task.open', array('task' => array( + 'id' => 2, 'title' => 'blah', 'project_name' => 'test', 'project_id' => 1, 'owner_id' => 0, 'creator_id' => 2 + ))); - // Project #3 allow everybody - $users = $n->getUsersList(3); - $this->assertNotEmpty($users); - $this->assertEquals(1, count($users)); - $this->assertEquals('user1@here', $users[0]['email']); + $this->assertEquals('user1@here', $this->container['emailClient']->email); + $this->assertEquals('user1', $this->container['emailClient']->name); + $this->assertEquals('[test][Task opened] blah (#2)', $this->container['emailClient']->subject); + $this->assertNotEmpty($this->container['emailClient']->html); + } - $users = $n->getUsersWithNotification(3); - $this->assertNotEmpty($users); - $this->assertEquals(2, count($users)); - $this->assertEquals('user1@here', $users[0]['email']); - $this->assertEquals('user3@here', $users[1]['email']); + public function testSendNotificationsToAnotherAssignee() + { + $u = new User($this->container); + $p = new Project($this->container); + $n = new Notification($this->container); + $pp = new ProjectPermission($this->container); + + $this->assertEquals(1, $p->create(array('name' => 'UnitTest1'))); + $this->assertEquals(2, $u->create(array('username' => 'user1', 'email' => 'user1@here', 'notifications_enabled' => 1))); + $this->assertTrue($pp->addMember(1, 2)); + + $n->sendNotifications('task.open', array('task' => array( + 'id' => 2, 'title' => 'blah', 'project_name' => 'test', 'project_id' => 1, 'owner_id' => 1, 'creator_id' => 1 + ))); + + $this->assertEmpty($this->container['emailClient']->email); + } + + public function testSendNotificationsToNotMember() + { + $u = new User($this->container); + $p = new Project($this->container); + $n = new Notification($this->container); + $pp = new ProjectPermission($this->container); + + $this->assertEquals(1, $p->create(array('name' => 'UnitTest1'))); + $this->assertEquals(2, $u->create(array('username' => 'user1', 'email' => 'user1@here', 'notifications_enabled' => 1))); + + $n->sendNotifications('task.open', array('task' => array( + 'id' => 2, 'title' => 'blah', 'project_name' => 'test', 'project_id' => 1, 'owner_id' => 0, 'creator_id' => 2 + ))); + + $this->assertEmpty($this->container['emailClient']->email); } } |