Run unit tests across different database backends + fix bugs
This commit is contained in:
parent
5f962bf4cd
commit
e1ddf7f012
|
|
@ -7,4 +7,4 @@ php:
|
|||
- "5.3"
|
||||
|
||||
before_script: wget https://phar.phpunit.de/phpunit.phar
|
||||
script: php phpunit.phar
|
||||
script: php phpunit.phar -c tests/units.sqlite.xml
|
||||
|
|
@ -58,12 +58,12 @@ Documentation
|
|||
#### Installation
|
||||
|
||||
- [Installation instructions](docs/installation.markdown)
|
||||
- [Upgrade Kanboard to a new version](docs/update.markdown)
|
||||
- [Installation on Ubuntu](docs/ubuntu-installation.markdown)
|
||||
- [Installation on Debian](docs/debian-installation.markdown)
|
||||
- [Installation on Centos](docs/centos-installation.markdown)
|
||||
- [Installation on Windows Server with IIS](docs/windows-iis-installation.markdown)
|
||||
- [Upgrade Kanboard to a new version](docs/update.markdown)
|
||||
- [Secure connections (HTTPS)](docs/secure-connections.markdown)
|
||||
- [Example with Nginx + HTTPS + SPDY + PHP-FPM](docs/secure-connections.markdown)
|
||||
|
||||
#### Database
|
||||
|
||||
|
|
|
|||
|
|
@ -10,18 +10,30 @@ namespace Core;
|
|||
*/
|
||||
class Loader
|
||||
{
|
||||
/**
|
||||
* List of paths
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $paths = array();
|
||||
|
||||
/**
|
||||
* Load the missing class
|
||||
*
|
||||
* @access public
|
||||
* @param string $class Class name
|
||||
* @param string $class Class name with namespace
|
||||
*/
|
||||
public function load($class)
|
||||
{
|
||||
$filename = __DIR__.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php';
|
||||
foreach ($this->paths as $path) {
|
||||
|
||||
if (file_exists($filename)) {
|
||||
require $filename;
|
||||
$filename = $path.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php';
|
||||
|
||||
if (file_exists($filename)) {
|
||||
require $filename;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -34,4 +46,17 @@ class Loader
|
|||
{
|
||||
spl_autoload_register(array($this, 'load'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new path
|
||||
*
|
||||
* @access public
|
||||
* @param string $path Path
|
||||
* @return Core\Loader
|
||||
*/
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->paths[] = $path;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -553,7 +553,8 @@ class Project extends Base
|
|||
*/
|
||||
public function update(array $values)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('id', $values['id'])->save($values);
|
||||
return $this->exists($values['id']) &&
|
||||
$this->db->table(self::TABLE)->eq('id', $values['id'])->save($values);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -568,6 +569,18 @@ class Project extends Base
|
|||
return $this->db->table(self::TABLE)->eq('id', $project_id)->remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the project exists
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id Project id
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists($project_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('id', $project_id)->count() === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a project
|
||||
*
|
||||
|
|
@ -577,10 +590,11 @@ class Project extends Base
|
|||
*/
|
||||
public function enable($project_id)
|
||||
{
|
||||
return $this->db
|
||||
return $this->exists($project_id) &&
|
||||
$this->db
|
||||
->table(self::TABLE)
|
||||
->eq('id', $project_id)
|
||||
->save(array('is_active' => 1));
|
||||
->update(array('is_active' => 1));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -592,10 +606,11 @@ class Project extends Base
|
|||
*/
|
||||
public function disable($project_id)
|
||||
{
|
||||
return $this->db
|
||||
return $this->exists($project_id) &&
|
||||
$this->db
|
||||
->table(self::TABLE)
|
||||
->eq('id', $project_id)
|
||||
->save(array('is_active' => 0));
|
||||
->update(array('is_active' => 0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -607,7 +622,8 @@ class Project extends Base
|
|||
*/
|
||||
public function enablePublicAccess($project_id)
|
||||
{
|
||||
return $this->db
|
||||
return $this->exists($project_id) &&
|
||||
$this->db
|
||||
->table(self::TABLE)
|
||||
->eq('id', $project_id)
|
||||
->save(array('is_public' => 1, 'token' => Security::generateToken()));
|
||||
|
|
@ -622,7 +638,8 @@ class Project extends Base
|
|||
*/
|
||||
public function disablePublicAccess($project_id)
|
||||
{
|
||||
return $this->db
|
||||
return $this->exists($project_id) &&
|
||||
$this->db
|
||||
->table(self::TABLE)
|
||||
->eq('id', $project_id)
|
||||
->save(array('is_public' => 0, 'token' => ''));
|
||||
|
|
|
|||
|
|
@ -150,16 +150,16 @@ class Task extends Base
|
|||
* Count all tasks for a given project and status
|
||||
*
|
||||
* @access public
|
||||
* @param integer $project_id Project id
|
||||
* @param array $status List of status id
|
||||
* @param integer $project_id Project id
|
||||
* @param integer $status_id Status id
|
||||
* @return array
|
||||
*/
|
||||
public function getAll($project_id, array $status = array(self::STATUS_OPEN, self::STATUS_CLOSED))
|
||||
public function getAll($project_id, $status_id = self::STATUS_OPEN)
|
||||
{
|
||||
return $this->db
|
||||
->table(self::TABLE)
|
||||
->eq('project_id', $project_id)
|
||||
->in('is_active', $status)
|
||||
->eq('is_active', $status_id)
|
||||
->findAll();
|
||||
}
|
||||
|
||||
|
|
@ -382,6 +382,10 @@ class Task extends Base
|
|||
if (isset($values['score']) && empty($values['score'])) {
|
||||
$values['score'] = 0;
|
||||
}
|
||||
|
||||
if (isset($values['is_active'])) {
|
||||
$values['is_active'] = (int) $values['is_active'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -487,6 +491,18 @@ class Task extends Base
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the project exists
|
||||
*
|
||||
* @access public
|
||||
* @param integer $task_id Task id
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists($task_id)
|
||||
{
|
||||
return $this->db->table(self::TABLE)->eq('id', $task_id)->count() === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a task closed
|
||||
*
|
||||
|
|
@ -496,6 +512,10 @@ class Task extends Base
|
|||
*/
|
||||
public function close($task_id)
|
||||
{
|
||||
if (! $this->exists($task_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $this->db
|
||||
->table(self::TABLE)
|
||||
->eq('id', $task_id)
|
||||
|
|
@ -520,12 +540,16 @@ class Task extends Base
|
|||
*/
|
||||
public function open($task_id)
|
||||
{
|
||||
if (! $this->exists($task_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $this->db
|
||||
->table(self::TABLE)
|
||||
->eq('id', $task_id)
|
||||
->update(array(
|
||||
'is_active' => 1,
|
||||
'date_completed' => ''
|
||||
'date_completed' => 0
|
||||
));
|
||||
|
||||
if ($result) {
|
||||
|
|
@ -544,6 +568,10 @@ class Task extends Base
|
|||
*/
|
||||
public function remove($task_id)
|
||||
{
|
||||
if (! $this->exists($task_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->file->removeAll($task_id);
|
||||
|
||||
return $this->db->table(self::TABLE)->eq('id', $task_id)->remove();
|
||||
|
|
|
|||
|
|
@ -33,8 +33,3 @@ if (! extension_loaded('mbstring')) {
|
|||
if (! is_writable('data')) {
|
||||
die('The directory "data" must be writeable by your web server user');
|
||||
}
|
||||
|
||||
// Include password_compat for PHP < 5.5
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '<')) {
|
||||
require __DIR__.'/../vendor/password.php';
|
||||
}
|
||||
|
|
|
|||
179
app/common.php
179
app/common.php
|
|
@ -1,183 +1,32 @@
|
|||
<?php
|
||||
|
||||
// Common file between cli and web interface
|
||||
|
||||
require __DIR__.'/Core/Loader.php';
|
||||
require __DIR__.'/helpers.php';
|
||||
require __DIR__.'/translator.php';
|
||||
require __DIR__.'/functions.php';
|
||||
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validator.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Base.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/Required.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/Unique.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/MaxLength.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/MinLength.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/Integer.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/Equals.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/AlphaNumeric.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/GreaterThan.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/Date.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/Email.php';
|
||||
require __DIR__.'/../vendor/SimpleValidator/Validators/Numeric.php';
|
||||
|
||||
use Core\Event;
|
||||
use Core\Loader;
|
||||
use Core\Registry;
|
||||
|
||||
// Include password_compat for PHP < 5.5
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '<')) {
|
||||
require __DIR__.'/../vendor/password.php';
|
||||
}
|
||||
|
||||
// Include custom config file
|
||||
if (file_exists('config.php')) {
|
||||
require 'config.php';
|
||||
}
|
||||
|
||||
// Board refresh frequency in seconds for the public board view
|
||||
defined('BOARD_PUBLIC_CHECK_INTERVAL') or define('BOARD_PUBLIC_CHECK_INTERVAL', 60);
|
||||
|
||||
// Board refresh frequency in seconds (the value 0 disable this feature)
|
||||
defined('BOARD_CHECK_INTERVAL') or define('BOARD_CHECK_INTERVAL', 10);
|
||||
|
||||
// Period (in second) to consider a task was modified recently
|
||||
defined('RECENT_TASK_PERIOD') or define('RECENT_TASK_PERIOD', 48*60*60);
|
||||
|
||||
// Custom session save path
|
||||
defined('SESSION_SAVE_PATH') or define('SESSION_SAVE_PATH', '');
|
||||
|
||||
// Application version
|
||||
defined('APP_VERSION') or define('APP_VERSION', 'master');
|
||||
|
||||
// Base directory
|
||||
define('BASE_URL_DIRECTORY', dirname($_SERVER['PHP_SELF']));
|
||||
|
||||
// Database driver: sqlite or mysql
|
||||
defined('DB_DRIVER') or define('DB_DRIVER', 'sqlite');
|
||||
|
||||
// Sqlite configuration
|
||||
defined('DB_FILENAME') or define('DB_FILENAME', 'data/db.sqlite');
|
||||
|
||||
// Mysql configuration
|
||||
defined('DB_USERNAME') or define('DB_USERNAME', 'root');
|
||||
defined('DB_PASSWORD') or define('DB_PASSWORD', '');
|
||||
defined('DB_HOSTNAME') or define('DB_HOSTNAME', 'localhost');
|
||||
defined('DB_NAME') or define('DB_NAME', 'kanboard');
|
||||
|
||||
// LDAP configuration
|
||||
defined('LDAP_AUTH') or define('LDAP_AUTH', false);
|
||||
defined('LDAP_SERVER') or define('LDAP_SERVER', '');
|
||||
defined('LDAP_PORT') or define('LDAP_PORT', 389);
|
||||
defined('LDAP_SSL_VERIFY') or define('LDAP_SSL_VERIFY', true);
|
||||
defined('LDAP_BIND_TYPE') or define('LDAP_BIND_TYPE', 'anonymous');
|
||||
defined('LDAP_USERNAME') or define('LDAP_USERNAME', null);
|
||||
defined('LDAP_PASSWORD') or define('LDAP_PASSWORD', null);
|
||||
defined('LDAP_ACCOUNT_BASE') or define('LDAP_ACCOUNT_BASE', '');
|
||||
defined('LDAP_USER_PATTERN') or define('LDAP_USER_PATTERN', '');
|
||||
defined('LDAP_ACCOUNT_FULLNAME') or define('LDAP_ACCOUNT_FULLNAME', 'displayname');
|
||||
defined('LDAP_ACCOUNT_EMAIL') or define('LDAP_ACCOUNT_EMAIL', 'mail');
|
||||
|
||||
// Google authentication
|
||||
defined('GOOGLE_AUTH') or define('GOOGLE_AUTH', false);
|
||||
defined('GOOGLE_CLIENT_ID') or define('GOOGLE_CLIENT_ID', '');
|
||||
defined('GOOGLE_CLIENT_SECRET') or define('GOOGLE_CLIENT_SECRET', '');
|
||||
|
||||
// GitHub authentication
|
||||
defined('GITHUB_AUTH') or define('GITHUB_AUTH', false);
|
||||
defined('GITHUB_CLIENT_ID') or define('GITHUB_CLIENT_ID', '');
|
||||
defined('GITHUB_CLIENT_SECRET') or define('GITHUB_CLIENT_SECRET', '');
|
||||
|
||||
// Proxy authentication
|
||||
defined('REVERSE_PROXY_AUTH') or define('REVERSE_PROXY_AUTH', false);
|
||||
defined('REVERSE_PROXY_USER_HEADER') or define('REVERSE_PROXY_USER_HEADER', 'REMOTE_USER');
|
||||
defined('REVERSE_PROXY_DEFAULT_ADMIN') or define('REVERSE_PROXY_DEFAULT_ADMIN', '');
|
||||
defined('REVERSE_PROXY_DEFAULT_DOMAIN') or define('REVERSE_PROXY_DEFAULT_DOMAIN', '');
|
||||
|
||||
// Mail configuration
|
||||
defined('MAIL_FROM') or define('MAIL_FROM', 'notifications@kanboard.net');
|
||||
defined('MAIL_TRANSPORT') or define('MAIL_TRANSPORT', 'mail');
|
||||
defined('MAIL_SMTP_HOSTNAME') or define('MAIL_SMTP_HOSTNAME', '');
|
||||
defined('MAIL_SMTP_PORT') or define('MAIL_SMTP_PORT', 25);
|
||||
defined('MAIL_SMTP_USERNAME') or define('MAIL_SMTP_USERNAME', '');
|
||||
defined('MAIL_SMTP_PASSWORD') or define('MAIL_SMTP_PASSWORD', '');
|
||||
defined('MAIL_SMTP_ENCRYPTION') or define('MAIL_SMTP_ENCRYPTION', null);
|
||||
defined('MAIL_SENDMAIL_COMMAND') or define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs');
|
||||
require __DIR__.'/constants.php';
|
||||
|
||||
$loader = new Loader;
|
||||
$loader->setPath('app');
|
||||
$loader->setPath('vendor');
|
||||
$loader->execute();
|
||||
|
||||
$registry = new Registry;
|
||||
|
||||
$registry->db = function() use ($registry) {
|
||||
require __DIR__.'/../vendor/PicoDb/Database.php';
|
||||
|
||||
switch (DB_DRIVER) {
|
||||
case 'sqlite':
|
||||
require __DIR__.'/Schema/Sqlite.php';
|
||||
|
||||
$params = array(
|
||||
'driver' => 'sqlite',
|
||||
'filename' => DB_FILENAME
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 'mysql':
|
||||
require __DIR__.'/Schema/Mysql.php';
|
||||
|
||||
$params = array(
|
||||
'driver' => 'mysql',
|
||||
'hostname' => DB_HOSTNAME,
|
||||
'username' => DB_USERNAME,
|
||||
'password' => DB_PASSWORD,
|
||||
'database' => DB_NAME,
|
||||
'charset' => 'utf8',
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 'postgres':
|
||||
require __DIR__.'/Schema/Postgres.php';
|
||||
|
||||
$params = array(
|
||||
'driver' => 'postgres',
|
||||
'hostname' => DB_HOSTNAME,
|
||||
'username' => DB_USERNAME,
|
||||
'password' => DB_PASSWORD,
|
||||
'database' => DB_NAME,
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
die('Database driver not supported');
|
||||
}
|
||||
|
||||
$db = new \PicoDb\Database($params);
|
||||
|
||||
if ($db->schema()->check(Schema\VERSION)) {
|
||||
return $db;
|
||||
}
|
||||
else {
|
||||
$errors = $db->getLogMessages();
|
||||
die('Unable to migrate database schema: <br/><br/><strong>'.(isset($errors[0]) ? $errors[0] : 'Unknown error').'</strong>');
|
||||
}
|
||||
};
|
||||
|
||||
$registry->event = function() use ($registry) {
|
||||
return new Event;
|
||||
};
|
||||
|
||||
$registry->mailer = function() use ($registry) {
|
||||
|
||||
require_once 'vendor/swiftmailer/swift_required.php';
|
||||
|
||||
switch (MAIL_TRANSPORT) {
|
||||
case 'smtp':
|
||||
$transport = Swift_SmtpTransport::newInstance(MAIL_SMTP_HOSTNAME, MAIL_SMTP_PORT);
|
||||
$transport->setUsername(MAIL_SMTP_USERNAME);
|
||||
$transport->setPassword(MAIL_SMTP_PASSWORD);
|
||||
$transport->setEncryption(MAIL_SMTP_ENCRYPTION);
|
||||
break;
|
||||
case 'sendmail':
|
||||
$transport = Swift_SendmailTransport::newInstance(MAIL_SENDMAIL_COMMAND);
|
||||
break;
|
||||
default:
|
||||
$transport = Swift_MailTransport::newInstance();
|
||||
}
|
||||
|
||||
return $transport;
|
||||
};
|
||||
$registry->db = setup_db();
|
||||
$registry->event = setup_events();
|
||||
$registry->mailer = setup_mailer();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
// Board refresh frequency in seconds for the public board view
|
||||
defined('BOARD_PUBLIC_CHECK_INTERVAL') or define('BOARD_PUBLIC_CHECK_INTERVAL', 60);
|
||||
|
||||
// Board refresh frequency in seconds (the value 0 disable this feature)
|
||||
defined('BOARD_CHECK_INTERVAL') or define('BOARD_CHECK_INTERVAL', 10);
|
||||
|
||||
// Period (in second) to consider a task was modified recently
|
||||
defined('RECENT_TASK_PERIOD') or define('RECENT_TASK_PERIOD', 48*60*60);
|
||||
|
||||
// Custom session save path
|
||||
defined('SESSION_SAVE_PATH') or define('SESSION_SAVE_PATH', '');
|
||||
|
||||
// Application version
|
||||
defined('APP_VERSION') or define('APP_VERSION', 'master');
|
||||
|
||||
// Base directory
|
||||
define('BASE_URL_DIRECTORY', dirname($_SERVER['PHP_SELF']));
|
||||
|
||||
// Database driver: sqlite or mysql
|
||||
defined('DB_DRIVER') or define('DB_DRIVER', 'sqlite');
|
||||
|
||||
// Sqlite configuration
|
||||
defined('DB_FILENAME') or define('DB_FILENAME', 'data/db.sqlite');
|
||||
|
||||
// Mysql configuration
|
||||
defined('DB_USERNAME') or define('DB_USERNAME', 'root');
|
||||
defined('DB_PASSWORD') or define('DB_PASSWORD', '');
|
||||
defined('DB_HOSTNAME') or define('DB_HOSTNAME', 'localhost');
|
||||
defined('DB_NAME') or define('DB_NAME', 'kanboard');
|
||||
|
||||
// LDAP configuration
|
||||
defined('LDAP_AUTH') or define('LDAP_AUTH', false);
|
||||
defined('LDAP_SERVER') or define('LDAP_SERVER', '');
|
||||
defined('LDAP_PORT') or define('LDAP_PORT', 389);
|
||||
defined('LDAP_SSL_VERIFY') or define('LDAP_SSL_VERIFY', true);
|
||||
defined('LDAP_BIND_TYPE') or define('LDAP_BIND_TYPE', 'anonymous');
|
||||
defined('LDAP_USERNAME') or define('LDAP_USERNAME', null);
|
||||
defined('LDAP_PASSWORD') or define('LDAP_PASSWORD', null);
|
||||
defined('LDAP_ACCOUNT_BASE') or define('LDAP_ACCOUNT_BASE', '');
|
||||
defined('LDAP_USER_PATTERN') or define('LDAP_USER_PATTERN', '');
|
||||
defined('LDAP_ACCOUNT_FULLNAME') or define('LDAP_ACCOUNT_FULLNAME', 'displayname');
|
||||
defined('LDAP_ACCOUNT_EMAIL') or define('LDAP_ACCOUNT_EMAIL', 'mail');
|
||||
|
||||
// Google authentication
|
||||
defined('GOOGLE_AUTH') or define('GOOGLE_AUTH', false);
|
||||
defined('GOOGLE_CLIENT_ID') or define('GOOGLE_CLIENT_ID', '');
|
||||
defined('GOOGLE_CLIENT_SECRET') or define('GOOGLE_CLIENT_SECRET', '');
|
||||
|
||||
// GitHub authentication
|
||||
defined('GITHUB_AUTH') or define('GITHUB_AUTH', false);
|
||||
defined('GITHUB_CLIENT_ID') or define('GITHUB_CLIENT_ID', '');
|
||||
defined('GITHUB_CLIENT_SECRET') or define('GITHUB_CLIENT_SECRET', '');
|
||||
|
||||
// Proxy authentication
|
||||
defined('REVERSE_PROXY_AUTH') or define('REVERSE_PROXY_AUTH', false);
|
||||
defined('REVERSE_PROXY_USER_HEADER') or define('REVERSE_PROXY_USER_HEADER', 'REMOTE_USER');
|
||||
defined('REVERSE_PROXY_DEFAULT_ADMIN') or define('REVERSE_PROXY_DEFAULT_ADMIN', '');
|
||||
defined('REVERSE_PROXY_DEFAULT_DOMAIN') or define('REVERSE_PROXY_DEFAULT_DOMAIN', '');
|
||||
|
||||
// Mail configuration
|
||||
defined('MAIL_FROM') or define('MAIL_FROM', 'notifications@kanboard.net');
|
||||
defined('MAIL_TRANSPORT') or define('MAIL_TRANSPORT', 'mail');
|
||||
defined('MAIL_SMTP_HOSTNAME') or define('MAIL_SMTP_HOSTNAME', '');
|
||||
defined('MAIL_SMTP_PORT') or define('MAIL_SMTP_PORT', 25);
|
||||
defined('MAIL_SMTP_USERNAME') or define('MAIL_SMTP_USERNAME', '');
|
||||
defined('MAIL_SMTP_PASSWORD') or define('MAIL_SMTP_PASSWORD', '');
|
||||
defined('MAIL_SMTP_ENCRYPTION') or define('MAIL_SMTP_ENCRYPTION', null);
|
||||
defined('MAIL_SENDMAIL_COMMAND') or define('MAIL_SENDMAIL_COMMAND', '/usr/sbin/sendmail -bs');
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
use Core\Event;
|
||||
use Core\Translator;
|
||||
use PicoDb\Database;
|
||||
|
||||
function debug($message)
|
||||
{
|
||||
error_log($message.PHP_EOL, 3, 'data/debug.log');
|
||||
}
|
||||
|
||||
function setup_events()
|
||||
{
|
||||
return new Event;
|
||||
}
|
||||
|
||||
function setup_mailer()
|
||||
{
|
||||
require_once __DIR__.'/../vendor/swiftmailer/swift_required.php';
|
||||
|
||||
switch (MAIL_TRANSPORT) {
|
||||
case 'smtp':
|
||||
$transport = Swift_SmtpTransport::newInstance(MAIL_SMTP_HOSTNAME, MAIL_SMTP_PORT);
|
||||
$transport->setUsername(MAIL_SMTP_USERNAME);
|
||||
$transport->setPassword(MAIL_SMTP_PASSWORD);
|
||||
$transport->setEncryption(MAIL_SMTP_ENCRYPTION);
|
||||
break;
|
||||
case 'sendmail':
|
||||
$transport = Swift_SendmailTransport::newInstance(MAIL_SENDMAIL_COMMAND);
|
||||
break;
|
||||
default:
|
||||
$transport = Swift_MailTransport::newInstance();
|
||||
}
|
||||
|
||||
return $transport;
|
||||
}
|
||||
|
||||
function setup_db()
|
||||
{
|
||||
switch (DB_DRIVER) {
|
||||
case 'sqlite':
|
||||
require_once __DIR__.'/Schema/Sqlite.php';
|
||||
|
||||
$params = array(
|
||||
'driver' => 'sqlite',
|
||||
'filename' => DB_FILENAME
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 'mysql':
|
||||
require_once __DIR__.'/Schema/Mysql.php';
|
||||
|
||||
$params = array(
|
||||
'driver' => 'mysql',
|
||||
'hostname' => DB_HOSTNAME,
|
||||
'username' => DB_USERNAME,
|
||||
'password' => DB_PASSWORD,
|
||||
'database' => DB_NAME,
|
||||
'charset' => 'utf8',
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 'postgres':
|
||||
require_once __DIR__.'/Schema/Postgres.php';
|
||||
|
||||
$params = array(
|
||||
'driver' => 'postgres',
|
||||
'hostname' => DB_HOSTNAME,
|
||||
'username' => DB_USERNAME,
|
||||
'password' => DB_PASSWORD,
|
||||
'database' => DB_NAME,
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
die('Database driver not supported');
|
||||
}
|
||||
|
||||
$db = new Database($params);
|
||||
|
||||
if ($db->schema()->check(Schema\VERSION)) {
|
||||
return $db;
|
||||
}
|
||||
else {
|
||||
$errors = $db->getLogMessages();
|
||||
die('Unable to migrate database schema: <br/><br/><strong>'.(isset($errors[0]) ? $errors[0] : 'Unknown error').'</strong>');
|
||||
}
|
||||
}
|
||||
|
||||
// Get a translation
|
||||
function t()
|
||||
{
|
||||
$t = new Translator;
|
||||
return call_user_func_array(array($t, 'translate'), func_get_args());
|
||||
}
|
||||
|
||||
// translate with no html escaping
|
||||
function e()
|
||||
{
|
||||
$t = new Translator;
|
||||
return call_user_func_array(array($t, 'translateNoEscaping'), func_get_args());
|
||||
}
|
||||
|
||||
// Get a locale currency
|
||||
function c($value)
|
||||
{
|
||||
$t = new Translator;
|
||||
return $t->currency($value);
|
||||
}
|
||||
|
||||
// Get a formatted number
|
||||
function n($value)
|
||||
{
|
||||
$t = new Translator;
|
||||
return $t->number($value);
|
||||
}
|
||||
|
||||
// Get a locale date
|
||||
function dt($format, $timestamp)
|
||||
{
|
||||
$t = new Translator;
|
||||
return $t->datetime($format, $timestamp);
|
||||
}
|
||||
|
||||
// Plurals, return $t2 if $value > 1
|
||||
function p($value, $t1, $t2) {
|
||||
return $value > 1 ? $t2 : $t1;
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
<?php
|
||||
|
||||
use Core\Translator;
|
||||
|
||||
// Get a translation
|
||||
function t()
|
||||
{
|
||||
$t = new Translator;
|
||||
return call_user_func_array(array($t, 'translate'), func_get_args());
|
||||
}
|
||||
|
||||
// translate with no html escaping
|
||||
function e()
|
||||
{
|
||||
$t = new Translator;
|
||||
return call_user_func_array(array($t, 'translateNoEscaping'), func_get_args());
|
||||
}
|
||||
|
||||
// Get a locale currency
|
||||
function c($value)
|
||||
{
|
||||
$t = new Translator;
|
||||
return $t->currency($value);
|
||||
}
|
||||
|
||||
// Get a formatted number
|
||||
function n($value)
|
||||
{
|
||||
$t = new Translator;
|
||||
return $t->number($value);
|
||||
}
|
||||
|
||||
// Get a locale date
|
||||
function dt($format, $timestamp)
|
||||
{
|
||||
$t = new Translator;
|
||||
return $t->datetime($format, $timestamp);
|
||||
}
|
||||
|
||||
// Plurals, return $t2 if $value > 1
|
||||
function p($value, $t1, $t2) {
|
||||
return $value > 1 ? $t2 : $t1;
|
||||
}
|
||||
|
|
@ -608,7 +608,7 @@ Response example:
|
|||
- Purpose: **Get all available tasks**
|
||||
- Parameters:
|
||||
- **project_id** (integer, required)
|
||||
- **status**: List of status id, the value 1 for active tasks and 0 for inactive (list, required)
|
||||
- **status**: The value 1 for active tasks and 0 for inactive (integer, required)
|
||||
- Result on success: **List of tasks**
|
||||
- Result on failure: **false**
|
||||
|
||||
|
|
@ -621,9 +621,7 @@ Request example to fetch all tasks on the board:
|
|||
"id": 133280317,
|
||||
"params": {
|
||||
"project_id": 1,
|
||||
"status": [
|
||||
1
|
||||
]
|
||||
"status": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
Centos Installation
|
||||
===================
|
||||
|
||||
Centos 7
|
||||
--------
|
||||
|
||||
|
||||
|
||||
Centos 6.5
|
||||
----------
|
||||
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
How to Enable Secure Connections
|
||||
================================
|
||||
|
||||
If you are hosting Kanboard on a public server, and plan on accessing it via the internet, it is a good idea to enable SSL connections to encrypt your data. This is very simple to do with a self-signed certificate. The following instructions were created and tested on a server running Debian 7 (Wheezy) but they should work for any other Linux distribution.
|
||||
|
||||
OpenSSL Installation and Configuration
|
||||
--------------------------------------
|
||||
Install OpenSSL:
|
||||
|
||||
```bash
|
||||
apt-get update
|
||||
apt-get install openssl
|
||||
```
|
||||
Enable OpenSSL:
|
||||
|
||||
```bash
|
||||
a2enmod ssl
|
||||
```
|
||||
|
||||
Create a self-signed certificate:
|
||||
|
||||
```bash
|
||||
mkdir /etc/apache2/ssl
|
||||
openssl req -new -x509 -days 365 -nodes -out /etc/apache2/ssl/kanboard.pem -keyout /etc/apache2/ssl/kanboard.key
|
||||
```
|
||||
|
||||
Apache Configuration
|
||||
--------------------
|
||||
Create an apache configuration file:
|
||||
|
||||
```bash
|
||||
nano /etc/apache2/conf.d/kanboard.conf
|
||||
```
|
||||
|
||||
The contents of this file should look like this:
|
||||
|
||||
```bash
|
||||
<VirtualHost 127.0.0.1:443>
|
||||
SSLEngine on
|
||||
SSLCertificateFile /etc/apache2/ssl/kanboard.pem
|
||||
SSLCertificateKeyFile /etc/apache2/ssl/kanboard.key
|
||||
DocumentRoot /var/www
|
||||
<Directory kanboard>
|
||||
AllowOverride All
|
||||
order allow, deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
```
|
||||
|
||||
Be sure to replace 127.0.0.1 with the IP address of your server. If you are hosting kanboard in a location other than /var/www , be sure to update the DocumentRoot to match the location where you are hosting your Kanboard site.
|
||||
|
||||
Restart Apache:
|
||||
|
||||
```bash
|
||||
service apache2 restart
|
||||
```
|
||||
|
||||
You will now be able to access your Kanboard site securely by navigating to `https://www.example.com/kanboard`. Your browser will indicate that the certificate is not trusted. This is due to the fact that it is self signed. You can safely ignore this warning, although the certificate is not trusted, your data is still encrypted.
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__.'/app/common.php';
|
||||
require __DIR__.'/vendor/JsonRPC/Server.php';
|
||||
|
||||
use Core\Translator;
|
||||
use JsonRPC\Server;
|
||||
|
|
@ -175,7 +174,7 @@ $server->register('getTask', function($task_id) use ($task) {
|
|||
return $task->getById($task_id);
|
||||
});
|
||||
|
||||
$server->register('getAllTasks', function($project_id, array $status) use ($task) {
|
||||
$server->register('getAllTasks', function($project_id, $status) use ($task) {
|
||||
return $task->getAll($project_id, $status);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
<phpunit>
|
||||
<testsuites>
|
||||
<testsuite name="Kanboard">
|
||||
<directory>tests/units</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<phpunit>
|
||||
<testsuites>
|
||||
<testsuite name="Kanboard">
|
||||
<directory>functionals</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<const name="API_URL" value="http://localhost:8000/jsonrpc.php" />
|
||||
<const name="API_KEY" value="19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929" />
|
||||
<const name="DB_DRIVER" value="mysql" />
|
||||
<const name="DB_NAME" value="kanboard" />
|
||||
<const name="DB_HOSTNAME" value="localhost" />
|
||||
<const name="DB_USERNAME" value="root" />
|
||||
<const name="DB_PASSWORD" value="" />
|
||||
</php>
|
||||
</phpunit>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<phpunit>
|
||||
<testsuites>
|
||||
<testsuite name="Kanboard">
|
||||
<directory>functionals</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<const name="API_URL" value="http://localhost:8000/jsonrpc.php" />
|
||||
<const name="API_KEY" value="19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929" />
|
||||
<const name="DB_DRIVER" value="postgres" />
|
||||
<const name="DB_NAME" value="kanboard" />
|
||||
<const name="DB_HOSTNAME" value="localhost" />
|
||||
<const name="DB_USERNAME" value="postgres" />
|
||||
<const name="DB_PASSWORD" value="postgres" />
|
||||
</php>
|
||||
</phpunit>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<phpunit>
|
||||
<testsuites>
|
||||
<testsuite name="Kanboard">
|
||||
<directory>functionals</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<const name="API_URL" value="http://localhost:8000/jsonrpc.php" />
|
||||
<const name="API_KEY" value="19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929" />
|
||||
<const name="DB_DRIVER" value="sqlite" />
|
||||
<const name="DB_FILENAME" value="data/db.sqlite" />
|
||||
</php>
|
||||
</phpunit>
|
||||
|
|
@ -1,21 +1,52 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__.'/../../vendor/PicoDb/Database.php';
|
||||
require_once __DIR__.'/../../vendor/JsonRPC/Client.php';
|
||||
require_once __DIR__.'/../../app/Core/Security.php';
|
||||
require_once __DIR__.'/../../app/functions.php';
|
||||
|
||||
class Api extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
const URL = 'http://localhost:8000/jsonrpc.php';
|
||||
const KEY = '19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929';
|
||||
|
||||
private $client;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
if (DB_DRIVER === 'sqlite') {
|
||||
@unlink(DB_FILENAME);
|
||||
$pdo = new PDO('sqlite:'.DB_FILENAME);
|
||||
}
|
||||
else if (DB_DRIVER === 'mysql') {
|
||||
$pdo = new PDO('mysql:host='.DB_HOSTNAME, DB_USERNAME, DB_PASSWORD);
|
||||
$pdo->exec('DROP DATABASE '.DB_NAME);
|
||||
$pdo->exec('CREATE DATABASE '.DB_NAME);
|
||||
$pdo = new PDO('mysql:host='.DB_HOSTNAME.';dbname='.DB_NAME, DB_USERNAME, DB_PASSWORD);
|
||||
}
|
||||
else if (DB_DRIVER === 'postgres') {
|
||||
$pdo = new PDO('pgsql:host='.DB_HOSTNAME, DB_USERNAME, DB_PASSWORD);
|
||||
$pdo->exec('DROP DATABASE '.DB_NAME);
|
||||
$pdo->exec('CREATE DATABASE '.DB_NAME.' WITH OWNER '.DB_USERNAME);
|
||||
$pdo = new PDO('pgsql:host='.DB_HOSTNAME.';dbname='.DB_NAME, DB_USERNAME, DB_PASSWORD);
|
||||
}
|
||||
|
||||
setup_db();
|
||||
|
||||
$pdo->exec("UPDATE config SET api_token='".API_KEY."'");
|
||||
$pdo = null;
|
||||
}
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->client = new JsonRPC\Client(self::URL);
|
||||
$this->client->authentication('jsonrpc', self::KEY);
|
||||
$this->client = new JsonRPC\Client(API_URL);
|
||||
$this->client->authentication('jsonrpc', API_KEY);
|
||||
}
|
||||
|
||||
$pdo = new PDO('sqlite:data/db.sqlite');
|
||||
$pdo->exec('UPDATE config SET api_token="'.self::KEY.'"');
|
||||
private function getTaskId()
|
||||
{
|
||||
$tasks = $this->client->getAllTasks(1, 1);
|
||||
$this->assertNotEmpty($tasks);
|
||||
$this->assertEquals(1, count($tasks));
|
||||
|
||||
return $tasks[0]['id'];
|
||||
}
|
||||
|
||||
public function testRemoveAll()
|
||||
|
|
@ -154,13 +185,13 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
|
||||
public function testGetAllTasks()
|
||||
{
|
||||
$tasks = $this->client->getAllTasks(1, array(1));
|
||||
$tasks = $this->client->getAllTasks(1, 1);
|
||||
|
||||
$this->assertNotFalse($tasks);
|
||||
$this->assertTrue(is_array($tasks));
|
||||
$this->assertEquals('Task #1', $tasks[0]['title']);
|
||||
|
||||
$tasks = $this->client->getAllTasks(2, array(1, 2));
|
||||
$tasks = $this->client->getAllTasks(2, 0);
|
||||
|
||||
$this->assertNotFalse($tasks);
|
||||
$this->assertTrue(is_array($tasks));
|
||||
|
|
@ -228,10 +259,10 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
|
||||
public function testUpdateUser()
|
||||
{
|
||||
$user = $this->client->getUser(2);
|
||||
$user = array();
|
||||
$user['id'] = 2;
|
||||
$user['username'] = 'titi';
|
||||
$user['name'] = 'Titi';
|
||||
unset($user['password']);
|
||||
|
||||
$this->assertTrue($this->client->updateUser($user));
|
||||
|
||||
|
|
@ -280,8 +311,12 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
|
||||
$this->assertTrue($this->client->execute('createTask', $task));
|
||||
|
||||
$tasks = $this->client->getAllTasks(1, 1);
|
||||
$this->assertNotEmpty($tasks);
|
||||
$this->assertEquals(1, count($tasks));
|
||||
|
||||
$comment = array(
|
||||
'task_id' => 1,
|
||||
'task_id' => $tasks[0]['id'],
|
||||
'user_id' => 2,
|
||||
'comment' => 'boo',
|
||||
);
|
||||
|
|
@ -294,7 +329,6 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
$comment = $this->client->getComment(1);
|
||||
$this->assertNotFalse($comment);
|
||||
$this->assertNotEmpty($comment);
|
||||
$this->assertEquals(1, $comment['task_id']);
|
||||
$this->assertEquals(2, $comment['user_id']);
|
||||
$this->assertEquals('boo', $comment['comment']);
|
||||
}
|
||||
|
|
@ -312,15 +346,17 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
|
||||
public function testGetAllComments()
|
||||
{
|
||||
$task_id = $this->getTaskId();
|
||||
|
||||
$comment = array(
|
||||
'task_id' => 1,
|
||||
'task_id' => $task_id,
|
||||
'user_id' => 1,
|
||||
'comment' => 'blabla',
|
||||
);
|
||||
|
||||
$this->assertTrue($this->client->createComment($comment));
|
||||
|
||||
$comments = $this->client->getAllComments(1);
|
||||
$comments = $this->client->getAllComments($task_id);
|
||||
$this->assertNotFalse($comments);
|
||||
$this->assertNotEmpty($comments);
|
||||
$this->assertTrue(is_array($comments));
|
||||
|
|
@ -329,9 +365,10 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
|
||||
public function testRemoveComment()
|
||||
{
|
||||
$this->assertTrue($this->client->removeComment(1));
|
||||
$task_id = $this->getTaskId();
|
||||
$this->assertTrue($this->client->removeComment($task_id));
|
||||
|
||||
$comments = $this->client->getAllComments(1);
|
||||
$comments = $this->client->getAllComments($task_id);
|
||||
$this->assertNotFalse($comments);
|
||||
$this->assertNotEmpty($comments);
|
||||
$this->assertTrue(is_array($comments));
|
||||
|
|
@ -341,7 +378,7 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
public function testCreateSubtask()
|
||||
{
|
||||
$subtask = array(
|
||||
'task_id' => 1,
|
||||
'task_id' => $this->getTaskId(),
|
||||
'title' => 'subtask #1',
|
||||
);
|
||||
|
||||
|
|
@ -353,7 +390,7 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
$subtask = $this->client->getSubtask(1);
|
||||
$this->assertNotFalse($subtask);
|
||||
$this->assertNotEmpty($subtask);
|
||||
$this->assertEquals(1, $subtask['task_id']);
|
||||
$this->assertEquals($this->getTaskId(), $subtask['task_id']);
|
||||
$this->assertEquals(0, $subtask['user_id']);
|
||||
$this->assertEquals('subtask #1', $subtask['title']);
|
||||
}
|
||||
|
|
@ -362,7 +399,7 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
{
|
||||
$subtask = array();
|
||||
$subtask['id'] = 1;
|
||||
$subtask['task_id'] = 1;
|
||||
$subtask['task_id'] = $this->getTaskId();
|
||||
$subtask['title'] = 'test';
|
||||
|
||||
$this->assertTrue($this->client->execute('updateSubtask', $subtask));
|
||||
|
|
@ -374,14 +411,14 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
public function testGetAllSubtasks()
|
||||
{
|
||||
$subtask = array(
|
||||
'task_id' => 1,
|
||||
'task_id' => $this->getTaskId(),
|
||||
'user_id' => 2,
|
||||
'title' => 'Subtask #2',
|
||||
);
|
||||
|
||||
$this->assertTrue($this->client->execute('createSubtask', $subtask));
|
||||
|
||||
$subtasks = $this->client->getAllSubtasks(1);
|
||||
$subtasks = $this->client->getAllSubtasks($this->getTaskId());
|
||||
$this->assertNotFalse($subtasks);
|
||||
$this->assertNotEmpty($subtasks);
|
||||
$this->assertTrue(is_array($subtasks));
|
||||
|
|
@ -392,7 +429,7 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
{
|
||||
$this->assertTrue($this->client->removeSubtask(1));
|
||||
|
||||
$subtasks = $this->client->getAllSubtasks(1);
|
||||
$subtasks = $this->client->getAllSubtasks($this->getTaskId());
|
||||
$this->assertNotFalse($subtasks);
|
||||
$this->assertNotEmpty($subtasks);
|
||||
$this->assertTrue(is_array($subtasks));
|
||||
|
|
@ -401,20 +438,10 @@ class Api extends PHPUnit_Framework_TestCase
|
|||
|
||||
public function testMoveTaskPosition()
|
||||
{
|
||||
$task = array(
|
||||
'title' => 'Task to move',
|
||||
'color_id' => 'blue',
|
||||
'owner_id' => 1,
|
||||
'project_id' => 1,
|
||||
'column_id' => 1,
|
||||
);
|
||||
|
||||
$this->assertTrue($this->client->execute('createTask', $task));
|
||||
|
||||
$this->assertTrue($this->client->moveTaskPosition(1, 1, 3, 1));
|
||||
|
||||
$task = $this->client->getTask(1);
|
||||
$task_id = $this->getTaskId();
|
||||
$this->assertTrue($this->client->moveTaskPosition(1, $task_id, 3, 1));
|
||||
|
||||
$task = $this->client->getTask($task_id);
|
||||
$this->assertNotFalse($task);
|
||||
$this->assertTrue(is_array($task));
|
||||
$this->assertEquals(1, $task['position']);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
<phpunit>
|
||||
<testsuites>
|
||||
<testsuite name="Kanboard">
|
||||
<directory>units</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<const name="DB_DRIVER" value="mysql" />
|
||||
<const name="DB_NAME" value="kanboard_unit_test" />
|
||||
</php>
|
||||
</phpunit>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<phpunit>
|
||||
<testsuites>
|
||||
<testsuite name="Kanboard">
|
||||
<directory>units</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<const name="DB_DRIVER" value="postgres" />
|
||||
<const name="DB_USERNAME" value="postgres" />
|
||||
<const name="DB_NAME" value="kanboard_unit_test" />
|
||||
</php>
|
||||
</phpunit>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<phpunit>
|
||||
<testsuites>
|
||||
<testsuite name="Kanboard">
|
||||
<directory>units</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<const name="DB_DRIVER" value="sqlite" />
|
||||
<const name="DB_FILENAME" value=":memory:" />
|
||||
</php>
|
||||
</phpunit>
|
||||
|
|
@ -9,7 +9,7 @@ use Model\Task;
|
|||
use Model\Category;
|
||||
|
||||
class ActionTest extends Base
|
||||
{/*
|
||||
{
|
||||
public function testFetchActions()
|
||||
{
|
||||
$action = new Action($this->registry);
|
||||
|
|
@ -86,15 +86,15 @@ class ActionTest extends Base
|
|||
// We move our task
|
||||
$task->movePosition(1, 1, 4, 1);
|
||||
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_COLUMN));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_UPDATE));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_COLUMN));
|
||||
$this->assertFalse($this->registry->shared('event')->isEventTriggered(Task::EVENT_UPDATE));
|
||||
|
||||
// Our task should be closed
|
||||
$t1 = $task->getById(1);
|
||||
$this->assertEquals(4, $t1['column_id']);
|
||||
$this->assertEquals(0, $t1['is_active']);
|
||||
}
|
||||
*/
|
||||
|
||||
public function testEventMovePosition()
|
||||
{
|
||||
$task = new Task($this->registry);
|
||||
|
|
@ -138,7 +138,7 @@ class ActionTest extends Base
|
|||
// We bind events
|
||||
$action->attachEvents();
|
||||
|
||||
$this->assertTrue($this->registry->event->hasListener(Task::EVENT_MOVE_POSITION, 'Action\TaskAssignColorCategory'));
|
||||
$this->assertTrue($this->registry->shared('event')->hasListener(Task::EVENT_MOVE_POSITION, 'Action\TaskAssignColorCategory'));
|
||||
|
||||
// Our task should have the color red and position=1
|
||||
$t1 = $task->getById(1);
|
||||
|
|
@ -153,7 +153,7 @@ class ActionTest extends Base
|
|||
|
||||
// We move our tasks
|
||||
$this->assertTrue($task->movePosition(1, 1, 1, 10)); // task #1 to the end of the column
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_POSITION));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_POSITION));
|
||||
|
||||
$t1 = $task->getById(1);
|
||||
$this->assertEquals(2, $t1['position']);
|
||||
|
|
@ -165,10 +165,10 @@ class ActionTest extends Base
|
|||
$this->assertEquals(1, $t1['is_active']);
|
||||
$this->assertEquals('yellow', $t1['color_id']);
|
||||
|
||||
$this->registry->event->clearTriggeredEvents();
|
||||
$this->registry->shared('event')->clearTriggeredEvents();
|
||||
$this->assertTrue($task->movePosition(1, 2, 1, 44)); // task #2 to position 1
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_POSITION));
|
||||
$this->assertEquals('Action\TaskAssignColorCategory', $this->registry->event->getLastListenerExecuted());
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_POSITION));
|
||||
$this->assertEquals('Action\TaskAssignColorCategory', $this->registry->shared('event')->getLastListenerExecuted());
|
||||
|
||||
$t1 = $task->getById(1);
|
||||
$this->assertEquals(1, $t1['position']);
|
||||
|
|
@ -180,7 +180,7 @@ class ActionTest extends Base
|
|||
$this->assertEquals(1, $t1['is_active']);
|
||||
$this->assertEquals('green', $t1['color_id']);
|
||||
}
|
||||
/*
|
||||
|
||||
public function testExecuteMultipleActions()
|
||||
{
|
||||
$task = new Task($this->registry);
|
||||
|
|
@ -225,8 +225,8 @@ class ActionTest extends Base
|
|||
$action->attachEvents();
|
||||
|
||||
// Events should be attached
|
||||
$this->assertTrue($this->registry->event->hasListener(Task::EVENT_CLOSE, 'Action\TaskDuplicateAnotherProject'));
|
||||
$this->assertTrue($this->registry->event->hasListener(Task::EVENT_MOVE_COLUMN, 'Action\TaskClose'));
|
||||
$this->assertTrue($this->registry->shared('event')->hasListener(Task::EVENT_CLOSE, 'Action\TaskDuplicateAnotherProject'));
|
||||
$this->assertTrue($this->registry->shared('event')->hasListener(Task::EVENT_MOVE_COLUMN, 'Action\TaskClose'));
|
||||
|
||||
// Our task should be open, linked to the first project and in the first column
|
||||
$t1 = $task->getById(1);
|
||||
|
|
@ -237,8 +237,8 @@ class ActionTest extends Base
|
|||
// We move our task
|
||||
$task->movePosition(1, 1, 4, 1);
|
||||
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CLOSE));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_COLUMN));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CLOSE));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_COLUMN));
|
||||
|
||||
// Our task should be closed
|
||||
$t1 = $task->getById(1);
|
||||
|
|
@ -252,5 +252,5 @@ class ActionTest extends Base
|
|||
$this->assertEquals(1, $t2['is_active']);
|
||||
$this->assertEquals(2, $t2['project_id']);
|
||||
$this->assertEquals('unit_test', $t2['title']);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,86 +1,48 @@
|
|||
<?php
|
||||
|
||||
require __DIR__.'/../../app/Core/Loader.php';
|
||||
require __DIR__.'/../../app/helpers.php';
|
||||
require __DIR__.'/../../app/functions.php';
|
||||
require __DIR__.'/../../app/constants.php';
|
||||
|
||||
use Core\Loader;
|
||||
use Core\Registry;
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.5.0', '<')) {
|
||||
require __DIR__.'/../../vendor/password.php';
|
||||
}
|
||||
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validator.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Base.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validators/Required.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validators/Unique.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validators/MaxLength.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validators/MinLength.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validators/Integer.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validators/Equals.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validators/AlphaNumeric.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validators/GreaterThan.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validators/Date.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validators/Email.php';
|
||||
require __DIR__.'/../../vendor/SimpleValidator/Validators/Numeric.php';
|
||||
date_default_timezone_set('UTC');
|
||||
|
||||
require_once __DIR__.'/../../app/Core/Security.php';
|
||||
|
||||
require_once __DIR__.'/../../vendor/PicoDb/Database.php';
|
||||
require_once __DIR__.'/../../app/Schema/Sqlite.php';
|
||||
|
||||
require_once __DIR__.'/../../app/Core/Registry.php';
|
||||
require_once __DIR__.'/../../app/Core/Tool.php';
|
||||
require_once __DIR__.'/../../app/Core/Listener.php';
|
||||
require_once __DIR__.'/../../app/Core/Event.php';
|
||||
require_once __DIR__.'/../../app/Core/Translator.php';
|
||||
require_once __DIR__.'/../../app/Core/Template.php';
|
||||
require_once __DIR__.'/../../app/translator.php';
|
||||
require_once __DIR__.'/../../app/helpers.php';
|
||||
|
||||
require_once __DIR__.'/../../app/Model/Base.php';
|
||||
require_once __DIR__.'/../../app/Model/Config.php';
|
||||
require_once __DIR__.'/../../app/Model/Task.php';
|
||||
require_once __DIR__.'/../../app/Model/Acl.php';
|
||||
require_once __DIR__.'/../../app/Model/Comment.php';
|
||||
require_once __DIR__.'/../../app/Model/Project.php';
|
||||
require_once __DIR__.'/../../app/Model/User.php';
|
||||
require_once __DIR__.'/../../app/Model/Board.php';
|
||||
require_once __DIR__.'/../../app/Model/Action.php';
|
||||
require_once __DIR__.'/../../app/Model/Category.php';
|
||||
require_once __DIR__.'/../../app/Model/SubTask.php';
|
||||
require_once __DIR__.'/../../app/Model/File.php';
|
||||
require_once __DIR__.'/../../app/Model/BaseHistory.php';
|
||||
require_once __DIR__.'/../../app/Model/TaskHistory.php';
|
||||
require_once __DIR__.'/../../app/Model/SubtaskHistory.php';
|
||||
require_once __DIR__.'/../../app/Model/CommentHistory.php';
|
||||
|
||||
require_once __DIR__.'/../../app/Action/Base.php';
|
||||
require_once __DIR__.'/../../app/Action/TaskClose.php';
|
||||
require_once __DIR__.'/../../app/Action/TaskAssignSpecificUser.php';
|
||||
require_once __DIR__.'/../../app/Action/TaskAssignColorUser.php';
|
||||
require_once __DIR__.'/../../app/Action/TaskAssignColorCategory.php';
|
||||
require_once __DIR__.'/../../app/Action/TaskAssignCurrentUser.php';
|
||||
require_once __DIR__.'/../../app/Action/TaskDuplicateAnotherProject.php';
|
||||
require_once __DIR__.'/../../app/Action/TaskMoveAnotherProject.php';
|
||||
$loader = new Loader;
|
||||
$loader->setPath('app');
|
||||
$loader->setPath('vendor');
|
||||
$loader->execute();
|
||||
|
||||
abstract class Base extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
date_default_timezone_set('UTC');
|
||||
$this->registry = new Registry;
|
||||
$this->registry->db = function() { return setup_db(); };
|
||||
$this->registry->event = function() { return setup_events(); };
|
||||
|
||||
$this->registry = new \Core\Registry;
|
||||
$this->registry->db = $this->getDbConnection();
|
||||
$this->registry->event = new \Core\Event;
|
||||
if (DB_DRIVER === 'mysql') {
|
||||
$pdo = new PDO('mysql:host='.DB_HOSTNAME, DB_USERNAME, DB_PASSWORD);
|
||||
$pdo->exec('DROP DATABASE '.DB_NAME);
|
||||
$pdo->exec('CREATE DATABASE '.DB_NAME);
|
||||
$pdo = null;
|
||||
}
|
||||
else if (DB_DRIVER === 'postgres') {
|
||||
$pdo = new PDO('pgsql:host='.DB_HOSTNAME, DB_USERNAME, DB_PASSWORD);
|
||||
$pdo->exec('DROP DATABASE '.DB_NAME);
|
||||
$pdo->exec('CREATE DATABASE '.DB_NAME.' WITH OWNER '.DB_USERNAME);
|
||||
$pdo = null;
|
||||
}
|
||||
}
|
||||
|
||||
public function getDbConnection()
|
||||
public function tearDown()
|
||||
{
|
||||
$db = new \PicoDb\Database(array(
|
||||
'driver' => 'sqlite',
|
||||
'filename' => ':memory:'
|
||||
));
|
||||
|
||||
if ($db->schema()->check(\Schema\VERSION)) {
|
||||
return $db;
|
||||
}
|
||||
else {
|
||||
die('Unable to migrate database schema!');
|
||||
}
|
||||
$this->registry->shared('db')->closeConnection();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class TaskHistoryTest extends Base
|
|||
$this->assertTrue($e->create(1, 1, 1, Task::EVENT_CLOSE));
|
||||
}
|
||||
|
||||
$this->assertEquals($nb_events, $this->registry->db->table('task_has_events')->count());
|
||||
$this->assertEquals($nb_events, $this->registry->shared('db')->table('task_has_events')->count());
|
||||
$e->cleanup($max);
|
||||
|
||||
$events = $e->getAllByProjectId(1);
|
||||
|
|
@ -93,6 +93,6 @@ class TaskHistoryTest extends Base
|
|||
$this->assertTrue($e->create(1, 1, 1, Task::EVENT_CLOSE));
|
||||
}
|
||||
|
||||
$this->assertEquals(TaskHistory::MAX_EVENTS, $this->registry->db->table('task_has_events')->count());
|
||||
$this->assertEquals(TaskHistory::MAX_EVENTS, $this->registry->shared('db')->table('task_has_events')->count());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,15 @@ class TaskTest extends Base
|
|||
$this->assertEquals(2, $task['position']);
|
||||
$this->assertEquals(time(), $task['date_creation']);
|
||||
$this->assertEquals(time(), $task['date_modification']);
|
||||
|
||||
$tasks = $t->getAll(1, 1);
|
||||
$this->assertNotEmpty($tasks);
|
||||
$this->assertTrue(is_array($tasks));
|
||||
$this->assertEquals(1, $tasks[0]['id']);
|
||||
$this->assertEquals(2, $tasks[1]['id']);
|
||||
|
||||
$tasks = $t->getAll(1, 0);
|
||||
$this->assertEmpty($tasks);
|
||||
}
|
||||
|
||||
public function testRemove()
|
||||
|
|
@ -53,11 +62,11 @@ class TaskTest extends Base
|
|||
$p = new Project($this->registry);
|
||||
|
||||
$this->assertEquals(1, $p->create(array('name' => 'Project #1')));
|
||||
$this->assertEquals(1, $this->registry->db->table('tasks')->insert(array('title' => 'A', 'column_id' => 1, 'project_id' => 1, 'position' => 1)));
|
||||
$this->assertEquals(1, $this->registry->shared('db')->table('tasks')->insert(array('title' => 'A', 'column_id' => 1, 'project_id' => 1, 'position' => 1)));
|
||||
|
||||
// Both tasks have the same position
|
||||
$this->assertEquals(2, $this->registry->db->table('tasks')->insert(array('title' => 'B', 'column_id' => 2, 'project_id' => 1, 'position' => 1)));
|
||||
$this->assertEquals(3, $this->registry->db->table('tasks')->insert(array('title' => 'C', 'column_id' => 2, 'project_id' => 1, 'position' => 1)));
|
||||
$this->assertEquals(2, $this->registry->shared('db')->table('tasks')->insert(array('title' => 'B', 'column_id' => 2, 'project_id' => 1, 'position' => 1)));
|
||||
$this->assertEquals(3, $this->registry->shared('db')->table('tasks')->insert(array('title' => 'C', 'column_id' => 2, 'project_id' => 1, 'position' => 1)));
|
||||
|
||||
// Move the first column to the last position of the 2nd column
|
||||
$this->assertTrue($t->movePosition(1, 1, 2, 3));
|
||||
|
|
@ -451,7 +460,7 @@ class TaskTest extends Base
|
|||
|
||||
// We duplicate our task
|
||||
$this->assertEquals(2, $t->duplicateSameProject($task));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CREATE));
|
||||
|
||||
// Check the values of the duplicated task
|
||||
$task = $t->getById(2);
|
||||
|
|
@ -483,7 +492,7 @@ class TaskTest extends Base
|
|||
|
||||
// We duplicate our task to the 2nd project
|
||||
$this->assertEquals(2, $t->duplicateToAnotherProject(2, $task));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CREATE));
|
||||
|
||||
// Check the values of the duplicated task
|
||||
$task = $t->getById(2);
|
||||
|
|
@ -517,7 +526,7 @@ class TaskTest extends Base
|
|||
// We duplicate our task to the 2nd project
|
||||
$task = $t->getById(1);
|
||||
$this->assertEquals(1, $t->moveToAnotherProject(2, $task));
|
||||
//$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE));
|
||||
//$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CREATE));
|
||||
|
||||
// Check the values of the duplicated task
|
||||
$task = $t->getById(1);
|
||||
|
|
@ -551,32 +560,32 @@ class TaskTest extends Base
|
|||
|
||||
// We create task
|
||||
$this->assertEquals(1, $t->create(array('title' => 'test', 'project_id' => 1, 'column_id' => 1)));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CREATE));
|
||||
|
||||
// We update a task
|
||||
$this->assertTrue($t->update(array('title' => 'test2', 'id' => 1)));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_UPDATE));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CREATE_UPDATE));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_UPDATE));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CREATE_UPDATE));
|
||||
|
||||
// We close our task
|
||||
$this->assertTrue($t->close(1));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_CLOSE));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_CLOSE));
|
||||
|
||||
// We open our task
|
||||
$this->assertTrue($t->open(1));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_OPEN));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_OPEN));
|
||||
|
||||
// We change the column of our task
|
||||
$this->assertTrue($t->movePosition(1, 1, 2, 1));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_COLUMN));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_COLUMN));
|
||||
|
||||
// We change the position of our task
|
||||
$this->assertEquals(2, $t->create(array('title' => 'test 2', 'project_id' => 1, 'column_id' => 2)));
|
||||
$this->assertTrue($t->movePosition(1, 1, 2, 2));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_POSITION));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_POSITION));
|
||||
|
||||
// We change the column and the position of our task
|
||||
$this->assertTrue($t->movePosition(1, 1, 1, 1));
|
||||
$this->assertTrue($this->registry->event->isEventTriggered(Task::EVENT_MOVE_COLUMN));
|
||||
$this->assertTrue($this->registry->shared('event')->isEventTriggered(Task::EVENT_MOVE_COLUMN));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,12 @@ class Database
|
|||
}
|
||||
|
||||
|
||||
public function closeConnection()
|
||||
{
|
||||
$this->pdo = null;
|
||||
}
|
||||
|
||||
|
||||
public function escapeIdentifier($value)
|
||||
{
|
||||
return $this->pdo->escapeIdentifier($value);
|
||||
|
|
|
|||
|
|
@ -44,7 +44,11 @@ class Table
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update
|
||||
*
|
||||
* Note: Do not use `rowCount()` the behaviour is different across drivers
|
||||
*/
|
||||
public function update(array $data)
|
||||
{
|
||||
$columns = array();
|
||||
|
|
@ -70,7 +74,7 @@ class Table
|
|||
|
||||
$result = $this->db->execute($sql, $values);
|
||||
|
||||
return $result !== false && $result->rowCount() > 0;
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue