Automatic actions
This commit is contained in:
parent
7bd4697dfc
commit
7749b8ed56
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Action;
|
||||||
|
|
||||||
|
abstract class Base implements \Core\Listener
|
||||||
|
{
|
||||||
|
private $project_id = 0;
|
||||||
|
private $params = array();
|
||||||
|
|
||||||
|
abstract public function doAction(array $data);
|
||||||
|
abstract public function getActionRequiredParameters();
|
||||||
|
abstract public function getEventRequiredParameters();
|
||||||
|
|
||||||
|
public function __construct($project_id)
|
||||||
|
{
|
||||||
|
$this->project_id = $project_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setParam($name, $value)
|
||||||
|
{
|
||||||
|
$this->params[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParam($name, $default_value = null)
|
||||||
|
{
|
||||||
|
return isset($this->params[$name]) ? $this->params[$name] : $default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isExecutable(array $data)
|
||||||
|
{
|
||||||
|
if (isset($data['project_id']) && $data['project_id'] == $this->project_id && $this->hasRequiredParameters($data)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasRequiredParameters(array $data)
|
||||||
|
{
|
||||||
|
foreach ($this->getEventRequiredParameters() as $parameter) {
|
||||||
|
if (! isset($data[$parameter])) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(array $data)
|
||||||
|
{
|
||||||
|
if ($this->isExecutable($data)) {
|
||||||
|
return $this->doAction($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Action;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
|
||||||
|
class TaskAssignCurrentUser extends Base
|
||||||
|
{
|
||||||
|
public function __construct($project_id, \Model\Task $task, \Model\Acl $acl)
|
||||||
|
{
|
||||||
|
parent::__construct($project_id);
|
||||||
|
$this->task = $task;
|
||||||
|
$this->acl = $acl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActionRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'column_id' => t('Column'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEventRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'task_id',
|
||||||
|
'column_id',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function doAction(array $data)
|
||||||
|
{
|
||||||
|
if ($data['column_id'] == $this->getParam('column_id')) {
|
||||||
|
|
||||||
|
$this->task->update(array(
|
||||||
|
'id' => $data['task_id'],
|
||||||
|
'owner_id' => $this->acl->getUserId(),
|
||||||
|
));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Action;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
|
||||||
|
class TaskAssignSpecificUser extends Base
|
||||||
|
{
|
||||||
|
public function __construct($project_id, \Model\Task $task)
|
||||||
|
{
|
||||||
|
parent::__construct($project_id);
|
||||||
|
$this->task = $task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActionRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'column_id' => t('Column'),
|
||||||
|
'user_id' => t('Assignee'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEventRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'task_id',
|
||||||
|
'column_id',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function doAction(array $data)
|
||||||
|
{
|
||||||
|
if ($data['column_id'] == $this->getParam('column_id')) {
|
||||||
|
|
||||||
|
$this->task->update(array(
|
||||||
|
'id' => $data['task_id'],
|
||||||
|
'owner_id' => $this->getParam('user_id'),
|
||||||
|
));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Action;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
|
||||||
|
class TaskClose extends Base
|
||||||
|
{
|
||||||
|
public function __construct($project_id, \Model\Task $task)
|
||||||
|
{
|
||||||
|
parent::__construct($project_id);
|
||||||
|
$this->task = $task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActionRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'column_id' => t('Column'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEventRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'task_id',
|
||||||
|
'column_id',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function doAction(array $data)
|
||||||
|
{
|
||||||
|
if ($data['column_id'] == $this->getParam('column_id')) {
|
||||||
|
$this->task->close($data['task_id']);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Action;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
|
||||||
|
class TaskDuplicateAnotherProject extends Base
|
||||||
|
{
|
||||||
|
public function __construct($project_id, \Model\Task $task)
|
||||||
|
{
|
||||||
|
parent::__construct($project_id);
|
||||||
|
$this->task = $task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActionRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'column_id' => t('Column'),
|
||||||
|
'project_id' => t('Project'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEventRequiredParameters()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'task_id',
|
||||||
|
'column_id',
|
||||||
|
'project_id',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function doAction(array $data)
|
||||||
|
{
|
||||||
|
if ($data['column_id'] == $this->getParam('column_id') && $data['project_id'] != $this->getParam('project_id')) {
|
||||||
|
|
||||||
|
$this->task->duplicateToAnotherProject($data['task_id'], $this->getParam('project_id'));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -140,6 +140,23 @@
|
||||||
|
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open("POST", "?controller=board&action=save&project_id=" + projectId, true);
|
xhr.open("POST", "?controller=board&action=save&project_id=" + projectId, true);
|
||||||
|
|
||||||
|
xhr.onreadystatechange = function(response) {
|
||||||
|
|
||||||
|
if (this.readyState == this.DONE) {
|
||||||
|
try {
|
||||||
|
var response = JSON.parse(this.responseText);
|
||||||
|
|
||||||
|
if (response.result == true) {
|
||||||
|
|
||||||
|
// TODO: don't refresh the whole page!
|
||||||
|
window.location = "?controller=board&action=show&project_id=" + projectId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
xhr.send(JSON.stringify(data));
|
xhr.send(JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,90 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require __DIR__.'/core/registry.php';
|
||||||
|
require __DIR__.'/core/helper.php';
|
||||||
|
require __DIR__.'/core/translator.php';
|
||||||
|
|
||||||
|
$registry = new Core\Registry;
|
||||||
|
|
||||||
|
$registry->db_version = 10;
|
||||||
|
|
||||||
|
$registry->db = function() use ($registry) {
|
||||||
|
require __DIR__.'/vendor/PicoDb/Database.php';
|
||||||
|
require __DIR__.'/models/schema.php';
|
||||||
|
|
||||||
|
$db = new \PicoDb\Database(array(
|
||||||
|
'driver' => 'sqlite',
|
||||||
|
'filename' => DB_FILENAME
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($db->schema()->check($registry->db_version)) {
|
||||||
|
return $db;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
die('Unable to migrate database schema!');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$registry->event = function() use ($registry) {
|
||||||
|
require __DIR__.'/core/event.php';
|
||||||
|
return new \Core\Event;
|
||||||
|
};
|
||||||
|
|
||||||
|
$registry->action = function() use ($registry) {
|
||||||
|
require_once __DIR__.'/models/action.php';
|
||||||
|
return new \Model\Action($registry->shared('db'), $registry->shared('event'));
|
||||||
|
};
|
||||||
|
|
||||||
|
$registry->config = function() use ($registry) {
|
||||||
|
require_once __DIR__.'/models/config.php';
|
||||||
|
return new \Model\Config($registry->shared('db'), $registry->shared('event'));
|
||||||
|
};
|
||||||
|
|
||||||
|
$registry->acl = function() use ($registry) {
|
||||||
|
require_once __DIR__.'/models/acl.php';
|
||||||
|
return new \Model\Acl($registry->shared('db'), $registry->shared('event'));
|
||||||
|
};
|
||||||
|
|
||||||
|
$registry->user = function() use ($registry) {
|
||||||
|
require_once __DIR__.'/models/user.php';
|
||||||
|
return new \Model\User($registry->shared('db'), $registry->shared('event'));
|
||||||
|
};
|
||||||
|
|
||||||
|
$registry->comment = function() use ($registry) {
|
||||||
|
require_once __DIR__.'/models/comment.php';
|
||||||
|
return new \Model\Comment($registry->shared('db'), $registry->shared('event'));
|
||||||
|
};
|
||||||
|
|
||||||
|
$registry->task = function() use ($registry) {
|
||||||
|
require_once __DIR__.'/models/task.php';
|
||||||
|
return new \Model\Task($registry->shared('db'), $registry->shared('event'));
|
||||||
|
};
|
||||||
|
|
||||||
|
$registry->board = function() use ($registry) {
|
||||||
|
require_once __DIR__.'/models/board.php';
|
||||||
|
return new \Model\Board($registry->shared('db'), $registry->shared('event'));
|
||||||
|
};
|
||||||
|
|
||||||
|
$registry->project = function() use ($registry) {
|
||||||
|
require_once __DIR__.'/models/project.php';
|
||||||
|
return new \Model\Project($registry->shared('db'), $registry->shared('event'));
|
||||||
|
};
|
||||||
|
|
||||||
|
$registry->action = function() use ($registry) {
|
||||||
|
require_once __DIR__.'/models/action.php';
|
||||||
|
return new \Model\Action($registry->shared('db'), $registry->shared('event'));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (file_exists('config.php')) require 'config.php';
|
||||||
|
|
||||||
|
// Auto-refresh frequency in seconds for the public board view
|
||||||
|
defined('AUTO_REFRESH_DURATION') or define('AUTO_REFRESH_DURATION', 60);
|
||||||
|
|
||||||
|
// Custom session save path
|
||||||
|
defined('SESSION_SAVE_PATH') or define('SESSION_SAVE_PATH', '');
|
||||||
|
|
||||||
|
// Database filename
|
||||||
|
defined('DB_FILENAME') or define('DB_FILENAME', 'data/db.sqlite');
|
||||||
|
|
||||||
|
// Application version
|
||||||
|
defined('APP_VERSION') or define('APP_VERSION', 'master');
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Controller;
|
||||||
|
|
||||||
|
require_once __DIR__.'/Base.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatic actions management
|
||||||
|
*
|
||||||
|
* @package controllers
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class Action extends Base
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* List of automatic actions for a given project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$project_id = $this->request->getIntegerParam('project_id');
|
||||||
|
$project = $this->project->getById($project_id);
|
||||||
|
|
||||||
|
if (! $project) {
|
||||||
|
$this->session->flashError(t('Project not found.'));
|
||||||
|
$this->response->redirect('?controller=project');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->html($this->template->layout('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(),
|
||||||
|
'columns_list' => $this->board->getColumnsList($project['id']),
|
||||||
|
'users_list' => $this->project->getUsersList($project['id'], false),
|
||||||
|
'projects_list' => $this->project->getList(false),
|
||||||
|
'menu' => 'projects',
|
||||||
|
'title' => t('Automatic actions')
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define action parameters (step 2)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function params()
|
||||||
|
{
|
||||||
|
$project_id = $this->request->getIntegerParam('project_id');
|
||||||
|
$project = $this->project->getById($project_id);
|
||||||
|
|
||||||
|
if (! $project) {
|
||||||
|
$this->session->flashError(t('Project not found.'));
|
||||||
|
$this->response->redirect('?controller=project');
|
||||||
|
}
|
||||||
|
|
||||||
|
$values = $this->request->getValues();
|
||||||
|
$action = $this->action->load($values['action_name'], $values['project_id']);
|
||||||
|
|
||||||
|
$this->response->html($this->template->layout('action_params', array(
|
||||||
|
'values' => $values,
|
||||||
|
'action_params' => $action->getActionRequiredParameters(),
|
||||||
|
'columns_list' => $this->board->getColumnsList($project['id']),
|
||||||
|
'users_list' => $this->project->getUsersList($project['id'], false),
|
||||||
|
'projects_list' => $this->project->getList(false),
|
||||||
|
'project' => $project,
|
||||||
|
'menu' => 'projects',
|
||||||
|
'title' => t('Automatic actions')
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new action (last step)
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$project_id = $this->request->getIntegerParam('project_id');
|
||||||
|
$project = $this->project->getById($project_id);
|
||||||
|
|
||||||
|
if (! $project) {
|
||||||
|
$this->session->flashError(t('Project not found.'));
|
||||||
|
$this->response->redirect('?controller=project');
|
||||||
|
}
|
||||||
|
|
||||||
|
$values = $this->request->getValues();
|
||||||
|
|
||||||
|
list($valid, $errors) = $this->action->validateCreation($values);
|
||||||
|
|
||||||
|
if ($valid) {
|
||||||
|
|
||||||
|
if ($this->action->create($values)) {
|
||||||
|
$this->session->flash(t('Your automatic action have been created successfully.'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$this->session->flashError(t('Unable to create your automatic action.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->redirect('?controller=action&action=index&project_id='.$project['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirmation dialog before removing an action
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function confirm()
|
||||||
|
{
|
||||||
|
$this->response->html($this->template->layout('action_remove', array(
|
||||||
|
'action' => $this->action->getById($this->request->getIntegerParam('action_id')),
|
||||||
|
'available_events' => $this->action->getAvailableEvents(),
|
||||||
|
'available_actions' => $this->action->getAvailableActions(),
|
||||||
|
'menu' => 'projects',
|
||||||
|
'title' => t('Remove an action')
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an action
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function remove()
|
||||||
|
{
|
||||||
|
$action = $this->action->getById($this->request->getIntegerParam('action_id'));
|
||||||
|
|
||||||
|
if ($action && $this->action->remove($action['id'])) {
|
||||||
|
$this->session->flash(t('Action removed successfully.'));
|
||||||
|
} else {
|
||||||
|
$this->session->flashError(t('Unable to remove this action.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->redirect('?controller=action&action=index&project_id='.$action['project_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Controller;
|
namespace Controller;
|
||||||
|
|
||||||
|
require_once __DIR__.'/Base.php';
|
||||||
|
|
||||||
class App extends Base
|
class App extends Base
|
||||||
{
|
{
|
||||||
public function index()
|
public function index()
|
||||||
|
|
|
||||||
|
|
@ -2,48 +2,18 @@
|
||||||
|
|
||||||
namespace Controller;
|
namespace Controller;
|
||||||
|
|
||||||
require __DIR__.'/../lib/request.php';
|
|
||||||
require __DIR__.'/../lib/response.php';
|
|
||||||
require __DIR__.'/../lib/session.php';
|
|
||||||
require __DIR__.'/../lib/template.php';
|
|
||||||
require __DIR__.'/../lib/helper.php';
|
|
||||||
require __DIR__.'/../lib/translator.php';
|
|
||||||
require __DIR__.'/../models/base.php';
|
|
||||||
require __DIR__.'/../models/acl.php';
|
|
||||||
require __DIR__.'/../models/config.php';
|
|
||||||
require __DIR__.'/../models/user.php';
|
|
||||||
require __DIR__.'/../models/project.php';
|
|
||||||
require __DIR__.'/../models/task.php';
|
|
||||||
require __DIR__.'/../models/board.php';
|
|
||||||
require __DIR__.'/../models/comment.php';
|
|
||||||
|
|
||||||
abstract class Base
|
abstract class Base
|
||||||
{
|
{
|
||||||
protected $request;
|
public function __construct(\Core\Registry $registry)
|
||||||
protected $response;
|
|
||||||
protected $session;
|
|
||||||
protected $template;
|
|
||||||
protected $user;
|
|
||||||
protected $project;
|
|
||||||
protected $task;
|
|
||||||
protected $board;
|
|
||||||
protected $config;
|
|
||||||
protected $acl;
|
|
||||||
protected $comment;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
{
|
||||||
$this->request = new \Request;
|
$this->acl = $registry->acl;
|
||||||
$this->response = new \Response;
|
$this->action = $registry->action;
|
||||||
$this->session = new \Session;
|
$this->board = $registry->board;
|
||||||
$this->template = new \Template;
|
$this->config = $registry->config;
|
||||||
$this->config = new \Model\Config;
|
$this->project = $registry->project;
|
||||||
$this->user = new \Model\User;
|
$this->task = $registry->task;
|
||||||
$this->project = new \Model\Project;
|
$this->user = $registry->user;
|
||||||
$this->task = new \Model\Task;
|
$this->comment = $registry->comment;
|
||||||
$this->board = new \Model\Board;
|
|
||||||
$this->acl = new \Model\Acl;
|
|
||||||
$this->comment = new \Model\Comment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function beforeAction($controller, $action)
|
public function beforeAction($controller, $action)
|
||||||
|
|
@ -74,6 +44,9 @@ abstract class Base
|
||||||
if (! $this->acl->isPageAccessAllowed($controller, $action)) {
|
if (! $this->acl->isPageAccessAllowed($controller, $action)) {
|
||||||
$this->response->redirect('?controller=user&action=forbidden');
|
$this->response->redirect('?controller=user&action=forbidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attach events for automatic actions
|
||||||
|
$this->action->attachEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkProjectPermissions($project_id)
|
public function checkProjectPermissions($project_id)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Controller;
|
namespace Controller;
|
||||||
|
|
||||||
|
require_once __DIR__.'/Base.php';
|
||||||
|
|
||||||
class Board extends Base
|
class Board extends Base
|
||||||
{
|
{
|
||||||
// Change a task assignee directly from the board
|
// Change a task assignee directly from the board
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Controller;
|
namespace Controller;
|
||||||
|
|
||||||
|
require_once __DIR__.'/Base.php';
|
||||||
|
|
||||||
class Config extends Base
|
class Config extends Base
|
||||||
{
|
{
|
||||||
// Settings page
|
// Settings page
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Controller;
|
namespace Controller;
|
||||||
|
|
||||||
|
require_once __DIR__.'/Base.php';
|
||||||
|
|
||||||
class Project extends Base
|
class Project extends Base
|
||||||
{
|
{
|
||||||
// Display access forbidden page
|
// Display access forbidden page
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Controller;
|
namespace Controller;
|
||||||
|
|
||||||
|
require_once __DIR__.'/Base.php';
|
||||||
|
|
||||||
class Task extends Base
|
class Task extends Base
|
||||||
{
|
{
|
||||||
// Webhook to create a task (useful for external software)
|
// Webhook to create a task (useful for external software)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Controller;
|
namespace Controller;
|
||||||
|
|
||||||
|
require_once __DIR__.'/Base.php';
|
||||||
|
|
||||||
class User extends Base
|
class User extends Base
|
||||||
{
|
{
|
||||||
// Display access forbidden page
|
// Display access forbidden page
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Deny from all
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event listener interface
|
||||||
|
*
|
||||||
|
* @package core
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
interface Listener {
|
||||||
|
public function execute(array $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event dispatcher class
|
||||||
|
*
|
||||||
|
* @package core
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class Event
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Contains all listeners
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $listeners = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last triggered event
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $lastEvent = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered events list
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $events = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach a listener object to an event
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $eventName Event name
|
||||||
|
* @param Listener $listener Object that implements the Listener interface
|
||||||
|
*/
|
||||||
|
public function attach($eventName, Listener $listener)
|
||||||
|
{
|
||||||
|
if (! isset($this->listeners[$eventName])) {
|
||||||
|
$this->listeners[$eventName] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->listeners[$eventName][] = $listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger an event
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $eventName Event name
|
||||||
|
* @param array $data Event data
|
||||||
|
*/
|
||||||
|
public function trigger($eventName, array $data)
|
||||||
|
{
|
||||||
|
$this->lastEvent = $eventName;
|
||||||
|
$this->events[] = $eventName;
|
||||||
|
|
||||||
|
if (isset($this->listeners[$eventName])) {
|
||||||
|
foreach ($this->listeners[$eventName] as $listener) {
|
||||||
|
$listener->execute($data); // TODO: keep an history of executed actions for unit test
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the last fired event
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return string Event name
|
||||||
|
*/
|
||||||
|
public function getLastTriggeredEvent()
|
||||||
|
{
|
||||||
|
return $this->lastEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of triggered events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTriggeredEvents()
|
||||||
|
{
|
||||||
|
return $this->events;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a listener bind to an event
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $eventName Event name
|
||||||
|
* @param mixed $instance Instance name or object itself
|
||||||
|
* @return bool Yes or no
|
||||||
|
*/
|
||||||
|
public function hasListener($eventName, $instance)
|
||||||
|
{
|
||||||
|
if (isset($this->listeners[$eventName])) {
|
||||||
|
foreach ($this->listeners[$eventName] as $listener) {
|
||||||
|
if ($listener instanceof $instance) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -89,6 +89,11 @@ function summary($value, $min_length = 5, $max_length = 120, $end = '[...]')
|
||||||
return $value;
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function contains($haystack, $needle)
|
||||||
|
{
|
||||||
|
return strpos($haystack, $needle) !== false;
|
||||||
|
}
|
||||||
|
|
||||||
function in_list($id, array $listing)
|
function in_list($id, array $listing)
|
||||||
{
|
{
|
||||||
if (isset($listing[$id])) {
|
if (isset($listing[$id])) {
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The registry class is a dependency injection container
|
||||||
|
*
|
||||||
|
* @package core
|
||||||
|
* @author Frederic Guillot
|
||||||
|
*/
|
||||||
|
class Registry
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Contains all dependencies
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $container = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains all instances
|
||||||
|
*
|
||||||
|
* @access private
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $instances = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a dependency
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $name Unique identifier for the service/parameter
|
||||||
|
* @param mixed $value The value of the parameter or a closure to define an object
|
||||||
|
*/
|
||||||
|
public function __set($name, $value)
|
||||||
|
{
|
||||||
|
$this->container[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a dependency
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $name Unique identifier for the service/parameter
|
||||||
|
* @return mixed The value of the parameter or an object
|
||||||
|
* @throws RuntimeException If the identifier is not found
|
||||||
|
*/
|
||||||
|
public function __get($name)
|
||||||
|
{
|
||||||
|
if (isset($this->container[$name])) {
|
||||||
|
|
||||||
|
if (is_callable($this->container[$name])) {
|
||||||
|
return $this->container[$name]();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $this->container[$name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \RuntimeException('Identifier not found in the registry: '.$name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a shared instance of a dependency
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $name Unique identifier for the service/parameter
|
||||||
|
* @return mixed Same object instance of the dependency
|
||||||
|
*/
|
||||||
|
public function shared($name)
|
||||||
|
{
|
||||||
|
if (! isset($this->instances[$name])) {
|
||||||
|
$this->instances[$name] = $this->$name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->instances[$name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace Core;
|
||||||
|
|
||||||
class Request
|
class Request
|
||||||
{
|
{
|
||||||
public function getStringParam($name, $default_value = '')
|
public function getStringParam($name, $default_value = '')
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace Core;
|
||||||
|
|
||||||
class Response
|
class Response
|
||||||
{
|
{
|
||||||
public function forceDownload($filename)
|
public function forceDownload($filename)
|
||||||
|
|
@ -1,12 +1,21 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace Core;
|
||||||
|
|
||||||
|
require __DIR__.'/request.php';
|
||||||
|
require __DIR__.'/response.php';
|
||||||
|
require __DIR__.'/session.php';
|
||||||
|
require __DIR__.'/template.php';
|
||||||
|
|
||||||
class Router
|
class Router
|
||||||
{
|
{
|
||||||
private $controller = '';
|
private $controller = '';
|
||||||
private $action = '';
|
private $action = '';
|
||||||
|
private $registry;
|
||||||
|
|
||||||
public function __construct($controller = '', $action = '')
|
public function __construct(Registry $registry, $controller = '', $action = '')
|
||||||
{
|
{
|
||||||
|
$this->registry = $registry;
|
||||||
$this->controller = empty($_GET['controller']) ? $controller : $_GET['controller'];
|
$this->controller = empty($_GET['controller']) ? $controller : $_GET['controller'];
|
||||||
$this->action = empty($_GET['action']) ? $controller : $_GET['action'];
|
$this->action = empty($_GET['action']) ? $controller : $_GET['action'];
|
||||||
}
|
}
|
||||||
|
|
@ -16,7 +25,7 @@ class Router
|
||||||
return ! ctype_alpha($value) || empty($value) ? $default_value : strtolower($value);
|
return ! ctype_alpha($value) || empty($value) ? $default_value : strtolower($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadController($filename, $class, $method)
|
public function load($filename, $class, $method)
|
||||||
{
|
{
|
||||||
if (file_exists($filename)) {
|
if (file_exists($filename)) {
|
||||||
|
|
||||||
|
|
@ -24,7 +33,11 @@ class Router
|
||||||
|
|
||||||
if (! method_exists($class, $method)) return false;
|
if (! method_exists($class, $method)) return false;
|
||||||
|
|
||||||
$instance = new $class;
|
$instance = new $class($this->registry);
|
||||||
|
$instance->request = new Request;
|
||||||
|
$instance->response = new Response;
|
||||||
|
$instance->session = new Session;
|
||||||
|
$instance->template = new Template;
|
||||||
$instance->beforeAction($this->controller, $this->action);
|
$instance->beforeAction($this->controller, $this->action);
|
||||||
$instance->$method();
|
$instance->$method();
|
||||||
|
|
||||||
|
|
@ -39,7 +52,7 @@ class Router
|
||||||
$this->controller = $this->sanitize($this->controller, 'app');
|
$this->controller = $this->sanitize($this->controller, 'app');
|
||||||
$this->action = $this->sanitize($this->action, 'index');
|
$this->action = $this->sanitize($this->action, 'index');
|
||||||
|
|
||||||
if (! $this->loadController('controllers/'.$this->controller.'.php', '\Controller\\'.$this->controller, $this->action)) {
|
if (! $this->load('controllers/'.$this->controller.'.php', '\Controller\\'.$this->controller, $this->action)) {
|
||||||
die('Page not found!');
|
die('Page not found!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace Core;
|
||||||
|
|
||||||
class Session
|
class Session
|
||||||
{
|
{
|
||||||
const SESSION_LIFETIME = 2678400; // 31 days
|
const SESSION_LIFETIME = 2678400; // 31 days
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace Core;
|
||||||
|
|
||||||
class Template
|
class Template
|
||||||
{
|
{
|
||||||
const PATH = 'templates/';
|
const PATH = 'templates/';
|
||||||
17
index.php
17
index.php
|
|
@ -1,19 +1,8 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require __DIR__.'/check_setup.php';
|
require __DIR__.'/check_setup.php';
|
||||||
require __DIR__.'/controllers/base.php';
|
require __DIR__.'/common.php';
|
||||||
require __DIR__.'/lib/router.php';
|
require __DIR__.'/core/router.php';
|
||||||
|
|
||||||
if (file_exists('config.php')) require 'config.php';
|
$router = new Core\Router($registry);
|
||||||
|
|
||||||
// Auto-refresh frequency in seconds for the public board view
|
|
||||||
defined('AUTO_REFRESH_DURATION') or define('AUTO_REFRESH_DURATION', 60);
|
|
||||||
|
|
||||||
// Custom session save path
|
|
||||||
defined('SESSION_SAVE_PATH') or define('SESSION_SAVE_PATH', '');
|
|
||||||
|
|
||||||
// Database filename
|
|
||||||
defined('DB_FILENAME') or define('DB_FILENAME', 'data/db.sqlite');
|
|
||||||
|
|
||||||
$router = new Router;
|
|
||||||
$router->execute();
|
$router->execute();
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ return array(
|
||||||
'Edit a task' => 'Modifier une tâche',
|
'Edit a task' => 'Modifier une tâche',
|
||||||
'Column' => 'Colonne',
|
'Column' => 'Colonne',
|
||||||
'Color' => 'Couleur',
|
'Color' => 'Couleur',
|
||||||
'Assignee' => 'Affectation',
|
'Assignee' => 'Personne assigné',
|
||||||
'Create another task' => 'Créer une autre tâche',
|
'Create another task' => 'Créer une autre tâche',
|
||||||
'New task' => 'Nouvelle tâche',
|
'New task' => 'Nouvelle tâche',
|
||||||
'Open a task' => 'Ouvrir une tâche',
|
'Open a task' => 'Ouvrir une tâche',
|
||||||
|
|
@ -218,4 +218,33 @@ return array(
|
||||||
'Invalid date' => 'Date invalide',
|
'Invalid date' => 'Date invalide',
|
||||||
'Must be done before %B %e, %G' => 'Doit être fait avant le %e %B %G',
|
'Must be done before %B %e, %G' => 'Doit être fait avant le %e %B %G',
|
||||||
'%B %e, %G' => '%e %B %G',
|
'%B %e, %G' => '%e %B %G',
|
||||||
|
'Automatic actions' => 'Actions automatisées',
|
||||||
|
'Your automatic action have been created successfully.' => 'Votre action automatisée a été ajouté avec succès.',
|
||||||
|
'Unable to create your automatic action.' => 'Impossible de créer votre action automatisée.',
|
||||||
|
'Remove an action' => 'Supprimer une action',
|
||||||
|
'Unable to remove this action.' => 'Impossible de supprimer cette action',
|
||||||
|
'Action removed successfully.' => 'Action supprimée avec succès.',
|
||||||
|
'Automatic actions for the project "%s"' => 'Actions automatisées pour le projet « %s »',
|
||||||
|
'Defined actions' => 'Actions définies',
|
||||||
|
'Event name' => 'Nom de l\'événement',
|
||||||
|
'Action name' => 'Nom de l\'action',
|
||||||
|
'Action parameters' => 'Paramètres de l\'action',
|
||||||
|
'Action' => 'Action',
|
||||||
|
'Event' => 'Événement',
|
||||||
|
'When the selected event occurs execute the corresponding action.' => 'Lorsque l\'événement sélectionné se déclenche, executer l\'action correspondante.',
|
||||||
|
'Next step' => 'Étape suivante',
|
||||||
|
'Define action parameters' => 'Définition des paramètres de l\'action',
|
||||||
|
'Save this action' => 'Sauvegarder cette action',
|
||||||
|
'Do you really want to remove this action: "%s"?' => 'Voulez-vous vraiment supprimer cette action « %s » ?',
|
||||||
|
'Remove an automatic action' => 'Supprimer une action automatisée',
|
||||||
|
'Close the task' => 'Fermer cette tâche',
|
||||||
|
'Assign the task to a specific user' => 'Assigner la tâche à un utilisateur spécifique',
|
||||||
|
'Assign the task to the person who does the action' => 'Assigner la tâche à la personne qui fait l\'action',
|
||||||
|
'Duplicate the task to another project' => 'Dupliquer la tâche vers un autre projet',
|
||||||
|
'Move a task to another column' => 'Déplacement d\'une tâche vers un autre colonne',
|
||||||
|
'Move a task to another position in the same column' => 'Déplacement d\'une tâche à une autre position mais dans la même colonne',
|
||||||
|
'Task modification' => 'Modification d\'une tâche',
|
||||||
|
'Task creation' => 'Création d\'une tâche',
|
||||||
|
'Open a closed task' => 'Ouverture d\'une tâche fermée',
|
||||||
|
'Closing a task' => 'Fermeture d\'une tâche',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -221,4 +221,33 @@ return array(
|
||||||
'Invalid date' => 'Błędna data',
|
'Invalid date' => 'Błędna data',
|
||||||
'Must be done before %B %e, %G' => 'Termin do %e %B %G',
|
'Must be done before %B %e, %G' => 'Termin do %e %B %G',
|
||||||
'%B %e, %G' => '%e %B %G',
|
'%B %e, %G' => '%e %B %G',
|
||||||
|
// 'Automatic actions' => '',
|
||||||
|
// 'Your automatic action have been created successfully.' => '',
|
||||||
|
// 'Unable to create your automatic action.' => '',
|
||||||
|
// 'Remove an action' => '',
|
||||||
|
// 'Unable to remove this action.' => '',
|
||||||
|
// 'Action removed successfully.' => '',
|
||||||
|
// 'Automatic actions for the project "%s"' => '',
|
||||||
|
// 'Defined actions' => '',
|
||||||
|
// 'Event name' => '',
|
||||||
|
// 'Action name' => '',
|
||||||
|
// 'Action parameters' => '',
|
||||||
|
// 'Action' => '',
|
||||||
|
// 'Event' => '',
|
||||||
|
// 'When the selected event occurs execute the corresponding action.' => '',
|
||||||
|
// 'Next step' => '',
|
||||||
|
// 'Define action parameters' => '',
|
||||||
|
// 'Save this action' => '',
|
||||||
|
// 'Do you really want to remove this action: "%s"?' => '',
|
||||||
|
// 'Remove an automatic action' => '',
|
||||||
|
// 'Close the task' => '',
|
||||||
|
// 'Assign the task to a specific user' => '',
|
||||||
|
// 'Assign the task to the person who does the action' => '',
|
||||||
|
// 'Duplicate the task to another project' => '',
|
||||||
|
// 'Move a task to another column' => '',
|
||||||
|
// 'Move a task to another position in the same column' => '',
|
||||||
|
// 'Task modification' => '',
|
||||||
|
// 'Task creation' => '',
|
||||||
|
// 'Open a closed task' => '',
|
||||||
|
// 'Closing a task' => '',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
|
||||||
class Acl extends Base
|
class Acl extends Base
|
||||||
{
|
{
|
||||||
// Controllers and actions allowed from outside
|
// Controllers and actions allowed from outside
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,247 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
require_once __DIR__.'/task.php';
|
||||||
|
|
||||||
|
use \SimpleValidator\Validator;
|
||||||
|
use \SimpleValidator\Validators;
|
||||||
|
|
||||||
|
class Action extends Base
|
||||||
|
{
|
||||||
|
const TABLE = 'actions';
|
||||||
|
const TABLE_PARAMS = 'action_has_params';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name and description of available actions
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAvailableActions()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
'TaskClose' => t('Close the 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'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name and description of available actions
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAvailableEvents()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
Task::EVENT_MOVE_COLUMN => t('Move a task to another column'),
|
||||||
|
Task::EVENT_MOVE_POSITION => t('Move a task to another position in the same column'),
|
||||||
|
Task::EVENT_UPDATE => t('Task modification'),
|
||||||
|
Task::EVENT_CREATE => t('Task creation'),
|
||||||
|
Task::EVENT_OPEN => t('Open a closed task'),
|
||||||
|
Task::EVENT_CLOSE => t('Closing a task'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return actions and parameters for a given project
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllByProject($project_id)
|
||||||
|
{
|
||||||
|
$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();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all actions and parameters
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAll()
|
||||||
|
{
|
||||||
|
$actions = $this->db->table(self::TABLE)->findAll();
|
||||||
|
|
||||||
|
foreach ($actions as &$action) {
|
||||||
|
$action['params'] = $this->db->table(self::TABLE_PARAMS)->eq('action_id', $action['id'])->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
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']);
|
||||||
|
$params += $action->getActionRequiredParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $params;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch an action
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $action_id Action id
|
||||||
|
* @return array Action data
|
||||||
|
*/
|
||||||
|
public function getById($action_id)
|
||||||
|
{
|
||||||
|
$action = $this->db->table(self::TABLE)->eq('id', $action_id)->findOne();
|
||||||
|
$action['params'] = $this->db->table(self::TABLE_PARAMS)->eq('action_id', $action_id)->findAll();
|
||||||
|
|
||||||
|
return $action;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an action
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param integer $action_id Action id
|
||||||
|
* @return bool Success or not
|
||||||
|
*/
|
||||||
|
public function remove($action_id)
|
||||||
|
{
|
||||||
|
return $this->db->table(self::TABLE)->eq('id', $action_id)->remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an action
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Required parameters to save an action
|
||||||
|
* @return bool Success or not
|
||||||
|
*/
|
||||||
|
public function create(array $values)
|
||||||
|
{
|
||||||
|
$this->db->startTransaction();
|
||||||
|
|
||||||
|
$action = array(
|
||||||
|
'project_id' => $values['project_id'],
|
||||||
|
'event_name' => $values['event_name'],
|
||||||
|
'action_name' => $values['action_name'],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (! $this->db->table(self::TABLE)->save($action)) {
|
||||||
|
$this->db->cancelTransaction();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$action_id = $this->db->getConnection()->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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->db->closeTransaction();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all actions and attach events
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function attachEvents()
|
||||||
|
{
|
||||||
|
foreach ($this->getAll() as $action) {
|
||||||
|
|
||||||
|
$listener = $this->load($action['action_name'], $action['project_id']);
|
||||||
|
|
||||||
|
foreach ($action['params'] as $param) {
|
||||||
|
$listener->setParam($param['name'], $param['value']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->event->attach($action['event_name'], $listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an action
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param string $name Action class name
|
||||||
|
* @param integer $project_id Project id
|
||||||
|
* @return mixed Action Instance
|
||||||
|
* @throw LogicException
|
||||||
|
*/
|
||||||
|
public function load($name, $project_id)
|
||||||
|
{
|
||||||
|
switch ($name) {
|
||||||
|
case 'TaskClose':
|
||||||
|
require_once __DIR__.'/../actions/task_close.php';
|
||||||
|
$className = '\Action\TaskClose';
|
||||||
|
return new $className($project_id, new Task($this->db, $this->event));
|
||||||
|
case 'TaskAssignCurrentUser':
|
||||||
|
require_once __DIR__.'/../actions/task_assign_current_user.php';
|
||||||
|
$className = '\Action\TaskAssignCurrentUser';
|
||||||
|
return new $className($project_id, new Task($this->db, $this->event), new Acl($this->db, $this->event));
|
||||||
|
case 'TaskAssignSpecificUser':
|
||||||
|
require_once __DIR__.'/../actions/task_assign_specific_user.php';
|
||||||
|
$className = '\Action\TaskAssignSpecificUser';
|
||||||
|
return new $className($project_id, new Task($this->db, $this->event));
|
||||||
|
case 'TaskDuplicateAnotherProject':
|
||||||
|
require_once __DIR__.'/../actions/task_duplicate_another_project.php';
|
||||||
|
$className = '\Action\TaskDuplicateAnotherProject';
|
||||||
|
return new $className($project_id, new Task($this->db, $this->event));
|
||||||
|
default:
|
||||||
|
throw new \LogicException('Action not found: '.$name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate action creation
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
* @param array $values Required parameters to save an action
|
||||||
|
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
|
||||||
|
*/
|
||||||
|
public function validateCreation(array $values)
|
||||||
|
{
|
||||||
|
$v = new Validator($values, array(
|
||||||
|
new Validators\Required('project_id', t('The project id is required')),
|
||||||
|
new Validators\Integer('project_id', t('This value must be an integer')),
|
||||||
|
new Validators\Required('event_name', t('This value is required')),
|
||||||
|
new Validators\Required('action_name', t('This value is required')),
|
||||||
|
new Validators\Required('params', t('This value is required')),
|
||||||
|
));
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$v->execute(),
|
||||||
|
$v->getErrors()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,45 +13,22 @@ require __DIR__.'/../vendor/SimpleValidator/Validators/Equals.php';
|
||||||
require __DIR__.'/../vendor/SimpleValidator/Validators/AlphaNumeric.php';
|
require __DIR__.'/../vendor/SimpleValidator/Validators/AlphaNumeric.php';
|
||||||
require __DIR__.'/../vendor/SimpleValidator/Validators/GreaterThan.php';
|
require __DIR__.'/../vendor/SimpleValidator/Validators/GreaterThan.php';
|
||||||
require __DIR__.'/../vendor/SimpleValidator/Validators/Date.php';
|
require __DIR__.'/../vendor/SimpleValidator/Validators/Date.php';
|
||||||
require __DIR__.'/../vendor/PicoDb/Database.php';
|
|
||||||
require __DIR__.'/schema.php';
|
|
||||||
|
|
||||||
abstract class Base
|
abstract class Base
|
||||||
{
|
{
|
||||||
const APP_VERSION = 'master';
|
|
||||||
const DB_VERSION = 9;
|
|
||||||
|
|
||||||
private static $dbInstance = null;
|
|
||||||
protected $db;
|
protected $db;
|
||||||
|
protected $event;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct(\PicoDb\Database $db, \Core\Event $event)
|
||||||
{
|
{
|
||||||
if (self::$dbInstance === null) {
|
$this->db = $db;
|
||||||
self::$dbInstance = $this->getDatabaseInstance();
|
$this->event = $event;
|
||||||
}
|
|
||||||
|
|
||||||
$this->db = self::$dbInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDatabaseInstance()
|
|
||||||
{
|
|
||||||
$db = new \PicoDb\Database(array(
|
|
||||||
'driver' => 'sqlite',
|
|
||||||
'filename' => DB_FILENAME
|
|
||||||
));
|
|
||||||
|
|
||||||
if ($db->schema()->check(self::DB_VERSION)) {
|
|
||||||
return $db;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
die('Unable to migrate database schema!');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a random token from /dev/urandom or with uniqid()
|
// Generate a random token from /dev/urandom or with uniqid()
|
||||||
public static function generateToken()
|
public static function generateToken()
|
||||||
{
|
{
|
||||||
if (ini_get('open_basedir') === '' and strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
|
if (ini_get('open_basedir') === '' && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
|
||||||
$token = file_get_contents('/dev/urandom', false, null, 0, 30);
|
$token = file_get_contents('/dev/urandom', false, null, 0, 30);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -60,19 +37,4 @@ abstract class Base
|
||||||
|
|
||||||
return hash('crc32b', $token);
|
return hash('crc32b', $token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTimestampFromDate($value, $format)
|
|
||||||
{
|
|
||||||
$date = \DateTime::createFromFormat($format, $value);
|
|
||||||
|
|
||||||
if ($date !== false) {
|
|
||||||
$errors = \DateTime::getLastErrors();
|
|
||||||
if ($errors['error_count'] === 0 && $errors['warning_count'] === 0) {
|
|
||||||
$timestamp = $date->getTimestamp();
|
|
||||||
return $timestamp > 0 ? $timestamp : 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
require_once __DIR__.'/task.php';
|
||||||
|
|
||||||
use \SimpleValidator\Validator;
|
use \SimpleValidator\Validator;
|
||||||
use \SimpleValidator\Validators;
|
use \SimpleValidator\Validators;
|
||||||
|
|
||||||
|
|
@ -14,8 +17,8 @@ class Board extends Base
|
||||||
{
|
{
|
||||||
$this->db->startTransaction();
|
$this->db->startTransaction();
|
||||||
|
|
||||||
$taskModel = new \Model\Task;
|
|
||||||
$results = array();
|
$results = array();
|
||||||
|
$taskModel = new Task($this->db, $this->event);
|
||||||
|
|
||||||
foreach ($values as $value) {
|
foreach ($values as $value) {
|
||||||
$results[] = $taskModel->move(
|
$results[] = $taskModel->move(
|
||||||
|
|
@ -30,7 +33,7 @@ class Board extends Base
|
||||||
return ! in_array(false, $results, true);
|
return ! in_array(false, $results, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create board with default columns => must executed inside a transaction
|
// Create board with default columns => must be executed inside a transaction
|
||||||
public function create($project_id, array $columns)
|
public function create($project_id, array $columns)
|
||||||
{
|
{
|
||||||
$position = 0;
|
$position = 0;
|
||||||
|
|
@ -75,11 +78,10 @@ class Board extends Base
|
||||||
// Get columns and tasks for each column
|
// Get columns and tasks for each column
|
||||||
public function get($project_id)
|
public function get($project_id)
|
||||||
{
|
{
|
||||||
$taskModel = new \Model\Task;
|
|
||||||
|
|
||||||
$this->db->startTransaction();
|
$this->db->startTransaction();
|
||||||
|
|
||||||
$columns = $this->getColumns($project_id);
|
$columns = $this->getColumns($project_id);
|
||||||
|
$taskModel = new Task($this->db, $this->event);
|
||||||
|
|
||||||
foreach ($columns as &$column) {
|
foreach ($columns as &$column) {
|
||||||
$column['tasks'] = $taskModel->getAllByColumnId($project_id, $column['id'], array(1));
|
$column['tasks'] = $taskModel->getAllByColumnId($project_id, $column['id'], array(1));
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
|
||||||
use \SimpleValidator\Validator;
|
use \SimpleValidator\Validator;
|
||||||
use \SimpleValidator\Validators;
|
use \SimpleValidator\Validators;
|
||||||
|
|
||||||
|
|
@ -17,9 +19,9 @@ class Comment extends Base
|
||||||
self::TABLE.'.id',
|
self::TABLE.'.id',
|
||||||
self::TABLE.'.date',
|
self::TABLE.'.date',
|
||||||
self::TABLE.'.comment',
|
self::TABLE.'.comment',
|
||||||
\Model\User::TABLE.'.username'
|
User::TABLE.'.username'
|
||||||
)
|
)
|
||||||
->join(\Model\User::TABLE, 'id', 'user_id')
|
->join(User::TABLE, 'id', 'user_id')
|
||||||
->orderBy(self::TABLE.'.date', 'ASC')
|
->orderBy(self::TABLE.'.date', 'ASC')
|
||||||
->eq(self::TABLE.'.task_id', $task_id)
|
->eq(self::TABLE.'.task_id', $task_id)
|
||||||
->findAll();
|
->findAll();
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
|
||||||
use \SimpleValidator\Validator;
|
use \SimpleValidator\Validator;
|
||||||
use \SimpleValidator\Validators;
|
use \SimpleValidator\Validators;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,11 @@
|
||||||
|
|
||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
require_once __DIR__.'/acl.php';
|
||||||
|
require_once __DIR__.'/board.php';
|
||||||
|
require_once __DIR__.'/task.php';
|
||||||
|
|
||||||
use \SimpleValidator\Validator;
|
use \SimpleValidator\Validator;
|
||||||
use \SimpleValidator\Validators;
|
use \SimpleValidator\Validators;
|
||||||
|
|
||||||
|
|
@ -13,16 +18,20 @@ class Project extends Base
|
||||||
const INACTIVE = 0;
|
const INACTIVE = 0;
|
||||||
|
|
||||||
// Get a list of people that can by assigned for tasks
|
// Get a list of people that can by assigned for tasks
|
||||||
public function getUsersList($project_id)
|
public function getUsersList($project_id, $prepend = true)
|
||||||
{
|
{
|
||||||
$allowed_users = $this->getAllowedUsers($project_id);
|
$allowed_users = $this->getAllowedUsers($project_id);
|
||||||
|
$userModel = new User($this->db, $this->event);
|
||||||
|
|
||||||
if (empty($allowed_users)) {
|
if (empty($allowed_users)) {
|
||||||
$userModel = new User;
|
|
||||||
$allowed_users = $userModel->getList();
|
$allowed_users = $userModel->getList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return array(t('Unassigned')) + $allowed_users;
|
if ($prepend) {
|
||||||
|
return array(t('Unassigned')) + $allowed_users;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $allowed_users;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of allowed people for a project
|
// Get a list of allowed people for a project
|
||||||
|
|
@ -30,7 +39,7 @@ class Project extends Base
|
||||||
{
|
{
|
||||||
return $this->db
|
return $this->db
|
||||||
->table(self::TABLE_USERS)
|
->table(self::TABLE_USERS)
|
||||||
->join(\Model\User::TABLE, 'id', 'user_id')
|
->join(User::TABLE, 'id', 'user_id')
|
||||||
->eq('project_id', $project_id)
|
->eq('project_id', $project_id)
|
||||||
->asc('username')
|
->asc('username')
|
||||||
->listing('user_id', 'username');
|
->listing('user_id', 'username');
|
||||||
|
|
@ -44,7 +53,7 @@ class Project extends Base
|
||||||
'not_allowed' => array(),
|
'not_allowed' => array(),
|
||||||
);
|
);
|
||||||
|
|
||||||
$userModel = new User;
|
$userModel = new User($this->db, $this->event);
|
||||||
$all_users = $userModel->getList();
|
$all_users = $userModel->getList();
|
||||||
|
|
||||||
$users['allowed'] = $this->getAllowedUsers($project_id);
|
$users['allowed'] = $this->getAllowedUsers($project_id);
|
||||||
|
|
@ -90,7 +99,7 @@ class Project extends Base
|
||||||
|
|
||||||
// Check if user has admin rights
|
// Check if user has admin rights
|
||||||
$nb_users = $this->db
|
$nb_users = $this->db
|
||||||
->table(\Model\User::TABLE)
|
->table(User::TABLE)
|
||||||
->eq('id', $user_id)
|
->eq('id', $user_id)
|
||||||
->eq('is_admin', 1)
|
->eq('is_admin', 1)
|
||||||
->count();
|
->count();
|
||||||
|
|
@ -133,9 +142,9 @@ class Project extends Base
|
||||||
->asc('name')
|
->asc('name')
|
||||||
->findAll();
|
->findAll();
|
||||||
|
|
||||||
$taskModel = new \Model\Task;
|
$boardModel = new Board($this->db, $this->event);
|
||||||
$boardModel = new \Model\Board;
|
$taskModel = new Task($this->db, $this->event);
|
||||||
$aclModel = new \Model\Acl;
|
$aclModel = new Acl($this->db, $this->event);
|
||||||
|
|
||||||
foreach ($projects as $pkey => &$project) {
|
foreach ($projects as $pkey => &$project) {
|
||||||
|
|
||||||
|
|
@ -163,9 +172,13 @@ class Project extends Base
|
||||||
return $projects;
|
return $projects;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getList()
|
public function getList($prepend = true)
|
||||||
{
|
{
|
||||||
return array(t('None')) + $this->db->table(self::TABLE)->asc('name')->listing('id', 'name');
|
if ($prepend) {
|
||||||
|
return array(t('None')) + $this->db->table(self::TABLE)->asc('name')->listing('id', 'name');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->db->table(self::TABLE)->asc('name')->listing('id', 'name');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAllByStatus($status)
|
public function getAllByStatus($status)
|
||||||
|
|
@ -218,7 +231,7 @@ class Project extends Base
|
||||||
|
|
||||||
$project_id = $this->db->getConnection()->getLastId();
|
$project_id = $this->db->getConnection()->getLastId();
|
||||||
|
|
||||||
$boardModel = new \Model\Board;
|
$boardModel = new Board($this->db, $this->event);
|
||||||
$boardModel->create($project_id, array(
|
$boardModel->create($project_id, array(
|
||||||
t('Backlog'),
|
t('Backlog'),
|
||||||
t('Ready'),
|
t('Ready'),
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,29 @@
|
||||||
|
|
||||||
namespace Schema;
|
namespace Schema;
|
||||||
|
|
||||||
|
function version_10($pdo)
|
||||||
|
{
|
||||||
|
$pdo->exec(
|
||||||
|
'CREATE TABLE actions (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
project_id INTEGER,
|
||||||
|
event_name TEXT,
|
||||||
|
action_name TEXT,
|
||||||
|
FOREIGN KEY(project_id) REFERENCES projects(id) ON DELETE CASCADE
|
||||||
|
)'
|
||||||
|
);
|
||||||
|
|
||||||
|
$pdo->exec(
|
||||||
|
'CREATE TABLE action_has_params (
|
||||||
|
id INTEGER PRIMARY KEY,
|
||||||
|
action_id INTEGER,
|
||||||
|
name TEXT,
|
||||||
|
value TEXT,
|
||||||
|
FOREIGN KEY(action_id) REFERENCES actions(id) ON DELETE CASCADE
|
||||||
|
)'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function version_9($pdo)
|
function version_9($pdo)
|
||||||
{
|
{
|
||||||
$pdo->exec("ALTER TABLE tasks ADD COLUMN date_due INTEGER");
|
$pdo->exec("ALTER TABLE tasks ADD COLUMN date_due INTEGER");
|
||||||
|
|
|
||||||
175
models/task.php
175
models/task.php
|
|
@ -2,12 +2,21 @@
|
||||||
|
|
||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
require_once __DIR__.'/comment.php';
|
||||||
|
|
||||||
use \SimpleValidator\Validator;
|
use \SimpleValidator\Validator;
|
||||||
use \SimpleValidator\Validators;
|
use \SimpleValidator\Validators;
|
||||||
|
|
||||||
class Task extends Base
|
class Task extends Base
|
||||||
{
|
{
|
||||||
const TABLE = 'tasks';
|
const TABLE = 'tasks';
|
||||||
|
const EVENT_MOVE_COLUMN = 'task.move.column';
|
||||||
|
const EVENT_MOVE_POSITION = 'task.move.position';
|
||||||
|
const EVENT_UPDATE = 'task.update';
|
||||||
|
const EVENT_CREATE = 'task.create';
|
||||||
|
const EVENT_CLOSE = 'task.close';
|
||||||
|
const EVENT_OPEN = 'task.open';
|
||||||
|
|
||||||
public function getColors()
|
public function getColors()
|
||||||
{
|
{
|
||||||
|
|
@ -42,13 +51,13 @@ class Task extends Base
|
||||||
self::TABLE.'.position',
|
self::TABLE.'.position',
|
||||||
self::TABLE.'.is_active',
|
self::TABLE.'.is_active',
|
||||||
self::TABLE.'.score',
|
self::TABLE.'.score',
|
||||||
\Model\Project::TABLE.'.name AS project_name',
|
Project::TABLE.'.name AS project_name',
|
||||||
\Model\Board::TABLE.'.title AS column_title',
|
Board::TABLE.'.title AS column_title',
|
||||||
\Model\User::TABLE.'.username'
|
User::TABLE.'.username'
|
||||||
)
|
)
|
||||||
->join(\Model\Project::TABLE, 'id', 'project_id')
|
->join(Project::TABLE, 'id', 'project_id')
|
||||||
->join(\Model\Board::TABLE, 'id', 'column_id')
|
->join(Board::TABLE, 'id', 'column_id')
|
||||||
->join(\Model\User::TABLE, 'id', 'owner_id')
|
->join(User::TABLE, 'id', 'owner_id')
|
||||||
->eq(self::TABLE.'.id', $task_id)
|
->eq(self::TABLE.'.id', $task_id)
|
||||||
->findOne();
|
->findOne();
|
||||||
}
|
}
|
||||||
|
|
@ -75,11 +84,11 @@ class Task extends Base
|
||||||
self::TABLE.'.position',
|
self::TABLE.'.position',
|
||||||
self::TABLE.'.is_active',
|
self::TABLE.'.is_active',
|
||||||
self::TABLE.'.score',
|
self::TABLE.'.score',
|
||||||
\Model\Board::TABLE.'.title AS column_title',
|
Board::TABLE.'.title AS column_title',
|
||||||
\Model\User::TABLE.'.username'
|
User::TABLE.'.username'
|
||||||
)
|
)
|
||||||
->join(\Model\Board::TABLE, 'id', 'column_id')
|
->join(Board::TABLE, 'id', 'column_id')
|
||||||
->join(\Model\User::TABLE, 'id', 'owner_id')
|
->join(User::TABLE, 'id', 'owner_id')
|
||||||
->eq(self::TABLE.'.project_id', $project_id)
|
->eq(self::TABLE.'.project_id', $project_id)
|
||||||
->in('is_active', $status)
|
->in('is_active', $status)
|
||||||
->desc('date_completed')
|
->desc('date_completed')
|
||||||
|
|
@ -107,7 +116,7 @@ class Task extends Base
|
||||||
->asc('position')
|
->asc('position')
|
||||||
->findAll();
|
->findAll();
|
||||||
|
|
||||||
$commentModel = new Comment;
|
$commentModel = new Comment($this->db, $this->event);
|
||||||
|
|
||||||
foreach ($tasks as &$task) {
|
foreach ($tasks as &$task) {
|
||||||
$task['nb_comments'] = $commentModel->count($task['id']);
|
$task['nb_comments'] = $commentModel->count($task['id']);
|
||||||
|
|
@ -126,19 +135,60 @@ class Task extends Base
|
||||||
->count();
|
->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function duplicateToAnotherProject($task_id, $project_id)
|
||||||
|
{
|
||||||
|
$this->db->startTransaction();
|
||||||
|
|
||||||
|
$boardModel = new Board($this->db, $this->event);
|
||||||
|
|
||||||
|
// Get the original task
|
||||||
|
$task = $this->getById($task_id);
|
||||||
|
|
||||||
|
// Cleanup data
|
||||||
|
unset($task['id']);
|
||||||
|
unset($task['date_completed']);
|
||||||
|
|
||||||
|
// Assign new values
|
||||||
|
$task['date_creation'] = time();
|
||||||
|
$task['owner_id'] = 0;
|
||||||
|
$task['is_active'] = 1;
|
||||||
|
$task['column_id'] = $boardModel->getFirstColumn($project_id);
|
||||||
|
$task['project_id'] = $project_id;
|
||||||
|
$task['position'] = $this->countByColumnId($task['project_id'], $task['column_id']);
|
||||||
|
|
||||||
|
// Save task
|
||||||
|
if (! $this->db->table(self::TABLE)->save($task)) {
|
||||||
|
$this->db->cancelTransaction();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$task_id = $this->db->getConnection()->getLastId();
|
||||||
|
|
||||||
|
$this->db->closeTransaction();
|
||||||
|
|
||||||
|
// Trigger events
|
||||||
|
$this->event->trigger(self::EVENT_CREATE, array('task_id' => $task_id) + $task);
|
||||||
|
|
||||||
|
return $task_id;
|
||||||
|
}
|
||||||
|
|
||||||
public function create(array $values)
|
public function create(array $values)
|
||||||
{
|
{
|
||||||
$this->db->startTransaction();
|
$this->db->startTransaction();
|
||||||
|
|
||||||
unset($values['another_task']);
|
// Prepare data
|
||||||
|
if (isset($values['another_task'])) {
|
||||||
|
unset($values['another_task']);
|
||||||
|
}
|
||||||
|
|
||||||
if (! empty($values['date_due'])) {
|
if (! empty($values['date_due']) && ! is_numeric($values['date_due'])) {
|
||||||
$values['date_due'] = $this->getTimestampFromDate($values['date_due'], t('m/d/Y')) ?: null;
|
$values['date_due'] = $this->getTimestampFromDate($values['date_due'], t('m/d/Y')) ?: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$values['date_creation'] = time();
|
$values['date_creation'] = time();
|
||||||
$values['position'] = $this->countByColumnId($values['project_id'], $values['column_id']);
|
$values['position'] = $this->countByColumnId($values['project_id'], $values['column_id']);
|
||||||
|
|
||||||
|
// Save task
|
||||||
if (! $this->db->table(self::TABLE)->save($values)) {
|
if (! $this->db->table(self::TABLE)->save($values)) {
|
||||||
$this->db->cancelTransaction();
|
$this->db->cancelTransaction();
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -148,38 +198,83 @@ class Task extends Base
|
||||||
|
|
||||||
$this->db->closeTransaction();
|
$this->db->closeTransaction();
|
||||||
|
|
||||||
|
// Trigger events
|
||||||
|
$this->event->trigger(self::EVENT_CREATE, array('task_id' => $task_id) + $values);
|
||||||
|
|
||||||
return $task_id;
|
return $task_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(array $values)
|
public function update(array $values)
|
||||||
{
|
{
|
||||||
if (! empty($values['date_due'])) {
|
// Prepare data
|
||||||
|
if (! empty($values['date_due']) && ! is_numeric($values['date_due'])) {
|
||||||
$values['date_due'] = $this->getTimestampFromDate($values['date_due'], t('m/d/Y')) ?: null;
|
$values['date_due'] = $this->getTimestampFromDate($values['date_due'], t('m/d/Y')) ?: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values);
|
$original_task = $this->getById($values['id']);
|
||||||
|
$result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values);
|
||||||
|
|
||||||
|
// Trigger events
|
||||||
|
if ($result) {
|
||||||
|
|
||||||
|
$events = array();
|
||||||
|
|
||||||
|
if ($this->event->getLastTriggeredEvent() !== self::EVENT_UPDATE) {
|
||||||
|
$events[] = self::EVENT_UPDATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($values['column_id']) && $original_task['column_id'] != $values['column_id']) {
|
||||||
|
$events[] = self::EVENT_MOVE_COLUMN;
|
||||||
|
}
|
||||||
|
else if (isset($values['position']) && $original_task['position'] != $values['position']) {
|
||||||
|
$events[] = self::EVENT_MOVE_POSITION;
|
||||||
|
}
|
||||||
|
|
||||||
|
$event_data = array_merge($original_task, $values);
|
||||||
|
$event_data['task_id'] = $original_task['id'];
|
||||||
|
|
||||||
|
foreach ($events as $event) {
|
||||||
|
$this->event->trigger($event, $event_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark a task closed
|
// Mark a task closed
|
||||||
public function close($task_id)
|
public function close($task_id)
|
||||||
{
|
{
|
||||||
return $this->db->table(self::TABLE)
|
$result = $this->db
|
||||||
->eq('id', $task_id)
|
->table(self::TABLE)
|
||||||
->update(array(
|
->eq('id', $task_id)
|
||||||
'is_active' => 0,
|
->update(array(
|
||||||
'date_completed' => time()
|
'is_active' => 0,
|
||||||
));
|
'date_completed' => time()
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
$this->event->trigger(self::EVENT_CLOSE, array('task_id' => $task_id) + $this->getById($task_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark a task open
|
// Mark a task open
|
||||||
public function open($task_id)
|
public function open($task_id)
|
||||||
{
|
{
|
||||||
return $this->db->table(self::TABLE)
|
$result = $this->db
|
||||||
->eq('id', $task_id)
|
->table(self::TABLE)
|
||||||
->update(array(
|
->eq('id', $task_id)
|
||||||
'is_active' => 1,
|
->update(array(
|
||||||
'date_completed' => ''
|
'is_active' => 1,
|
||||||
));
|
'date_completed' => ''
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
$this->event->trigger(self::EVENT_OPEN, array('task_id' => $task_id) + $this->getById($task_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a task
|
// Remove a task
|
||||||
|
|
@ -191,10 +286,11 @@ class Task extends Base
|
||||||
// Move a task to another column or to another position
|
// Move a task to another column or to another position
|
||||||
public function move($task_id, $column_id, $position)
|
public function move($task_id, $column_id, $position)
|
||||||
{
|
{
|
||||||
return (bool) $this->db
|
return $this->update(array(
|
||||||
->table(self::TABLE)
|
'id' => $task_id,
|
||||||
->eq('id', $task_id)
|
'column_id' => $column_id,
|
||||||
->update(array('column_id' => $column_id, 'position' => $position));
|
'position' => $position,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validateCreation(array $values)
|
public function validateCreation(array $values)
|
||||||
|
|
@ -271,4 +367,19 @@ class Task extends Base
|
||||||
$v->getErrors()
|
$v->getErrors()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getTimestampFromDate($value, $format)
|
||||||
|
{
|
||||||
|
$date = \DateTime::createFromFormat($format, $value);
|
||||||
|
|
||||||
|
if ($date !== false) {
|
||||||
|
$errors = \DateTime::getLastErrors();
|
||||||
|
if ($errors['error_count'] === 0 && $errors['warning_count'] === 0) {
|
||||||
|
$timestamp = $date->getTimestamp();
|
||||||
|
return $timestamp > 0 ? $timestamp : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
namespace Model;
|
namespace Model;
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
|
||||||
use \SimpleValidator\Validator;
|
use \SimpleValidator\Validator;
|
||||||
use \SimpleValidator\Validators;
|
use \SimpleValidator\Validators;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
<section id="main">
|
||||||
|
<div class="page-header">
|
||||||
|
<h2><?= t('Automatic actions for the project "%s"', $project['name']) ?></h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="?controller=project"><?= t('All projects') ?></a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<section>
|
||||||
|
|
||||||
|
<?php if (! empty($actions)): ?>
|
||||||
|
|
||||||
|
<h3><?= t('Defined actions') ?></h3>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th><?= t('Event name') ?></th>
|
||||||
|
<th><?= t('Action name') ?></th>
|
||||||
|
<th><?= t('Action parameters') ?></th>
|
||||||
|
<th><?= t('Action') ?></th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<?php foreach ($actions as $action): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?= Helper\in_list($action['event_name'], $available_events) ?></td>
|
||||||
|
<td><?= Helper\in_list($action['action_name'], $available_actions) ?></td>
|
||||||
|
<td>
|
||||||
|
<ul>
|
||||||
|
<?php foreach ($action['params'] as $param): ?>
|
||||||
|
<li>
|
||||||
|
<?= Helper\in_list($param['name'], $available_params) ?> =
|
||||||
|
<strong>
|
||||||
|
<?php if (Helper\contains($param['name'], 'column_id')): ?>
|
||||||
|
<?= Helper\in_list($param['value'], $columns_list) ?>
|
||||||
|
<?php elseif (Helper\contains($param['name'], 'user_id')): ?>
|
||||||
|
<?= Helper\in_list($param['value'], $users_list) ?>
|
||||||
|
<?php elseif (Helper\contains($param['name'], 'project_id')): ?>
|
||||||
|
<?= Helper\in_list($param['value'], $projects_list) ?>
|
||||||
|
<?php endif ?>
|
||||||
|
</strong>
|
||||||
|
</li>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="?controller=action&action=confirm&action_id=<?= $action['id'] ?>"><?= t('Remove') ?></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach ?>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<h3><?= t('Add an action') ?></h3>
|
||||||
|
<form method="post" action="?controller=action&action=params&project_id=<?= $project['id'] ?>" autocomplete="off">
|
||||||
|
|
||||||
|
<?= Helper\form_hidden('project_id', $values) ?>
|
||||||
|
|
||||||
|
<?= Helper\form_label(t('Event'), 'event_name') ?>
|
||||||
|
<?= Helper\form_select('event_name', $available_events, $values) ?><br/>
|
||||||
|
|
||||||
|
<?= Helper\form_label(t('Action'), 'action_name') ?>
|
||||||
|
<?= Helper\form_select('action_name', $available_actions, $values) ?><br/>
|
||||||
|
|
||||||
|
<div class="form-help">
|
||||||
|
<?= t('When the selected event occurs execute the corresponding action.') ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<input type="submit" value="<?= t('Next step') ?>" class="btn btn-blue"/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
<section id="main">
|
||||||
|
<div class="page-header">
|
||||||
|
<h2><?= t('Automatic actions for the project "%s"', $project['name']) ?></h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="?controller=project"><?= t('All projects') ?></a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<section>
|
||||||
|
|
||||||
|
<h3><?= t('Define action parameters') ?></h3>
|
||||||
|
<form method="post" action="?controller=action&action=create&project_id=<?= $project['id'] ?>" autocomplete="off">
|
||||||
|
|
||||||
|
<?= Helper\form_hidden('project_id', $values) ?>
|
||||||
|
<?= Helper\form_hidden('event_name', $values) ?>
|
||||||
|
<?= Helper\form_hidden('action_name', $values) ?>
|
||||||
|
|
||||||
|
<?php foreach ($action_params as $param_name => $param_desc): ?>
|
||||||
|
|
||||||
|
<?php if (Helper\contains($param_name, 'column_id')): ?>
|
||||||
|
<?= Helper\form_label($param_desc, $param_name) ?>
|
||||||
|
<?= Helper\form_select('params['.$param_name.']', $columns_list, $values) ?><br/>
|
||||||
|
<?php elseif (Helper\contains($param_name, 'user_id')): ?>
|
||||||
|
<?= Helper\form_label($param_desc, $param_name) ?>
|
||||||
|
<?= Helper\form_select('params['.$param_name.']', $users_list, $values) ?><br/>
|
||||||
|
<?php elseif (Helper\contains($param_name, 'project_id')): ?>
|
||||||
|
<?= Helper\form_label($param_desc, $param_name) ?>
|
||||||
|
<?= Helper\form_select('params['.$param_name.']', $projects_list, $values) ?><br/>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<?php endforeach ?>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<input type="submit" value="<?= t('Save this action') ?>" class="btn btn-blue"/>
|
||||||
|
<?= t('or') ?> <a href="?controller=action&action=index&project_id=<?= $project['id'] ?>"><?= t('cancel') ?></a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<section id="main">
|
||||||
|
<div class="page-header">
|
||||||
|
<h2><?= t('Remove an automatic action') ?></h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="confirm">
|
||||||
|
<p class="alert alert-info">
|
||||||
|
<?= t('Do you really want to remove this action: "%s"?', Helper\in_list($action['event_name'], $available_events).'/'.Helper\in_list($action['action_name'], $available_actions)) ?>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="form-actions">
|
||||||
|
<a href="?controller=action&action=remove&action_id=<?= $action['id'] ?>" class="btn btn-red"><?= t('Yes') ?></a>
|
||||||
|
<?= t('or') ?> <a href="?controller=action&action=index&project_id=<?= $action['project_id'] ?>"><?= t('cancel') ?></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
@ -45,7 +45,7 @@
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<?= t('Application version:') ?>
|
<?= t('Application version:') ?>
|
||||||
<?= Model\Base::APP_VERSION ?>
|
<?= APP_VERSION ?>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,9 @@
|
||||||
<li>
|
<li>
|
||||||
<a href="?controller=board&action=edit&project_id=<?= $project['id'] ?>"><?= t('Edit board') ?></a>
|
<a href="?controller=board&action=edit&project_id=<?= $project['id'] ?>"><?= t('Edit board') ?></a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="?controller=action&action=index&project_id=<?= $project['id'] ?>"><?= t('Automatic actions') ?></a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<?php if ($project['is_active']): ?>
|
<?php if ($project['is_active']): ?>
|
||||||
<a href="?controller=project&action=disable&project_id=<?= $project['id'] ?>"><?= t('Disable') ?></a>
|
<a href="?controller=project&action=disable&project_id=<?= $project['id'] ?>"><?= t('Disable') ?></a>
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,18 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once __DIR__.'/../models/base.php';
|
require_once __DIR__.'/base.php';
|
||||||
require_once __DIR__.'/../models/acl.php';
|
|
||||||
|
|
||||||
use Model\Acl;
|
use Model\Acl;
|
||||||
|
|
||||||
class AclTest extends PHPUnit_Framework_TestCase
|
class AclTest extends Base
|
||||||
{
|
{
|
||||||
public function setUp()
|
|
||||||
{
|
|
||||||
defined('DB_FILENAME') or define('DB_FILENAME', ':memory:');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testAllowedAction()
|
public function testAllowedAction()
|
||||||
{
|
{
|
||||||
$acl_rules = array(
|
$acl_rules = array(
|
||||||
'controller1' => array('action1', 'action3'),
|
'controller1' => array('action1', 'action3'),
|
||||||
);
|
);
|
||||||
|
|
||||||
$acl = new Acl;
|
$acl = new Acl($this->db, $this->event);
|
||||||
$this->assertTrue($acl->isAllowedAction($acl_rules, 'controller1', 'action1'));
|
$this->assertTrue($acl->isAllowedAction($acl_rules, 'controller1', 'action1'));
|
||||||
$this->assertTrue($acl->isAllowedAction($acl_rules, 'controller1', 'action3'));
|
$this->assertTrue($acl->isAllowedAction($acl_rules, 'controller1', 'action3'));
|
||||||
$this->assertFalse($acl->isAllowedAction($acl_rules, 'controller1', 'action2'));
|
$this->assertFalse($acl->isAllowedAction($acl_rules, 'controller1', 'action2'));
|
||||||
|
|
@ -28,7 +22,7 @@ class AclTest extends PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testIsAdmin()
|
public function testIsAdmin()
|
||||||
{
|
{
|
||||||
$acl = new Acl;
|
$acl = new Acl($this->db, $this->event);
|
||||||
|
|
||||||
$_SESSION = array();
|
$_SESSION = array();
|
||||||
$this->assertFalse($acl->isAdminUser());
|
$this->assertFalse($acl->isAdminUser());
|
||||||
|
|
@ -51,7 +45,7 @@ class AclTest extends PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testIsUser()
|
public function testIsUser()
|
||||||
{
|
{
|
||||||
$acl = new Acl;
|
$acl = new Acl($this->db, $this->event);
|
||||||
|
|
||||||
$_SESSION = array();
|
$_SESSION = array();
|
||||||
$this->assertFalse($acl->isRegularUser());
|
$this->assertFalse($acl->isRegularUser());
|
||||||
|
|
@ -74,7 +68,7 @@ class AclTest extends PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testIsPageAllowed()
|
public function testIsPageAllowed()
|
||||||
{
|
{
|
||||||
$acl = new Acl;
|
$acl = new Acl($this->db, $this->event);
|
||||||
|
|
||||||
// Public access
|
// Public access
|
||||||
$_SESSION = array();
|
$_SESSION = array();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__.'/base.php';
|
||||||
|
|
||||||
|
use Model\Action;
|
||||||
|
use Model\Project;
|
||||||
|
use Model\Board;
|
||||||
|
use Model\Task;
|
||||||
|
|
||||||
|
class ActionTest extends Base
|
||||||
|
{/*
|
||||||
|
public function testFetchActions()
|
||||||
|
{
|
||||||
|
$action = new Action($this->db, $this->event);
|
||||||
|
$board = new Board($this->db, $this->event);
|
||||||
|
$project = new Project($this->db, $this->event);
|
||||||
|
|
||||||
|
$this->assertEquals(1, $project->create(array('name' => 'unit_test')));
|
||||||
|
|
||||||
|
// We should have nothing
|
||||||
|
$this->assertEmpty($action->getAll());
|
||||||
|
$this->assertEmpty($action->getAllByProject(1));
|
||||||
|
|
||||||
|
// We create a new action
|
||||||
|
$this->assertTrue($action->create(array(
|
||||||
|
'project_id' => 1,
|
||||||
|
'event_name' => Task::EVENT_MOVE_COLUMN,
|
||||||
|
'action_name' => 'TaskClose',
|
||||||
|
'params' => array(
|
||||||
|
'column_id' => 4,
|
||||||
|
)
|
||||||
|
)));
|
||||||
|
|
||||||
|
// We should have our action
|
||||||
|
$this->assertNotEmpty($action->getAll());
|
||||||
|
$this->assertEquals($action->getAll(), $action->getAllByProject(1));
|
||||||
|
|
||||||
|
$actions = $action->getAll();
|
||||||
|
|
||||||
|
$this->assertEquals(1, count($actions));
|
||||||
|
$this->assertEquals(1, $actions[0]['project_id']);
|
||||||
|
$this->assertEquals(Task::EVENT_MOVE_COLUMN, $actions[0]['event_name']);
|
||||||
|
$this->assertEquals('TaskClose', $actions[0]['action_name']);
|
||||||
|
$this->assertEquals('column_id', $actions[0]['params'][0]['name']);
|
||||||
|
$this->assertEquals(4, $actions[0]['params'][0]['value']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExecuteAction()
|
||||||
|
{
|
||||||
|
$task = new Task($this->db, $this->event);
|
||||||
|
$board = new Board($this->db, $this->event);
|
||||||
|
$project = new Project($this->db, $this->event);
|
||||||
|
$action = new Action($this->db, $this->event);
|
||||||
|
|
||||||
|
// We create a project
|
||||||
|
$this->assertEquals(1, $project->create(array('name' => 'unit_test')));
|
||||||
|
|
||||||
|
// We create a task
|
||||||
|
$this->assertEquals(1, $task->create(array(
|
||||||
|
'title' => 'unit_test',
|
||||||
|
'project_id' => 1,
|
||||||
|
'owner_id' => 1,
|
||||||
|
'color_id' => 'red',
|
||||||
|
'column_id' => 1,
|
||||||
|
)));
|
||||||
|
|
||||||
|
// We create a new action
|
||||||
|
$this->assertTrue($action->create(array(
|
||||||
|
'project_id' => 1,
|
||||||
|
'event_name' => Task::EVENT_MOVE_COLUMN,
|
||||||
|
'action_name' => 'TaskClose',
|
||||||
|
'params' => array(
|
||||||
|
'column_id' => 4,
|
||||||
|
)
|
||||||
|
)));
|
||||||
|
|
||||||
|
// We bind events
|
||||||
|
$action->attachEvents();
|
||||||
|
|
||||||
|
// Our task should be open
|
||||||
|
$t1 = $task->getById(1);
|
||||||
|
$this->assertEquals(1, $t1['is_active']);
|
||||||
|
$this->assertEquals(1, $t1['column_id']);
|
||||||
|
|
||||||
|
// We move our task
|
||||||
|
$task->move(1, 4, 1);
|
||||||
|
|
||||||
|
// Our task should be closed
|
||||||
|
$t1 = $task->getById(1);
|
||||||
|
$this->assertEquals(4, $t1['column_id']);
|
||||||
|
$this->assertEquals(0, $t1['is_active']);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public function testExecuteMultipleActions()
|
||||||
|
{
|
||||||
|
$task = new Task($this->db, $this->event);
|
||||||
|
$board = new Board($this->db, $this->event);
|
||||||
|
$project = new Project($this->db, $this->event);
|
||||||
|
$action = new Action($this->db, $this->event);
|
||||||
|
|
||||||
|
// We create 2 projects
|
||||||
|
$this->assertEquals(1, $project->create(array('name' => 'unit_test1')));
|
||||||
|
$this->assertEquals(2, $project->create(array('name' => 'unit_test2')));
|
||||||
|
|
||||||
|
// We create a task
|
||||||
|
$this->assertEquals(1, $task->create(array(
|
||||||
|
'title' => 'unit_test',
|
||||||
|
'project_id' => 1,
|
||||||
|
'owner_id' => 1,
|
||||||
|
'color_id' => 'red',
|
||||||
|
'column_id' => 1,
|
||||||
|
)));
|
||||||
|
|
||||||
|
// We create 2 actions
|
||||||
|
$this->assertTrue($action->create(array(
|
||||||
|
'project_id' => 1,
|
||||||
|
'event_name' => Task::EVENT_CLOSE,
|
||||||
|
'action_name' => 'TaskDuplicateAnotherProject',
|
||||||
|
'params' => array(
|
||||||
|
'column_id' => 4,
|
||||||
|
'project_id' => 2,
|
||||||
|
)
|
||||||
|
)));
|
||||||
|
|
||||||
|
$this->assertTrue($action->create(array(
|
||||||
|
'project_id' => 1,
|
||||||
|
'event_name' => Task::EVENT_MOVE_COLUMN,
|
||||||
|
'action_name' => 'TaskClose',
|
||||||
|
'params' => array(
|
||||||
|
'column_id' => 4,
|
||||||
|
)
|
||||||
|
)));
|
||||||
|
|
||||||
|
// We bind events
|
||||||
|
$action->attachEvents();
|
||||||
|
|
||||||
|
// Events should be attached
|
||||||
|
$this->assertTrue($this->event->hasListener(Task::EVENT_CLOSE, 'Action\TaskDuplicateAnotherProject'));
|
||||||
|
$this->assertTrue($this->event->hasListener(Task::EVENT_MOVE_COLUMN, 'Action\TaskClose'));
|
||||||
|
|
||||||
|
// Our task should be open, linked to the first project and in the first column
|
||||||
|
$t1 = $task->getById(1);
|
||||||
|
$this->assertEquals(1, $t1['is_active']);
|
||||||
|
$this->assertEquals(1, $t1['column_id']);
|
||||||
|
$this->assertEquals(1, $t1['project_id']);
|
||||||
|
|
||||||
|
// We move our task
|
||||||
|
$task->move(1, 4, 1);
|
||||||
|
$this->assertEquals(Task::EVENT_CREATE, $this->event->getLastTriggeredEvent());
|
||||||
|
|
||||||
|
// Our task should be closed
|
||||||
|
$t1 = $task->getById(1);
|
||||||
|
$this->assertEquals(4, $t1['column_id']);
|
||||||
|
$this->assertEquals(0, $t1['is_active']);
|
||||||
|
|
||||||
|
// Our task should be duplicated to the 2nd project
|
||||||
|
$t2 = $task->getById(2);
|
||||||
|
$this->assertNotEmpty($t2);
|
||||||
|
$this->assertNotEquals(4, $t2['column_id']);
|
||||||
|
$this->assertEquals(1, $t2['is_active']);
|
||||||
|
$this->assertEquals(2, $t2['project_id']);
|
||||||
|
$this->assertEquals('unit_test', $t2['title']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__.'/../vendor/PicoDb/Database.php';
|
||||||
|
require_once __DIR__.'/../core/event.php';
|
||||||
|
require_once __DIR__.'/../core/translator.php';
|
||||||
|
require_once __DIR__.'/../models/schema.php';
|
||||||
|
require_once __DIR__.'/../models/task.php';
|
||||||
|
require_once __DIR__.'/../models/acl.php';
|
||||||
|
require_once __DIR__.'/../models/comment.php';
|
||||||
|
require_once __DIR__.'/../models/project.php';
|
||||||
|
require_once __DIR__.'/../models/user.php';
|
||||||
|
require_once __DIR__.'/../models/board.php';
|
||||||
|
require_once __DIR__.'/../models/action.php';
|
||||||
|
|
||||||
|
abstract class Base extends PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$this->db = $this->getDbConnection();
|
||||||
|
$this->event = new \Core\Event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDbConnection()
|
||||||
|
{
|
||||||
|
$db = new \PicoDb\Database(array(
|
||||||
|
'driver' => 'sqlite',
|
||||||
|
'filename' => ':memory:'
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($db->schema()->check(10)) {
|
||||||
|
return $db;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
die('Unable to migrate database schema!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,24 +1,19 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once __DIR__.'/../lib/translator.php';
|
require_once __DIR__.'/base.php';
|
||||||
require_once __DIR__.'/../models/base.php';
|
|
||||||
require_once __DIR__.'/../models/board.php';
|
|
||||||
require_once __DIR__.'/../models/user.php';
|
|
||||||
require_once __DIR__.'/../models/project.php';
|
|
||||||
|
|
||||||
use Model\Project;
|
use Model\Project;
|
||||||
use Model\User;
|
use Model\User;
|
||||||
|
use Model\Task;
|
||||||
|
use Model\Acl;
|
||||||
|
use Model\Board;
|
||||||
|
|
||||||
class ProjectTest extends PHPUnit_Framework_TestCase
|
class ProjectTest extends Base
|
||||||
{
|
{
|
||||||
public function setUp()
|
|
||||||
{
|
|
||||||
defined('DB_FILENAME') or define('DB_FILENAME', ':memory:');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCreation()
|
public function testCreation()
|
||||||
{
|
{
|
||||||
$p = new Project;
|
$p = new Project($this->db, $this->event);
|
||||||
|
|
||||||
$this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
|
$this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
|
||||||
$this->assertNotEmpty($p->getById(1));
|
$this->assertNotEmpty($p->getById(1));
|
||||||
}
|
}
|
||||||
|
|
@ -26,10 +21,10 @@ class ProjectTest extends PHPUnit_Framework_TestCase
|
||||||
public function testAllowEverybody()
|
public function testAllowEverybody()
|
||||||
{
|
{
|
||||||
// We create a regular user
|
// We create a regular user
|
||||||
$user = new User;
|
$user = new User($this->db, $this->event);
|
||||||
$user->create(array('username' => 'unittest', 'password' => 'unittest'));
|
$user->create(array('username' => 'unittest', 'password' => 'unittest'));
|
||||||
|
|
||||||
$p = new Project;
|
$p = new Project($this->db, $this->event);
|
||||||
$this->assertEmpty($p->getAllowedUsers(1)); // Nobody is specified for the given project
|
$this->assertEmpty($p->getAllowedUsers(1)); // Nobody is specified for the given project
|
||||||
$this->assertTrue($p->isUserAllowed(1, 1)); // Everybody should be allowed
|
$this->assertTrue($p->isUserAllowed(1, 1)); // Everybody should be allowed
|
||||||
$this->assertTrue($p->isUserAllowed(1, 2)); // Everybody should be allowed
|
$this->assertTrue($p->isUserAllowed(1, 2)); // Everybody should be allowed
|
||||||
|
|
@ -37,7 +32,12 @@ class ProjectTest extends PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testAllowUser()
|
public function testAllowUser()
|
||||||
{
|
{
|
||||||
$p = new Project;
|
$p = new Project($this->db, $this->event);
|
||||||
|
$user = new User($this->db, $this->event);
|
||||||
|
$user->create(array('username' => 'unittest', 'password' => 'unittest'));
|
||||||
|
|
||||||
|
// We create a project
|
||||||
|
$this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
|
||||||
|
|
||||||
// We allow the admin user
|
// We allow the admin user
|
||||||
$this->assertTrue($p->allowUser(1, 1));
|
$this->assertTrue($p->allowUser(1, 1));
|
||||||
|
|
@ -58,7 +58,13 @@ class ProjectTest extends PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testRevokeUser()
|
public function testRevokeUser()
|
||||||
{
|
{
|
||||||
$p = new Project;
|
$p = new Project($this->db, $this->event);
|
||||||
|
|
||||||
|
$user = new User($this->db, $this->event);
|
||||||
|
$user->create(array('username' => 'unittest', 'password' => 'unittest'));
|
||||||
|
|
||||||
|
// We create a project
|
||||||
|
$this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
|
||||||
|
|
||||||
// We revoke our admin user
|
// We revoke our admin user
|
||||||
$this->assertTrue($p->revokeUser(1, 1));
|
$this->assertTrue($p->revokeUser(1, 1));
|
||||||
|
|
@ -107,7 +113,13 @@ class ProjectTest extends PHPUnit_Framework_TestCase
|
||||||
|
|
||||||
public function testUsersList()
|
public function testUsersList()
|
||||||
{
|
{
|
||||||
$p = new Project;
|
$p = new Project($this->db, $this->event);
|
||||||
|
|
||||||
|
$user = new User($this->db, $this->event);
|
||||||
|
$user->create(array('username' => 'unittest', 'password' => 'unittest'));
|
||||||
|
|
||||||
|
// We create project
|
||||||
|
$this->assertEquals(1, $p->create(array('name' => 'UnitTest')));
|
||||||
|
|
||||||
// No restriction, we should have everybody
|
// No restriction, we should have everybody
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,15 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once __DIR__.'/../models/base.php';
|
require_once __DIR__.'/base.php';
|
||||||
require_once __DIR__.'/../models/task.php';
|
|
||||||
|
|
||||||
use Model\Task;
|
use Model\Task;
|
||||||
|
use Model\Project;
|
||||||
|
|
||||||
class TaskTest extends PHPUnit_Framework_TestCase
|
class TaskTest extends Base
|
||||||
{
|
{
|
||||||
public function setUp()
|
|
||||||
{
|
|
||||||
defined('DB_FILENAME') or define('DB_FILENAME', ':memory:');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDateFormat()
|
public function testDateFormat()
|
||||||
{
|
{
|
||||||
$t = new Task;
|
$t = new Task($this->db, $this->event);
|
||||||
|
|
||||||
$this->assertEquals('2014-03-05', date('Y-m-d', $t->getTimestampFromDate('05/03/2014', 'd/m/Y')));
|
$this->assertEquals('2014-03-05', date('Y-m-d', $t->getTimestampFromDate('05/03/2014', 'd/m/Y')));
|
||||||
$this->assertEquals('2014-03-05', date('Y-m-d', $t->getTimestampFromDate('03/05/2014', 'm/d/Y')));
|
$this->assertEquals('2014-03-05', date('Y-m-d', $t->getTimestampFromDate('03/05/2014', 'm/d/Y')));
|
||||||
|
|
@ -24,4 +19,58 @@ class TaskTest extends PHPUnit_Framework_TestCase
|
||||||
$this->assertEquals(0, $t->getTimestampFromDate('5/3/14', 'd/m/Y'));
|
$this->assertEquals(0, $t->getTimestampFromDate('5/3/14', 'd/m/Y'));
|
||||||
$this->assertEquals(0, $t->getTimestampFromDate('5-3-2014', 'd/m/Y'));
|
$this->assertEquals(0, $t->getTimestampFromDate('5-3-2014', 'd/m/Y'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testDuplicateToAnotherProject()
|
||||||
|
{
|
||||||
|
$t = new Task($this->db, $this->event);
|
||||||
|
$p = new Project($this->db, $this->event);
|
||||||
|
|
||||||
|
// We create 2 projects
|
||||||
|
$this->assertEquals(1, $p->create(array('name' => 'test1')));
|
||||||
|
$this->assertEquals(2, $p->create(array('name' => 'test2')));
|
||||||
|
|
||||||
|
// We create a task
|
||||||
|
$this->assertEquals(1, $t->create(array('title' => 'test', 'project_id' => 1, 'column_id' => 1)));
|
||||||
|
|
||||||
|
// We duplicate our task to the 2nd project
|
||||||
|
$this->assertEquals(2, $t->duplicateToAnotherProject(1, 2));
|
||||||
|
$this->assertEquals(Task::EVENT_CREATE, $this->event->getLastTriggeredEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEvents()
|
||||||
|
{
|
||||||
|
$t = new Task($this->db, $this->event);
|
||||||
|
$p = new Project($this->db, $this->event);
|
||||||
|
|
||||||
|
// We create a project
|
||||||
|
$this->assertEquals(1, $p->create(array('name' => 'test')));
|
||||||
|
|
||||||
|
// We create task
|
||||||
|
$this->assertEquals(1, $t->create(array('title' => 'test', 'project_id' => 1, 'column_id' => 1)));
|
||||||
|
$this->assertEquals(Task::EVENT_CREATE, $this->event->getLastTriggeredEvent());
|
||||||
|
|
||||||
|
// We update a task
|
||||||
|
$this->assertTrue($t->update(array('title' => 'test2', 'id' => 1)));
|
||||||
|
$this->assertEquals(Task::EVENT_UPDATE, $this->event->getLastTriggeredEvent());
|
||||||
|
|
||||||
|
// We close our task
|
||||||
|
$this->assertTrue($t->close(1));
|
||||||
|
$this->assertEquals(Task::EVENT_CLOSE, $this->event->getLastTriggeredEvent());
|
||||||
|
|
||||||
|
// We open our task
|
||||||
|
$this->assertTrue($t->open(1));
|
||||||
|
$this->assertEquals(Task::EVENT_OPEN, $this->event->getLastTriggeredEvent());
|
||||||
|
|
||||||
|
// We change the column of our task
|
||||||
|
$this->assertTrue($t->move(1, 2, 1));
|
||||||
|
$this->assertEquals(Task::EVENT_MOVE_COLUMN, $this->event->getLastTriggeredEvent());
|
||||||
|
|
||||||
|
// We change the position of our task
|
||||||
|
$this->assertTrue($t->move(1, 2, 2));
|
||||||
|
$this->assertEquals(Task::EVENT_MOVE_POSITION, $this->event->getLastTriggeredEvent());
|
||||||
|
|
||||||
|
// We change the column and the position of our task
|
||||||
|
$this->assertTrue($t->move(1, 1, 3));
|
||||||
|
$this->assertEquals(Task::EVENT_MOVE_COLUMN, $this->event->getLastTriggeredEvent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue