Merge pull request #1 from fguillot/master

please merge
This commit is contained in:
Busfreak
2015-12-23 00:18:32 +01:00
33 changed files with 937 additions and 399 deletions

View File

@@ -3,12 +3,14 @@ Version 1.0.23 (unreleased)
New features: New features:
- Add report to compare working hours between open and closed tasks - Added report to compare working hours between open and closed tasks
- Added the possiblity to define custom routes from plugins
Bug fixes: Bug fixes:
- Fix wrong constant name that cause a PHP error in project management section - Fix wrong constant name that cause a PHP error in project management section
- Fix pagination in group members listing - Fix pagination in group members listing
- Avoid PHP error when enabling LDAP group provider with PHP < 5.5
Version 1.0.22 Version 1.0.22
-------------- --------------

View File

@@ -25,12 +25,13 @@ class Comment extends \Kanboard\Core\Base
return $this->comment->remove($comment_id); return $this->comment->remove($comment_id);
} }
public function createComment($task_id, $user_id, $content) public function createComment($task_id, $user_id, $content, $reference = '')
{ {
$values = array( $values = array(
'task_id' => $task_id, 'task_id' => $task_id,
'user_id' => $user_id, 'user_id' => $user_id,
'comment' => $content, 'comment' => $content,
'reference' => $reference,
); );
list($valid, ) = $this->comment->validateCreation($values); list($valid, ) = $this->comment->validateCreation($values);

View File

@@ -20,7 +20,7 @@ class Activity extends Base
$project = $this->getProject(); $project = $this->getProject();
$this->response->html($this->template->layout('activity/project', array( $this->response->html($this->template->layout('activity/project', array(
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'events' => $this->projectActivity->getProject($project['id']), 'events' => $this->projectActivity->getProject($project['id']),
'project' => $project, 'project' => $project,
'title' => t('%s\'s activity', $project['name']) 'title' => t('%s\'s activity', $project['name'])

View File

@@ -21,7 +21,7 @@ class Analytic extends Base
*/ */
private function layout($template, array $params) private function layout($template, array $params)
{ {
$params['board_selector'] = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); $params['board_selector'] = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
$params['content_for_sublayout'] = $this->template->render($template, $params); $params['content_for_sublayout'] = $this->template->render($template, $params);
return $this->template->layout('analytic/layout', $params); return $this->template->layout('analytic/layout', $params);

View File

@@ -22,7 +22,7 @@ class App extends Base
*/ */
private function layout($template, array $params) private function layout($template, array $params)
{ {
$params['board_selector'] = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); $params['board_selector'] = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
$params['content_for_sublayout'] = $this->template->render($template, $params); $params['content_for_sublayout'] = $this->template->render($template, $params);
return $this->template->layout('app/layout', $params); return $this->template->layout('app/layout', $params);

View File

@@ -190,7 +190,7 @@ abstract class Base extends \Kanboard\Core\Base
$content = $this->template->render($template, $params); $content = $this->template->render($template, $params);
$params['task_content_for_layout'] = $content; $params['task_content_for_layout'] = $content;
$params['title'] = $params['task']['project_name'].' &gt; '.$params['task']['title']; $params['title'] = $params['task']['project_name'].' &gt; '.$params['task']['title'];
$params['board_selector'] = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); $params['board_selector'] = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
return $this->template->layout('task/layout', $params); return $this->template->layout('task/layout', $params);
} }
@@ -208,7 +208,7 @@ abstract class Base extends \Kanboard\Core\Base
$content = $this->template->render($template, $params); $content = $this->template->render($template, $params);
$params['project_content_for_layout'] = $content; $params['project_content_for_layout'] = $content;
$params['title'] = $params['project']['name'] === $params['title'] ? $params['title'] : $params['project']['name'].' &gt; '.$params['title']; $params['title'] = $params['project']['name'] === $params['title'] ? $params['title'] : $params['project']['name'].' &gt; '.$params['title'];
$params['board_selector'] = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); $params['board_selector'] = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
$params['sidebar_template'] = $sidebar_template; $params['sidebar_template'] = $sidebar_template;
return $this->template->layout('project/layout', $params); return $this->template->layout('project/layout', $params);
@@ -289,7 +289,7 @@ abstract class Base extends \Kanboard\Core\Base
{ {
$project = $this->getProject(); $project = $this->getProject();
$search = $this->request->getStringParam('search', $this->userSession->getFilters($project['id'])); $search = $this->request->getStringParam('search', $this->userSession->getFilters($project['id']));
$board_selector = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); $board_selector = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
unset($board_selector[$project['id']]); unset($board_selector[$project['id']]);
$filters = array( $filters = array(

View File

@@ -20,7 +20,7 @@ class Config extends Base
*/ */
private function layout($template, array $params) private function layout($template, array $params)
{ {
$params['board_selector'] = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); $params['board_selector'] = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
$params['values'] = $this->config->getAll(); $params['values'] = $this->config->getAll();
$params['errors'] = array(); $params['errors'] = array();
$params['config_content_for_layout'] = $this->template->render($template, $params); $params['config_content_for_layout'] = $this->template->render($template, $params);

View File

@@ -20,7 +20,7 @@ class Currency extends Base
*/ */
private function layout($template, array $params) private function layout($template, array $params)
{ {
$params['board_selector'] = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); $params['board_selector'] = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
$params['config_content_for_layout'] = $this->template->render($template, $params); $params['config_content_for_layout'] = $this->template->render($template, $params);
return $this->template->layout('config/layout', $params); return $this->template->layout('config/layout', $params);

View File

@@ -53,7 +53,7 @@ class Doc extends Base
} }
$this->response->html($this->template->layout('doc/show', $this->readFile($filename) + array( $this->response->html($this->template->layout('doc/show', $this->readFile($filename) + array(
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
))); )));
} }
} }

View File

@@ -26,7 +26,7 @@ class Gantt extends Base
$this->response->html($this->template->layout('gantt/projects', array( $this->response->html($this->template->layout('gantt/projects', array(
'projects' => $this->projectGanttFormatter->filter($project_ids)->format(), 'projects' => $this->projectGanttFormatter->filter($project_ids)->format(),
'title' => t('Gantt chart for all projects'), 'title' => t('Gantt chart for all projects'),
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
))); )));
} }

View File

@@ -25,7 +25,7 @@ class Group extends Base
->calculate(); ->calculate();
$this->response->html($this->template->layout('group/index', array( $this->response->html($this->template->layout('group/index', array(
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'title' => t('Groups').' ('.$paginator->getTotal().')', 'title' => t('Groups').' ('.$paginator->getTotal().')',
'paginator' => $paginator, 'paginator' => $paginator,
))); )));
@@ -49,7 +49,7 @@ class Group extends Base
->calculate(); ->calculate();
$this->response->html($this->template->layout('group/users', array( $this->response->html($this->template->layout('group/users', array(
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'title' => t('Members of %s', $group['name']).' ('.$paginator->getTotal().')', 'title' => t('Members of %s', $group['name']).' ('.$paginator->getTotal().')',
'paginator' => $paginator, 'paginator' => $paginator,
'group' => $group, 'group' => $group,
@@ -64,7 +64,7 @@ class Group extends Base
public function create(array $values = array(), array $errors = array()) public function create(array $values = array(), array $errors = array())
{ {
$this->response->html($this->template->layout('group/create', array( $this->response->html($this->template->layout('group/create', array(
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'errors' => $errors, 'errors' => $errors,
'values' => $values, 'values' => $values,
'title' => t('New group') 'title' => t('New group')
@@ -105,7 +105,7 @@ class Group extends Base
} }
$this->response->html($this->template->layout('group/edit', array( $this->response->html($this->template->layout('group/edit', array(
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'errors' => $errors, 'errors' => $errors,
'values' => $values, 'values' => $values,
'title' => t('Edit group') 'title' => t('Edit group')
@@ -149,7 +149,7 @@ class Group extends Base
} }
$this->response->html($this->template->layout('group/associate', array( $this->response->html($this->template->layout('group/associate', array(
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'users' => $this->user->prepareList($this->groupMember->getNotMembers($group_id)), 'users' => $this->user->prepareList($this->groupMember->getNotMembers($group_id)),
'group' => $group, 'group' => $group,
'errors' => $errors, 'errors' => $errors,

View File

@@ -21,7 +21,7 @@ class Link extends Base
*/ */
private function layout($template, array $params) private function layout($template, array $params)
{ {
$params['board_selector'] = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); $params['board_selector'] = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
$params['config_content_for_layout'] = $this->template->render($template, $params); $params['config_content_for_layout'] = $this->template->render($template, $params);
return $this->template->layout('config/layout', $params); return $this->template->layout('config/layout', $params);

View File

@@ -33,7 +33,7 @@ class Project extends Base
->calculate(); ->calculate();
$this->response->html($this->template->layout('project/index', array( $this->response->html($this->template->layout('project/index', array(
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'paginator' => $paginator, 'paginator' => $paginator,
'nb_projects' => $nb_projects, 'nb_projects' => $nb_projects,
'title' => t('Projects').' ('.$nb_projects.')' 'title' => t('Projects').' ('.$nb_projects.')'
@@ -302,7 +302,7 @@ class Project extends Base
$is_private = isset($values['is_private']) && $values['is_private'] == 1; $is_private = isset($values['is_private']) && $values['is_private'] == 1;
$this->response->html($this->template->layout('project/new', array( $this->response->html($this->template->layout('project/new', array(
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'values' => $values, 'values' => $values,
'errors' => $errors, 'errors' => $errors,
'is_private' => $is_private, 'is_private' => $is_private,

View File

@@ -24,7 +24,7 @@ class Projectuser extends Base
*/ */
private function layout($template, array $params) private function layout($template, array $params)
{ {
$params['board_selector'] = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); $params['board_selector'] = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
$params['content_for_sublayout'] = $this->template->render($template, $params); $params['content_for_sublayout'] = $this->template->render($template, $params);
$params['filter'] = array('user_id' => $params['user_id']); $params['filter'] = array('user_id' => $params['user_id']);

View File

@@ -26,7 +26,7 @@ class User extends Base
{ {
$content = $this->template->render($template, $params); $content = $this->template->render($template, $params);
$params['user_content_for_layout'] = $content; $params['user_content_for_layout'] = $content;
$params['board_selector'] = $this->projectUserRole->getProjectsByUser($this->userSession->getId()); $params['board_selector'] = $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId());
if (isset($params['user'])) { if (isset($params['user'])) {
$params['title'] = ($params['user']['name'] ?: $params['user']['username']).' (#'.$params['user']['id'].')'; $params['title'] = ($params['user']['name'] ?: $params['user']['username']).' (#'.$params['user']['id'].')';
@@ -51,7 +51,7 @@ class User extends Base
$this->response->html( $this->response->html(
$this->template->layout('user/index', array( $this->template->layout('user/index', array(
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'title' => t('Users').' ('.$paginator->getTotal().')', 'title' => t('Users').' ('.$paginator->getTotal().')',
'paginator' => $paginator, 'paginator' => $paginator,
))); )));
@@ -72,7 +72,7 @@ class User extends Base
$this->response->html( $this->response->html(
$this->template->layout('user/profile', array( $this->template->layout('user/profile', array(
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'title' => $user['name'] ?: $user['username'], 'title' => $user['name'] ?: $user['username'],
'user' => $user, 'user' => $user,
) )
@@ -92,7 +92,7 @@ class User extends Base
'timezones' => $this->config->getTimezones(true), 'timezones' => $this->config->getTimezones(true),
'languages' => $this->config->getLanguages(true), 'languages' => $this->config->getLanguages(true),
'roles' => $this->role->getApplicationRoles(), 'roles' => $this->role->getApplicationRoles(),
'board_selector' => $this->projectUserRole->getProjectsByUser($this->userSession->getId()), 'board_selector' => $this->projectUserRole->getActiveProjectsByUser($this->userSession->getId()),
'projects' => $this->project->getList(), 'projects' => $this->project->getList(),
'errors' => $errors, 'errors' => $errors,
'values' => $values + array('role' => Role::APP_USER), 'values' => $values + array('role' => Role::APP_USER),

View File

@@ -18,6 +18,7 @@ use Pimple\Container;
* @property \Kanboard\Core\Http\Request $request * @property \Kanboard\Core\Http\Request $request
* @property \Kanboard\Core\Http\Response $response * @property \Kanboard\Core\Http\Response $response
* @property \Kanboard\Core\Http\Router $router * @property \Kanboard\Core\Http\Router $router
* @property \Kanboard\Core\Http\Route $route
* @property \Kanboard\Core\Mail\Client $emailClient * @property \Kanboard\Core\Mail\Client $emailClient
* @property \Kanboard\Core\ObjectStorage\ObjectStorageInterface $objectStorage * @property \Kanboard\Core\ObjectStorage\ObjectStorageInterface $objectStorage
* @property \Kanboard\Core\Plugin\Hook $hook * @property \Kanboard\Core\Plugin\Hook $hook

View File

@@ -41,6 +41,16 @@ class Request extends Base
$this->cookies = empty($cookies) ? $_COOKIE : $cookies; $this->cookies = empty($cookies) ? $_COOKIE : $cookies;
} }
/**
* Set GET parameters
*
* @param array $params
*/
public function setParams(array $params)
{
$this->get = array_merge($this->get, $params);
}
/** /**
* Get query string string parameter * Get query string string parameter
* *
@@ -146,6 +156,17 @@ class Request extends Base
return isset($this->files[$name]['tmp_name']) ? $this->files[$name]['tmp_name'] : ''; return isset($this->files[$name]['tmp_name']) ? $this->files[$name]['tmp_name'] : '';
} }
/**
* Return HTTP method
*
* @access public
* @return bool
*/
public function getMethod()
{
return $this->getServerVariable('REQUEST_METHOD');
}
/** /**
* Return true if the HTTP request is sent with the POST method * Return true if the HTTP request is sent with the POST method
* *
@@ -154,7 +175,7 @@ class Request extends Base
*/ */
public function isPost() public function isPost()
{ {
return isset($this->server['REQUEST_METHOD']) && $this->server['REQUEST_METHOD'] === 'POST'; return $this->getServerVariable('REQUEST_METHOD') === 'POST';
} }
/** /**
@@ -203,7 +224,7 @@ class Request extends Base
public function getHeader($name) public function getHeader($name)
{ {
$name = 'HTTP_'.str_replace('-', '_', strtoupper($name)); $name = 'HTTP_'.str_replace('-', '_', strtoupper($name));
return isset($this->server[$name]) ? $this->server[$name] : ''; return $this->getServerVariable($name);
} }
/** /**
@@ -214,18 +235,18 @@ class Request extends Base
*/ */
public function getRemoteUser() public function getRemoteUser()
{ {
return isset($this->server[REVERSE_PROXY_USER_HEADER]) ? $this->server[REVERSE_PROXY_USER_HEADER] : ''; return $this->getServerVariable(REVERSE_PROXY_USER_HEADER);
} }
/** /**
* Returns current request's query string, useful for redirecting * Returns query string
* *
* @access public * @access public
* @return string * @return string
*/ */
public function getQueryString() public function getQueryString()
{ {
return isset($this->server['QUERY_STRING']) ? $this->server['QUERY_STRING'] : ''; return $this->getServerVariable('QUERY_STRING');
} }
/** /**
@@ -236,7 +257,7 @@ class Request extends Base
*/ */
public function getUri() public function getUri()
{ {
return isset($this->server['REQUEST_URI']) ? $this->server['REQUEST_URI'] : ''; return $this->getServerVariable('REQUEST_URI');
} }
/** /**
@@ -269,7 +290,7 @@ class Request extends Base
); );
foreach ($keys as $key) { foreach ($keys as $key) {
if (! empty($this->server[$key])) { if ($this->getServerVariable($key) !== '') {
foreach (explode(',', $this->server[$key]) as $ipAddress) { foreach (explode(',', $this->server[$key]) as $ipAddress) {
return trim($ipAddress); return trim($ipAddress);
} }
@@ -287,6 +308,18 @@ class Request extends Base
*/ */
public function getStartTime() public function getStartTime()
{ {
return isset($this->server['REQUEST_TIME_FLOAT']) ? $this->server['REQUEST_TIME_FLOAT'] : 0; return $this->getServerVariable('REQUEST_TIME_FLOAT') ?: 0;
}
/**
* Get server variable
*
* @access public
* @param string $variable
* @return string
*/
public function getServerVariable($variable)
{
return isset($this->server[$variable]) ? $this->server[$variable] : '';
} }
} }

188
app/Core/Http/Route.php Normal file
View File

@@ -0,0 +1,188 @@
<?php
namespace Kanboard\Core\Http;
use RuntimeException;
use Kanboard\Core\Base;
/**
* Route Handler
*
* @package http
* @author Frederic Guillot
*/
class Route extends Base
{
/**
* Flag that enable the routing table
*
* @access private
* @var boolean
*/
private $activated = false;
/**
* Store routes for path lookup
*
* @access private
* @var array
*/
private $paths = array();
/**
* Store routes for url lookup
*
* @access private
* @var array
*/
private $urls = array();
/**
* Enable routing table
*
* @access public
* @return Route
*/
public function enable()
{
$this->activated = true;
return $this;
}
/**
* Add route
*
* @access public
* @param string $path
* @param string $controller
* @param string $action
* @param string $plugin
* @return Route
*/
public function addRoute($path, $controller, $action, $plugin = '')
{
if ($this->activated) {
$path = ltrim($path, '/');
$items = explode('/', $path);
$params = $this->findParams($items);
$this->paths[] = array(
'items' => $items,
'count' => count($items),
'controller' => $controller,
'action' => $action,
'plugin' => $plugin,
);
$this->urls[$plugin][$controller][$action][] = array(
'path' => $path,
'params' => $params,
'count' => count($params),
);
}
return $this;
}
/**
* Find a route according to the given path
*
* @access public
* @param string $path
* @return array
*/
public function findRoute($path)
{
$items = explode('/', ltrim($path, '/'));
$count = count($items);
foreach ($this->paths as $route) {
if ($count === $route['count']) {
$params = array();
for ($i = 0; $i < $count; $i++) {
if ($route['items'][$i]{0} === ':') {
$params[substr($route['items'][$i], 1)] = $items[$i];
} elseif ($route['items'][$i] !== $items[$i]) {
break;
}
}
if ($i === $count) {
$this->request->setParams($params);
return array(
'controller' => $route['controller'],
'action' => $route['action'],
'plugin' => $route['plugin'],
);
}
}
}
return array(
'controller' => 'app',
'action' => 'index',
'plugin' => '',
);
}
/**
* Find route url
*
* @access public
* @param string $controller
* @param string $action
* @param array $params
* @param string $plugin
* @return string
*/
public function findUrl($controller, $action, array $params = array(), $plugin = '')
{
if ($plugin === '' && isset($params['plugin'])) {
$plugin = $params['plugin'];
unset($params['plugin']);
}
if (! isset($this->urls[$plugin][$controller][$action])) {
return '';
}
foreach ($this->urls[$plugin][$controller][$action] as $route) {
if (array_diff_key($params, $route['params']) === array()) {
$url = $route['path'];
$i = 0;
foreach ($params as $variable => $value) {
$url = str_replace(':'.$variable, $value, $url);
$i++;
}
if ($i === $route['count']) {
return $url;
}
}
}
return '';
}
/**
* Find url params
*
* @access public
* @param array $items
* @return array
*/
public function findParams(array $items)
{
$params = array();
foreach ($items as $item) {
if ($item !== '' && $item{0} === ':') {
$params[substr($item, 1)] = true;
}
}
return $params;
}
}

View File

@@ -6,13 +6,21 @@ use RuntimeException;
use Kanboard\Core\Base; use Kanboard\Core\Base;
/** /**
* Router class * Route Dispatcher
* *
* @package http * @package http
* @author Frederic Guillot * @author Frederic Guillot
*/ */
class Router extends Base class Router extends Base
{ {
/**
* Plugin name
*
* @access private
* @var string
*/
private $plugin = '';
/** /**
* Controller * Controller
* *
@@ -30,30 +38,14 @@ class Router extends Base
private $action = ''; private $action = '';
/** /**
* Store routes for path lookup * Get plugin name
*
* @access private
* @var array
*/
private $paths = array();
/**
* Store routes for url lookup
*
* @access private
* @var array
*/
private $urls = array();
/**
* Get action
* *
* @access public * @access public
* @return string * @return string
*/ */
public function getAction() public function getPlugin()
{ {
return $this->action; return $this->plugin;
} }
/** /**
@@ -67,23 +59,32 @@ class Router extends Base
return $this->controller; return $this->controller;
} }
/**
* Get action
*
* @access public
* @return string
*/
public function getAction()
{
return $this->action;
}
/** /**
* Get the path to compare patterns * Get the path to compare patterns
* *
* @access public * @access public
* @param string $uri
* @param string $query_string
* @return string * @return string
*/ */
public function getPath($uri, $query_string = '') public function getPath()
{ {
$path = substr($uri, strlen($this->helper->url->dir())); $path = substr($this->request->getUri(), strlen($this->helper->url->dir()));
if (! empty($query_string)) { if ($this->request->getQueryString() !== '') {
$path = substr($path, 0, - strlen($query_string) - 1); $path = substr($path, 0, - strlen($this->request->getQueryString()) - 1);
} }
if (! empty($path) && $path{0} === '/') { if ($path !== '' && $path{0} === '/') {
$path = substr($path, 1); $path = substr($path, 1);
} }
@@ -91,140 +92,78 @@ class Router extends Base
} }
/** /**
* Add route * Find controller/action from the route table or from get arguments
* *
* @access public * @access public
* @param string $path
* @param string $controller
* @param string $action
* @param array $params
*/ */
public function addRoute($path, $controller, $action, array $params = array()) public function dispatch()
{ {
$pattern = explode('/', $path); $controller = $this->request->getStringParam('controller');
$action = $this->request->getStringParam('action');
$plugin = $this->request->getStringParam('plugin');
$this->paths[] = array( if ($controller === '') {
'pattern' => $pattern, $route = $this->route->findRoute($this->getPath());
'count' => count($pattern), $controller = $route['controller'];
'controller' => $controller, $action = $route['action'];
'action' => $action, $plugin = $route['plugin'];
);
$this->urls[$controller][$action][] = array(
'path' => $path,
'params' => array_flip($params),
'count' => count($params),
);
}
/**
* Find a route according to the given path
*
* @access public
* @param string $path
* @return array
*/
public function findRoute($path)
{
$parts = explode('/', $path);
$count = count($parts);
foreach ($this->paths as $route) {
if ($count === $route['count']) {
$params = array();
for ($i = 0; $i < $count; $i++) {
if ($route['pattern'][$i]{0} === ':') {
$params[substr($route['pattern'][$i], 1)] = $parts[$i];
} elseif ($route['pattern'][$i] !== $parts[$i]) {
break;
}
}
if ($i === $count) {
$_GET = array_merge($_GET, $params);
return array($route['controller'], $route['action']);
}
}
} }
return array('app', 'index'); $this->controller = ucfirst($this->sanitize($controller, 'app'));
} $this->action = $this->sanitize($action, 'index');
$this->plugin = ucfirst($this->sanitize($plugin));
/** return $this->executeAction();
* Find route url
*
* @access public
* @param string $controller
* @param string $action
* @param array $params
* @return string
*/
public function findUrl($controller, $action, array $params = array())
{
if (! isset($this->urls[$controller][$action])) {
return '';
}
foreach ($this->urls[$controller][$action] as $pattern) {
if (array_diff_key($params, $pattern['params']) === array()) {
$url = $pattern['path'];
$i = 0;
foreach ($params as $variable => $value) {
$url = str_replace(':'.$variable, $value, $url);
$i++;
}
if ($i === $pattern['count']) {
return $url;
}
}
}
return '';
} }
/** /**
* Check controller and action parameter * Check controller and action parameter
* *
* @access public * @access public
* @param string $value Controller or action name * @param string $value
* @param string $default_value Default value if validation fail * @param string $default
* @return string * @return string
*/ */
public function sanitize($value, $default_value) public function sanitize($value, $default = '')
{ {
return ! preg_match('/^[a-zA-Z_0-9]+$/', $value) ? $default_value : $value; return preg_match('/^[a-zA-Z_0-9]+$/', $value) ? $value : $default;
} }
/** /**
* Find controller/action from the route table or from get arguments * Execute controller action
* *
* @access public * @access private
* @param string $uri
* @param string $query_string
*/ */
public function dispatch($uri, $query_string = '') private function executeAction()
{ {
if (! empty($_GET['controller']) && ! empty($_GET['action'])) { $class = $this->getControllerClassName();
$this->controller = $this->sanitize($_GET['controller'], 'app');
$this->action = $this->sanitize($_GET['action'], 'index'); if (! class_exists($class)) {
$plugin = ! empty($_GET['plugin']) ? $this->sanitize($_GET['plugin'], '') : ''; throw new RuntimeException('Controller not found');
} else {
list($this->controller, $this->action) = $this->findRoute($this->getPath($uri, $query_string)); // TODO: add plugin for routes
$plugin = '';
} }
$class = '\Kanboard\\'; if (! method_exists($class, $this->action)) {
$class .= empty($plugin) ? 'Controller\\'.ucfirst($this->controller) : 'Plugin\\'.ucfirst($plugin).'\Controller\\'.ucfirst($this->controller); throw new RuntimeException('Action not implemented');
if (! class_exists($class) || ! method_exists($class, $this->action)) {
throw new RuntimeException('Controller or method not found for the given url!');
} }
$instance = new $class($this->container); $instance = new $class($this->container);
$instance->beforeAction($this->controller, $this->action); $instance->beforeAction($this->controller, $this->action);
$instance->{$this->action}(); $instance->{$this->action}();
return $instance;
}
/**
* Get controller class name
*
* @access private
* @return string
*/
private function getControllerClassName()
{
if ($this->plugin !== '') {
return '\Kanboard\Plugin\\'.$this->plugin.'\Controller\\'.$this->controller;
}
return '\Kanboard\Controller\\'.$this->controller;
} }
} }

View File

@@ -45,7 +45,7 @@ class LdapBackendGroupProvider extends Base implements GroupBackendProviderInter
*/ */
public function getLdapGroupPattern($input) public function getLdapGroupPattern($input)
{ {
if (empty(LDAP_GROUP_FILTER)) { if (LDAP_GROUP_FILTER === '') {
throw new LogicException('LDAP group filter empty, check the parameter LDAP_GROUP_FILTER'); throw new LogicException('LDAP group filter empty, check the parameter LDAP_GROUP_FILTER');
} }

View File

@@ -2,14 +2,27 @@
namespace Kanboard\Helper; namespace Kanboard\Helper;
use Kanboard\Core\Base;
/** /**
* Application helpers * Application helpers
* *
* @package helper * @package helper
* @author Frederic Guillot * @author Frederic Guillot
*/ */
class App extends \Kanboard\Core\Base class App extends Base
{ {
/**
* Get plugin name from route
*
* @access public
* @return string
*/
public function getPluginName()
{
return $this->router->getPlugin();
}
/** /**
* Get router controller * Get router controller
* *

View File

@@ -103,8 +103,8 @@ class Url extends Base
*/ */
public function dir() public function dir()
{ {
if (empty($this->directory) && isset($_SERVER['REQUEST_METHOD'])) { if ($this->directory === '' && $this->request->getMethod() !== '') {
$this->directory = str_replace('\\', '/', dirname($_SERVER['PHP_SELF'])); $this->directory = str_replace('\\', '/', dirname($this->request->getServerVariable('PHP_SELF')));
$this->directory = $this->directory !== '/' ? $this->directory.'/' : '/'; $this->directory = $this->directory !== '/' ? $this->directory.'/' : '/';
$this->directory = str_replace('//', '/', $this->directory); $this->directory = str_replace('//', '/', $this->directory);
} }
@@ -120,13 +120,13 @@ class Url extends Base
*/ */
public function server() public function server()
{ {
if (empty($_SERVER['SERVER_NAME'])) { if ($this->request->getServerVariable('SERVER_NAME') === '') {
return 'http://localhost/'; return 'http://localhost/';
} }
$url = $this->request->isHTTPS() ? 'https://' : 'http://'; $url = $this->request->isHTTPS() ? 'https://' : 'http://';
$url .= $_SERVER['SERVER_NAME']; $url .= $this->request->getServerVariable('SERVER_NAME');
$url .= $_SERVER['SERVER_PORT'] == 80 || $_SERVER['SERVER_PORT'] == 443 ? '' : ':'.$_SERVER['SERVER_PORT']; $url .= $this->request->getServerVariable('SERVER_PORT') == 80 || $this->request->getServerVariable('SERVER_PORT') == 443 ? '' : ':'.$this->request->getServerVariable('SERVER_PORT');
$url .= $this->dir() ?: '/'; $url .= $this->dir() ?: '/';
return $url; return $url;
@@ -147,13 +147,15 @@ class Url extends Base
*/ */
private function build($separator, $controller, $action, array $params = array(), $csrf = false, $anchor = '', $absolute = false) private function build($separator, $controller, $action, array $params = array(), $csrf = false, $anchor = '', $absolute = false)
{ {
$path = $this->router->findUrl($controller, $action, $params); $path = $this->route->findUrl($controller, $action, $params);
$qs = array(); $qs = array();
if (empty($path)) { if (empty($path)) {
$qs['controller'] = $controller; $qs['controller'] = $controller;
$qs['action'] = $action; $qs['action'] = $action;
$qs += $params; $qs += $params;
} else {
unset($params['plugin']);
} }
if ($csrf) { if ($csrf) {

View File

@@ -203,6 +203,7 @@ class Comment extends Base
new Validators\Integer('id', t('This value must be an integer')), new Validators\Integer('id', t('This value must be an integer')),
new Validators\Integer('task_id', t('This value must be an integer')), new Validators\Integer('task_id', t('This value must be an integer')),
new Validators\Integer('user_id', t('This value must be an integer')), new Validators\Integer('user_id', t('This value must be an integer')),
new Validators\MaxLength('reference', t('The maximum length is %d characters', 50), 50),
new Validators\Required('comment', t('Comment is required')) new Validators\Required('comment', t('Comment is required'))
); );
} }

View File

@@ -100,7 +100,7 @@ class ProjectPermission extends Base
*/ */
public function getActiveProjectIds($user_id) public function getActiveProjectIds($user_id)
{ {
return array_keys($this->projectUserRole->getProjectsByUser($user_id, array(Project::ACTIVE))); return array_keys($this->projectUserRole->getActiveProjectsByUser($user_id));
} }
/** /**

View File

@@ -20,7 +20,19 @@ class ProjectUserRole extends Base
const TABLE = 'project_has_users'; const TABLE = 'project_has_users';
/** /**
* Get the list of project visible by the given user * Get the list of active project for the given user
*
* @access public
* @param integer $user_id
* @return array
*/
public function getActiveProjectsByUser($user_id)
{
return $this->getProjectsByUser($user_id, $status = array(Project::ACTIVE));
}
/**
* Get the list of project visible for the given user
* *
* @access public * @access public
* @param integer $user_id * @param integer $user_id

View File

@@ -4,6 +4,7 @@ namespace Kanboard\ServiceProvider;
use Pimple\Container; use Pimple\Container;
use Pimple\ServiceProviderInterface; use Pimple\ServiceProviderInterface;
use Kanboard\Core\Http\Route;
use Kanboard\Core\Http\Router; use Kanboard\Core\Http\Router;
/** /**
@@ -24,183 +25,186 @@ class RouteProvider implements ServiceProviderInterface
public function register(Container $container) public function register(Container $container)
{ {
$container['router'] = new Router($container); $container['router'] = new Router($container);
$container['route'] = new Route($container);
if (ENABLE_URL_REWRITE) { if (ENABLE_URL_REWRITE) {
$container['route']->enable();
// Dashboard // Dashboard
$container['router']->addRoute('dashboard', 'app', 'index'); $container['route']->addRoute('dashboard', 'app', 'index');
$container['router']->addRoute('dashboard/:user_id', 'app', 'index', array('user_id')); $container['route']->addRoute('dashboard/:user_id', 'app', 'index');
$container['router']->addRoute('dashboard/:user_id/projects', 'app', 'projects', array('user_id')); $container['route']->addRoute('dashboard/:user_id/projects', 'app', 'projects');
$container['router']->addRoute('dashboard/:user_id/tasks', 'app', 'tasks', array('user_id')); $container['route']->addRoute('dashboard/:user_id/tasks', 'app', 'tasks');
$container['router']->addRoute('dashboard/:user_id/subtasks', 'app', 'subtasks', array('user_id')); $container['route']->addRoute('dashboard/:user_id/subtasks', 'app', 'subtasks');
$container['router']->addRoute('dashboard/:user_id/calendar', 'app', 'calendar', array('user_id')); $container['route']->addRoute('dashboard/:user_id/calendar', 'app', 'calendar');
$container['router']->addRoute('dashboard/:user_id/activity', 'app', 'activity', array('user_id')); $container['route']->addRoute('dashboard/:user_id/activity', 'app', 'activity');
// Search routes // Search routes
$container['router']->addRoute('search', 'search', 'index'); $container['route']->addRoute('search', 'search', 'index');
$container['router']->addRoute('search/:search', 'search', 'index', array('search')); $container['route']->addRoute('search/:search', 'search', 'index');
// Project routes // Project routes
$container['router']->addRoute('projects', 'project', 'index'); $container['route']->addRoute('projects', 'project', 'index');
$container['router']->addRoute('project/create', 'project', 'create'); $container['route']->addRoute('project/create', 'project', 'create');
$container['router']->addRoute('project/create/private', 'project', 'createPrivate'); $container['route']->addRoute('project/create/private', 'project', 'createPrivate');
$container['router']->addRoute('project/:project_id', 'project', 'show', array('project_id')); $container['route']->addRoute('project/:project_id', 'project', 'show');
$container['router']->addRoute('p/:project_id', 'project', 'show', array('project_id')); $container['route']->addRoute('p/:project_id', 'project', 'show');
$container['router']->addRoute('project/:project_id/customer-filter', 'customfilter', 'index', array('project_id')); $container['route']->addRoute('project/:project_id/customer-filter', 'customfilter', 'index');
$container['router']->addRoute('project/:project_id/share', 'project', 'share', array('project_id')); $container['route']->addRoute('project/:project_id/share', 'project', 'share');
$container['router']->addRoute('project/:project_id/notifications', 'project', 'notifications', array('project_id')); $container['route']->addRoute('project/:project_id/notifications', 'project', 'notifications');
$container['router']->addRoute('project/:project_id/edit', 'project', 'edit', array('project_id')); $container['route']->addRoute('project/:project_id/edit', 'project', 'edit');
$container['router']->addRoute('project/:project_id/integrations', 'project', 'integrations', array('project_id')); $container['route']->addRoute('project/:project_id/integrations', 'project', 'integrations');
$container['router']->addRoute('project/:project_id/duplicate', 'project', 'duplicate', array('project_id')); $container['route']->addRoute('project/:project_id/duplicate', 'project', 'duplicate');
$container['router']->addRoute('project/:project_id/remove', 'project', 'remove', array('project_id')); $container['route']->addRoute('project/:project_id/remove', 'project', 'remove');
$container['router']->addRoute('project/:project_id/disable', 'project', 'disable', array('project_id')); $container['route']->addRoute('project/:project_id/disable', 'project', 'disable');
$container['router']->addRoute('project/:project_id/enable', 'project', 'enable', array('project_id')); $container['route']->addRoute('project/:project_id/enable', 'project', 'enable');
$container['router']->addRoute('project/:project_id/permissions', 'ProjectPermission', 'index', array('project_id')); $container['route']->addRoute('project/:project_id/permissions', 'ProjectPermission', 'index');
$container['router']->addRoute('project/:project_id/import', 'taskImport', 'step1', array('project_id')); $container['route']->addRoute('project/:project_id/import', 'taskImport', 'step1');
// ProjectUser routes // ProjectUser routes
$container['router']->addRoute('projects/managers/:user_id', 'projectuser', 'managers', array('user_id')); $container['route']->addRoute('projects/managers/:user_id', 'projectuser', 'managers');
$container['router']->addRoute('projects/members/:user_id', 'projectuser', 'members', array('user_id')); $container['route']->addRoute('projects/members/:user_id', 'projectuser', 'members');
$container['router']->addRoute('projects/tasks/:user_id/opens', 'projectuser', 'opens', array('user_id')); $container['route']->addRoute('projects/tasks/:user_id/opens', 'projectuser', 'opens');
$container['router']->addRoute('projects/tasks/:user_id/closed', 'projectuser', 'closed', array('user_id')); $container['route']->addRoute('projects/tasks/:user_id/closed', 'projectuser', 'closed');
$container['router']->addRoute('projects/managers', 'projectuser', 'managers'); $container['route']->addRoute('projects/managers', 'projectuser', 'managers');
// Action routes // Action routes
$container['router']->addRoute('project/:project_id/actions', 'action', 'index', array('project_id')); $container['route']->addRoute('project/:project_id/actions', 'action', 'index');
$container['router']->addRoute('project/:project_id/action/:action_id/confirm', 'action', 'confirm', array('project_id', 'action_id')); $container['route']->addRoute('project/:project_id/action/:action_id/confirm', 'action', 'confirm');
// Column routes // Column routes
$container['router']->addRoute('project/:project_id/columns', 'column', 'index', array('project_id')); $container['route']->addRoute('project/:project_id/columns', 'column', 'index');
$container['router']->addRoute('project/:project_id/column/:column_id/edit', 'column', 'edit', array('project_id', 'column_id')); $container['route']->addRoute('project/:project_id/column/:column_id/edit', 'column', 'edit');
$container['router']->addRoute('project/:project_id/column/:column_id/confirm', 'column', 'confirm', array('project_id', 'column_id')); $container['route']->addRoute('project/:project_id/column/:column_id/confirm', 'column', 'confirm');
$container['router']->addRoute('project/:project_id/column/:column_id/move/:direction', 'column', 'move', array('project_id', 'column_id', 'direction')); $container['route']->addRoute('project/:project_id/column/:column_id/move/:direction', 'column', 'move');
// Swimlane routes // Swimlane routes
$container['router']->addRoute('project/:project_id/swimlanes', 'swimlane', 'index', array('project_id')); $container['route']->addRoute('project/:project_id/swimlanes', 'swimlane', 'index');
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/edit', 'swimlane', 'edit', array('project_id', 'swimlane_id')); $container['route']->addRoute('project/:project_id/swimlane/:swimlane_id/edit', 'swimlane', 'edit');
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/confirm', 'swimlane', 'confirm', array('project_id', 'swimlane_id')); $container['route']->addRoute('project/:project_id/swimlane/:swimlane_id/confirm', 'swimlane', 'confirm');
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/disable', 'swimlane', 'disable', array('project_id', 'swimlane_id')); $container['route']->addRoute('project/:project_id/swimlane/:swimlane_id/disable', 'swimlane', 'disable');
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/enable', 'swimlane', 'enable', array('project_id', 'swimlane_id')); $container['route']->addRoute('project/:project_id/swimlane/:swimlane_id/enable', 'swimlane', 'enable');
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/up', 'swimlane', 'moveup', array('project_id', 'swimlane_id')); $container['route']->addRoute('project/:project_id/swimlane/:swimlane_id/up', 'swimlane', 'moveup');
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/down', 'swimlane', 'movedown', array('project_id', 'swimlane_id')); $container['route']->addRoute('project/:project_id/swimlane/:swimlane_id/down', 'swimlane', 'movedown');
// Category routes // Category routes
$container['router']->addRoute('project/:project_id/categories', 'category', 'index', array('project_id')); $container['route']->addRoute('project/:project_id/categories', 'category', 'index');
$container['router']->addRoute('project/:project_id/category/:category_id/edit', 'category', 'edit', array('project_id', 'category_id')); $container['route']->addRoute('project/:project_id/category/:category_id/edit', 'category', 'edit');
$container['router']->addRoute('project/:project_id/category/:category_id/confirm', 'category', 'confirm', array('project_id', 'category_id')); $container['route']->addRoute('project/:project_id/category/:category_id/confirm', 'category', 'confirm');
// Task routes // Task routes
$container['router']->addRoute('project/:project_id/task/:task_id', 'task', 'show', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id', 'task', 'show');
$container['router']->addRoute('t/:task_id', 'task', 'show', array('task_id')); $container['route']->addRoute('t/:task_id', 'task', 'show');
$container['router']->addRoute('public/task/:task_id/:token', 'task', 'readonly', array('task_id', 'token')); $container['route']->addRoute('public/task/:task_id/:token', 'task', 'readonly');
$container['router']->addRoute('project/:project_id/task/:task_id/activity', 'activity', 'task', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/activity', 'activity', 'task');
$container['router']->addRoute('project/:project_id/task/:task_id/screenshot', 'file', 'screenshot', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/screenshot', 'file', 'screenshot');
$container['router']->addRoute('project/:project_id/task/:task_id/upload', 'file', 'create', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/upload', 'file', 'create');
$container['router']->addRoute('project/:project_id/task/:task_id/comment', 'comment', 'create', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/comment', 'comment', 'create');
$container['router']->addRoute('project/:project_id/task/:task_id/link', 'tasklink', 'create', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/link', 'tasklink', 'create');
$container['router']->addRoute('project/:project_id/task/:task_id/transitions', 'task', 'transitions', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/transitions', 'task', 'transitions');
$container['router']->addRoute('project/:project_id/task/:task_id/analytics', 'task', 'analytics', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/analytics', 'task', 'analytics');
$container['router']->addRoute('project/:project_id/task/:task_id/remove', 'task', 'remove', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/remove', 'task', 'remove');
$container['router']->addRoute('project/:project_id/task/:task_id/edit', 'taskmodification', 'edit', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/edit', 'taskmodification', 'edit');
$container['router']->addRoute('project/:project_id/task/:task_id/description', 'taskmodification', 'description', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/description', 'taskmodification', 'description');
$container['router']->addRoute('project/:project_id/task/:task_id/recurrence', 'taskmodification', 'recurrence', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/recurrence', 'taskmodification', 'recurrence');
$container['router']->addRoute('project/:project_id/task/:task_id/close', 'taskstatus', 'close', array('task_id', 'project_id')); $container['route']->addRoute('project/:project_id/task/:task_id/close', 'taskstatus', 'close');
$container['router']->addRoute('project/:project_id/task/:task_id/open', 'taskstatus', 'open', array('task_id', 'project_id')); $container['route']->addRoute('project/:project_id/task/:task_id/open', 'taskstatus', 'open');
$container['router']->addRoute('project/:project_id/task/:task_id/duplicate', 'taskduplication', 'duplicate', array('task_id', 'project_id')); $container['route']->addRoute('project/:project_id/task/:task_id/duplicate', 'taskduplication', 'duplicate');
$container['router']->addRoute('project/:project_id/task/:task_id/copy', 'taskduplication', 'copy', array('task_id', 'project_id')); $container['route']->addRoute('project/:project_id/task/:task_id/copy', 'taskduplication', 'copy');
$container['router']->addRoute('project/:project_id/task/:task_id/copy/:dst_project_id', 'taskduplication', 'copy', array('task_id', 'project_id', 'dst_project_id')); $container['route']->addRoute('project/:project_id/task/:task_id/copy/:dst_project_id', 'taskduplication', 'copy');
$container['router']->addRoute('project/:project_id/task/:task_id/move', 'taskduplication', 'move', array('task_id', 'project_id')); $container['route']->addRoute('project/:project_id/task/:task_id/move', 'taskduplication', 'move');
$container['router']->addRoute('project/:project_id/task/:task_id/move/:dst_project_id', 'taskduplication', 'move', array('task_id', 'project_id', 'dst_project_id')); $container['route']->addRoute('project/:project_id/task/:task_id/move/:dst_project_id', 'taskduplication', 'move');
// Exports // Exports
$container['router']->addRoute('export/tasks/:project_id', 'export', 'tasks', array('project_id')); $container['route']->addRoute('export/tasks/:project_id', 'export', 'tasks');
$container['router']->addRoute('export/subtasks/:project_id', 'export', 'subtasks', array('project_id')); $container['route']->addRoute('export/subtasks/:project_id', 'export', 'subtasks');
$container['router']->addRoute('export/transitions/:project_id', 'export', 'transitions', array('project_id')); $container['route']->addRoute('export/transitions/:project_id', 'export', 'transitions');
$container['router']->addRoute('export/summary/:project_id', 'export', 'summary', array('project_id')); $container['route']->addRoute('export/summary/:project_id', 'export', 'summary');
// Board routes // Board routes
$container['router']->addRoute('board/:project_id', 'board', 'show', array('project_id')); $container['route']->addRoute('board/:project_id', 'board', 'show');
$container['router']->addRoute('b/:project_id', 'board', 'show', array('project_id')); $container['route']->addRoute('b/:project_id', 'board', 'show');
$container['router']->addRoute('public/board/:token', 'board', 'readonly', array('token')); $container['route']->addRoute('public/board/:token', 'board', 'readonly');
// Calendar routes // Calendar routes
$container['router']->addRoute('calendar/:project_id', 'calendar', 'show', array('project_id')); $container['route']->addRoute('calendar/:project_id', 'calendar', 'show');
$container['router']->addRoute('c/:project_id', 'calendar', 'show', array('project_id')); $container['route']->addRoute('c/:project_id', 'calendar', 'show');
// Listing routes // Listing routes
$container['router']->addRoute('list/:project_id', 'listing', 'show', array('project_id')); $container['route']->addRoute('list/:project_id', 'listing', 'show');
$container['router']->addRoute('l/:project_id', 'listing', 'show', array('project_id')); $container['route']->addRoute('l/:project_id', 'listing', 'show');
// Gantt routes // Gantt routes
$container['router']->addRoute('gantt/:project_id', 'gantt', 'project', array('project_id')); $container['route']->addRoute('gantt/:project_id', 'gantt', 'project');
$container['router']->addRoute('gantt/:project_id/sort/:sorting', 'gantt', 'project', array('project_id', 'sorting')); $container['route']->addRoute('gantt/:project_id/sort/:sorting', 'gantt', 'project');
// Subtask routes // Subtask routes
$container['router']->addRoute('project/:project_id/task/:task_id/subtask/create', 'subtask', 'create', array('project_id', 'task_id')); $container['route']->addRoute('project/:project_id/task/:task_id/subtask/create', 'subtask', 'create');
$container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/remove', 'subtask', 'confirm', array('project_id', 'task_id', 'subtask_id')); $container['route']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/remove', 'subtask', 'confirm');
$container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/edit', 'subtask', 'edit', array('project_id', 'task_id', 'subtask_id')); $container['route']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/edit', 'subtask', 'edit');
// Feed routes // Feed routes
$container['router']->addRoute('feed/project/:token', 'feed', 'project', array('token')); $container['route']->addRoute('feed/project/:token', 'feed', 'project');
$container['router']->addRoute('feed/user/:token', 'feed', 'user', array('token')); $container['route']->addRoute('feed/user/:token', 'feed', 'user');
// Ical routes // Ical routes
$container['router']->addRoute('ical/project/:token', 'ical', 'project', array('token')); $container['route']->addRoute('ical/project/:token', 'ical', 'project');
$container['router']->addRoute('ical/user/:token', 'ical', 'user', array('token')); $container['route']->addRoute('ical/user/:token', 'ical', 'user');
// Users // Users
$container['router']->addRoute('users', 'user', 'index'); $container['route']->addRoute('users', 'user', 'index');
$container['router']->addRoute('user/profile/:user_id', 'user', 'profile', array('user_id')); $container['route']->addRoute('user/profile/:user_id', 'user', 'profile');
$container['router']->addRoute('user/show/:user_id', 'user', 'show', array('user_id')); $container['route']->addRoute('user/show/:user_id', 'user', 'show');
$container['router']->addRoute('user/show/:user_id/timesheet', 'user', 'timesheet', array('user_id')); $container['route']->addRoute('user/show/:user_id/timesheet', 'user', 'timesheet');
$container['router']->addRoute('user/show/:user_id/last-logins', 'user', 'last', array('user_id')); $container['route']->addRoute('user/show/:user_id/last-logins', 'user', 'last');
$container['router']->addRoute('user/show/:user_id/sessions', 'user', 'sessions', array('user_id')); $container['route']->addRoute('user/show/:user_id/sessions', 'user', 'sessions');
$container['router']->addRoute('user/:user_id/edit', 'user', 'edit', array('user_id')); $container['route']->addRoute('user/:user_id/edit', 'user', 'edit');
$container['router']->addRoute('user/:user_id/password', 'user', 'password', array('user_id')); $container['route']->addRoute('user/:user_id/password', 'user', 'password');
$container['router']->addRoute('user/:user_id/share', 'user', 'share', array('user_id')); $container['route']->addRoute('user/:user_id/share', 'user', 'share');
$container['router']->addRoute('user/:user_id/notifications', 'user', 'notifications', array('user_id')); $container['route']->addRoute('user/:user_id/notifications', 'user', 'notifications');
$container['router']->addRoute('user/:user_id/accounts', 'user', 'external', array('user_id')); $container['route']->addRoute('user/:user_id/accounts', 'user', 'external');
$container['router']->addRoute('user/:user_id/integrations', 'user', 'integrations', array('user_id')); $container['route']->addRoute('user/:user_id/integrations', 'user', 'integrations');
$container['router']->addRoute('user/:user_id/authentication', 'user', 'authentication', array('user_id')); $container['route']->addRoute('user/:user_id/authentication', 'user', 'authentication');
$container['router']->addRoute('user/:user_id/remove', 'user', 'remove', array('user_id')); $container['route']->addRoute('user/:user_id/remove', 'user', 'remove');
$container['router']->addRoute('user/:user_id/2fa', 'twofactor', 'index', array('user_id')); $container['route']->addRoute('user/:user_id/2fa', 'twofactor', 'index');
// Groups // Groups
$container['router']->addRoute('groups', 'group', 'index'); $container['route']->addRoute('groups', 'group', 'index');
$container['router']->addRoute('groups/create', 'group', 'create'); $container['route']->addRoute('groups/create', 'group', 'create');
$container['router']->addRoute('group/:group_id/associate', 'group', 'associate', array('group_id')); $container['route']->addRoute('group/:group_id/associate', 'group', 'associate');
$container['router']->addRoute('group/:group_id/dissociate/:user_id', 'group', 'dissociate', array('group_id', 'user_id')); $container['route']->addRoute('group/:group_id/dissociate/:user_id', 'group', 'dissociate');
$container['router']->addRoute('group/:group_id/edit', 'group', 'edit', array('group_id')); $container['route']->addRoute('group/:group_id/edit', 'group', 'edit');
$container['router']->addRoute('group/:group_id/members', 'group', 'users', array('group_id')); $container['route']->addRoute('group/:group_id/members', 'group', 'users');
$container['router']->addRoute('group/:group_id/remove', 'group', 'confirm', array('group_id')); $container['route']->addRoute('group/:group_id/remove', 'group', 'confirm');
// Config // Config
$container['router']->addRoute('settings', 'config', 'index'); $container['route']->addRoute('settings', 'config', 'index');
$container['router']->addRoute('settings/plugins', 'config', 'plugins'); $container['route']->addRoute('settings/plugins', 'config', 'plugins');
$container['router']->addRoute('settings/application', 'config', 'application'); $container['route']->addRoute('settings/application', 'config', 'application');
$container['router']->addRoute('settings/project', 'config', 'project'); $container['route']->addRoute('settings/project', 'config', 'project');
$container['router']->addRoute('settings/project', 'config', 'project'); $container['route']->addRoute('settings/project', 'config', 'project');
$container['router']->addRoute('settings/board', 'config', 'board'); $container['route']->addRoute('settings/board', 'config', 'board');
$container['router']->addRoute('settings/calendar', 'config', 'calendar'); $container['route']->addRoute('settings/calendar', 'config', 'calendar');
$container['router']->addRoute('settings/integrations', 'config', 'integrations'); $container['route']->addRoute('settings/integrations', 'config', 'integrations');
$container['router']->addRoute('settings/webhook', 'config', 'webhook'); $container['route']->addRoute('settings/webhook', 'config', 'webhook');
$container['router']->addRoute('settings/api', 'config', 'api'); $container['route']->addRoute('settings/api', 'config', 'api');
$container['router']->addRoute('settings/links', 'link', 'index'); $container['route']->addRoute('settings/links', 'link', 'index');
$container['router']->addRoute('settings/currencies', 'currency', 'index'); $container['route']->addRoute('settings/currencies', 'currency', 'index');
// Doc // Doc
$container['router']->addRoute('documentation/:file', 'doc', 'show', array('file')); $container['route']->addRoute('documentation/:file', 'doc', 'show');
$container['router']->addRoute('documentation', 'doc', 'show'); $container['route']->addRoute('documentation', 'doc', 'show');
// Auth routes // Auth routes
$container['router']->addRoute('oauth/google', 'oauth', 'google'); $container['route']->addRoute('oauth/google', 'oauth', 'google');
$container['router']->addRoute('oauth/github', 'oauth', 'github'); $container['route']->addRoute('oauth/github', 'oauth', 'github');
$container['router']->addRoute('oauth/gitlab', 'oauth', 'gitlab'); $container['route']->addRoute('oauth/gitlab', 'oauth', 'gitlab');
$container['router']->addRoute('login', 'auth', 'login'); $container['route']->addRoute('login', 'auth', 'login');
$container['router']->addRoute('logout', 'auth', 'logout'); $container['route']->addRoute('logout', 'auth', 'logout');
} }
return $container; return $container;

View File

@@ -0,0 +1,85 @@
Custom Routes
=============
When URL rewriting is enabled, you can define custom routes from your plugins.
Define new routes
-----------------
Routes are handled by the class `Kanboard\Core\Http\Route`.
New routes can be added by using the method `addRoute($path, $controller, $action, $plugin)`, here an example:
```php
$this->route->addRoute('/my/custom/route', 'myController', 'myAction', 'myplugin');
```
When the end-user go to the URL `/my/custom/route`, the method `Kanboard\Plugin\Myplugin\Controller\MyController::myAction()` will be executed.
The first character of the controller and the plugin name will converted in uppercase with the function `ucfirst()`.
You can also define routes with variables:
```php
$this->route->addRoute('/my/route/:my_variable', 'myController', 'myAction', 'myplugin');
```
The colon prefix `:`, define a variable.
For example `:my_variable` declare a new variable named `my_variable`.
To fetch the value of the variable you can use the method `getStringParam()` or `getIntegerParam()` from the class `Kanboard\Core\Http\Request`:
If we have the URL `/my/route/foobar`, the value of `my_variable` is `foobar`:
```php
$this->request->getStringParam('my_variable'); // Return foobar
```
Generate links based on the routing table
-----------------------------------------
From templates, you have to use the helper `Kanboard\Helper\Url`.
### Generate a HTML link
```php
<?= $this->url->link('My link', 'mycontroller', 'myaction', array('plugin' => 'myplugin')) ?>
```
Will generate this HTML:
```html
<a href="/my/custom/route">My link</a>
```
### Generate only the attribute `href`:
```php
<?= $this->url->href('My link', 'mycontroller', 'myaction', array('plugin' => 'myplugin')) ?>
```
HTML output:
```html
/my/custom/route
```
HTML output when URL rewriting is not enabled:
```html
?controller=mycontroller&amp;action=myaction&amp;plugin=myplugin
```
### Generate redirect link:
From a controller, if you need to perform a redirection:
```php
$this->url->to('mycontroller', 'myaction', array('plugin' => 'myplugin'));
```
Generate:
```
?controller=mycontroller&action=myaction&plugin=myplugin
```

View File

@@ -11,6 +11,7 @@ Plugin creators should specify explicitly the compatible versions of Kanboard. I
- [Using plugin hooks](plugin-hooks.markdown) - [Using plugin hooks](plugin-hooks.markdown)
- [Override default application behaviors](plugin-overrides.markdown) - [Override default application behaviors](plugin-overrides.markdown)
- [Add schema migrations for plugins](plugin-schema-migrations.markdown) - [Add schema migrations for plugins](plugin-schema-migrations.markdown)
- [Custom routes](plugin-routes.markdown)
- [Add mail transports](plugin-mail-transports.markdown) - [Add mail transports](plugin-mail-transports.markdown)
- [Add notification types](plugin-notifications.markdown) - [Add notification types](plugin-notifications.markdown)
- [Attach metadata to users, tasks and projects](plugin-metadata.markdown) - [Attach metadata to users, tasks and projects](plugin-metadata.markdown)

View File

@@ -2,7 +2,7 @@
try { try {
require __DIR__.'/app/common.php'; require __DIR__.'/app/common.php';
$container['router']->dispatch($_SERVER['REQUEST_URI'], isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''); $container['router']->dispatch();
} catch (Exception $e) { } catch (Exception $e) {
echo 'Internal Error: '.$e->getMessage(); echo 'Internal Error: '.$e->getMessage();
} }

View File

@@ -0,0 +1,79 @@
<?php
require_once __DIR__.'/../../Base.php';
use Kanboard\Core\Http\Route;
class RouteTest extends Base
{
public function testFindParams()
{
$route = new Route($this->container);
$route->enable();
$this->assertEquals(array('p1' => true, 'p2' => true), $route->findParams(array('something', ':p1', ':p2')));
$this->assertEquals(array('p1' => true), $route->findParams(array('something', ':p1', '')));
$this->assertEquals(array('p1' => true), $route->findParams(array('something', ':p1', 'something else')));
}
public function testFindRoute()
{
$route = new Route($this->container);
$route->enable();
$route->addRoute('/mycontroller/myaction', 'mycontroller', 'myaction');
$this->assertEquals(
array('controller' => 'mycontroller', 'action' => 'myaction', 'plugin' => ''),
$route->findRoute('/mycontroller/myaction')
);
$route->addRoute('/a/b/c', 'mycontroller', 'myaction', 'myplugin');
$this->assertEquals(
array('controller' => 'mycontroller', 'action' => 'myaction', 'plugin' => 'myplugin'),
$route->findRoute('/a/b/c')
);
$this->assertEquals(
array('controller' => 'app', 'action' => 'index', 'plugin' => ''),
$route->findRoute('/notfound')
);
$route->addRoute('/a/b/:c', 'mycontroller', 'myaction', 'myplugin');
$this->assertEquals(
array('controller' => 'mycontroller', 'action' => 'myaction', 'plugin' => 'myplugin'),
$route->findRoute('/a/b/myvalue')
);
$this->assertEquals('myvalue', $this->container['request']->getStringParam('c'));
$route->addRoute('/a/:p1/b/:p2', 'mycontroller', 'myaction');
$this->assertEquals(
array('controller' => 'mycontroller', 'action' => 'myaction', 'plugin' => ''),
$route->findRoute('/a/v1/b/v2')
);
$this->assertEquals('v1', $this->container['request']->getStringParam('p1'));
$this->assertEquals('v2', $this->container['request']->getStringParam('p2'));
}
public function testFindUrl()
{
$route = new Route($this->container);
$route->enable();
$route->addRoute('a/b', 'controller1', 'action1');
$route->addRoute('a/:myvar1/b/:myvar2', 'controller2', 'action2');
$route->addRoute('/something', 'controller1', 'action1', 'myplugin');
$route->addRoute('/myplugin/myroute', 'controller1', 'action2', 'myplugin');
$route->addRoute('/foo/:myvar', 'controller1', 'action3', 'myplugin');
$this->assertEquals('a/1/b/2', $route->findUrl('controller2', 'action2', array('myvar1' => 1, 'myvar2' => 2)));
$this->assertEquals('', $route->findUrl('controller2', 'action2', array('myvar1' => 1)));
$this->assertEquals('a/b', $route->findUrl('controller1', 'action1'));
$this->assertEquals('', $route->findUrl('controller1', 'action2'));
$this->assertEquals('myplugin/myroute', $route->findUrl('controller1', 'action2', array(), 'myplugin'));
$this->assertEquals('something', $route->findUrl('controller1', 'action1', array(), 'myplugin'));
$this->assertEquals('foo/123', $route->findUrl('controller1', 'action3', array('myvar' => 123), 'myplugin'));
$this->assertEquals('foo/123', $route->findUrl('controller1', 'action3', array('myvar' => 123, 'plugin' => 'myplugin')));
}
}

View File

@@ -1,81 +1,203 @@
<?php <?php
require_once __DIR__.'/../../Base.php'; namespace Kanboard\Controller {
use Kanboard\Core\Http\Router; class FakeController {
public function beforeAction() {}
class RouterTest extends Base public function myAction() {}
{ }
public function testSanitize() }
{
$r = new Router($this->container); namespace Kanboard\Plugin\Myplugin\Controller {
$this->assertEquals('PloP', $r->sanitize('PloP', 'default')); class FakeController {
$this->assertEquals('default', $r->sanitize('', 'default')); public function beforeAction() {}
$this->assertEquals('default', $r->sanitize('123-AB', 'default')); public function myAction() {}
$this->assertEquals('default', $r->sanitize('R&D', 'default')); }
$this->assertEquals('Test123', $r->sanitize('Test123', 'default')); }
$this->assertEquals('Test_123', $r->sanitize('Test_123', 'default'));
$this->assertEquals('userImport', $r->sanitize('userImport', 'default')); namespace {
}
require_once __DIR__.'/../../Base.php';
public function testPath()
{ use Kanboard\Core\Helper;
$r = new Router($this->container); use Kanboard\Core\Http\Route;
use Kanboard\Core\Http\Router;
$this->assertEquals('a/b/c', $r->getPath('/a/b/c')); use Kanboard\Core\Http\Request;
$this->assertEquals('a/b/something', $r->getPath('/a/b/something?test=a', 'test=a'));
class RouterTest extends Base
$_SERVER['REQUEST_METHOD'] = 'GET'; {
$_SERVER['PHP_SELF'] = '/a/index.php'; public function testSanitize()
{
$this->assertEquals('b/c', $r->getPath('/a/b/c')); $dispatcher = new Router($this->container);
$this->assertEquals('b/c', $r->getPath('/a/b/c?e=f', 'e=f'));
} $this->assertEquals('PloP', $dispatcher->sanitize('PloP', 'default'));
$this->assertEquals('default', $dispatcher->sanitize('', 'default'));
public function testFindRouteWithEmptyTable() $this->assertEquals('default', $dispatcher->sanitize('123-AB', 'default'));
{ $this->assertEquals('default', $dispatcher->sanitize('R&D', 'default'));
$r = new Router($this->container); $this->assertEquals('Test123', $dispatcher->sanitize('Test123', 'default'));
$this->assertEquals(array('app', 'index'), $r->findRoute('')); $this->assertEquals('Test_123', $dispatcher->sanitize('Test_123', 'default'));
$this->assertEquals(array('app', 'index'), $r->findRoute('/')); $this->assertEquals('userImport', $dispatcher->sanitize('userImport', 'default'));
} }
public function testFindRouteWithoutPlaceholders() public function testGetPath()
{ {
$r = new Router($this->container); $dispatcher = new Router($this->container);
$r->addRoute('a/b', 'controller', 'action');
$this->assertEquals(array('app', 'index'), $r->findRoute('a/b/c')); $this->container['helper'] = new Helper($this->container);
$this->assertEquals(array('controller', 'action'), $r->findRoute('a/b')); $this->container['request'] = new Request($this->container, array('PHP_SELF' => '/index.php', 'REQUEST_URI' => '/a/b/c', 'REQUEST_METHOD' => 'GET'));
} $this->assertEquals('a/b/c', $dispatcher->getPath());
public function testFindRouteWithPlaceholders() $this->container['helper'] = new Helper($this->container);
{ $this->container['request'] = new Request($this->container, array('PHP_SELF' => '/index.php', 'REQUEST_URI' => '/a/b/something?test=a', 'QUERY_STRING' => 'test=a', 'REQUEST_METHOD' => 'GET'));
$r = new Router($this->container); $this->assertEquals('a/b/something', $dispatcher->getPath());
$r->addRoute('a/:myvar1/b/:myvar2', 'controller', 'action');
$this->assertEquals(array('app', 'index'), $r->findRoute('a/123/b')); $this->container['helper'] = new Helper($this->container);
$this->assertEquals(array('controller', 'action'), $r->findRoute('a/456/b/789')); $this->container['request'] = new Request($this->container, array('PHP_SELF' => '/a/index.php', 'REQUEST_URI' => '/a/b/something?test=a', 'QUERY_STRING' => 'test=a', 'REQUEST_METHOD' => 'GET'));
$this->assertEquals(array('myvar1' => 456, 'myvar2' => 789), $_GET); $this->assertEquals('b/something', $dispatcher->getPath());
} }
public function testFindMultipleRoutes() public function testDispatcherWithControllerNotFound()
{ {
$r = new Router($this->container); $this->container['request'] = new Request($this->container, array(
$r->addRoute('a/b', 'controller1', 'action1'); 'PHP_SELF' => '/kanboard/index.php',
$r->addRoute('a/b', 'duplicate', 'duplicate'); 'REQUEST_URI' => '/kanboard/?controller=FakeControllerNotFound&action=myAction&myvar=value1',
$r->addRoute('a', 'controller2', 'action2'); 'QUERY_STRING' => 'controller=FakeControllerNotFound&action=myAction&myvar=value1',
$this->assertEquals(array('controller1', 'action1'), $r->findRoute('a/b')); 'REQUEST_METHOD' => 'GET'
$this->assertEquals(array('controller2', 'action2'), $r->findRoute('a')); ),
} array(
'controller' => 'FakeControllerNotFound',
public function testFindUrl() 'action' => 'myAction',
{ 'myvar' => 'value1',
$r = new Router($this->container); )
$r->addRoute('a/b', 'controller1', 'action1'); );
$r->addRoute('a/:myvar1/b/:myvar2', 'controller2', 'action2', array('myvar1', 'myvar2'));
$this->setExpectedException('RuntimeException', 'Controller not found');
$this->assertEquals('a/1/b/2', $r->findUrl('controller2', 'action2', array('myvar1' => 1, 'myvar2' => 2)));
$this->assertEquals('', $r->findUrl('controller2', 'action2', array('myvar1' => 1))); $dispatcher = new Router($this->container);
$this->assertEquals('a/b', $r->findUrl('controller1', 'action1')); $dispatcher->dispatch();
$this->assertEquals('', $r->findUrl('controller1', 'action2')); }
public function testDispatcherWithActionNotFound()
{
$this->container['request'] = new Request($this->container, array(
'PHP_SELF' => '/kanboard/index.php',
'REQUEST_URI' => '/kanboard/?controller=FakeController&action=myActionNotFound&myvar=value1',
'QUERY_STRING' => 'controller=FakeController&action=myActionNotFound&myvar=value1',
'REQUEST_METHOD' => 'GET'
),
array(
'controller' => 'FakeController',
'action' => 'myActionNotFound',
'myvar' => 'value1',
)
);
$this->setExpectedException('RuntimeException', 'Action not implemented');
$dispatcher = new Router($this->container);
$dispatcher->dispatch();
}
public function testDispatcherWithNoUrlRewrite()
{
$this->container['request'] = new Request($this->container, array(
'PHP_SELF' => '/kanboard/index.php',
'REQUEST_URI' => '/kanboard/?controller=FakeController&action=myAction&myvar=value1',
'QUERY_STRING' => 'controller=FakeController&action=myAction&myvar=value1',
'REQUEST_METHOD' => 'GET'
),
array(
'controller' => 'FakeController',
'action' => 'myAction',
'myvar' => 'value1',
)
);
$dispatcher = new Router($this->container);
$this->assertInstanceOf('\Kanboard\Controller\FakeController', $dispatcher->dispatch());
$this->assertEquals('FakeController', $dispatcher->getController());
$this->assertEquals('myAction', $dispatcher->getAction());
$this->assertEquals('', $dispatcher->getPlugin());
$this->assertEquals('value1', $this->container['request']->getStringParam('myvar'));
}
public function testDispatcherWithNoUrlRewriteAndPlugin()
{
$this->container['request'] = new Request($this->container, array(
'PHP_SELF' => '/kanboard/index.php',
'REQUEST_URI' => '/kanboard/?controller=FakeController&action=myAction&myvar=value1&plugin=myplugin',
'QUERY_STRING' => 'controller=FakeController&action=myAction&myvar=value1&plugin=myplugin',
'REQUEST_METHOD' => 'GET'
),
array(
'controller' => 'FakeController',
'action' => 'myAction',
'myvar' => 'value1',
'plugin' => 'myplugin',
)
);
$dispatcher = new Router($this->container);
$this->assertInstanceOf('\Kanboard\Plugin\Myplugin\Controller\FakeController', $dispatcher->dispatch());
$this->assertEquals('FakeController', $dispatcher->getController());
$this->assertEquals('myAction', $dispatcher->getAction());
$this->assertEquals('Myplugin', $dispatcher->getPlugin());
$this->assertEquals('value1', $this->container['request']->getStringParam('myvar'));
}
public function testDispatcherWithUrlRewrite()
{
$this->container['request'] = new Request($this->container, array(
'PHP_SELF' => '/kanboard/index.php',
'REQUEST_URI' => '/kanboard/my/route/123?myvar=value1',
'QUERY_STRING' => 'myvar=value1',
'REQUEST_METHOD' => 'GET'
),
array(
'myvar' => 'value1',
)
);
$this->container['route'] = new Route($this->container);
$this->container['route']->enable();
$dispatcher = new Router($this->container);
$this->container['route']->addRoute('/my/route/:param', 'FakeController', 'myAction');
$this->assertInstanceOf('\Kanboard\Controller\FakeController', $dispatcher->dispatch());
$this->assertEquals('FakeController', $dispatcher->getController());
$this->assertEquals('myAction', $dispatcher->getAction());
$this->assertEquals('', $dispatcher->getPlugin());
$this->assertEquals('value1', $this->container['request']->getStringParam('myvar'));
$this->assertEquals('123', $this->container['request']->getStringParam('param'));
}
public function testDispatcherWithUrlRewriteWithPlugin()
{
$this->container['request'] = new Request($this->container, array(
'PHP_SELF' => '/kanboard/index.php',
'REQUEST_URI' => '/kanboard/my/plugin/route/123?myvar=value1',
'QUERY_STRING' => 'myvar=value1',
'REQUEST_METHOD' => 'GET'
),
array(
'myvar' => 'value1',
)
);
$this->container['route'] = new Route($this->container);
$this->container['route']->enable();
$dispatcher = new Router($this->container);
$this->container['route']->addRoute('/my/plugin/route/:param', 'fakeController', 'myAction', 'Myplugin');
$this->assertInstanceOf('\Kanboard\Plugin\Myplugin\Controller\FakeController', $dispatcher->dispatch());
$this->assertEquals('FakeController', $dispatcher->getController());
$this->assertEquals('myAction', $dispatcher->getAction());
$this->assertEquals('Myplugin', $dispatcher->getPlugin());
$this->assertEquals('value1', $this->container['request']->getStringParam('myvar'));
$this->assertEquals('123', $this->container['request']->getStringParam('param'));
}
} }
} }

View File

@@ -0,0 +1,16 @@
<?php
require_once __DIR__.'/../Base.php';
use Kanboard\Group\LdapBackendGroupProvider;
class LdapBackendGroupProviderTest extends Base
{
public function testGetLdapGroupPattern()
{
$this->setExpectedException('LogicException', 'LDAP group filter empty, check the parameter LDAP_GROUP_FILTER');
$backend = new LdapBackendGroupProvider($this->container);
$backend->getLdapGroupPattern('test');
}
}

View File

@@ -4,10 +4,32 @@ require_once __DIR__.'/../Base.php';
use Kanboard\Helper\Url; use Kanboard\Helper\Url;
use Kanboard\Model\Config; use Kanboard\Model\Config;
use Kanboard\Core\Http\Request;
class UrlHelperTest extends Base class UrlHelperTest extends Base
{ {
public function testLink() public function testPluginLink()
{
$h = new Url($this->container);
$this->assertEquals(
'<a href="?controller=a&amp;action=b&amp;d=e&amp;plugin=something" class="f" title="g" target="_blank">label</a>',
$h->link('label', 'a', 'b', array('d' => 'e', 'plugin' => 'something'), false, 'f', 'g', true)
);
}
public function testPluginLinkWithRouteDefined()
{
$this->container['route']->enable();
$this->container['route']->addRoute('/myplugin/something/:d', 'a', 'b', 'something');
$h = new Url($this->container);
$this->assertEquals(
'<a href="myplugin/something/e" class="f" title="g" target="_blank">label</a>',
$h->link('label', 'a', 'b', array('d' => 'e', 'plugin' => 'something'), false, 'f', 'g', true)
);
}
public function testAppLink()
{ {
$h = new Url($this->container); $h = new Url($this->container);
$this->assertEquals( $this->assertEquals(
@@ -36,42 +58,59 @@ class UrlHelperTest extends Base
public function testDir() public function testDir()
{ {
$h = new Url($this->container); $this->container['request'] = new Request($this->container, array(
$this->assertEquals('', $h->dir()); 'PHP_SELF' => '/kanboard/index.php',
'REQUEST_METHOD' => 'GET'
)
);
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['PHP_SELF'] = '/plop/index.php';
$h = new Url($this->container); $h = new Url($this->container);
$this->assertEquals('/plop/', $h->dir()); $this->assertEquals('/kanboard/', $h->dir());
$this->container['request'] = new Request($this->container, array(
'PHP_SELF' => '/index.php',
'REQUEST_METHOD' => 'GET'
)
);
$_SERVER['REQUEST_METHOD'] = 'GET';
$_SERVER['PHP_SELF'] = '';
$h = new Url($this->container); $h = new Url($this->container);
$this->assertEquals('/', $h->dir()); $this->assertEquals('/', $h->dir());
} }
public function testServer() public function testServer()
{ {
$h = new Url($this->container); $this->container['request'] = new Request($this->container, array(
'PHP_SELF' => '/index.php',
'REQUEST_METHOD' => 'GET',
'SERVER_NAME' => 'localhost',
'SERVER_PORT' => 80,
)
);
$h = new Url($this->container);
$this->assertEquals('http://localhost/', $h->server()); $this->assertEquals('http://localhost/', $h->server());
$_SERVER['PHP_SELF'] = '/'; $this->container['request'] = new Request($this->container, array(
$_SERVER['SERVER_NAME'] = 'kb'; 'PHP_SELF' => '/index.php',
$_SERVER['SERVER_PORT'] = 1234; 'REQUEST_METHOD' => 'GET',
'SERVER_NAME' => 'kb',
'SERVER_PORT' => 1234,
)
);
$h = new Url($this->container);
$this->assertEquals('http://kb:1234/', $h->server()); $this->assertEquals('http://kb:1234/', $h->server());
} }
public function testBase() public function testBase()
{ {
$h = new Url($this->container); $this->container['request'] = new Request($this->container, array(
'PHP_SELF' => '/index.php',
$this->assertEquals('http://localhost/', $h->base()); 'REQUEST_METHOD' => 'GET',
'SERVER_NAME' => 'kb',
$_SERVER['PHP_SELF'] = '/'; 'SERVER_PORT' => 1234,
$_SERVER['SERVER_NAME'] = 'kb'; )
$_SERVER['SERVER_PORT'] = 1234; );
$h = new Url($this->container); $h = new Url($this->container);
$this->assertEquals('http://kb:1234/', $h->base()); $this->assertEquals('http://kb:1234/', $h->base());