Skip to content

Commit cb0916d

Browse files
committed
Add automatic action to send a task by email
1 parent 7056d14 commit cb0916d

15 files changed

+280
-40
lines changed

app/Action/TaskEmail.php

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
3+
namespace Action;
4+
5+
use Model\Task;
6+
7+
/**
8+
* Email a task to someone
9+
*
10+
* @package action
11+
* @author Frederic Guillot
12+
*/
13+
class TaskEmail extends Base
14+
{
15+
/**
16+
* Get the list of compatible events
17+
*
18+
* @access public
19+
* @return array
20+
*/
21+
public function getCompatibleEvents()
22+
{
23+
return array(
24+
Task::EVENT_MOVE_COLUMN,
25+
Task::EVENT_CLOSE,
26+
);
27+
}
28+
29+
/**
30+
* Get the required parameter for the action (defined by the user)
31+
*
32+
* @access public
33+
* @return array
34+
*/
35+
public function getActionRequiredParameters()
36+
{
37+
return array(
38+
'column_id' => t('Column'),
39+
'user_id' => t('User that will receive the email'),
40+
'subject' => t('Email subject'),
41+
);
42+
}
43+
44+
/**
45+
* Get the required parameter for the event
46+
*
47+
* @access public
48+
* @return string[]
49+
*/
50+
public function getEventRequiredParameters()
51+
{
52+
return array(
53+
'task_id',
54+
'column_id',
55+
);
56+
}
57+
58+
/**
59+
* Execute the action (move the task to another column)
60+
*
61+
* @access public
62+
* @param array $data Event data dictionary
63+
* @return bool True if the action was executed or false when not executed
64+
*/
65+
public function doAction(array $data)
66+
{
67+
$user = $this->user->getById($this->getParam('user_id'));
68+
69+
if (! empty($user['email'])) {
70+
71+
$task = $this->taskFinder->getDetails($data['task_id']);
72+
73+
$this->emailClient->send(
74+
$user['email'],
75+
$user['name'] ?: $user['username'],
76+
$this->getParam('subject'),
77+
$this->template->render('notification/task_create', array('task' => $task, 'application_url' => $this->config->get('application_url')))
78+
);
79+
80+
return true;
81+
}
82+
83+
return false;
84+
}
85+
86+
/**
87+
* Check if the event data meet the action condition
88+
*
89+
* @access public
90+
* @param array $data Event data dictionary
91+
* @return bool
92+
*/
93+
public function hasRequiredCondition(array $data)
94+
{
95+
return $data['column_id'] == $this->getParam('column_id');
96+
}
97+
}

app/Helper/Url.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,7 @@ public function to($controller, $action, array $params = array())
8888
*/
8989
public function base()
9090
{
91-
$application_url = $this->config->get('application_url');
92-
93-
if (! empty($application_url)) {
94-
return $application_url;
95-
}
96-
97-
return $this->server();
91+
return $this->config->get('application_url') ?: $this->server();
9892
}
9993

