First draft for plugins system
This commit is contained in:
parent
c405f99fc8
commit
a6a00a0040
|
|
@ -5,6 +5,7 @@ New features:
|
|||
|
||||
* Add LDAP group sync
|
||||
* Add swimlane description
|
||||
* New plugin system (alpha)
|
||||
|
||||
Improvements:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Core;
|
||||
|
||||
/**
|
||||
* Plugin Base class
|
||||
*
|
||||
* @package core
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
abstract class PluginBase extends Base
|
||||
{
|
||||
/**
|
||||
* Method called for each request
|
||||
*
|
||||
* @abstract
|
||||
* @access public
|
||||
*/
|
||||
abstract public function initialize();
|
||||
|
||||
/**
|
||||
* Returns all classes that needs to be stored in the DI container
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getClasses()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
namespace Core;
|
||||
|
||||
use DirectoryIterator;
|
||||
use PDOException;
|
||||
|
||||
/**
|
||||
* Plugin Loader
|
||||
*
|
||||
* @package core
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class PluginLoader extends Base
|
||||
{
|
||||
/**
|
||||
* Schema version table for plugins
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TABLE_SCHEMA = 'plugin_schema_versions';
|
||||
|
||||
/**
|
||||
* Plugin folder
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PATH = __DIR__.'/../../plugins';
|
||||
|
||||
/**
|
||||
* Scan plugin folder and load plugins
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function scan()
|
||||
{
|
||||
if (file_exists(self::PATH)) {
|
||||
$dir = new DirectoryIterator(self::PATH);
|
||||
|
||||
foreach ($dir as $fileinfo) {
|
||||
if (! $fileinfo->isDot() && $fileinfo->isDir()) {
|
||||
$plugin = $fileinfo->getFilename();
|
||||
$this->loadSchema($plugin);
|
||||
$this->load($plugin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugin
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function load($plugin)
|
||||
{
|
||||
$class = '\Plugin\\'.$plugin.'\\Plugin';
|
||||
$instance = new $class($this->container);
|
||||
|
||||
Tool::buildDic($this->container, $instance->getClasses());
|
||||
|
||||
$instance->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load plugin schema
|
||||
*
|
||||
* @access public
|
||||
* @param string $plugin
|
||||
*/
|
||||
public function loadSchema($plugin)
|
||||
{
|
||||
$filename = __DIR__.'/../../plugins/'.$plugin.'/Schema/'.ucfirst(DB_DRIVER).'.php';
|
||||
|
||||
if (file_exists($filename)) {
|
||||
require($filename);
|
||||
$this->migrateSchema($plugin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute plugin schema migrations
|
||||
*
|
||||
* @access public
|
||||
* @param string $plugin
|
||||
*/
|
||||
public function migrateSchema($plugin)
|
||||
{
|
||||
$last_version = constant('\Plugin\\'.$plugin.'\Schema\VERSION');
|
||||
$current_version = $this->getSchemaVersion($plugin);
|
||||
|
||||
try {
|
||||
|
||||
$this->db->startTransaction();
|
||||
$this->db->getDriver()->disableForeignKeys();
|
||||
|
||||
for ($i = $current_version + 1; $i <= $last_version; $i++) {
|
||||
$function_name = '\Plugin\\'.$plugin.'\Schema\version_'.$i;
|
||||
|
||||
if (function_exists($function_name)) {
|
||||
call_user_func($function_name, $this->db->getConnection());
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->getDriver()->enableForeignKeys();
|
||||
$this->db->closeTransaction();
|
||||
$this->setSchemaVersion($plugin, $i - 1);
|
||||
}
|
||||
catch (PDOException $e) {
|
||||
$this->db->cancelTransaction();
|
||||
$this->db->getDriver()->enableForeignKeys();
|
||||
die('Unable to migrate schema for the plugin: '.$plugin.' => '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current plugin schema version
|
||||
*
|
||||
* @access public
|
||||
* @param string $plugin
|
||||
* @return integer
|
||||
*/
|
||||
public function getSchemaVersion($plugin)
|
||||
{
|
||||
return (int) $this->db->table(self::TABLE_SCHEMA)->eq('plugin', strtolower($plugin))->findOneColumn('version');
|
||||
}
|
||||
|
||||
/**
|
||||
* Save last plugin schema version
|
||||
*
|
||||
* @access public
|
||||
* @param string $plugin
|
||||
* @param integer $version
|
||||
* @return boolean
|
||||
*/
|
||||
public function setSchemaVersion($plugin, $version)
|
||||
{
|
||||
$dictionary = array(
|
||||
strtolower($plugin) => $version
|
||||
);
|
||||
|
||||
return $this->db->getDriver()->upsert(self::TABLE_SCHEMA, 'plugin', 'version', $dictionary);
|
||||
}
|
||||
}
|
||||
|
|
@ -213,49 +213,17 @@ class Router extends Base
|
|||
if (! empty($_GET['controller']) && ! empty($_GET['action'])) {
|
||||
$controller = $this->sanitize($_GET['controller'], 'app');
|
||||
$action = $this->sanitize($_GET['action'], 'index');
|
||||
$plugin = ! empty($_GET['plugin']) ? $this->sanitize($_GET['plugin'], '') : '';
|
||||
}
|
||||
else {
|
||||
list($controller, $action) = $this->findRoute($this->getPath($uri, $query_string));
|
||||
list($controller, $action) = $this->findRoute($this->getPath($uri, $query_string)); // TODO: add plugin for routes
|
||||
$plugin = '';
|
||||
}
|
||||
|
||||
return $this->load(
|
||||
__DIR__.'/../Controller/'.ucfirst($controller).'.php',
|
||||
$controller,
|
||||
'\Controller\\'.ucfirst($controller),
|
||||
$action
|
||||
);
|
||||
}
|
||||
$class = empty($plugin) ? '\Controller\\'.ucfirst($controller) : '\Plugin\\'.ucfirst($plugin).'\Controller\\'.ucfirst($controller);
|
||||
|
||||
/**
|
||||
* Load a controller and execute the action
|
||||
*
|
||||
* @access private
|
||||
* @param string $filename
|
||||
* @param string $controller
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
* @return bool
|
||||
*/
|
||||
private function load($filename, $controller, $class, $method)
|
||||
{
|
||||
if (file_exists($filename)) {
|
||||
|
||||
require $filename;
|
||||
|
||||
if (! method_exists($class, $method)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->action = $method;
|
||||
$this->controller = $controller;
|
||||
|
||||
$instance = new $class($this->container);
|
||||
$instance->beforeAction($controller, $method);
|
||||
$instance->$method();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
$instance = new $class($this->container);
|
||||
$instance->beforeAction($controller, $action);
|
||||
$instance->$action();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,12 @@ use LogicException;
|
|||
class Template extends Helper
|
||||
{
|
||||
/**
|
||||
* Template path
|
||||
* List of template overrides
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
const PATH = 'app/Template/';
|
||||
private $overrides = array();
|
||||
|
||||
/**
|
||||
* Render a template
|
||||
|
|
@ -33,16 +34,10 @@ class Template extends Helper
|
|||
*/
|
||||
public function render($__template_name, array $__template_args = array())
|
||||
{
|
||||
$__template_file = self::PATH.$__template_name.'.php';
|
||||
|
||||
if (! file_exists($__template_file)) {
|
||||
throw new LogicException('Unable to load the template: "'.$__template_name.'"');
|
||||
}
|
||||
|
||||
extract($__template_args);
|
||||
|
||||
ob_start();
|
||||
include $__template_file;
|
||||
include $this->getTemplateFile($__template_name);
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
|
|
@ -62,4 +57,41 @@ class Template extends Helper
|
|||
$template_args + array('content_for_layout' => $this->render($template_name, $template_args))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a new template override
|
||||
*
|
||||
* @access public
|
||||
* @param string $original_template
|
||||
* @param string $new_template
|
||||
*/
|
||||
public function setTemplateOverride($original_template, $new_template)
|
||||
{
|
||||
$this->overrides[$original_template] = $new_template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find template filename
|
||||
*
|
||||
* Core template name: 'task/show'
|
||||
* Plugin template name: 'myplugin:task/show'
|
||||
*
|
||||
* @access public
|
||||
* @param string $template_name
|
||||
* @return string
|
||||
*/
|
||||
public function getTemplateFile($template_name)
|
||||
{
|
||||
$template_name = isset($this->overrides[$template_name]) ? $this->overrides[$template_name] : $template_name;
|
||||
|
||||
if (strpos($template_name, ':') !== false) {
|
||||
list($plugin, $template) = explode(':', $template_name);
|
||||
$path = __DIR__.'/../../plugins/'.ucfirst($plugin).'/Template/'.$template.'.php';
|
||||
}
|
||||
else {
|
||||
$path = __DIR__.'/../Template/'.$template_name.'.php';
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Core;
|
||||
|
||||
use Pimple\Container;
|
||||
|
||||
/**
|
||||
* Tool class
|
||||
*
|
||||
|
|
@ -23,7 +25,6 @@ class Tool
|
|||
$fp = fopen($filename, 'w');
|
||||
|
||||
if (is_resource($fp)) {
|
||||
|
||||
foreach ($rows as $fields) {
|
||||
fputcsv($fp, $fields);
|
||||
}
|
||||
|
|
@ -51,4 +52,24 @@ class Tool
|
|||
|
||||
return $identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build dependency injection container from an array
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @param Container $container
|
||||
* @param array $namespaces
|
||||
*/
|
||||
public static function buildDIC(Container $container, array $namespaces)
|
||||
{
|
||||
foreach ($namespaces as $namespace => $classes) {
|
||||
foreach ($classes as $name) {
|
||||
$class = '\\'.$namespace.'\\'.$name;
|
||||
$container[lcfirst($name)] = function ($c) use ($class) {
|
||||
return new $class($c);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class Translator
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
const PATH = 'app/Locale/';
|
||||
const PATH = 'app/Locale';
|
||||
|
||||
/**
|
||||
* Locale
|
||||
|
|
@ -196,18 +196,27 @@ class Translator
|
|||
* @static
|
||||
* @access public
|
||||
* @param string $language Locale code: fr_FR
|
||||
* @param string $path Locale folder
|
||||
*/
|
||||
public static function load($language)
|
||||
public static function load($language, $path = self::PATH)
|
||||
{
|
||||
setlocale(LC_TIME, $language.'.UTF-8', $language);
|
||||
|
||||
$filename = self::PATH.$language.DIRECTORY_SEPARATOR.'translations.php';
|
||||
$filename = $path.DIRECTORY_SEPARATOR.$language.DIRECTORY_SEPARATOR.'translations.php';
|
||||
|
||||
if (file_exists($filename)) {
|
||||
self::$locales = require $filename;
|
||||
}
|
||||
else {
|
||||
self::$locales = array();
|
||||
self::$locales = array_merge(self::$locales, require($filename));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear locales stored in memory
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
*/
|
||||
public static function unload()
|
||||
{
|
||||
self::$locales = array();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Helper;
|
||||
|
||||
/**
|
||||
* Template Hook helpers
|
||||
*
|
||||
* @package helper
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Hook extends \Core\Base
|
||||
{
|
||||
private $hooks = array();
|
||||
|
||||
/**
|
||||
* Render all attached hooks
|
||||
*
|
||||
* @access public
|
||||
* @param string $hook
|
||||
* @param array $variables
|
||||
* @return string
|
||||
*/
|
||||
public function render($hook, array $variables = array())
|
||||
{
|
||||
$buffer = '';
|
||||
|
||||
foreach ($this->hooks as $name => $template) {
|
||||
if ($hook === $name) {
|
||||
$buffer .= $this->template->render($template, $variables);
|
||||
}
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a template to a hook
|
||||
*
|
||||
* @access public
|
||||
* @param string $hook
|
||||
* @param string $template
|
||||
* @return \Helper\Hook
|
||||
*/
|
||||
public function attach($hook, $template)
|
||||
{
|
||||
$this->hooks[$hook] = $template;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
@ -94,6 +94,18 @@ class Acl extends Base
|
|||
'twofactor' => array('disable'),
|
||||
);
|
||||
|
||||
/**
|
||||
* Extend ACL rules
|
||||
*
|
||||
* @access public
|
||||
* @param string $acl_name
|
||||
* @param aray $rules
|
||||
*/
|
||||
public function extend($acl_name, array $rules)
|
||||
{
|
||||
$this->$acl_name = array_merge($this->$acl_name, $rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the specified controller/action match the given acl
|
||||
*
|
||||
|
|
|
|||
|
|
@ -6,7 +6,18 @@ use PDO;
|
|||
use Core\Security;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 86;
|
||||
const VERSION = 87;
|
||||
|
||||
function version_87($pdo)
|
||||
{
|
||||
$pdo->exec("
|
||||
CREATE TABLE plugin_schema_versions (
|
||||
plugin VARCHAR(80) NOT NULL,
|
||||
version INT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY(plugin)
|
||||
) ENGINE=InnoDB CHARSET=utf8
|
||||
");
|
||||
}
|
||||
|
||||
function version_86($pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,17 @@ use PDO;
|
|||
use Core\Security;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 66;
|
||||
const VERSION = 67;
|
||||
|
||||
function version_67($pdo)
|
||||
{
|
||||
$pdo->exec("
|
||||
CREATE TABLE plugin_schema_versions (
|
||||
plugin VARCHAR(80) NOT NULL PRIMARY KEY,
|
||||
version INTEGER NOT NULL DEFAULT 0
|
||||
)
|
||||
");
|
||||
}
|
||||
|
||||
function version_66($pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,17 @@ use Core\Security;
|
|||
use PDO;
|
||||
use Model\Link;
|
||||
|
||||
const VERSION = 82;
|
||||
const VERSION = 83;
|
||||
|
||||
function version_83($pdo)
|
||||
{
|
||||
$pdo->exec("
|
||||
CREATE TABLE plugin_schema_versions (
|
||||
plugin TEXT NOT NULL PRIMARY KEY,
|
||||
version INTEGER NOT NULL DEFAULT 0
|
||||
)
|
||||
");
|
||||
}
|
||||
|
||||
function version_82($pdo)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace ServiceProvider;
|
|||
|
||||
use Core\Paginator;
|
||||
use Core\OAuth2;
|
||||
use Core\Tool;
|
||||
use Model\Config;
|
||||
use Model\Project;
|
||||
use Model\Webhook;
|
||||
|
|
@ -94,17 +95,7 @@ class ClassProvider implements ServiceProviderInterface
|
|||
|
||||
public function register(Container $container)
|
||||
{
|
||||
foreach ($this->classes as $namespace => $classes) {
|
||||
|
||||
foreach ($classes as $name) {
|
||||
|
||||
$class = '\\'.$namespace.'\\'.$name;
|
||||
|
||||
$container[lcfirst($name)] = function ($c) use ($class) {
|
||||
return new $class($c);
|
||||
};
|
||||
}
|
||||
}
|
||||
Tool::buildDIC($container, $this->classes);
|
||||
|
||||
$container['paginator'] = $container->factory(function ($c) {
|
||||
return new Paginator($c);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
<li <?= $this->app->getRouterAction() === 'activity' ? 'class="active"' : '' ?>>
|
||||
<?= $this->url->link(t('My activity stream'), 'app', 'activity', array('user_id' => $user['id'])) ?>
|
||||
</li>
|
||||
<?= $this->hook->render('dashboard:sidebar') ?>
|
||||
</ul>
|
||||
<div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div>
|
||||
<div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div>
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
<li>
|
||||
<?= $this->url->link(t('Documentation'), 'doc', 'show') ?>
|
||||
</li>
|
||||
<?= $this->hook->render('config:sidebar') ?>
|
||||
</ul>
|
||||
<div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div>
|
||||
<div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
<li <?= $this->app->getRouterAction() === 'summary' ? 'class="active"' : '' ?>>
|
||||
<?= $this->url->link(t('Daily project summary'), 'export', 'summary', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<?= $this->hook->render('export:sidebar') ?>
|
||||
</ul>
|
||||
<div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div>
|
||||
<div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<header>
|
||||
<nav>
|
||||
<h1><?= $this->url->link('K<span>B</span>', 'app', 'index', array(), false, 'logo', t('Dashboard')).' '.$this->e($title) ?>
|
||||
<?php if (! empty($description)): ?>
|
||||
<span class="tooltip" title='<?= $this->e($this->text->markdown($description)) ?>'>
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</span>
|
||||
<?php endif ?>
|
||||
</h1>
|
||||
<ul>
|
||||
<?php if (isset($board_selector) && ! empty($board_selector)): ?>
|
||||
<li>
|
||||
<select id="board-selector"
|
||||
class="chosen-select select-auto-redirect"
|
||||
tabindex="-1"
|
||||
data-notfound="<?= t('No results match:') ?>"
|
||||
data-placeholder="<?= t('Display another project') ?>"
|
||||
data-redirect-regex="PROJECT_ID"
|
||||
data-redirect-url="<?= $this->url->href('board', 'show', array('project_id' => 'PROJECT_ID')) ?>">
|
||||
<option value=""></option>
|
||||
<?php foreach($board_selector as $board_id => $board_name): ?>
|
||||
<option value="<?= $board_id ?>"><?= $this->e($board_name) ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
<li>
|
||||
<?= $this->url->link(t('Logout'), 'auth', 'logout') ?>
|
||||
<span class="username hide-tablet">(<?= $this->user->getProfileLink() ?>)</span>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
|
@ -28,6 +28,8 @@
|
|||
<link rel="apple-touch-icon" sizes="144x144" href="<?= $this->url->dir() ?>assets/img/touch-icon-ipad-retina.png">
|
||||
|
||||
<title><?= isset($title) ? $this->e($title) : 'Kanboard' ?></title>
|
||||
|
||||
<?= $this->hook->render('layout:head') ?>
|
||||
</head>
|
||||
<body data-status-url="<?= $this->url->href('app', 'status') ?>"
|
||||
data-login-url="<?= $this->url->href('auth', 'login') ?>"
|
||||
|
|
@ -38,43 +40,17 @@
|
|||
<?php if (isset($no_layout) && $no_layout): ?>
|
||||
<?= $content_for_layout ?>
|
||||
<?php else: ?>
|
||||
<header>
|
||||
<nav>
|
||||
<h1><?= $this->url->link('K<span>B</span>', 'app', 'index', array(), false, 'logo', t('Dashboard')).' '.$this->e($title) ?>
|
||||
<?php if (! empty($description)): ?>
|
||||
<span class="tooltip" title='<?= $this->e($this->text->markdown($description)) ?>'>
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</span>
|
||||
<?php endif ?>
|
||||
</h1>
|
||||
<ul>
|
||||
<?php if (isset($board_selector) && ! empty($board_selector)): ?>
|
||||
<li>
|
||||
<select id="board-selector"
|
||||
class="chosen-select select-auto-redirect"
|
||||
tabindex="-1"
|
||||
data-notfound="<?= t('No results match:') ?>"
|
||||
data-placeholder="<?= t('Display another project') ?>"
|
||||
data-redirect-regex="PROJECT_ID"
|
||||
data-redirect-url="<?= $this->url->href('board', 'show', array('project_id' => 'PROJECT_ID')) ?>">
|
||||
<option value=""></option>
|
||||
<?php foreach($board_selector as $board_id => $board_name): ?>
|
||||
<option value="<?= $board_id ?>"><?= $this->e($board_name) ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
<li>
|
||||
<?= $this->url->link(t('Logout'), 'auth', 'logout') ?>
|
||||
<span class="username hide-tablet">(<?= $this->user->getProfileLink() ?>)</span>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
<?= $this->hook->render('layout:top') ?>
|
||||
<?= $this->render('header', array(
|
||||
'title' => $title,
|
||||
'description' => isset($description) ? $description : '',
|
||||
'board_selector' => $board_selector,
|
||||
)) ?>
|
||||
<section class="page">
|
||||
<?= $this->app->flashMessage() ?>
|
||||
<?= $content_for_layout ?>
|
||||
</section>
|
||||
<?= $this->hook->render('layout:bottom') ?>
|
||||
<?php endif ?>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -9,21 +9,23 @@
|
|||
</li>
|
||||
<?php endif ?>
|
||||
|
||||
<?= $this->hook->render('project:dropdown', array('project' => $project)) ?>
|
||||
|
||||
<?php if ($this->user->isProjectManagementAllowed($project['id'])): ?>
|
||||
<li>
|
||||
<i class="fa fa-line-chart fa-fw"></i>
|
||||
<?= $this->url->link(t('Analytics'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-pie-chart fa-fw"></i>
|
||||
<?= $this->url->link(t('Budget'), 'budget', 'index', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-download fa-fw"></i>
|
||||
<?= $this->url->link(t('Exports'), 'export', 'tasks', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-cog fa-fw"></i>
|
||||
<?= $this->url->link(t('Settings'), 'project', 'show', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-line-chart fa-fw"></i>
|
||||
<?= $this->url->link(t('Analytics'), 'analytic', 'tasks', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-pie-chart fa-fw"></i>
|
||||
<?= $this->url->link(t('Budget'), 'budget', 'index', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-download fa-fw"></i>
|
||||
<?= $this->url->link(t('Exports'), 'export', 'tasks', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-cog fa-fw"></i>
|
||||
<?= $this->url->link(t('Settings'), 'project', 'show', array('project_id' => $project['id'])) ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@
|
|||
</li>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
|
||||
<?= $this->hook->render('project:sidebar') ?>
|
||||
</ul>
|
||||
<div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div>
|
||||
<div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div>
|
||||
|
|
|
|||
|
|
@ -24,5 +24,7 @@
|
|||
<li <?= $this->app->getRouterAction() === 'closed' ? 'class="active"' : '' ?>>
|
||||
<?= $this->url->link(t('Closed tasks'), 'projectuser', 'closed', $filter) ?>
|
||||
</li>
|
||||
|
||||
<?= $this->hook->render('project-user:sidebar') ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
@ -18,6 +18,8 @@
|
|||
<?= $this->url->link(t('Time tracking'), 'task', 'timetracking', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
|
||||
<?= $this->hook->render('task:sidebar:information') ?>
|
||||
</ul>
|
||||
<h2><?= t('Actions') ?></h2>
|
||||
<ul>
|
||||
|
|
@ -66,6 +68,8 @@
|
|||
<?= $this->url->link(t('Remove'), 'task', 'remove', array('task_id' => $task['id'], 'project_id' => $task['project_id'])) ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
|
||||
<?= $this->hook->render('task:sidebar:actions') ?>
|
||||
</ul>
|
||||
<div class="sidebar-collapse"><a href="#" title="<?= t('Hide sidebar') ?>"><i class="fa fa-chevron-left"></i></a></div>
|
||||
<div class="sidebar-expand" style="display: none"><a href="#" title="<?= t('Expand sidebar') ?>"><i class="fa fa-chevron-right"></i></a></div>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
<?= $this->url->link(t('Persistent connections'), 'user', 'sessions', array('user_id' => $user['id'])) ?>
|
||||
</li>
|
||||
<?php endif ?>
|
||||
|
||||
<?= $this->hook->render('user:sidebar:information') ?>
|
||||
</ul>
|
||||
|
||||
<h2><?= t('Actions') ?></h2>
|
||||
|
|
@ -68,6 +70,8 @@
|
|||
</li>
|
||||
<?php endif ?>
|
||||
|
||||
<?= $this->hook->render('user:sidebar:actions', array('user' => $user)) ?>
|
||||
|
||||
<?php if ($this->user->isAdmin() && ! $this->user->isCurrentUser($user['id'])): ?>
|
||||
<li <?= $this->app->getRouterController() === 'user' && $this->app->getRouterAction() === 'remove' ? 'class="active"' : '' ?>>
|
||||
<?= $this->url->link(t('Remove'), 'user', 'remove', array('user_id' => $user['id'])) ?>
|
||||
|
|
|
|||
120
app/common.php
120
app/common.php
|
|
@ -30,120 +30,8 @@ $container->register(new ServiceProvider\ClassProvider);
|
|||
$container->register(new ServiceProvider\EventDispatcherProvider);
|
||||
|
||||
if (ENABLE_URL_REWRITE) {
|
||||
|
||||
// Dashboard
|
||||
$container['router']->addRoute('dashboard', 'app', 'index');
|
||||
$container['router']->addRoute('dashboard/:user_id', 'app', 'index', array('user_id'));
|
||||
$container['router']->addRoute('dashboard/:user_id/projects', 'app', 'projects', array('user_id'));
|
||||
$container['router']->addRoute('dashboard/:user_id/tasks', 'app', 'tasks', array('user_id'));
|
||||
$container['router']->addRoute('dashboard/:user_id/subtasks', 'app', 'subtasks', array('user_id'));
|
||||
$container['router']->addRoute('dashboard/:user_id/calendar', 'app', 'calendar', array('user_id'));
|
||||
$container['router']->addRoute('dashboard/:user_id/activity', 'app', 'activity', array('user_id'));
|
||||
|
||||
// Search routes
|
||||
$container['router']->addRoute('search', 'search', 'index');
|
||||
$container['router']->addRoute('search/:search', 'search', 'index', array('search'));
|
||||
|
||||
// Project routes
|
||||
$container['router']->addRoute('projects', 'project', 'index');
|
||||
$container['router']->addRoute('project/create', 'project', 'create');
|
||||
$container['router']->addRoute('project/create/:private', 'project', 'create', array('private'));
|
||||
$container['router']->addRoute('project/:project_id', 'project', 'show', array('project_id'));
|
||||
$container['router']->addRoute('p/:project_id', 'project', 'show', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/share', 'project', 'share', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/edit', 'project', 'edit', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/integration', 'project', 'integration', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/users', 'project', 'users', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/duplicate', 'project', 'duplicate', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/remove', 'project', 'remove', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/disable', 'project', 'disable', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/enable', 'project', 'enable', array('project_id'));
|
||||
|
||||
// Action routes
|
||||
$container['router']->addRoute('project/:project_id/actions', 'action', 'index', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/action/:action_id/confirm', 'action', 'confirm', array('project_id', 'action_id'));
|
||||
|
||||
// Column routes
|
||||
$container['router']->addRoute('project/:project_id/columns', 'column', 'index', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/column/:column_id/edit', 'column', 'edit', array('project_id', 'column_id'));
|
||||
$container['router']->addRoute('project/:project_id/column/:column_id/confirm', 'column', 'confirm', array('project_id', 'column_id'));
|
||||
$container['router']->addRoute('project/:project_id/column/:column_id/move/:direction', 'column', 'move', array('project_id', 'column_id', 'direction'));
|
||||
|
||||
// Swimlane routes
|
||||
$container['router']->addRoute('project/:project_id/swimlanes', 'swimlane', 'index', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/edit', 'swimlane', 'edit', array('project_id', 'swimlane_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/confirm', 'swimlane', 'confirm', array('project_id', 'swimlane_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/disable', 'swimlane', 'disable', array('project_id', 'swimlane_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/enable', 'swimlane', 'enable', array('project_id', 'swimlane_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/up', 'swimlane', 'moveup', array('project_id', 'swimlane_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/down', 'swimlane', 'movedown', array('project_id', 'swimlane_id'));
|
||||
|
||||
// Category routes
|
||||
$container['router']->addRoute('project/:project_id/categories', 'category', 'index', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/category/:category_id/edit', 'category', 'edit', array('project_id', 'category_id'));
|
||||
$container['router']->addRoute('project/:project_id/category/:category_id/confirm', 'category', 'confirm', array('project_id', 'category_id'));
|
||||
|
||||
// Task routes
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id', 'task', 'show', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('t/:task_id', 'task', 'show', array('task_id'));
|
||||
$container['router']->addRoute('public/task/:task_id/:token', 'task', 'readonly', array('task_id', 'token'));
|
||||
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/activity', 'activity', 'task', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/screenshot', 'file', 'screenshot', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/upload', 'file', 'create', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/comment', 'comment', 'create', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/link', 'tasklink', 'create', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/transitions', 'task', 'transitions', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/analytics', 'task', 'analytics', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/remove', 'task', 'remove', array('project_id', 'task_id'));
|
||||
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/edit', 'taskmodification', 'edit', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/description', 'taskmodification', 'description', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/recurrence', 'taskmodification', 'recurrence', array('project_id', 'task_id'));
|
||||
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/close', 'taskstatus', 'close', array('task_id', 'project_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/open', 'taskstatus', 'open', array('task_id', 'project_id'));
|
||||
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/duplicate', 'taskduplication', 'duplicate', array('task_id', 'project_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/copy', 'taskduplication', 'copy', array('task_id', 'project_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/copy/:dst_project_id', 'taskduplication', 'copy', array('task_id', 'project_id', 'dst_project_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/move', 'taskduplication', 'move', array('task_id', 'project_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/move/:dst_project_id', 'taskduplication', 'move', array('task_id', 'project_id', 'dst_project_id'));
|
||||
|
||||
// Board routes
|
||||
$container['router']->addRoute('board/:project_id', 'board', 'show', array('project_id'));
|
||||
$container['router']->addRoute('b/:project_id', 'board', 'show', array('project_id'));
|
||||
$container['router']->addRoute('public/board/:token', 'board', 'readonly', array('token'));
|
||||
|
||||
// Calendar routes
|
||||
$container['router']->addRoute('calendar/:project_id', 'calendar', 'show', array('project_id'));
|
||||
$container['router']->addRoute('c/:project_id', 'calendar', 'show', array('project_id'));
|
||||
|
||||
// Listing routes
|
||||
$container['router']->addRoute('list/:project_id', 'listing', 'show', array('project_id'));
|
||||
$container['router']->addRoute('l/:project_id', 'listing', 'show', array('project_id'));
|
||||
|
||||
// Gantt routes
|
||||
$container['router']->addRoute('gantt/:project_id', 'gantt', 'project', array('project_id'));
|
||||
$container['router']->addRoute('gantt/:project_id/sort/:sorting', 'gantt', 'project', array('project_id', 'sorting'));
|
||||
|
||||
// Subtask routes
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/subtask/create', 'subtask', 'create', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/remove', 'subtask', 'confirm', array('project_id', 'task_id', 'subtask_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/edit', 'subtask', 'edit', array('project_id', 'task_id', 'subtask_id'));
|
||||
|
||||
// Feed routes
|
||||
$container['router']->addRoute('feed/project/:token', 'feed', 'project', array('token'));
|
||||
$container['router']->addRoute('feed/user/:token', 'feed', 'user', array('token'));
|
||||
|
||||
// Ical routes
|
||||
$container['router']->addRoute('ical/project/:token', 'ical', 'project', array('token'));
|
||||
$container['router']->addRoute('ical/user/:token', 'ical', 'user', array('token'));
|
||||
|
||||
// Auth routes
|
||||
$container['router']->addRoute('oauth/google', 'oauth', 'google');
|
||||
$container['router']->addRoute('oauth/github', 'oauth', 'github');
|
||||
$container['router']->addRoute('oauth/gitlab', 'oauth', 'gitlab');
|
||||
$container['router']->addRoute('login', 'auth', 'login');
|
||||
$container['router']->addRoute('logout', 'auth', 'logout');
|
||||
require __DIR__.'/routes.php';
|
||||
}
|
||||
|
||||
$plugin = new Core\PluginLoader($container);
|
||||
$plugin->scan();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
// Dashboard
|
||||
$container['router']->addRoute('dashboard', 'app', 'index');
|
||||
$container['router']->addRoute('dashboard/:user_id', 'app', 'index', array('user_id'));
|
||||
$container['router']->addRoute('dashboard/:user_id/projects', 'app', 'projects', array('user_id'));
|
||||
$container['router']->addRoute('dashboard/:user_id/tasks', 'app', 'tasks', array('user_id'));
|
||||
$container['router']->addRoute('dashboard/:user_id/subtasks', 'app', 'subtasks', array('user_id'));
|
||||
$container['router']->addRoute('dashboard/:user_id/calendar', 'app', 'calendar', array('user_id'));
|
||||
$container['router']->addRoute('dashboard/:user_id/activity', 'app', 'activity', array('user_id'));
|
||||
|
||||
// Search routes
|
||||
$container['router']->addRoute('search', 'search', 'index');
|
||||
$container['router']->addRoute('search/:search', 'search', 'index', array('search'));
|
||||
|
||||
// Project routes
|
||||
$container['router']->addRoute('projects', 'project', 'index');
|
||||
$container['router']->addRoute('project/create', 'project', 'create');
|
||||
$container['router']->addRoute('project/create/:private', 'project', 'create', array('private'));
|
||||
$container['router']->addRoute('project/:project_id', 'project', 'show', array('project_id'));
|
||||
$container['router']->addRoute('p/:project_id', 'project', 'show', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/share', 'project', 'share', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/edit', 'project', 'edit', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/integration', 'project', 'integration', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/users', 'project', 'users', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/duplicate', 'project', 'duplicate', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/remove', 'project', 'remove', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/disable', 'project', 'disable', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/enable', 'project', 'enable', array('project_id'));
|
||||
|
||||
// Action routes
|
||||
$container['router']->addRoute('project/:project_id/actions', 'action', 'index', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/action/:action_id/confirm', 'action', 'confirm', array('project_id', 'action_id'));
|
||||
|
||||
// Column routes
|
||||
$container['router']->addRoute('project/:project_id/columns', 'column', 'index', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/column/:column_id/edit', 'column', 'edit', array('project_id', 'column_id'));
|
||||
$container['router']->addRoute('project/:project_id/column/:column_id/confirm', 'column', 'confirm', array('project_id', 'column_id'));
|
||||
$container['router']->addRoute('project/:project_id/column/:column_id/move/:direction', 'column', 'move', array('project_id', 'column_id', 'direction'));
|
||||
|
||||
// Swimlane routes
|
||||
$container['router']->addRoute('project/:project_id/swimlanes', 'swimlane', 'index', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/edit', 'swimlane', 'edit', array('project_id', 'swimlane_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/confirm', 'swimlane', 'confirm', array('project_id', 'swimlane_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/disable', 'swimlane', 'disable', array('project_id', 'swimlane_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/enable', 'swimlane', 'enable', array('project_id', 'swimlane_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/up', 'swimlane', 'moveup', array('project_id', 'swimlane_id'));
|
||||
$container['router']->addRoute('project/:project_id/swimlane/:swimlane_id/down', 'swimlane', 'movedown', array('project_id', 'swimlane_id'));
|
||||
|
||||
// Category routes
|
||||
$container['router']->addRoute('project/:project_id/categories', 'category', 'index', array('project_id'));
|
||||
$container['router']->addRoute('project/:project_id/category/:category_id/edit', 'category', 'edit', array('project_id', 'category_id'));
|
||||
$container['router']->addRoute('project/:project_id/category/:category_id/confirm', 'category', 'confirm', array('project_id', 'category_id'));
|
||||
|
||||
// Task routes
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id', 'task', 'show', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('t/:task_id', 'task', 'show', array('task_id'));
|
||||
$container['router']->addRoute('public/task/:task_id/:token', 'task', 'readonly', array('task_id', 'token'));
|
||||
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/activity', 'activity', 'task', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/screenshot', 'file', 'screenshot', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/upload', 'file', 'create', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/comment', 'comment', 'create', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/link', 'tasklink', 'create', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/transitions', 'task', 'transitions', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/analytics', 'task', 'analytics', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/remove', 'task', 'remove', array('project_id', 'task_id'));
|
||||
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/edit', 'taskmodification', 'edit', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/description', 'taskmodification', 'description', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/recurrence', 'taskmodification', 'recurrence', array('project_id', 'task_id'));
|
||||
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/close', 'taskstatus', 'close', array('task_id', 'project_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/open', 'taskstatus', 'open', array('task_id', 'project_id'));
|
||||
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/duplicate', 'taskduplication', 'duplicate', array('task_id', 'project_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/copy', 'taskduplication', 'copy', array('task_id', 'project_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/copy/:dst_project_id', 'taskduplication', 'copy', array('task_id', 'project_id', 'dst_project_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/move', 'taskduplication', 'move', array('task_id', 'project_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/move/:dst_project_id', 'taskduplication', 'move', array('task_id', 'project_id', 'dst_project_id'));
|
||||
|
||||
// Board routes
|
||||
$container['router']->addRoute('board/:project_id', 'board', 'show', array('project_id'));
|
||||
$container['router']->addRoute('b/:project_id', 'board', 'show', array('project_id'));
|
||||
$container['router']->addRoute('public/board/:token', 'board', 'readonly', array('token'));
|
||||
|
||||
// Calendar routes
|
||||
$container['router']->addRoute('calendar/:project_id', 'calendar', 'show', array('project_id'));
|
||||
$container['router']->addRoute('c/:project_id', 'calendar', 'show', array('project_id'));
|
||||
|
||||
// Listing routes
|
||||
$container['router']->addRoute('list/:project_id', 'listing', 'show', array('project_id'));
|
||||
$container['router']->addRoute('l/:project_id', 'listing', 'show', array('project_id'));
|
||||
|
||||
// Gantt routes
|
||||
$container['router']->addRoute('gantt/:project_id', 'gantt', 'project', array('project_id'));
|
||||
$container['router']->addRoute('gantt/:project_id/sort/:sorting', 'gantt', 'project', array('project_id', 'sorting'));
|
||||
|
||||
// Subtask routes
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/subtask/create', 'subtask', 'create', array('project_id', 'task_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/remove', 'subtask', 'confirm', array('project_id', 'task_id', 'subtask_id'));
|
||||
$container['router']->addRoute('project/:project_id/task/:task_id/subtask/:subtask_id/edit', 'subtask', 'edit', array('project_id', 'task_id', 'subtask_id'));
|
||||
|
||||
// Feed routes
|
||||
$container['router']->addRoute('feed/project/:token', 'feed', 'project', array('token'));
|
||||
$container['router']->addRoute('feed/user/:token', 'feed', 'user', array('token'));
|
||||
|
||||
// Ical routes
|
||||
$container['router']->addRoute('ical/project/:token', 'ical', 'project', array('token'));
|
||||
$container['router']->addRoute('ical/user/:token', 'ical', 'user', array('token'));
|
||||
|
||||
// Auth routes
|
||||
$container['router']->addRoute('oauth/google', 'oauth', 'google');
|
||||
$container['router']->addRoute('oauth/github', 'oauth', 'github');
|
||||
$container['router']->addRoute('oauth/gitlab', 'oauth', 'gitlab');
|
||||
$container['router']->addRoute('login', 'auth', 'login');
|
||||
$container['router']->addRoute('logout', 'auth', 'logout');
|
||||
|
|
@ -19,6 +19,10 @@
|
|||
"gregwar/captcha": "1.*"
|
||||
},
|
||||
"autoload" : {
|
||||
"classmap" : ["app/"],
|
||||
"psr-4" : {
|
||||
"Plugin\\": "plugins/"
|
||||
},
|
||||
"psr-0" : {
|
||||
"" : "app/"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!/.gitignore
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__.'/../Base.php';
|
||||
|
||||
use Core\PluginLoader;
|
||||
|
||||
class PluginLoaderTest extends Base
|
||||
{
|
||||
public function testGetSchemaVersion()
|
||||
{
|
||||
$p = new PluginLoader($this->container);
|
||||
$this->assertEquals(0, $p->getSchemaVersion('not_found'));
|
||||
|
||||
$this->assertTrue($p->setSchemaVersion('plugin1', 1));
|
||||
$this->assertEquals(1, $p->getSchemaVersion('plugin1'));
|
||||
|
||||
$this->assertTrue($p->setSchemaVersion('plugin2', 33));
|
||||
$this->assertEquals(33, $p->getSchemaVersion('plugin2'));
|
||||
|
||||
$this->assertTrue($p->setSchemaVersion('plugin1', 2));
|
||||
$this->assertEquals(2, $p->getSchemaVersion('plugin1'));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__.'/../Base.php';
|
||||
|
||||
use Core\Template;
|
||||
|
||||
class TemplateTest extends Base
|
||||
{
|
||||
public function testGetTemplateFile()
|
||||
{
|
||||
$t = new Template($this->container);
|
||||
$this->assertStringEndsWith('app/Core/../Template/a/b.php', $t->getTemplateFile('a/b'));
|
||||
}
|
||||
|
||||
public function testGetPluginTemplateFile()
|
||||
{
|
||||
$t = new Template($this->container);
|
||||
$this->assertStringEndsWith('app/Core/../../plugins/Myplugin/Template/a/b.php', $t->getTemplateFile('myplugin:a/b'));
|
||||
}
|
||||
|
||||
public function testGetOverridedTemplateFile()
|
||||
{
|
||||
$t = new Template($this->container);
|
||||
$t->setTemplateOverride('a/b', 'myplugin:c');
|
||||
$this->assertStringEndsWith('app/Core/../../plugins/Myplugin/Template/c.php', $t->getTemplateFile('a/b'));
|
||||
$this->assertStringEndsWith('app/Core/../Template/d.php', $t->getTemplateFile('d'));
|
||||
}
|
||||
}
|
||||
|
|
@ -290,4 +290,16 @@ class AclTest extends Base
|
|||
$this->assertFalse($acl->isAllowed('task', 'remove', 1));
|
||||
$this->assertTrue($acl->isAllowed('app', 'index', 1));
|
||||
}
|
||||
|
||||
public function testExtend()
|
||||
{
|
||||
$acl = new Acl($this->container);
|
||||
|
||||
$this->assertFalse($acl->isProjectManagerAction('plop', 'show'));
|
||||
|
||||
$acl->extend('project_manager_acl', array('plop' => '*'));
|
||||
|
||||
$this->assertTrue($acl->isProjectManagerAction('plop', 'show'));
|
||||
$this->assertTrue($acl->isProjectManagerAction('swimlane', 'index'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class ProjectTest extends Base
|
|||
$this->assertNotFalse($p->create(array('name' => 'UnitTest '.$locale)), 'Unable to create project with '.$locale.':'.$language);
|
||||
}
|
||||
|
||||
Translator::load('en_US');
|
||||
Translator::unload();
|
||||
}
|
||||
|
||||
public function testCreation()
|
||||
|
|
|
|||
Loading…
Reference in New Issue