summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2015-06-07 20:06:31 -0400
committerFrederic Guillot <fred@kanboard.net>2015-06-07 20:06:31 -0400
commit4f32352fe62e47ad5ea760eb00493bdc061b2407 (patch)
tree8d5f087907dd5cba196dbfc06e626b3146659e1f
parent9d9e3afba2054bfa23ba6f019b7c8885c2d8415e (diff)
Add user filter/condition for notifications
-rw-r--r--app/Console/TaskOverdueNotification.php20
-rw-r--r--app/Controller/User.php6
-rw-r--r--app/Model/Base.php19
-rw-r--r--app/Model/Notification.php335
-rw-r--r--app/Model/SubtaskTimeTracking.php3
-rw-r--r--app/Model/Task.php1
-rw-r--r--app/Model/TaskFinder.php2
-rw-r--r--app/Schema/Mysql.php7
-rw-r--r--app/Schema/Postgres.php7
-rw-r--r--app/Schema/Sqlite.php7
-rw-r--r--app/Subscriber/NotificationSubscriber.php27
-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.php16
-rw-r--r--tests/units/Base.php17
-rw-r--r--tests/units/NotificationTest.php272
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);
}
}