diff options
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | README.markdown | 4 | ||||
-rw-r--r-- | app/Core/Loader.php | 33 | ||||
-rw-r--r-- | app/Model/Project.php | 31 | ||||
-rw-r--r-- | app/Model/Task.php | 38 | ||||
-rw-r--r-- | app/check_setup.php | 5 | ||||
-rw-r--r-- | app/common.php | 179 | ||||
-rw-r--r-- | app/constants.php | 70 | ||||
-rw-r--r-- | app/functions.php | 131 | ||||
-rw-r--r-- | app/translator.php | 43 | ||||
-rw-r--r-- | docs/api-json-rpc.markdown | 6 | ||||
-rw-r--r-- | docs/centos-installation.markdown | 5 | ||||
-rw-r--r-- | docs/secure-connections.markdown | 59 | ||||
-rw-r--r-- | jsonrpc.php | 3 | ||||
-rw-r--r-- | phpunit.xml | 7 | ||||
-rw-r--r-- | tests/functionals.mysql.xml | 16 | ||||
-rw-r--r-- | tests/functionals.postgres.xml | 16 | ||||
-rw-r--r-- | tests/functionals.sqlite.xml | 13 | ||||
-rw-r--r-- | tests/functionals/ApiTest.php | 99 | ||||
-rw-r--r-- | tests/units.mysql.xml | 11 | ||||
-rw-r--r-- | tests/units.postgres.xml | 12 | ||||
-rw-r--r-- | tests/units.sqlite.xml | 11 | ||||
-rw-r--r-- | tests/units/ActionTest.php | 30 | ||||
-rw-r--r-- | tests/units/Base.php | 100 | ||||
-rw-r--r-- | tests/units/TaskHistoryTest.php | 4 | ||||
-rw-r--r-- | tests/units/TaskTest.php | 37 | ||||
-rw-r--r-- | vendor/PicoDb/Database.php | 6 | ||||
-rw-r--r-- | vendor/PicoDb/Table.php | 8 |
28 files changed, 537 insertions, 442 deletions
diff --git a/.travis.yml b/.travis.yml index edd10551..66f9c288 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,4 +7,4 @@ php: - "5.3" before_script: wget https://phar.phpunit.de/phpunit.phar -script: php phpunit.phar
\ No newline at end of file +script: php phpunit.phar -c tests/units.sqlite.xml
\ No newline at end of file diff --git a/README.markdown b/README.markdown index efb002ed..bbf81456 100644 --- a/README.markdown +++ b/README.markdown @@ -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 diff --git a/app/Core/Loader.php b/app/Core/Loader.php index 7c437654..151081c1 100644 --- a/app/Core/Loader.php +++ b/app/Core/Loader.php @@ -11,17 +11,29 @@ 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) { + + $filename = $path.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php'; - if (file_exists($filename)) { - require $filename; + 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; + } } diff --git a/app/Model/Project.php b/app/Model/Project.php index 0ba18498..f8df1ae1 100644 --- a/app/Model/Project.php +++ b/app/Model/Project.php @@ -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); } /** @@ -569,6 +570,18 @@ class Project extends Base } /** + * 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 * * @access public @@ -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' => '')); diff --git a/app/Model/Task.php b/app/Model/Task.php index 6f62c3d2..fcee67f7 100644 --- a/app/Model/Task.php +++ b/app/Model/Task.php @@ -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']; + } } /** @@ -488,6 +492,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 * * @access public @@ -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(); diff --git a/app/check_setup.php b/app/check_setup.php index 9ed16967..c4359d7a 100644 --- a/app/check_setup.php +++ b/app/check_setup.php @@ -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'; -} diff --git a/app/common.php b/app/common.php index f46e3c6b..0ba7df9d 100644 --- a/app/common.php +++ b/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__.'/../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'; +require __DIR__.'/functions.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(); diff --git a/app/constants.php b/app/constants.php new file mode 100644 index 00000000..d52997d7 --- /dev/null +++ b/app/constants.php @@ -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'); diff --git a/app/functions.php b/app/functions.php new file mode 100644 index 00000000..4cbbbbfe --- /dev/null +++ b/app/functions.php @@ -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; +} diff --git a/app/translator.php b/app/translator.php deleted file mode 100644 index ac4d72e2..00000000 --- a/app/translator.php +++ /dev/null @@ -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; -} diff --git a/docs/api-json-rpc.markdown b/docs/api-json-rpc.markdown index fa9fec85..a6420149 100644 --- a/docs/api-json-rpc.markdown +++ b/docs/api-json-rpc.markdown @@ -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 } } ``` diff --git a/docs/centos-installation.markdown b/docs/centos-installation.markdown index f8963ecd..f5a31043 100644 --- a/docs/centos-installation.markdown +++ b/docs/centos-installation.markdown @@ -1,6 +1,11 @@ Centos Installation =================== +Centos 7 +-------- + + + Centos 6.5 ---------- diff --git a/docs/secure-connections.markdown b/docs/secure-connections.markdown deleted file mode 100644 index 109574ae..00000000 --- a/docs/secure-connections.markdown +++ /dev/null @@ -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. diff --git a/jsonrpc.php b/jsonrpc.php index f6a2da45..71795a60 100644 --- a/jsonrpc.php +++ b/jsonrpc.php @@ -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); }); diff --git a/phpunit.xml b/phpunit.xml deleted file mode 100644 index 5c4ce58c..00000000 --- a/phpunit.xml +++ /dev/null @@ -1,7 +0,0 @@ -<phpunit> - <testsuites> - <testsuite name="Kanboard"> - <directory>tests/units</directory> - </testsuite> - </testsuites> -</phpunit>
\ No newline at end of file diff --git a/tests/functionals.mysql.xml b/tests/functionals.mysql.xml new file mode 100644 index 00000000..f667cafa --- /dev/null +++ b/tests/functionals.mysql.xml @@ -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>
\ No newline at end of file diff --git a/tests/functionals.postgres.xml b/tests/functionals.postgres.xml new file mode 100644 index 00000000..38904d1a --- /dev/null +++ b/tests/functionals.postgres.xml @@ -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>
\ No newline at end of file diff --git a/tests/functionals.sqlite.xml b/tests/functionals.sqlite.xml new file mode 100644 index 00000000..bf5d4117 --- /dev/null +++ b/tests/functionals.sqlite.xml @@ -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>
\ No newline at end of file diff --git a/tests/functionals/ApiTest.php b/tests/functionals/ApiTest.php index 9a03c891..0960eba7 100644 --- a/tests/functionals/ApiTest.php +++ b/tests/functionals/ApiTest.php @@ -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); + } + + private function getTaskId() + { + $tasks = $this->client->getAllTasks(1, 1); + $this->assertNotEmpty($tasks); + $this->assertEquals(1, count($tasks)); - $pdo = new PDO('sqlite:data/db.sqlite'); - $pdo->exec('UPDATE config SET api_token="'.self::KEY.'"'); + 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']); diff --git a/tests/units.mysql.xml b/tests/units.mysql.xml new file mode 100644 index 00000000..0e308a05 --- /dev/null +++ b/tests/units.mysql.xml @@ -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>
\ No newline at end of file diff --git a/tests/units.postgres.xml b/tests/units.postgres.xml new file mode 100644 index 00000000..0583c7f8 --- /dev/null +++ b/tests/units.postgres.xml @@ -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>
\ No newline at end of file diff --git a/tests/units.sqlite.xml b/tests/units.sqlite.xml new file mode 100644 index 00000000..9771a2a2 --- /dev/null +++ b/tests/units.sqlite.xml @@ -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>
\ No newline at end of file diff --git a/tests/units/ActionTest.php b/tests/units/ActionTest.php index b07af992..23148c44 100644 --- a/tests/units/ActionTest.php +++ b/tests/units/ActionTest.php @@ -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']); - }*/ + } } diff --git a/tests/units/Base.php b/tests/units/Base.php index cea9764c..3a46a4ae 100644 --- a/tests/units/Base.php +++ b/tests/units/Base.php @@ -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'; - -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'; +date_default_timezone_set('UTC'); -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 \Core\Registry; - $this->registry->db = $this->getDbConnection(); - $this->registry->event = new \Core\Event; + $this->registry = new Registry; + $this->registry->db = function() { return setup_db(); }; + $this->registry->event = function() { return setup_events(); }; + + 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(); } } diff --git a/tests/units/TaskHistoryTest.php b/tests/units/TaskHistoryTest.php index 0d24be58..085162ea 100644 --- a/tests/units/TaskHistoryTest.php +++ b/tests/units/TaskHistoryTest.php @@ -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()); } } diff --git a/tests/units/TaskTest.php b/tests/units/TaskTest.php index c9468efd..b876f7e4 100644 --- a/tests/units/TaskTest.php +++ b/tests/units/TaskTest.php @@ -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)); } } diff --git a/vendor/PicoDb/Database.php b/vendor/PicoDb/Database.php index 4d7b7031..5d0beb8a 100644 --- a/vendor/PicoDb/Database.php +++ b/vendor/PicoDb/Database.php @@ -78,6 +78,12 @@ class Database } + public function closeConnection() + { + $this->pdo = null; + } + + public function escapeIdentifier($value) { return $this->pdo->escapeIdentifier($value); diff --git a/vendor/PicoDb/Table.php b/vendor/PicoDb/Table.php index b333feb4..cc637434 100644 --- a/vendor/PicoDb/Table.php +++ b/vendor/PicoDb/Table.php @@ -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; } |