Improve Automatic Actions plugin api

This commit is contained in:
Frederic Guillot
2016-01-03 16:43:13 -05:00
parent d578b612ea
commit a296ba5b18
82 changed files with 3011 additions and 1665 deletions

View File

@@ -3,7 +3,6 @@
namespace Kanboard\Action;
use Kanboard\Event\GenericEvent;
use Pimple\Container;
/**
* Base class for automatic actions
@@ -13,6 +12,14 @@ use Pimple\Container;
*/
abstract class Base extends \Kanboard\Core\Base
{
/**
* Extended events
*
* @access private
* @var array
*/
private $compatibleEvents = array();
/**
* Flag for called listener
*
@@ -27,7 +34,7 @@ abstract class Base extends \Kanboard\Core\Base
* @access private
* @var integer
*/
private $project_id = 0;
private $projectId = 0;
/**
* User parameters
@@ -38,20 +45,25 @@ abstract class Base extends \Kanboard\Core\Base
private $params = array();
/**
* Attached event name
* Get automatic action name
*
* @access protected
* @var string
* @final
* @access public
* @return string
*/
protected $event_name = '';
final public function getName()
{
return '\\'.get_called_class();
}
/**
* Container instance
* Get automatic action description
*
* @access protected
* @var \Pimple\Container
* @abstract
* @access public
* @return string
*/
protected $container;
abstract public function getDescription();
/**
* Execute the action
@@ -99,22 +111,6 @@ abstract class Base extends \Kanboard\Core\Base
*/
abstract public function hasRequiredCondition(array $data);
/**
* Constructor
*
* @access public
* @param \Pimple\Container $container Container
* @param integer $project_id Project id
* @param string $event_name Attached event name
*/
public function __construct(Container $container, $project_id, $event_name)
{
$this->container = $container;
$this->project_id = $project_id;
$this->event_name = $event_name;
$this->called = false;
}
/**
* Return class information
*
@@ -123,7 +119,19 @@ abstract class Base extends \Kanboard\Core\Base
*/
public function __toString()
{
return get_called_class();
return $this->getName();
}
/**
* Set project id
*
* @access public
* @return Base
*/
public function setProjectId($project_id)
{
$this->projectId = $project_id;
return $this;
}
/**
@@ -134,7 +142,7 @@ abstract class Base extends \Kanboard\Core\Base
*/
public function getProjectId()
{
return $this->project_id;
return $this->projectId;
}
/**
@@ -143,10 +151,12 @@ abstract class Base extends \Kanboard\Core\Base
* @access public
* @param string $name Parameter name
* @param mixed $value Value
* @param Base
*/
public function setParam($name, $value)
{
$this->params[$name] = $value;
return $this;
}
/**
@@ -154,24 +164,25 @@ abstract class Base extends \Kanboard\Core\Base
*
* @access public
* @param string $name Parameter name
* @param mixed $default_value Default value
* @param mixed $default Default value
* @return mixed
*/
public function getParam($name, $default_value = null)
public function getParam($name, $default = null)
{
return isset($this->params[$name]) ? $this->params[$name] : $default_value;
return isset($this->params[$name]) ? $this->params[$name] : $default;
}
/**
* Check if an action is executable (right project and required parameters)
*
* @access public
* @param array $data Event data dictionary
* @return bool True if the action is executable
* @param array $data
* @param string $eventName
* @return bool
*/
public function isExecutable(array $data)
public function isExecutable(array $data, $eventName)
{
return $this->hasCompatibleEvent() &&
return $this->hasCompatibleEvent($eventName) &&
$this->hasRequiredProject($data) &&
$this->hasRequiredParameters($data) &&
$this->hasRequiredCondition($data);
@@ -181,11 +192,12 @@ abstract class Base extends \Kanboard\Core\Base
* Check if the event is compatible with the action
*
* @access public
* @param string $eventName
* @return bool
*/
public function hasCompatibleEvent()
public function hasCompatibleEvent($eventName)
{
return in_array($this->event_name, $this->getCompatibleEvents());
return in_array($eventName, $this->getEvents());
}
/**
@@ -197,7 +209,7 @@ abstract class Base extends \Kanboard\Core\Base
*/
public function hasRequiredProject(array $data)
{
return isset($data['project_id']) && $data['project_id'] == $this->project_id;
return isset($data['project_id']) && $data['project_id'] == $this->getProjectId();
}
/**
@@ -222,10 +234,11 @@ abstract class Base extends \Kanboard\Core\Base
* Execute the action
*
* @access public
* @param \Event\GenericEvent $event Event data dictionary
* @return bool True if the action was executed or false when not executed
* @param \Kanboard\Event\GenericEvent $event
* @param string $eventName
* @return bool
*/
public function execute(GenericEvent $event)
public function execute(GenericEvent $event, $eventName)
{
// Avoid infinite loop, a listener instance can be called only one time
if ($this->called) {
@@ -235,15 +248,38 @@ abstract class Base extends \Kanboard\Core\Base
$data = $event->getAll();
$result = false;
if ($this->isExecutable($data)) {
if ($this->isExecutable($data, $eventName)) {
$this->called = true;
$result = $this->doAction($data);
}
if (DEBUG) {
$this->logger->debug(get_called_class().' => '.($result ? 'true' : 'false'));
}
$this->logger->debug('AutomaticAction '.$this->getName().' => '.($result ? 'true' : 'false'));
return $result;
}
/**
* Register a new event for the automatic action
*
* @access public
* @param string $event
* @param string $description
*/
public function addEvent($event, $description)
{
$this->eventManager->register($event, $description);
$this->compatibleEvents[] = $event;
return $this;
}
/**
* Get all compatible events of an automatic action
*
* @access public
* @return array
*/
public function getEvents()
{
return array_unique(array_merge($this->getCompatibleEvents(), $this->compatibleEvents));
}
}

View File

@@ -14,6 +14,17 @@ use Kanboard\Integration\GitlabWebhook;
*/
class CommentCreation extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Create a comment from an external provider');
}
/**
* Get the list of compatible events
*
@@ -67,9 +78,9 @@ class CommentCreation extends Base
{
return (bool) $this->comment->create(array(
'reference' => isset($data['reference']) ? $data['reference'] : '',
'comment' => empty($data['comment']) ? $data['commit_comment'] : $data['comment'],
'comment' => $data['comment'],
'task_id' => $data['task_id'],
'user_id' => empty($data['user_id']) ? 0 : $data['user_id'],
'user_id' => isset($data['user_id']) && $this->projectPermission->isAssignable($this->getProjectId(), $data['user_id']) ? $data['user_id'] : 0,
));
}
@@ -82,6 +93,6 @@ class CommentCreation extends Base
*/
public function hasRequiredCondition(array $data)
{
return ! empty($data['comment']) || ! empty($data['commit_comment']);
return ! empty($data['comment']);
}
}

View File

@@ -5,13 +5,24 @@ namespace Kanboard\Action;
use Kanboard\Model\Task;
/**
* Add a log of the triggering event to the task description.
* Add a comment of the triggering event to the task description.
*
* @package action
* @author Oren Ben-Kiki
*/
class TaskLogMoveAnotherColumn extends Base
class CommentCreationMoveTaskColumn extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Add a comment log when moving the task between columns');
}
/**
* Get the list of compatible events
*

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskAssignCategoryColor extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Assign automatically a category based on a color');
}
/**
* Get the list of compatible events
*

View File

@@ -12,6 +12,17 @@ use Kanboard\Integration\GithubWebhook;
*/
class TaskAssignCategoryLabel extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Change the category based on an external label');
}
/**
* Get the list of compatible events
*
@@ -64,7 +75,7 @@ class TaskAssignCategoryLabel extends Base
{
$values = array(
'id' => $data['task_id'],
'category_id' => isset($data['category_id']) ? $data['category_id'] : $this->getParam('category_id'),
'category_id' => $this->getParam('category_id'),
);
return $this->taskModification->update($values);
@@ -79,6 +90,6 @@ class TaskAssignCategoryLabel extends Base
*/
public function hasRequiredCondition(array $data)
{
return $data['label'] == $this->getParam('label');
return $data['label'] == $this->getParam('label') && empty($data['category_id']);
}
}

View File

@@ -13,6 +13,17 @@ use Kanboard\Model\TaskLink;
*/
class TaskAssignCategoryLink extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Assign automatically a category based on a link');
}
/**
* Get the list of compatible events
*
@@ -65,7 +76,7 @@ class TaskAssignCategoryLink extends Base
{
$values = array(
'id' => $data['task_id'],
'category_id' => isset($data['category_id']) ? $data['category_id'] : $this->getParam('category_id'),
'category_id' => $this->getParam('category_id'),
);
return $this->taskModification->update($values);

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskAssignColorCategory extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Assign automatically a color based on a category');
}
/**
* Get the list of compatible events
*

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskAssignColorColumn extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Assign a color when the task is moved to a specific column');
}
/**
* Get the list of compatible events
*

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\TaskLink;
*/
class TaskAssignColorLink extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Change task color when using a specific task link');
}
/**
* Get the list of compatible events
*

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskAssignColorUser extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Assign a color to a specific user');
}
/**
* Get the list of compatible events
*

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskAssignCurrentUser extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Assign the task to the person who does the action');
}
/**
* Get the list of compatible events
*
@@ -22,7 +33,6 @@ class TaskAssignCurrentUser extends Base
{
return array(
Task::EVENT_CREATE,
Task::EVENT_MOVE_COLUMN,
);
}
@@ -34,9 +44,7 @@ class TaskAssignCurrentUser extends Base
*/
public function getActionRequiredParameters()
{
return array(
'column_id' => t('Column'),
);
return array();
}
/**
@@ -49,7 +57,6 @@ class TaskAssignCurrentUser extends Base
{
return array(
'task_id',
'column_id',
);
}
@@ -83,6 +90,6 @@ class TaskAssignCurrentUser extends Base
*/
public function hasRequiredCondition(array $data)
{
return $data['column_id'] == $this->getParam('column_id');
return true;
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace Kanboard\Action;
use Kanboard\Model\Task;
/**
* Assign a task to the logged user on column change
*
* @package action
* @author Frederic Guillot
*/
class TaskAssignCurrentUserColumn extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Assign the task to the person who does the action when the column is changed');
}
/**
* Get the list of compatible events
*
* @access public
* @return array
*/
public function getCompatibleEvents()
{
return array(
Task::EVENT_MOVE_COLUMN,
);
}
/**
* Get the required parameter for the action (defined by the user)
*
* @access public
* @return array
*/
public function getActionRequiredParameters()
{
return array(
'column_id' => t('Column'),
);
}
/**
* Get the required parameter for the event
*
* @access public
* @return string[]
*/
public function getEventRequiredParameters()
{
return array(
'task_id',
'column_id',
);
}
/**
* Execute the action
*
* @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)
{
if (! $this->userSession->isLogged()) {
return false;
}
$values = array(
'id' => $data['task_id'],
'owner_id' => $this->userSession->getId(),
);
return $this->taskModification->update($values);
}
/**
* 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 $data['column_id'] == $this->getParam('column_id');
}
}

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskAssignSpecificUser extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Assign the task to a specific user');
}
/**
* Get the list of compatible events
*

View File

@@ -13,6 +13,17 @@ use Kanboard\Integration\BitbucketWebhook;
*/
class TaskAssignUser extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Change the assignee based on an external username');
}
/**
* Get the list of compatible events
*
@@ -78,6 +89,6 @@ class TaskAssignUser extends Base
*/
public function hasRequiredCondition(array $data)
{
return true;
return $this->projectPermission->isAssignable($this->getProjectId(), $data['owner_id']);
}
}

View File

@@ -15,6 +15,17 @@ use Kanboard\Model\Task;
*/
class TaskClose extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Close a task');
}
/**
* Get the list of compatible events
*
@@ -24,7 +35,6 @@ class TaskClose extends Base
public function getCompatibleEvents()
{
return array(
Task::EVENT_MOVE_COLUMN,
GithubWebhook::EVENT_COMMIT,
GithubWebhook::EVENT_ISSUE_CLOSED,
GitlabWebhook::EVENT_COMMIT,
@@ -42,17 +52,7 @@ class TaskClose extends Base
*/
public function getActionRequiredParameters()
{
switch ($this->event_name) {
case GithubWebhook::EVENT_COMMIT:
case GithubWebhook::EVENT_ISSUE_CLOSED:
case GitlabWebhook::EVENT_COMMIT:
case GitlabWebhook::EVENT_ISSUE_CLOSED:
case BitbucketWebhook::EVENT_COMMIT:
case BitbucketWebhook::EVENT_ISSUE_CLOSED:
return array();
default:
return array('column_id' => t('Column'));
}
return array();
}
/**
@@ -63,17 +63,7 @@ class TaskClose extends Base
*/
public function getEventRequiredParameters()
{
switch ($this->event_name) {
case GithubWebhook::EVENT_COMMIT:
case GithubWebhook::EVENT_ISSUE_CLOSED:
case GitlabWebhook::EVENT_COMMIT:
case GitlabWebhook::EVENT_ISSUE_CLOSED:
case BitbucketWebhook::EVENT_COMMIT:
case BitbucketWebhook::EVENT_ISSUE_CLOSED:
return array('task_id');
default:
return array('task_id', 'column_id');
}
return array('task_id');
}
/**
@@ -97,16 +87,6 @@ class TaskClose extends Base
*/
public function hasRequiredCondition(array $data)
{
switch ($this->event_name) {
case GithubWebhook::EVENT_COMMIT:
case GithubWebhook::EVENT_ISSUE_CLOSED:
case GitlabWebhook::EVENT_COMMIT:
case GitlabWebhook::EVENT_ISSUE_CLOSED:
case BitbucketWebhook::EVENT_COMMIT:
case BitbucketWebhook::EVENT_ISSUE_CLOSED:
return true;
default:
return $data['column_id'] == $this->getParam('column_id');
}
return true;
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace Kanboard\Action;
use Kanboard\Model\Task;
/**
* Close automatically a task in a specific column
*
* @package action
* @author Frederic Guillot
*/
class TaskCloseColumn extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Close a task in a specific column');
}
/**
* Get the list of compatible events
*
* @access public
* @return array
*/
public function getCompatibleEvents()
{
return array(
Task::EVENT_MOVE_COLUMN,
);
}
/**
* Get the required parameter for the action (defined by the user)
*
* @access public
* @return array
*/
public function getActionRequiredParameters()
{
return array('column_id' => t('Column'));
}
/**
* Get the required parameter for the event
*
* @access public
* @return string[]
*/
public function getEventRequiredParameters()
{
return array('task_id', 'column_id');
}
/**
* 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)
{
return $this->taskStatus->close($data['task_id']);
}
/**
* 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 $data['column_id'] == $this->getParam('column_id');
}
}

View File

@@ -14,6 +14,17 @@ use Kanboard\Integration\BitbucketWebhook;
*/
class TaskCreation extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Create a task from an external provider');
}
/**
* Get the list of compatible events
*

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskDuplicateAnotherProject extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Duplicate the task to another project');
}
/**
* Get the list of compatible events
*
@@ -51,7 +62,6 @@ class TaskDuplicateAnotherProject extends Base
return array(
'task_id',
'column_id',
'project_id',
);
}
@@ -65,7 +75,6 @@ class TaskDuplicateAnotherProject extends Base
public function doAction(array $data)
{
$destination_column_id = $this->board->getFirstColumn($this->getParam('project_id'));
return (bool) $this->taskDuplication->duplicateToProject($data['task_id'], $this->getParam('project_id'), null, $destination_column_id);
}

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskEmail extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Send a task by email to someone');
}
/**
* Get the list of compatible events
*

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskMoveAnotherProject extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Move the task to another project');
}
/**
* Get the list of compatible events
*

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskMoveColumnAssigned extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Move the task to another column when assigned to a user');
}
/**
* Get the list of compatible events
*
@@ -51,7 +62,6 @@ class TaskMoveColumnAssigned extends Base
return array(
'task_id',
'column_id',
'project_id',
'owner_id'
);
}

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskMoveColumnCategoryChange extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Move the task to another column when the category is changed');
}
/**
* Get the list of compatible events
*
@@ -50,7 +61,6 @@ class TaskMoveColumnCategoryChange extends Base
return array(
'task_id',
'column_id',
'project_id',
'category_id',
);
}
@@ -71,7 +81,8 @@ class TaskMoveColumnCategoryChange extends Base
$data['task_id'],
$this->getParam('dest_column_id'),
$original_task['position'],
$original_task['swimlane_id']
$original_task['swimlane_id'],
false
);
}

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskMoveColumnUnAssigned extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Move the task to another column when assignee is cleared');
}
/**
* Get the list of compatible events
*
@@ -51,7 +62,6 @@ class TaskMoveColumnUnAssigned extends Base
return array(
'task_id',
'column_id',
'project_id',
'owner_id'
);
}

View File

@@ -14,6 +14,17 @@ use Kanboard\Integration\BitbucketWebhook;
*/
class TaskOpen extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Open a task');
}
/**
* Get the list of compatible events
*

View File

@@ -12,6 +12,17 @@ use Kanboard\Model\Task;
*/
class TaskUpdateStartDate extends Base
{
/**
* Get automatic action description
*
* @access public
* @return string
*/
public function getDescription()
{
return t('Automatically update the start date');
}
/**
* Get the list of compatible events
*

View File

@@ -12,17 +12,17 @@ class Action extends \Kanboard\Core\Base
{
public function getAvailableActions()
{
return $this->action->getAvailableActions();
return $this->actionManager->getAvailableActions();
}
public function getAvailableActionEvents()
{
return $this->action->getAvailableEvents();
return $this->eventManager->getAll();
}
public function getCompatibleActionEvents($action_name)
{
return $this->action->getCompatibleEvents($action_name);
return $this->actionManager->getCompatibleEvents($action_name);
}
public function removeAction($action_id)
@@ -32,22 +32,10 @@ class Action extends \Kanboard\Core\Base
public function getActions($project_id)
{
$actions = $this->action->getAllByProject($project_id);
foreach ($actions as $index => $action) {
$params = array();
foreach ($action['params'] as $param) {
$params[$param['name']] = $param['value'];
}
$actions[$index]['params'] = $params;
}
return $actions;
return $this->action->getAllByProject($project_id);
}
public function createAction($project_id, $event_name, $action_name, $params)
public function createAction($project_id, $event_name, $action_name, array $params)
{
$values = array(
'project_id' => $project_id,
@@ -63,16 +51,16 @@ class Action extends \Kanboard\Core\Base
}
// Check if the action exists
$actions = $this->action->getAvailableActions();
$actions = $this->actionManager->getAvailableActions();
if (! isset($actions[$action_name])) {
return false;
}
// Check the event
$action = $this->action->load($action_name, $project_id, $event_name);
$action = $this->actionManager->getAction($action_name);
if (! in_array($event_name, $action->getCompatibleEvents())) {
if (! in_array($event_name, $action->getEvents())) {
return false;
}

View File

@@ -18,17 +18,18 @@ class Action extends Base
public function index()
{
$project = $this->getProject();
$actions = $this->action->getAllByProject($project['id']);
$this->response->html($this->projectLayout('action/index', array(
'values' => array('project_id' => $project['id']),
'project' => $project,
'actions' => $this->action->getAllByProject($project['id']),
'available_actions' => $this->action->getAvailableActions(),
'available_events' => $this->action->getAvailableEvents(),
'available_params' => $this->action->getAllActionParameters(),
'actions' => $actions,
'available_actions' => $this->actionManager->getAvailableActions(),
'available_events' => $this->eventManager->getAll(),
'available_params' => $this->actionManager->getAvailableParameters($actions),
'columns_list' => $this->board->getColumnsList($project['id']),
'users_list' => $this->projectUserRole->getAssignableUsersList($project['id']),
'projects_list' => $this->project->getList(false),
'projects_list' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()),
'colors_list' => $this->color->getList(),
'categories_list' => $this->category->getList($project['id']),
'links_list' => $this->link->getList(0, false),
@@ -53,7 +54,7 @@ class Action extends Base
$this->response->html($this->projectLayout('action/event', array(
'values' => $values,
'project' => $project,
'events' => $this->action->getCompatibleEvents($values['action_name']),
'events' => $this->actionManager->getCompatibleEvents($values['action_name']),
'title' => t('Automatic actions')
)));
}
@@ -72,14 +73,14 @@ class Action extends Base
$this->response->redirect($this->helper->url->to('action', 'index', array('project_id' => $project['id'])));
}
$action = $this->action->load($values['action_name'], $values['project_id'], $values['event_name']);
$action = $this->actionManager->getAction($values['action_name']);
$action_params = $action->getActionRequiredParameters();
if (empty($action_params)) {
$this->doCreation($project, $values + array('params' => array()));
}
$projects_list = $this->project->getList(false);
$projects_list = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
unset($projects_list[$project['id']]);
$this->response->html($this->projectLayout('action/params', array(
@@ -139,8 +140,8 @@ class Action extends Base
$this->response->html($this->projectLayout('action/remove', array(
'action' => $this->action->getById($this->request->getIntegerParam('action_id')),
'available_events' => $this->action->getAvailableEvents(),
'available_actions' => $this->action->getAvailableActions(),
'available_events' => $this->eventManager->getAll(),
'available_actions' => $this->actionManager->getAvailableActions(),
'project' => $project,
'title' => t('Remove an action')
)));

View File

@@ -0,0 +1,141 @@
<?php
namespace Kanboard\Core\Action;
use RuntimeException;
use Kanboard\Core\Base;
use Kanboard\Action\Base as ActionBase;
/**
* Action Manager
*
* @package action
* @author Frederic Guillot
*/
class ActionManager extends Base
{
/**
* List of automatic actions
*
* @access private
* @var array
*/
private $actions = array();
/**
* Register a new automatic action
*
* @access public
* @param ActionBase $action
* @return ActionManager
*/
public function register(ActionBase $action)
{
$this->actions[$action->getName()] = $action;
return $this;
}
/**
* Get automatic action instance
*
* @access public
* @param string $name Absolute class name with namespace
* @return ActionBase
*/
public function getAction($name)
{
if (isset($this->actions[$name])) {
return $this->actions[$name];
}
throw new RuntimeException('Automatic Action Not Found: '.$name);
}
/**
* Get available automatic actions
*
* @access public
* @return array
*/
public function getAvailableActions()
{
$actions = array();
foreach ($this->actions as $action) {
if (count($action->getEvents()) > 0) {
$actions[$action->getName()] = $action->getDescription();
}
}
asort($actions);
return $actions;
}
/**
* Get all available action parameters
*
* @access public
* @param array $actions
* @return array
*/
public function getAvailableParameters(array $actions)
{
$params = array();
foreach ($actions as $action) {
$currentAction = $this->getAction($action['action_name']);
$params[$currentAction->getName()] = $currentAction->getActionRequiredParameters();
}
return $params;
}
/**
* Get list of compatible events for a given action
*
* @access public
* @param string $name
* @return array
*/
public function getCompatibleEvents($name)
{
$events = array();
$actionEvents = $this->getAction($name)->getEvents();
foreach ($this->eventManager->getAll() as $event => $description) {
if (in_array($event, $actionEvents)) {
$events[$event] = $description;
}
}
return $events;
}
/**
* Bind automatic actions to events
*
* @access public
* @return ActionManager
*/
public function attachEvents()
{
if ($this->userSession->isLogged()) {
$actions = $this->action->getAllByUser($this->userSession->getId());
} else {
$actions = $this->action->getAll();
}
foreach ($actions as $action) {
$listener = $this->getAction($action['action_name'])->setProjectId($action['project_id']);
foreach ($action['params'] as $param_name => $param_value) {
$listener->setParam($param_name, $param_value);
}
$this->dispatcher->addListener($action['event_name'], array($listener, 'execute'));
}
return $this;
}
}

View File

@@ -10,7 +10,9 @@ use Pimple\Container;
* @package core
* @author Frederic Guillot
*
* @property \Kanboard\Core\Action\ActionManager $actionManager
* @property \Kanboard\Core\Cache\MemoryCache $memoryCache
* @property \Kanboard\Core\Event\EventManager $eventManager
* @property \Kanboard\Core\Group\GroupManager $groupManager
* @property \Kanboard\Core\Http\Client $httpClient
* @property \Kanboard\Core\Http\OAuth2 $oauth
@@ -54,6 +56,7 @@ use Pimple\Container;
* @property \Kanboard\Formatter\UserFilterAutoCompleteFormatter $userFilterAutoCompleteFormatter
* @property \Kanboard\Formatter\GroupAutoCompleteFormatter $groupAutoCompleteFormatter
* @property \Kanboard\Model\Action $action
* @property \Kanboard\Model\ActionParameter $actionParameter
* @property \Kanboard\Model\Authentication $authentication
* @property \Kanboard\Model\Board $board
* @property \Kanboard\Model\Category $category

View File

@@ -0,0 +1,83 @@
<?php
namespace Kanboard\Core\Event;
use Kanboard\Integration\GitlabWebhook;
use Kanboard\Integration\GithubWebhook;
use Kanboard\Integration\BitbucketWebhook;
use Kanboard\Model\Task;
use Kanboard\Model\TaskLink;
/**
* Event Manager
*
* @package event
* @author Frederic Guillot
*/
class EventManager
{
/**
* Extended events
*
* @access private
* @var array
*/
private $events = array();
/**
* Add new event
*
* @access public
* @param string $event
* @param string $description
* @return EventManager
*/
public function register($event, $description)
{
$this->events[$event] = $description;
return $this;
}
/**
* Get the list of events and description that can be used from the user interface
*
* @access public
* @return array
*/
public function getAll()
{
$events = array(
TaskLink::EVENT_CREATE_UPDATE => t('Task link creation or modification'),
Task::EVENT_MOVE_COLUMN => t('Move a task to another column'),
Task::EVENT_UPDATE => t('Task modification'),
Task::EVENT_CREATE => t('Task creation'),
Task::EVENT_OPEN => t('Reopen a task'),
Task::EVENT_CLOSE => t('Closing a task'),
Task::EVENT_CREATE_UPDATE => t('Task creation or modification'),
Task::EVENT_ASSIGNEE_CHANGE => t('Task assignee change'),
GithubWebhook::EVENT_COMMIT => t('Github commit received'),
GithubWebhook::EVENT_ISSUE_OPENED => t('Github issue opened'),
GithubWebhook::EVENT_ISSUE_CLOSED => t('Github issue closed'),
GithubWebhook::EVENT_ISSUE_REOPENED => t('Github issue reopened'),
GithubWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE => t('Github issue assignee change'),
GithubWebhook::EVENT_ISSUE_LABEL_CHANGE => t('Github issue label change'),
GithubWebhook::EVENT_ISSUE_COMMENT => t('Github issue comment created'),
GitlabWebhook::EVENT_COMMIT => t('Gitlab commit received'),
GitlabWebhook::EVENT_ISSUE_OPENED => t('Gitlab issue opened'),
GitlabWebhook::EVENT_ISSUE_REOPENED => t('Gitlab issue reopened'),
GitlabWebhook::EVENT_ISSUE_CLOSED => t('Gitlab issue closed'),
GitlabWebhook::EVENT_ISSUE_COMMENT => t('Gitlab issue comment created'),
BitbucketWebhook::EVENT_COMMIT => t('Bitbucket commit received'),
BitbucketWebhook::EVENT_ISSUE_OPENED => t('Bitbucket issue opened'),
BitbucketWebhook::EVENT_ISSUE_CLOSED => t('Bitbucket issue closed'),
BitbucketWebhook::EVENT_ISSUE_REOPENED => t('Bitbucket issue reopened'),
BitbucketWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE => t('Bitbucket issue assignee change'),
BitbucketWebhook::EVENT_ISSUE_COMMENT => t('Bitbucket issue comment created'),
);
$events = array_merge($events, $this->events);
asort($events);
return $events;
}
}

View File

@@ -45,19 +45,21 @@ class Client extends Base
*/
public function send($email, $name, $subject, $html)
{
$this->container['logger']->debug('Sending email to '.$email.' ('.MAIL_TRANSPORT.')');
if (! empty($email)) {
$this->logger->debug('Sending email to '.$email.' ('.MAIL_TRANSPORT.')');
$start_time = microtime(true);
$author = 'Kanboard';
$start_time = microtime(true);
$author = 'Kanboard';
if ($this->userSession->isLogged()) {
$author = e('%s via Kanboard', $this->helper->user->getFullname());
}
if ($this->userSession->isLogged()) {
$author = e('%s via Kanboard', $this->helper->user->getFullname());
}
$this->getTransport(MAIL_TRANSPORT)->sendEmail($email, $name, $subject, $html, $author);
$this->getTransport(MAIL_TRANSPORT)->sendEmail($email, $name, $subject, $html, $author);
if (DEBUG) {
$this->logger->debug('Email sent in '.round(microtime(true) - $start_time, 6).' seconds');
if (DEBUG) {
$this->logger->debug('Email sent in '.round(microtime(true) - $start_time, 6).' seconds');
}
}
return $this;

View File

@@ -303,7 +303,7 @@ class BitbucketWebhook extends \Kanboard\Core\Base
'task_id' => $task_id,
'commit_message' => $commit['message'],
'commit_url' => $commit['links']['html']['href'],
'commit_comment' => $commit['message']."\n\n[".t('Commit made by @%s on Bitbucket', $actor['display_name']).']('.$commit['links']['html']['href'].')',
'comment' => $commit['message']."\n\n[".t('Commit made by @%s on Bitbucket', $actor['display_name']).']('.$commit['links']['html']['href'].')',
) + $task)
);

View File

@@ -98,7 +98,7 @@ class GithubWebhook extends \Kanboard\Core\Base
'task_id' => $task_id,
'commit_message' => $commit['message'],
'commit_url' => $commit['url'],
'commit_comment' => $commit['message']."\n\n[".t('Commit made by @%s on Github', $commit['author']['username']).']('.$commit['url'].')'
'comment' => $commit['message']."\n\n[".t('Commit made by @%s on Github', $commit['author']['username']).']('.$commit['url'].')'
) + $task)
);
}

View File

@@ -144,7 +144,7 @@ class GitlabWebhook extends \Kanboard\Core\Base
'task_id' => $task_id,
'commit_message' => $commit['message'],
'commit_url' => $commit['url'],
'commit_comment' => $commit['message']."\n\n[".t('Commit made by @%s on Gitlab', $commit['author']['name']).']('.$commit['url'].')'
'comment' => $commit['message']."\n\n[".t('Commit made by @%s on Gitlab', $commit['author']['name']).']('.$commit['url'].')'
) + $task)
);

View File

@@ -2,14 +2,11 @@
namespace Kanboard\Model;
use Kanboard\Integration\GitlabWebhook;
use Kanboard\Integration\GithubWebhook;
use Kanboard\Integration\BitbucketWebhook;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
/**
* Action model
* Action Model
*
* @package model
* @author Frederic Guillot
@@ -24,143 +21,33 @@ class Action extends Base
const TABLE = 'actions';
/**
* SQL table name for action parameters
*
* @var string
*/
const TABLE_PARAMS = 'action_has_params';
/**
* Extended actions
*
* @access private
* @var array
*/
private $actions = array();
/**
* Extend the list of default actions
*
* @access public
* @param string $className
* @param string $description
* @return Action
*/
public function extendActions($className, $description)
{
$this->actions[$className] = $description;
return $this;
}
/**
* Return the name and description of available actions
* Return actions and parameters for a given user
*
* @access public
* @param integer $user_id
* @return array
*/
public function getAvailableActions()
public function getAllByUser($user_id)
{
$values = array(
'TaskClose' => t('Close a task'),
'TaskOpen' => t('Open a task'),
'TaskAssignSpecificUser' => t('Assign the task to a specific user'),
'TaskAssignCurrentUser' => t('Assign the task to the person who does the action'),
'TaskDuplicateAnotherProject' => t('Duplicate the task to another project'),
'TaskMoveAnotherProject' => t('Move the task to another project'),
'TaskMoveColumnAssigned' => t('Move the task to another column when assigned to a user'),
'TaskMoveColumnUnAssigned' => t('Move the task to another column when assignee is cleared'),
'TaskAssignColorColumn' => t('Assign a color when the task is moved to a specific column'),
'TaskAssignColorUser' => t('Assign a color to a specific user'),
'TaskAssignColorCategory' => t('Assign automatically a color based on a category'),
'TaskAssignCategoryColor' => t('Assign automatically a category based on a color'),
'TaskAssignCategoryLink' => t('Assign automatically a category based on a link'),
'CommentCreation' => t('Create a comment from an external provider'),
'TaskCreation' => t('Create a task from an external provider'),
'TaskLogMoveAnotherColumn' => t('Add a comment log when moving the task between columns'),
'TaskAssignUser' => t('Change the assignee based on an external username'),
'TaskAssignCategoryLabel' => t('Change the category based on an external label'),
'TaskUpdateStartDate' => t('Automatically update the start date'),
'TaskMoveColumnCategoryChange' => t('Move the task to another column when the category is changed'),
'TaskEmail' => t('Send a task by email to someone'),
'TaskAssignColorLink' => t('Change task color when using a specific task link'),
);
$project_ids = $this->projectPermission->getActiveProjectIds($user_id);
$actions = array();
$values = array_merge($values, $this->actions);
if (! empty($project_ids)) {
$actions = $this->db->table(self::TABLE)->in('project_id', $project_ids)->findAll();
asort($values);
return $values;
}
/**
* Return the name and description of available actions
*
* @access public
* @return array
*/
public function getAvailableEvents()
{
$values = array(
TaskLink::EVENT_CREATE_UPDATE => t('Task link creation or modification'),
Task::EVENT_MOVE_COLUMN => t('Move a task to another column'),
Task::EVENT_UPDATE => t('Task modification'),
Task::EVENT_CREATE => t('Task creation'),
Task::EVENT_OPEN => t('Reopen a task'),
Task::EVENT_CLOSE => t('Closing a task'),
Task::EVENT_CREATE_UPDATE => t('Task creation or modification'),
Task::EVENT_ASSIGNEE_CHANGE => t('Task assignee change'),
GithubWebhook::EVENT_COMMIT => t('Github commit received'),
GithubWebhook::EVENT_ISSUE_OPENED => t('Github issue opened'),
GithubWebhook::EVENT_ISSUE_CLOSED => t('Github issue closed'),
GithubWebhook::EVENT_ISSUE_REOPENED => t('Github issue reopened'),
GithubWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE => t('Github issue assignee change'),
GithubWebhook::EVENT_ISSUE_LABEL_CHANGE => t('Github issue label change'),
GithubWebhook::EVENT_ISSUE_COMMENT => t('Github issue comment created'),
GitlabWebhook::EVENT_COMMIT => t('Gitlab commit received'),
GitlabWebhook::EVENT_ISSUE_OPENED => t('Gitlab issue opened'),
GitlabWebhook::EVENT_ISSUE_REOPENED => t('Gitlab issue reopened'),
GitlabWebhook::EVENT_ISSUE_CLOSED => t('Gitlab issue closed'),
GitlabWebhook::EVENT_ISSUE_COMMENT => t('Gitlab issue comment created'),
BitbucketWebhook::EVENT_COMMIT => t('Bitbucket commit received'),
BitbucketWebhook::EVENT_ISSUE_OPENED => t('Bitbucket issue opened'),
BitbucketWebhook::EVENT_ISSUE_CLOSED => t('Bitbucket issue closed'),
BitbucketWebhook::EVENT_ISSUE_REOPENED => t('Bitbucket issue reopened'),
BitbucketWebhook::EVENT_ISSUE_ASSIGNEE_CHANGE => t('Bitbucket issue assignee change'),
BitbucketWebhook::EVENT_ISSUE_COMMENT => t('Bitbucket issue comment created'),
);
asort($values);
return $values;
}
/**
* Return the name and description of compatible actions
*
* @access public
* @param string $action_name Action name
* @return array
*/
public function getCompatibleEvents($action_name)
{
$action = $this->load($action_name, 0, '');
$compatible_events = $action->getCompatibleEvents();
$events = array();
foreach ($this->getAvailableEvents() as $event_name => $event_description) {
if (in_array($event_name, $compatible_events)) {
$events[$event_name] = $event_description;
foreach ($actions as &$action) {
$action['params'] = $this->actionParameter->getAll($action['id']);
}
}
return $events;
return $actions;
}
/**
* Return actions and parameters for a given project
*
* @access public
* @param $project_id
* @param integer $project_id
* @return array
*/
public function getAllByProject($project_id)
@@ -168,7 +55,7 @@ class Action extends Base
$actions = $this->db->table(self::TABLE)->eq('project_id', $project_id)->findAll();
foreach ($actions as &$action) {
$action['params'] = $this->db->table(self::TABLE_PARAMS)->eq('action_id', $action['id'])->findAll();
$action['params'] = $this->actionParameter->getAll($action['id']);
}
return $actions;
@@ -183,52 +70,27 @@ class Action extends Base
public function getAll()
{
$actions = $this->db->table(self::TABLE)->findAll();
$params = $this->db->table(self::TABLE_PARAMS)->findAll();
foreach ($actions as &$action) {
$action['params'] = array();
foreach ($params as $param) {
if ($param['action_id'] === $action['id']) {
$action['params'][] = $param;
}
}
$action['params'] = $this->actionParameter->getAll($action['id']);
}
return $actions;
}
/**
* Get all required action parameters for all registered actions
*
* @access public
* @return array All required parameters for all actions
*/
public function getAllActionParameters()
{
$params = array();
foreach ($this->getAll() as $action) {
$action = $this->load($action['action_name'], $action['project_id'], $action['event_name']);
$params += $action->getActionRequiredParameters();
}
return $params;
}
/**
* Fetch an action
*
* @access public
* @param integer $action_id Action id
* @return array Action data
* @param integer $action_id
* @return array
*/
public function getById($action_id)
{
$action = $this->db->table(self::TABLE)->eq('id', $action_id)->findOne();
if (! empty($action)) {
$action['params'] = $this->db->table(self::TABLE_PARAMS)->eq('action_id', $action_id)->findAll();
$action['params'] = $this->actionParameter->getAll($action_id);
}
return $action;
@@ -238,8 +100,8 @@ class Action extends Base
* Remove an action
*
* @access public
* @param integer $action_id Action id
* @return bool Success or not
* @param integer $action_id
* @return bool
*/
public function remove($action_id)
{
@@ -263,24 +125,16 @@ class Action extends Base
'action_name' => $values['action_name'],
);
if (! $this->db->table(self::TABLE)->save($action)) {
if (! $this->db->table(self::TABLE)->insert($action)) {
$this->db->cancelTransaction();
return false;
}
$action_id = $this->db->getLastId();
foreach ($values['params'] as $param_name => $param_value) {
$action_param = array(
'action_id' => $action_id,
'name' => $param_name,
'value' => $param_value,
);
if (! $this->db->table(self::TABLE_PARAMS)->save($action_param)) {
$this->db->cancelTransaction();
return false;
}
if (! $this->actionParameter->create($action_id, $values)) {
$this->db->cancelTransaction();
return false;
}
$this->db->closeTransaction();
@@ -288,42 +142,6 @@ class Action extends Base
return $action_id;
}
/**
* Load all actions and attach events
*
* @access public
*/
public function attachEvents()
{
$actions = $this->getAll();
foreach ($actions as $action) {
$listener = $this->load($action['action_name'], $action['project_id'], $action['event_name']);
foreach ($action['params'] as $param) {
$listener->setParam($param['name'], $param['value']);
}
$this->container['dispatcher']->addListener($action['event_name'], array($listener, 'execute'));
}
}
/**
* Load an action
*
* @access public
* @param string $name Action class name
* @param integer $project_id Project id
* @param string $event Event name
* @return \Action\Base
*/
public function load($name, $project_id, $event)
{
$className = $name{0}
!== '\\' ? '\Kanboard\Action\\'.$name : $name;
return new $className($this->container, $project_id, $event);
}
/**
* Copy actions from a project to another one (skip actions that cannot resolve parameters)
*
@@ -346,15 +164,14 @@ class Action extends Base
);
if (! $this->db->table(self::TABLE)->insert($values)) {
$this->container['logger']->debug('Action::duplicate => unable to create '.$action['action_name']);
$this->db->cancelTransaction();
continue;
}
$action_id = $this->db->getLastId();
if (! $this->duplicateParameters($dst_project_id, $action_id, $action['params'])) {
$this->container['logger']->debug('Action::duplicate => unable to copy parameters for '.$action['action_name']);
if (! $this->actionParameter->duplicateParameters($dst_project_id, $action_id, $action['params'])) {
$this->logger->error('Action::duplicate => skip action '.$action['action_name'].' '.$action['id']);
$this->db->cancelTransaction();
continue;
}
@@ -365,74 +182,6 @@ class Action extends Base
return true;
}
/**
* Duplicate action parameters
*
* @access public
* @param integer $project_id
* @param integer $action_id
* @param array $params
* @return boolean
*/
public function duplicateParameters($project_id, $action_id, array $params)
{
foreach ($params as $param) {
$value = $this->resolveParameters($param, $project_id);
if ($value === false) {
$this->container['logger']->debug('Action::duplicateParameters => unable to resolve '.$param['name'].'='.$param['value']);
return false;
}
$values = array(
'action_id' => $action_id,
'name' => $param['name'],
'value' => $value,
);
if (! $this->db->table(self::TABLE_PARAMS)->insert($values)) {
return false;
}
}
return true;
}
/**
* Resolve action parameter values according to another project
*
* @author Antonio Rabelo
* @access public
* @param array $param Action parameter
* @param integer $project_id Project to find the corresponding values
* @return mixed
*/
public function resolveParameters(array $param, $project_id)
{
switch ($param['name']) {
case 'project_id':
return $project_id;
case 'category_id':
return $this->category->getIdByName($project_id, $this->category->getNameById($param['value'])) ?: false;
case 'src_column_id':
case 'dest_column_id':
case 'dst_column_id':
case 'column_id':
$column = $this->board->getColumn($param['value']);
if (empty($column)) {
return false;
}
return $this->board->getColumnIdByTitle($project_id, $column['title']) ?: false;
case 'user_id':
case 'owner_id':
return $this->projectPermission->isAssignable($project_id, $param['value']) ? $param['value'] : false;
default:
return $param['value'];
}
}
/**
* Validate action creation
*

View File

@@ -0,0 +1,122 @@
<?php
namespace Kanboard\Model;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
/**
* Action Parameter Model
*
* @package model
* @author Frederic Guillot
*/
class ActionParameter extends Base
{
/**
* SQL table name
*
* @var string
*/
const TABLE = 'action_has_params';
/**
* Get all action params
*
* @access public
* @param integer $action_id
* @return array
*/
public function getAll($action_id)
{
return $this->db->hashtable(self::TABLE)->eq('action_id', $action_id)->getAll('name', 'value');
}
/**
* Insert new parameters for an action
*
* @access public
* @param integer $action_id
* @param array $values
* @return boolean
*/
public function create($action_id, array $values)
{
foreach ($values['params'] as $name => $value) {
$param = array(
'action_id' => $action_id,
'name' => $name,
'value' => $value,
);
if (! $this->db->table(self::TABLE)->save($param)) {
return false;
}
}
return true;
}
/**
* Duplicate action parameters
*
* @access public
* @param integer $project_id
* @param integer $action_id
* @param array $params
* @return boolean
*/
public function duplicateParameters($project_id, $action_id, array $params)
{
foreach ($params as $name => $value) {
$value = $this->resolveParameter($project_id, $name, $value);
if ($value === false) {
$this->logger->error('ActionParameter::duplicateParameters => unable to resolve '.$name.'='.$value);
return false;
}
$values = array(
'action_id' => $action_id,
'name' => $name,
'value' => $value,
);
if (! $this->db->table(self::TABLE)->insert($values)) {
return false;
}
}
return true;
}
/**
* Resolve action parameter values according to another project
*
* @access private
* @param integer $project_id
* @param string $name
* @param string $value
* @return mixed
*/
private function resolveParameter($project_id, $name, $value)
{
switch ($name) {
case 'project_id':
return $value != $project_id ? $value : false;
case 'category_id':
return $this->category->getIdByName($project_id, $this->category->getNameById($value)) ?: false;
case 'src_column_id':
case 'dest_column_id':
case 'dst_column_id':
case 'column_id':
$column = $this->board->getColumn($value);
return empty($column) ? false : $this->board->getColumnIdByTitle($project_id, $column['title']) ?: false;
case 'user_id':
case 'owner_id':
return $this->projectPermission->isAssignable($project_id, $value) ? $value : false;
default:
return $value;
}
}
}

View File

@@ -75,6 +75,7 @@ class Comment extends Base
self::TABLE.'.user_id',
self::TABLE.'.date_creation',
self::TABLE.'.comment',
self::TABLE.'.reference',
User::TABLE.'.username',
User::TABLE.'.name'
)

View File

@@ -52,11 +52,11 @@ class ProjectUserRole extends Base
->getAll(Project::TABLE.'.id', Project::TABLE.'.name');
$groupProjects = $this->projectGroupRole->getProjectsByUser($user_id, $status);
$groups = $userProjects + $groupProjects;
$projects = $userProjects + $groupProjects;
asort($groups);
asort($projects);
return $groups;
return $projects;
}
/**

View File

@@ -6,7 +6,30 @@ use Kanboard\Core\Security\Token;
use Kanboard\Core\Security\Role;
use PDO;
const VERSION = 91;
const VERSION = 92;
function version_92(PDO $pdo)
{
$rq = $pdo->prepare('SELECT * FROM actions');
$rq->execute();
$rows = $rq->fetchAll(PDO::FETCH_ASSOC) ?: array();
$rq = $pdo->prepare('UPDATE actions SET action_name=? WHERE id=?');
foreach ($rows as $row) {
if ($row['action_name'] === 'TaskAssignCurrentUser' && $row['event_name'] === 'task.move.column') {
$row['action_name'] = '\Kanboard\Action\TaskAssignCurrentUserColumn';
} elseif ($row['action_name'] === 'TaskClose' && $row['event_name'] === 'task.move.column') {
$row['action_name'] = '\Kanboard\Action\TaskCloseColumn';
} elseif ($row['action_name'] === 'TaskLogMoveAnotherColumn') {
$row['action_name'] = '\Kanboard\Action\CommentCreationMoveTaskColumn';
} elseif ($row['action_name']{0} !== '\\') {
$row['action_name'] = '\Kanboard\Action\\'.$row['action_name'];
}
$rq->execute(array($row['action_name'], $row['id']));
}
}
function version_91(PDO $pdo)
{

View File

@@ -0,0 +1,78 @@
<?php
namespace Kanboard\ServiceProvider;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
use Kanboard\Core\Action\ActionManager;
use Kanboard\Action\CommentCreation;
use Kanboard\Action\CommentCreationMoveTaskColumn;
use Kanboard\Action\TaskAssignCategoryColor;
use Kanboard\Action\TaskAssignCategoryLabel;
use Kanboard\Action\TaskAssignCategoryLink;
use Kanboard\Action\TaskAssignColorCategory;
use Kanboard\Action\TaskAssignColorColumn;
use Kanboard\Action\TaskAssignColorLink;
use Kanboard\Action\TaskAssignColorUser;
use Kanboard\Action\TaskAssignCurrentUser;
use Kanboard\Action\TaskAssignCurrentUserColumn;
use Kanboard\Action\TaskAssignSpecificUser;
use Kanboard\Action\TaskAssignUser;
use Kanboard\Action\TaskClose;
use Kanboard\Action\TaskCloseColumn;
use Kanboard\Action\TaskCreation;
use Kanboard\Action\TaskDuplicateAnotherProject;
use Kanboard\Action\TaskEmail;
use Kanboard\Action\TaskMoveAnotherProject;
use Kanboard\Action\TaskMoveColumnAssigned;
use Kanboard\Action\TaskMoveColumnCategoryChange;
use Kanboard\Action\TaskMoveColumnUnAssigned;
use Kanboard\Action\TaskOpen;
use Kanboard\Action\TaskUpdateStartDate;
/**
* Action Provider
*
* @package serviceProvider
* @author Frederic Guillot
*/
class ActionProvider implements ServiceProviderInterface
{
/**
* Register providers
*
* @access public
* @param \Pimple\Container $container
* @return \Pimple\Container
*/
public function register(Container $container)
{
$container['actionManager'] = new ActionManager($container);
$container['actionManager']->register(new CommentCreation($container));
$container['actionManager']->register(new CommentCreationMoveTaskColumn($container));
$container['actionManager']->register(new TaskAssignCategoryColor($container));
$container['actionManager']->register(new TaskAssignCategoryLabel($container));
$container['actionManager']->register(new TaskAssignCategoryLink($container));
$container['actionManager']->register(new TaskAssignColorCategory($container));
$container['actionManager']->register(new TaskAssignColorColumn($container));
$container['actionManager']->register(new TaskAssignColorLink($container));
$container['actionManager']->register(new TaskAssignColorUser($container));
$container['actionManager']->register(new TaskAssignCurrentUser($container));
$container['actionManager']->register(new TaskAssignCurrentUserColumn($container));
$container['actionManager']->register(new TaskAssignSpecificUser($container));
$container['actionManager']->register(new TaskAssignUser($container));
$container['actionManager']->register(new TaskClose($container));
$container['actionManager']->register(new TaskCloseColumn($container));
$container['actionManager']->register(new TaskCreation($container));
$container['actionManager']->register(new TaskDuplicateAnotherProject($container));
$container['actionManager']->register(new TaskEmail($container));
$container['actionManager']->register(new TaskMoveAnotherProject($container));
$container['actionManager']->register(new TaskMoveColumnAssigned($container));
$container['actionManager']->register(new TaskMoveColumnCategoryChange($container));
$container['actionManager']->register(new TaskMoveColumnUnAssigned($container));
$container['actionManager']->register(new TaskOpen($container));
$container['actionManager']->register(new TaskUpdateStartDate($container));
return $container;
}
}

View File

@@ -17,6 +17,7 @@ class ClassProvider implements ServiceProviderInterface
private $classes = array(
'Model' => array(
'Action',
'ActionParameter',
'Authentication',
'Board',
'Category',
@@ -90,6 +91,9 @@ class ClassProvider implements ServiceProviderInterface
'Lexer',
'Template',
),
'Core\Event' => array(
'EventManager',
),
'Core\Http' => array(
'Request',
'Response',

View File

@@ -30,9 +30,6 @@ class EventDispatcherProvider implements ServiceProviderInterface
$container['dispatcher']->addSubscriber(new TransitionSubscriber($container));
$container['dispatcher']->addSubscriber(new RecurringTaskSubscriber($container));
// Automatic actions
$container['action']->attachEvents();
return $container;
}
}

View File

@@ -3,21 +3,26 @@
namespace Kanboard\Subscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Kanboard\Core\Base;
class BootstrapSubscriber extends \Kanboard\Core\Base implements EventSubscriberInterface
class BootstrapSubscriber extends Base implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
'app.bootstrap' => array('setup', 0),
'app.bootstrap' => 'execute',
);
}
public function setup()
public function execute()
{
$this->config->setupTranslations();
$this->config->setupTimezone();
$this->sessionStorage->hasSubtaskInProgress = $this->subtask->hasSubtaskInProgress($this->userSession->getId());
$this->actionManager->attachEvents();
if ($this->userSession->isLogged()) {
$this->sessionStorage->hasSubtaskInProgress = $this->subtask->hasSubtaskInProgress($this->userSession->getId());
}
}
public function __destruct()

View File

@@ -28,24 +28,24 @@
</td>
<td>
<ul>
<?php foreach ($action['params'] as $param): ?>
<?php foreach ($action['params'] as $param_name => $param_value): ?>
<li>
<?= $this->text->in($param['name'], $available_params) ?> =
<?= $this->text->in($param_name, $available_params[$action['action_name']]) ?> =
<strong>
<?php if ($this->text->contains($param['name'], 'column_id')): ?>
<?= $this->text->in($param['value'], $columns_list) ?>
<?php elseif ($this->text->contains($param['name'], 'user_id')): ?>
<?= $this->text->in($param['value'], $users_list) ?>
<?php elseif ($this->text->contains($param['name'], 'project_id')): ?>
<?= $this->text->in($param['value'], $projects_list) ?>
<?php elseif ($this->text->contains($param['name'], 'color_id')): ?>
<?= $this->text->in($param['value'], $colors_list) ?>
<?php elseif ($this->text->contains($param['name'], 'category_id')): ?>
<?= $this->text->in($param['value'], $categories_list) ?>
<?php elseif ($this->text->contains($param['name'], 'link_id')): ?>
<?= $this->text->in($param['value'], $links_list) ?>
<?php if ($this->text->contains($param_name, 'column_id')): ?>
<?= $this->text->in($param_value, $columns_list) ?>
<?php elseif ($this->text->contains($param_name, 'user_id')): ?>
<?= $this->text->in($param_value, $users_list) ?>
<?php elseif ($this->text->contains($param_name, 'project_id')): ?>
<?= $this->text->in($param_value, $projects_list) ?>
<?php elseif ($this->text->contains($param_name, 'color_id')): ?>
<?= $this->text->in($param_value, $colors_list) ?>
<?php elseif ($this->text->contains($param_name, 'category_id')): ?>
<?= $this->text->in($param_value, $categories_list) ?>
<?php elseif ($this->text->contains($param_name, 'link_id')): ?>
<?= $this->text->in($param_value, $links_list) ?>
<?php else: ?>
<?= $this->e($param['value']) ?>
<?= $this->e($param_value) ?>
<?php endif ?>
</strong>
</li>

View File

@@ -33,4 +33,5 @@ $container->register(new Kanboard\ServiceProvider\ClassProvider);
$container->register(new Kanboard\ServiceProvider\EventDispatcherProvider);
$container->register(new Kanboard\ServiceProvider\GroupProvider);
$container->register(new Kanboard\ServiceProvider\RouteProvider);
$container->register(new Kanboard\ServiceProvider\ActionProvider);
$container->register(new Kanboard\ServiceProvider\PluginProvider);