10094
/**

app/Model/Action.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public function getAvailableActions()
5858
'TaskAssignCategoryLabel' => t('Change the category based on an external label'),
5959
'TaskUpdateStartDate' => t('Automatically update the start date'),
6060
'TaskMoveColumnCategoryChange' => t('Move the task to another column when the category is changed'),
61+
'TaskEmail' => t('Send a task by email to someone'),
6162
);
6263

6364
asort($values);
@@ -351,10 +352,13 @@ private function resolveDuplicatedParameters($param, $project_to)
351352
$categoryTemplate = $this->category->getById($param['value']);
352353
$categoryFromNewProject = $this->db->table(Category::TABLE)->eq('project_id', $project_to)->eq('name', $categoryTemplate['name'])->findOne();
353354
return $categoryFromNewProject['id'];
355+
case 'src_column_id':
356+
case 'dest_column_id':
354357
case 'column_id':
355358
$boardTemplate = $this->board->getColumn($param['value']);
356359
$boardFromNewProject = $this->db->table(Board::TABLE)->eq('project_id', $project_to)->eq('title', $boardTemplate['title'])->findOne();
357360
return $boardFromNewProject['id'];
361+
// TODO: Add user_id
358362
default:
359363
return $param['value'];
360364
}

app/Template/action/index.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<?= $this->text->in($param['value'], $colors_list) ?>
4343
<?php elseif ($this->text->contains($param['name'], 'category_id')): ?>
4444
<?= $this->text->in($param['value'], $categories_list) ?>
45-
<?php elseif ($this->text->contains($param['name'], 'label')): ?>
45+
<?php else: ?>
4646
<?= $this->e($param['value']) ?>
4747
<?php endif ?>
4848
</strong>

app/Template/action/params.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
<?php elseif ($this->text->contains($param_name, 'category_id')): ?>
2929
<?= $this->form->label($param_desc, $param_name) ?>
3030
<?= $this->form->select('params['.$param_name.']', $categories_list, $values) ?><br/>
31-
<?php elseif ($this->text->contains($param_name, 'label')): ?>
31+
<?php else: ?>
3232
<?= $this->form->label($param_desc, $param_name) ?>
3333
<?= $this->form->text('params['.$param_name.']', $values) ?>
3434
<?php endif ?>

docs/automatic-actions.markdown

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ List of available actions
6464
- Change the category based on an external label
6565
- Create a comment from an external provider
6666
- Automatically update the start date
67+
- Send a task by email to someone
6768

6869
Examples
6970
--------

tests/units.mysql.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<phpunit>
1+
<phpunit stopOnError="true" stopOnFailure="true" colors="true">
22
<testsuites>
33
<testsuite name="Kanboard">
44
<directory>units</directory>

tests/units.postgres.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<phpunit>
1+
<phpunit stopOnError="true" stopOnFailure="true" colors="true">
22
<testsuites>
33
<testsuite name="Kanboard">
44
<directory>units</directory>

tests/units.sqlite.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<phpunit>
1+
<phpunit stopOnError="true" stopOnFailure="true" colors="true">
22
<testsuites>
33
<testsuite name="Kanboard">
44
<directory>units</directory>

tests/units/ActionTaskEmailTest.php

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<?php
2+
3+
require_once __DIR__.'/Base.php';
4+
5+
use Event\GenericEvent;
6+
use Model\Task;
7+
use Model\TaskCreation;
8+
use Model\TaskFinder;
9+
use Model\Project;
10+
use Model\User;
11+
12+
class ActionTaskEmailTest extends Base
13+
{
14+
public function testNoEmail()
15+
{
16+
$action = new Action\TaskEmail($this->container, 1, Task::EVENT_MOVE_COLUMN);
17+
$action->setParam('column_id', 2);
18+
$action->setParam('user_id', 1);
19+
$action->setParam('subject', 'My email subject');
20+
21+
// We create a task in the first column
22+
$tc = new TaskCreation($this->container);
23+
$tf = new TaskFinder($this->container);
24+
$p = new Project($this->container);
25+
$u = new User($this->container);
26+
27+
$this->assertEquals(1, $p->create(array('name' => 'test')));
28+
$this->assertEquals(1, $tc->create(array('title' => 'test', 'project_id' => 1, 'column_id' => 1)));
29+
30+
// We create an event to move the task to the 2nd column
31+
$event = array(
32+
'project_id' => 1,
33+
'task_id' => 1,
34+
'column_id' => 2,
35+
);
36+
37+
// Email should be not be sent
38+
$this->container['emailClient']->expects($this->never())->method('send');
39+
40+
// Our event should be executed
41+
$this->assertFalse($action->execute(new GenericEvent($event)));
42+
}
43+
44+
public function testWrongColumn()
45+
{
46+
$action = new Action\TaskEmail($this->container, 1, Task::EVENT_MOVE_COLUMN);
47+
$action->setParam('column_id', 2);
48+
$action->setParam('user_id', 1);
49+
$action->setParam('subject', 'My email subject');
50+
51+
// We create a task in the first column
52+
$tc = new TaskCreation($this->container);
53+
$tf = new TaskFinder($this->container);
54+
$p = new Project($this->container);
55+
$u = new User($this->container);
56+
57+
$this->assertEquals(1, $p->create(array('name' => 'test')));
58+
$this->assertEquals(1, $tc->create(array('title' => 'test', 'project_id' => 1, 'column_id' => 1)));
59+
60+
// We create an event to move the task to the 2nd column
61+
$event = array(
62+
'project_id' => 1,
63+
'task_id' => 1,
64+
'column_id' => 3,
65+
);
66+
67+
// Email should be not be sent
68+
$this->container['emailClient']->expects($this->never())->method('send');
69+
70+
// Our event should be executed
71+
$this->assertFalse($action->execute(new GenericEvent($event)));
72+
}
73+
74+
public function testMoveColumn()
75+
{
76+
$action = new Action\TaskEmail($this->container, 1, Task::EVENT_MOVE_COLUMN);
77+
$action->setParam('column_id', 2);
78+
$action->setParam('user_id', 1);
79+
$action->setParam('subject', 'My email subject');
80+
81+
// We create a task in the first column
82+
$tc = new TaskCreation($this->container);
83+
$tf = new TaskFinder($this->container);
84+
$p = new Project($this->container);
85+
$u = new User($this->container);
86+
87+
$this->assertEquals(1, $p->create(array('name' => 'test')));
88+
$this->assertEquals(1, $tc->create(array('title' => 'test', 'project_id' => 1, 'column_id' => 1)));
89+
$this->assertTrue($u->update(array('id' => 1, 'email' => 'admin@localhost')));
90+
91+
// We create an event to move the task to the 2nd column
92+
$event = array(
93+
'project_id' => 1,
94+
'task_id' => 1,
95+
'column_id' => 2,
96+
);
97+
98+
// Email should be sent
99+
$this->container['emailClient']->expects($this->once())
100+
->method('send')
101+
->with(
102+
$this->equalTo('admin@localhost'),
103+
$this->equalTo('admin'),
104+
$this->equalTo('My email subject'),
105+
$this->stringContains('test')
106+
);
107+
108+
// Our event should be executed
109+
$this->assertTrue($action->execute(new GenericEvent($event)));
110+
}
111+
112+
public function testTaskClose()
113+
{
114+
$action = new Action\TaskEmail($this->container, 1, Task::EVENT_CLOSE);
115+
$action->setParam('column_id', 2);
116+
$action->setParam('user_id', 1);
117+
$action->setParam('subject', 'My email subject');
118+
119+
// We create a task in the first column
120+
$tc = new TaskCreation($this->container);
121+
$tf = new TaskFinder($this->container);
122+
$p = new Project($this->container);
123+
$u = new User($this->container);
124+
125+
$this->assertEquals(1, $p->create(array('name' => 'test')));
126+
$this->assertEquals(1, $tc->create(array('title' => 'test', 'project_id' => 1, 'column_id' => 1)));
127+
$this->assertTrue($u->update(array('id' => 1, 'email' => 'admin@localhost')));
128+
129+
// We create an event
130+
$event = array(
131+
'project_id' => 1,
132+
'task_id' => 1,
133+
'column_id' => 2,
134+
);
135+
136+
// Email should be sent
137+
$this->container['emailClient']->expects($this->once())
138+
->method('send')
139+
->with(
140+
$this->equalTo('admin@localhost'),
141+
$this->equalTo('admin'),
142+
$this->equalTo('My email subject'),
143+
$this->stringContains('test')
144+
);
145+
146+
// Our event should be executed
147+
$this->assertTrue($action->execute(new GenericEvent($event)));
148+
}
149+
}

tests/units/ActionTaskUpdateStartDateTest.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use Model\TaskCreation;
88
use Model\TaskFinder;
99
use Model\Project;
10-
use Integration\GithubWebhook;
1110

1211
class ActionTaskUpdateStartDateTest extends Base
1312
{

tests/units/Base.php

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,6 @@
1111

1212
date_default_timezone_set('UTC');
1313

14-
class FakeEmailClient
15-
{
16-
public $email;
17-
public $name;
18-
public $subject;
19-
public $html;
20-
21-
public function send($email, $name, $subject, $html)
22-
{
23-
$this->email = $email;
24-
$this->name = $name;
25-
$this->subject = $subject;
26-
$this->html = $html;
27-
}
28-
}
29-
3014
class FakeHttpClient
3115
{
3216
private $url = '';
@@ -103,7 +87,7 @@ public function setUp()
10387
$this->container['logger'] = new Logger;
10488
$this->container['logger']->setLogger(new File('/dev/null'));
10589
$this->container['httpClient'] = new FakeHttpClient;
106-
$this->container['emailClient'] = new FakeEmailClient;
90+
$this->container['emailClient'] = $this->getMockBuilder('EmailClient')->setMethods(array('send'))->getMock();
10791
}
10892

10993
public function tearDown()

tests/units/ConfigTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public function testDefaultValues()
1717
$this->assertEmpty($c->get('webhook_url_task_modification'));
1818
$this->assertEmpty($c->get('webhook_url_task_creation'));
1919
$this->assertEmpty($c->get('board_columns'));
20+
$this->assertEmpty($c->get('application_url'));
2021

2122
$this->assertNotEmpty($c->get('webhook_token'));
2223
$this->assertNotEmpty($c->get('api_token'));
@@ -55,4 +56,11 @@ public function testGetWithSession()
5556
session_id('');
5657
unset($this->container['session']);
5758
}
59+
60+
public function testSave()
61+
{
62+
$c = new Config($this->container);
63+
$this->assertTrue($c->save(array('application_url' => 'http://localhost/')));
64+
$this->assertEquals('http://localhost/', $c->get('application_url'));
65+
}
5866
}

0 commit comments

Comments
 (0)