Added automatic actions based on a daily event
This commit is contained in:
@@ -6,6 +6,13 @@ New features:
|
|||||||
* Add project owner (Directly Responsible Individual)
|
* Add project owner (Directly Responsible Individual)
|
||||||
* Add configurable task priority
|
* Add configurable task priority
|
||||||
* Add Greek translation
|
* Add Greek translation
|
||||||
|
* Add automatic actions to close tasks with no activity
|
||||||
|
* Add automatic actions to send an email when there is no activity on a task
|
||||||
|
* Regroup all daily background tasks in one command: "cronjob"
|
||||||
|
|
||||||
|
Improvements:
|
||||||
|
|
||||||
|
* Show progress for task links in board tooltips
|
||||||
|
|
||||||
Version 1.0.24
|
Version 1.0.24
|
||||||
--------------
|
--------------
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ abstract class Base extends \Kanboard\Core\Base
|
|||||||
$params[] = $key.'='.var_export($value, true);
|
$params[] = $key.'='.var_export($value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getName().'('.implode('|', $params).'])';
|
return $this->getName().'('.implode('|', $params).')';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
95
app/Action/TaskCloseNoActivity.php
Normal file
95
app/Action/TaskCloseNoActivity.php
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Action;
|
||||||
|
|
||||||
|
use Kanboard\Model\Task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close automatically a task after when inactive
|
||||||
|
*
|
||||||
|
* @package action
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TaskCloseNoActivity extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get automatic action description
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDescription()
|
||||||
|
{
|
||||||
|
return t('Close a task when there is no activity');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of compatible events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCompatibleEvents()
|
||||||
|
{
|
||||||
|
return array(Task::EVENT_DAILY_CRONJOB);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the action (defined by the user)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getActionRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'duration' => t('Duration in days')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the event
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getEventRequiredParameters()
|
||||||
|
{
|
||||||
|
return array('tasks');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action (close the task)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool True if the action was executed or false when not executed
|
||||||
|
*/
|
||||||
|
public function doAction(array $data)
|
||||||
|
{
|
||||||
|
$results = array();
|
||||||
|
$max = $this->getParam('duration') * 86400;
|
||||||
|
|
||||||
|
foreach ($data['tasks'] as $task) {
|
||||||
|
$duration = time() - $task['date_modification'];
|
||||||
|
|
||||||
|
if ($duration > $max) {
|
||||||
|
$results[] = $this->taskStatus->close($task['id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return in_array(true, $results, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return count($data['tasks']) > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
124
app/Action/TaskEmailNoActivity.php
Normal file
124
app/Action/TaskEmailNoActivity.php
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Action;
|
||||||
|
|
||||||
|
use Kanboard\Model\Task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email a task with no activity
|
||||||
|
*
|
||||||
|
* @package action
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class TaskEmailNoActivity extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get automatic action description
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDescription()
|
||||||
|
{
|
||||||
|
return t('Send email when there is no activity on a task');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of compatible events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getCompatibleEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
Task::EVENT_DAILY_CRONJOB,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the action (defined by the user)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getActionRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'user_id' => t('User that will receive the email'),
|
||||||
|
'subject' => t('Email subject'),
|
||||||
|
'duration' => t('Duration in days'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the required parameter for the event
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getEventRequiredParameters()
|
||||||
|
{
|
||||||
|
return array('tasks');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the event data meet the action condition
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasRequiredCondition(array $data)
|
||||||
|
{
|
||||||
|
return count($data['tasks']) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the action (move the task to another column)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $data Event data dictionary
|
||||||
|
* @return bool True if the action was executed or false when not executed
|
||||||
|
*/
|
||||||
|
public function doAction(array $data)
|
||||||
|
{
|
||||||
|
$results = array();
|
||||||
|
$max = $this->getParam('duration') * 86400;
|
||||||
|
$user = $this->user->getById($this->getParam('user_id'));
|
||||||
|
|
||||||
|
if (! empty($user['email'])) {
|
||||||
|
foreach ($data['tasks'] as $task) {
|
||||||
|
$duration = time() - $task['date_modification'];
|
||||||
|
|
||||||
|
if ($duration > $max) {
|
||||||
|
$results[] = $this->sendEmail($task['id'], $user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return in_array(true, $results, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send email
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @param integer $task_id
|
||||||
|
* @param array $user
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
private function sendEmail($task_id, array $user)
|
||||||
|
{
|
||||||
|
$task = $this->taskFinder->getDetails($task_id);
|
||||||
|
|
||||||
|
$this->emailClient->send(
|
||||||
|
$user['email'],
|
||||||
|
$user['name'] ?: $user['username'],
|
||||||
|
$this->getParam('subject'),
|
||||||
|
$this->template->render('notification/task_create', array('task' => $task, 'application_url' => $this->config->get('application_url')))
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
app/Console/Cronjob.php
Normal file
33
app/Console/Cronjob.php
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Console;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\ArrayInput;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Output\NullOutput;
|
||||||
|
|
||||||
|
class Cronjob extends Base
|
||||||
|
{
|
||||||
|
private $commands = array(
|
||||||
|
'projects:daily-stats',
|
||||||
|
'notification:overdue-tasks',
|
||||||
|
'trigger:tasks',
|
||||||
|
);
|
||||||
|
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->setName('cronjob')
|
||||||
|
->setDescription('Execute daily cronjob');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
foreach ($this->commands as $command) {
|
||||||
|
$job = $this->getApplication()->find($command);
|
||||||
|
$job->run(new ArrayInput(array('command' => $command)), new NullOutput());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
app/Console/TaskTrigger.php
Normal file
52
app/Console/TaskTrigger.php
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Console;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Kanboard\Model\Task;
|
||||||
|
use Kanboard\Event\TaskListEvent;
|
||||||
|
|
||||||
|
class TaskTrigger extends Base
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->setName('trigger:tasks')
|
||||||
|
->setDescription('Trigger scheduler event for all tasks');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
foreach ($this->getProjectIds() as $project_id) {
|
||||||
|
$tasks = $this->taskFinder->getAll($project_id);
|
||||||
|
$nb_tasks = count($tasks);
|
||||||
|
|
||||||
|
if ($nb_tasks > 0) {
|
||||||
|
$output->writeln('Trigger task event: project_id='.$project_id.', nb_tasks='.$nb_tasks);
|
||||||
|
$this->sendEvent($tasks, $project_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getProjectIds()
|
||||||
|
{
|
||||||
|
$listeners = $this->dispatcher->getListeners(Task::EVENT_DAILY_CRONJOB);
|
||||||
|
$project_ids = array();
|
||||||
|
|
||||||
|
foreach ($listeners as $listener) {
|
||||||
|
$project_ids[] = $listener[0]->getProjectId();
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_unique($project_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendEvent(array &$tasks, $project_id)
|
||||||
|
{
|
||||||
|
$event = new TaskListEvent(array('project_id' => $project_id));
|
||||||
|
$event->setTasks($tasks);
|
||||||
|
|
||||||
|
$this->dispatcher->dispatch(Task::EVENT_DAILY_CRONJOB, $event);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,6 +52,7 @@ class EventManager
|
|||||||
Task::EVENT_CLOSE => t('Closing a task'),
|
Task::EVENT_CLOSE => t('Closing a task'),
|
||||||
Task::EVENT_CREATE_UPDATE => t('Task creation or modification'),
|
Task::EVENT_CREATE_UPDATE => t('Task creation or modification'),
|
||||||
Task::EVENT_ASSIGNEE_CHANGE => t('Task assignee change'),
|
Task::EVENT_ASSIGNEE_CHANGE => t('Task assignee change'),
|
||||||
|
Task::EVENT_DAILY_CRONJOB => t('Daily background job for tasks'),
|
||||||
);
|
);
|
||||||
|
|
||||||
$events = array_merge($events, $this->events);
|
$events = array_merge($events, $this->events);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use Symfony\Component\EventDispatcher\Event as BaseEvent;
|
|||||||
|
|
||||||
class GenericEvent extends BaseEvent implements ArrayAccess
|
class GenericEvent extends BaseEvent implements ArrayAccess
|
||||||
{
|
{
|
||||||
private $container = array();
|
protected $container = array();
|
||||||
|
|
||||||
public function __construct(array $values = array())
|
public function __construct(array $values = array())
|
||||||
{
|
{
|
||||||
|
|||||||
11
app/Event/TaskListEvent.php
Normal file
11
app/Event/TaskListEvent.php
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Kanboard\Event;
|
||||||
|
|
||||||
|
class TaskListEvent extends GenericEvent
|
||||||
|
{
|
||||||
|
public function setTasks(array &$tasks)
|
||||||
|
{
|
||||||
|
$this->container['tasks'] =& $tasks;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,6 +42,7 @@ class Task extends Base
|
|||||||
const EVENT_ASSIGNEE_CHANGE = 'task.assignee_change';
|
const EVENT_ASSIGNEE_CHANGE = 'task.assignee_change';
|
||||||
const EVENT_OVERDUE = 'task.overdue';
|
const EVENT_OVERDUE = 'task.overdue';
|
||||||
const EVENT_USER_MENTION = 'task.user.mention';
|
const EVENT_USER_MENTION = 'task.user.mention';
|
||||||
|
const EVENT_DAILY_CRONJOB = 'task.cronjob.daily';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recurrence: status
|
* Recurrence: status
|
||||||
|
|||||||
@@ -23,12 +23,14 @@ use Kanboard\Action\TaskCloseColumn;
|
|||||||
use Kanboard\Action\TaskCreation;
|
use Kanboard\Action\TaskCreation;
|
||||||
use Kanboard\Action\TaskDuplicateAnotherProject;
|
use Kanboard\Action\TaskDuplicateAnotherProject;
|
||||||
use Kanboard\Action\TaskEmail;
|
use Kanboard\Action\TaskEmail;
|
||||||
|
use Kanboard\Action\TaskEmailNoActivity;
|
||||||
use Kanboard\Action\TaskMoveAnotherProject;
|
use Kanboard\Action\TaskMoveAnotherProject;
|
||||||
use Kanboard\Action\TaskMoveColumnAssigned;
|
use Kanboard\Action\TaskMoveColumnAssigned;
|
||||||
use Kanboard\Action\TaskMoveColumnCategoryChange;
|
use Kanboard\Action\TaskMoveColumnCategoryChange;
|
||||||
use Kanboard\Action\TaskMoveColumnUnAssigned;
|
use Kanboard\Action\TaskMoveColumnUnAssigned;
|
||||||
use Kanboard\Action\TaskOpen;
|
use Kanboard\Action\TaskOpen;
|
||||||
use Kanboard\Action\TaskUpdateStartDate;
|
use Kanboard\Action\TaskUpdateStartDate;
|
||||||
|
use Kanboard\Action\TaskCloseNoActivity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action Provider
|
* Action Provider
|
||||||
@@ -63,9 +65,11 @@ class ActionProvider implements ServiceProviderInterface
|
|||||||
$container['actionManager']->register(new TaskAssignUser($container));
|
$container['actionManager']->register(new TaskAssignUser($container));
|
||||||
$container['actionManager']->register(new TaskClose($container));
|
$container['actionManager']->register(new TaskClose($container));
|
||||||
$container['actionManager']->register(new TaskCloseColumn($container));
|
$container['actionManager']->register(new TaskCloseColumn($container));
|
||||||
|
$container['actionManager']->register(new TaskCloseNoActivity($container));
|
||||||
$container['actionManager']->register(new TaskCreation($container));
|
$container['actionManager']->register(new TaskCreation($container));
|
||||||
$container['actionManager']->register(new TaskDuplicateAnotherProject($container));
|
$container['actionManager']->register(new TaskDuplicateAnotherProject($container));
|
||||||
$container['actionManager']->register(new TaskEmail($container));
|
$container['actionManager']->register(new TaskEmail($container));
|
||||||
|
$container['actionManager']->register(new TaskEmailNoActivity($container));
|
||||||
$container['actionManager']->register(new TaskMoveAnotherProject($container));
|
$container['actionManager']->register(new TaskMoveAnotherProject($container));
|
||||||
$container['actionManager']->register(new TaskMoveColumnAssigned($container));
|
$container['actionManager']->register(new TaskMoveColumnAssigned($container));
|
||||||
$container['actionManager']->register(new TaskMoveColumnCategoryChange($container));
|
$container['actionManager']->register(new TaskMoveColumnCategoryChange($container));
|
||||||
|
|||||||
@@ -15,22 +15,25 @@
|
|||||||
|
|
||||||
<?php if ($this->text->contains($param_name, 'column_id')): ?>
|
<?php if ($this->text->contains($param_name, 'column_id')): ?>
|
||||||
<?= $this->form->label($param_desc, $param_name) ?>
|
<?= $this->form->label($param_desc, $param_name) ?>
|
||||||
<?= $this->form->select('params['.$param_name.']', $columns_list, $values) ?><br/>
|
<?= $this->form->select('params['.$param_name.']', $columns_list, $values) ?>
|
||||||
<?php elseif ($this->text->contains($param_name, 'user_id')): ?>
|
<?php elseif ($this->text->contains($param_name, 'user_id')): ?>
|
||||||
<?= $this->form->label($param_desc, $param_name) ?>
|
<?= $this->form->label($param_desc, $param_name) ?>
|
||||||
<?= $this->form->select('params['.$param_name.']', $users_list, $values) ?><br/>
|
<?= $this->form->select('params['.$param_name.']', $users_list, $values) ?>
|
||||||
<?php elseif ($this->text->contains($param_name, 'project_id')): ?>
|
<?php elseif ($this->text->contains($param_name, 'project_id')): ?>
|
||||||
<?= $this->form->label($param_desc, $param_name) ?>
|
<?= $this->form->label($param_desc, $param_name) ?>
|
||||||
<?= $this->form->select('params['.$param_name.']', $projects_list, $values) ?><br/>
|
<?= $this->form->select('params['.$param_name.']', $projects_list, $values) ?>
|
||||||
<?php elseif ($this->text->contains($param_name, 'color_id')): ?>
|
<?php elseif ($this->text->contains($param_name, 'color_id')): ?>
|
||||||
<?= $this->form->label($param_desc, $param_name) ?>
|
<?= $this->form->label($param_desc, $param_name) ?>
|
||||||
<?= $this->form->select('params['.$param_name.']', $colors_list, $values) ?><br/>
|
<?= $this->form->select('params['.$param_name.']', $colors_list, $values) ?>
|
||||||
<?php elseif ($this->text->contains($param_name, 'category_id')): ?>
|
<?php elseif ($this->text->contains($param_name, 'category_id')): ?>
|
||||||
<?= $this->form->label($param_desc, $param_name) ?>
|
<?= $this->form->label($param_desc, $param_name) ?>
|
||||||
<?= $this->form->select('params['.$param_name.']', $categories_list, $values) ?><br/>
|
<?= $this->form->select('params['.$param_name.']', $categories_list, $values) ?>
|
||||||
<?php elseif ($this->text->contains($param_name, 'link_id')): ?>
|
<?php elseif ($this->text->contains($param_name, 'link_id')): ?>
|
||||||
<?= $this->form->label($param_desc, $param_name) ?>
|
<?= $this->form->label($param_desc, $param_name) ?>
|
||||||
<?= $this->form->select('params['.$param_name.']', $links_list, $values) ?><br/>
|
<?= $this->form->select('params['.$param_name.']', $links_list, $values) ?>
|
||||||
|
<?php elseif ($this->text->contains($param_name, 'duration')): ?>
|
||||||
|
<?= $this->form->label($param_desc, $param_name) ?>
|
||||||
|
<?= $this->form->number('params['.$param_name.']', $values) ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?= $this->form->label($param_desc, $param_name) ?>
|
<?= $this->form->label($param_desc, $param_name) ?>
|
||||||
<?= $this->form->text('params['.$param_name.']', $values) ?>
|
<?= $this->form->text('params['.$param_name.']', $values) ?>
|
||||||
|
|||||||
@@ -62,9 +62,4 @@ This chart show the average lead and cycle time for the last 1000 tasks over tim
|
|||||||
|
|
||||||
Those metrics are calculated and recorded every day for the whole project.
|
Those metrics are calculated and recorded every day for the whole project.
|
||||||
|
|
||||||
Don't forget to run the daily job for statistics calculation
|
Note: Don't forget to run the [daily cronjob](cronjob.markdown) to have accurate statistics.
|
||||||
-------------------------------------------------------
|
|
||||||
|
|
||||||
To generate accurate analytic data, you should run the daily cronjob **project daily statistics**.
|
|
||||||
|
|
||||||
[Read the documentation of Kanboard CLI](cli.markdown)
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
Centos Installation
|
Centos Installation
|
||||||
===================
|
===================
|
||||||
|
|
||||||
|
Note: Some features of Kanboard require that you run [a daily background job](cronjob.markdown).
|
||||||
|
|
||||||
Centos 7
|
Centos 7
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Command Line Interface
|
|||||||
Kanboard provides a simple command line interface that can be used from any Unix terminal.
|
Kanboard provides a simple command line interface that can be used from any Unix terminal.
|
||||||
This tool can be used only on the local machine.
|
This tool can be used only on the local machine.
|
||||||
|
|
||||||
This feature is useful to run commands outside the web server process by example running a huge report.
|
This feature is useful to run commands outside of the web server processes.
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
@@ -28,6 +28,7 @@ Options:
|
|||||||
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
|
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
|
||||||
|
|
||||||
Available commands:
|
Available commands:
|
||||||
|
cronjob Execute daily cronjob
|
||||||
help Displays help for a command
|
help Displays help for a command
|
||||||
list Lists commands
|
list Lists commands
|
||||||
export
|
export
|
||||||
@@ -42,6 +43,8 @@ Available commands:
|
|||||||
notification:overdue-tasks Send notifications for overdue tasks
|
notification:overdue-tasks Send notifications for overdue tasks
|
||||||
projects
|
projects
|
||||||
projects:daily-stats Calculate daily statistics for all projects
|
projects:daily-stats Calculate daily statistics for all projects
|
||||||
|
trigger
|
||||||
|
trigger:tasks Trigger scheduler event for all tasks
|
||||||
```
|
```
|
||||||
|
|
||||||
Available commands
|
Available commands
|
||||||
@@ -116,7 +119,7 @@ Emails will be sent to all users with notifications enabled.
|
|||||||
You can also display the overdue tasks with the flag `--show`:
|
You can also display the overdue tasks with the flag `--show`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ ./kanboard notification:overdue-tasks --show
|
./kanboard notification:overdue-tasks --show
|
||||||
+-----+---------+------------+------------+--------------+----------+
|
+-----+---------+------------+------------+--------------+----------+
|
||||||
| Id | Title | Due date | Project Id | Project name | Assignee |
|
| Id | Title | Due date | Project Id | Project name | Assignee |
|
||||||
+-----+---------+------------+------------+--------------+----------+
|
+-----+---------+------------+------------+--------------+----------+
|
||||||
@@ -125,20 +128,22 @@ $ ./kanboard notification:overdue-tasks --show
|
|||||||
+-----+---------+------------+------------+--------------+----------+
|
+-----+---------+------------+------------+--------------+----------+
|
||||||
```
|
```
|
||||||
|
|
||||||
Cronjob example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Everyday at 8am we check for due tasks
|
|
||||||
0 8 * * * cd /path/to/kanboard && ./kanboard notification:overdue-tasks >/dev/null 2>&1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run daily project stats calculation
|
### Run daily project stats calculation
|
||||||
|
|
||||||
You can add a background task to calculate the project statistics every day:
|
This command calculate the statistics of each project:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ ./kanboard projects:daily-stats
|
./kanboard projects:daily-stats
|
||||||
Run calculation for Project #0
|
Run calculation for Project #0
|
||||||
Run calculation for Project #1
|
Run calculation for Project #1
|
||||||
Run calculation for Project #10
|
Run calculation for Project #10
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Trigger for tasks
|
||||||
|
|
||||||
|
This command send a "daily cronjob event" to all open tasks of each project.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./kanboard trigger:tasks
|
||||||
|
Trigger task event: project_id=2, nb_tasks=1
|
||||||
|
```
|
||||||
|
|||||||
32
doc/cronjob.markdown
Normal file
32
doc/cronjob.markdown
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
Background Job Scheduling
|
||||||
|
=========================
|
||||||
|
|
||||||
|
To work properly, Kanboard requires that a background job run on a daily basis.
|
||||||
|
Usually on Unix platforms, this process is done by `cron`.
|
||||||
|
|
||||||
|
This background job is necessary for these features:
|
||||||
|
|
||||||
|
- Reports and analytics (calculate daily stats of each projects)
|
||||||
|
- Send overdue task notifications
|
||||||
|
- Execute automatic actions connected to the event "Daily background job for tasks"
|
||||||
|
|
||||||
|
Configuration on Unix and Linux platforms
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
There are multiple ways to define a cronjob on Unix/Linux operating systems, this example is for Ubuntu 14.04.
|
||||||
|
The procedure is similar to other systems.
|
||||||
|
|
||||||
|
Edit the crontab of your web server user:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo crontab -u www-data -e
|
||||||
|
```
|
||||||
|
|
||||||
|
Example to execute the daily cronjob at 8am:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
0 8 * * * cd /path/to/kanboard && ./kanboard cronjob >/dev/null 2>&1
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: the cronjob process must have write access to the database in case you are using Sqlite.
|
||||||
|
Usually, running the cronjob under the web server user is enough.
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
How to install Kanboard on Debian?
|
How to install Kanboard on Debian?
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
|
Note: Some features of Kanboard require that you run [a daily background job](cronjob.markdown).
|
||||||
|
|
||||||
Debian 8 (Jessie)
|
Debian 8 (Jessie)
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ Generally 3 elements have to be installed:
|
|||||||
Fetch and extract ports...
|
Fetch and extract ports...
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ portsnap fetch
|
$ portsnap fetch
|
||||||
$ portsnap extract
|
$ portsnap extract
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -122,6 +122,7 @@ there is no need to install it manually.
|
|||||||
Please note
|
Please note
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Port is being hosted on [bitbucket](https://bitbucket.org/if0/freebsd-kanboard/). Feel free to comment,
|
- Port is being hosted on [bitbucket](https://bitbucket.org/if0/freebsd-kanboard/). Feel free to comment,
|
||||||
fork and suggest updates!
|
fork and suggest updates!
|
||||||
|
- Some features of Kanboard require that you run [a daily background job](cronjob.markdown).
|
||||||
|
|
||||||
|
|||||||
@@ -35,5 +35,5 @@ heroku open
|
|||||||
Limitations
|
Limitations
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
The storage of Heroku is ephemeral, that means uploaded files through Kanboard are not persistent after a reboot.
|
- The storage of Heroku is ephemeral, that means uploaded files through Kanboard are not persistent after a reboot. You may want to install a plugin to store your files in a cloud storage provider like [Amazon S3](https://github.com/kanboard/plugin-s3).
|
||||||
We may want to install a plugin to store your files in a cloud storage provider like [Amazon S3](https://github.com/kanboard/plugin-s3).
|
- Some features of Kanboard require that you run [a daily background job](cronjob.markdown).
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ Technical details
|
|||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
- [Config file](config.markdown)
|
- [Config file](config.markdown)
|
||||||
|
- [Background tasks](cronjob.markdown)
|
||||||
- [Email configuration](email-configuration.markdown)
|
- [Email configuration](email-configuration.markdown)
|
||||||
- [URL rewriting](nice-urls.markdown)
|
- [URL rewriting](nice-urls.markdown)
|
||||||
|
|
||||||
|
|||||||
@@ -39,3 +39,8 @@ Security
|
|||||||
|
|
||||||
- Don't forget to change the default user/password
|
- Don't forget to change the default user/password
|
||||||
- Don't allow everybody to access to the directory `data` from the URL. There is already a `.htaccess` for Apache but nothing for Nginx.
|
- Don't allow everybody to access to the directory `data` from the URL. There is already a `.htaccess` for Apache but nothing for Nginx.
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
|
||||||
|
- Some features of Kanboard require that you run [a daily background job](cronjob.markdown)
|
||||||
|
|||||||
@@ -26,3 +26,5 @@ sudo unzip kanboard-latest.zip
|
|||||||
sudo chown -R www-data:www-data kanboard/data
|
sudo chown -R www-data:www-data kanboard/data
|
||||||
sudo rm kanboard-latest.zip
|
sudo rm kanboard-latest.zip
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Some features of Kanboard require that you run [a daily background job](cronjob.markdown).
|
||||||
|
|||||||
@@ -123,3 +123,8 @@ Tested configuration
|
|||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
- Windows 2008 R2 / Apache 2.4.12 / PHP 5.6.8
|
- Windows 2008 R2 / Apache 2.4.12 / PHP 5.6.8
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
|
||||||
|
- Some features of Kanboard require that you run [a daily background job](cronjob.markdown).
|
||||||
|
|||||||
@@ -65,3 +65,9 @@ Tested configurations
|
|||||||
|
|
||||||
- Windows 2008 R2 Standard Edition / IIS 7.5 / PHP 5.5.16
|
- Windows 2008 R2 Standard Edition / IIS 7.5 / PHP 5.5.16
|
||||||
- Windows 2012 Standard Edition / IIS 8.5 / PHP 5.3.29
|
- Windows 2012 Standard Edition / IIS 8.5 / PHP 5.3.29
|
||||||
|
|
||||||
|
Notes
|
||||||
|
-----
|
||||||
|
|
||||||
|
- Some features of Kanboard require that you run [a daily background job](cronjob.markdown).
|
||||||
|
|
||||||
|
|||||||
4
kanboard
4
kanboard
@@ -13,6 +13,8 @@ use Kanboard\Console\ProjectDailyColumnStatsExport;
|
|||||||
use Kanboard\Console\TransitionExport;
|
use Kanboard\Console\TransitionExport;
|
||||||
use Kanboard\Console\LocaleSync;
|
use Kanboard\Console\LocaleSync;
|
||||||
use Kanboard\Console\LocaleComparator;
|
use Kanboard\Console\LocaleComparator;
|
||||||
|
use Kanboard\Console\TaskTrigger;
|
||||||
|
use Kanboard\Console\Cronjob;
|
||||||
|
|
||||||
$container['dispatcher']->dispatch('app.bootstrap', new Event);
|
$container['dispatcher']->dispatch('app.bootstrap', new Event);
|
||||||
|
|
||||||
@@ -25,4 +27,6 @@ $application->add(new ProjectDailyColumnStatsExport($container));
|
|||||||
$application->add(new TransitionExport($container));
|
$application->add(new TransitionExport($container));
|
||||||
$application->add(new LocaleSync($container));
|
$application->add(new LocaleSync($container));
|
||||||
$application->add(new LocaleComparator($container));
|
$application->add(new LocaleComparator($container));
|
||||||
|
$application->add(new TaskTrigger($container));
|
||||||
|
$application->add(new Cronjob($container));
|
||||||
$application->run();
|
$application->run();
|
||||||
|
|||||||
Reference in New Issue
Block a user