This commit is contained in:
i00171 2016-06-26 18:35:25 +02:00
commit 47039d32c8
111 changed files with 3276 additions and 2659 deletions

View File

@ -0,0 +1 @@
@daily www-data cd /var/www/html/kanboard && ./kanboard cronjob >/dev/null 2>&1

6
.dockerignore Normal file
View File

@ -0,0 +1,6 @@
.git
.git*
data/*
Makefile
.*.yml
*.json

View File

@ -1,11 +1,18 @@
Version 1.0.31 (unreleased)
--------------
New features:
* Added application and project roles validation for API procedure calls
* Added new API call: "getProjectByIdentifier"
Improvements:
* Added argument owner_id and identifier to project API calls
* Rewrite integration tests to run with Docker containers
* Use the same task form layout everywhere
* Remove some tasks dropdown menus that are now available with task edit form
* Make embedded documentation available in multiple languages
* Removed some tasks dropdown menus that are now available with task edit form
* Make embedded documentation readable in multiple languages (if a translation is available)
Bug fixes:

View File

@ -24,8 +24,7 @@ COPY .docker/php/conf.d/local.ini /etc/php5/conf.d/
COPY .docker/php/php-fpm.conf /etc/php5/
COPY .docker/nginx/nginx.conf /etc/nginx/
COPY .docker/kanboard/config.php /var/www/kanboard/
COPY .docker/kanboard/config.php /var/www/kanboard/
COPY .docker/crontab/kanboard /var/spool/cron/crontabs/nginx
COPY .docker/crontab/cronjob.alpine /var/spool/cron/crontabs/nginx
EXPOSE 80

View File

@ -58,7 +58,28 @@ test-postgres:
unittest: test-sqlite test-mysql test-postgres
test-browser:
@ phpunit -c tests/acceptance.xml
@ phpunit -c tests/acceptance.xml
integration-test-mysql:
@ composer install
@ docker-compose -f tests/docker/compose.integration.mysql.yaml build
@ docker-compose -f tests/docker/compose.integration.mysql.yaml up -d mysql app
@ docker-compose -f tests/docker/compose.integration.mysql.yaml up tests
@ docker-compose -f tests/docker/compose.integration.mysql.yaml down
integration-test-postgres:
@ composer install
@ docker-compose -f tests/docker/compose.integration.postgres.yaml build
@ docker-compose -f tests/docker/compose.integration.postgres.yaml up -d postgres app
@ docker-compose -f tests/docker/compose.integration.postgres.yaml up tests
@ docker-compose -f tests/docker/compose.integration.postgres.yaml down
integration-test-sqlite:
@ composer install
@ docker-compose -f tests/docker/compose.integration.sqlite.yaml build
@ docker-compose -f tests/docker/compose.integration.sqlite.yaml up -d app
@ docker-compose -f tests/docker/compose.integration.sqlite.yaml up tests
@ docker-compose -f tests/docker/compose.integration.sqlite.yaml down
sql:
@ pg_dump --schema-only --no-owner --no-privileges --quote-all-identifiers -n public --file app/Schema/Sql/postgres.sql kanboard

View File

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class ActionAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class ActionAuthorization extends ProjectAuthorization
{
public function check($class, $method, $action_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->actionModel->getProjectId($action_id));
}
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class CategoryAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class CategoryAuthorization extends ProjectAuthorization
{
public function check($class, $method, $category_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->categoryModel->getProjectId($category_id));
}
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class ColumnAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class ColumnAuthorization extends ProjectAuthorization
{
public function check($class, $method, $column_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->columnModel->getProjectId($column_id));
}
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class CommentAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class CommentAuthorization extends ProjectAuthorization
{
public function check($class, $method, $comment_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->commentModel->getProjectId($comment_id));
}
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Kanboard\Api\Authorization;
use JsonRPC\Exception\AccessDeniedException;
use Kanboard\Core\Base;
/**
* Class ProcedureAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class ProcedureAuthorization extends Base
{
private $userSpecificProcedures = array(
'getMe',
'getMyDashboard',
'getMyActivityStream',
'createMyPrivateProject',
'getMyProjectsList',
'getMyProjects',
'getMyOverdueTasks',
);
public function check($procedure)
{
if (! $this->userSession->isLogged() && in_array($procedure, $this->userSpecificProcedures)) {
throw new AccessDeniedException('This procedure is not available with the API credentials');
}
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace Kanboard\Api\Authorization;
use JsonRPC\Exception\AccessDeniedException;
use Kanboard\Core\Base;
/**
* Class ProjectAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class ProjectAuthorization extends Base
{
public function check($class, $method, $project_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $project_id);
}
}
protected function checkProjectPermission($class, $method, $project_id)
{
if (empty($project_id)) {
throw new AccessDeniedException('Project not found');
}
$role = $this->projectUserRoleModel->getUserRole($project_id, $this->userSession->getId());
if (! $this->apiProjectAuthorization->isAllowed($class, $method, $role)) {
throw new AccessDeniedException('Project access denied');
}
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class SubtaskAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class SubtaskAuthorization extends ProjectAuthorization
{
public function check($class, $method, $subtask_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->subtaskModel->getProjectId($subtask_id));
}
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class TaskAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class TaskAuthorization extends ProjectAuthorization
{
public function check($class, $method, $category_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->taskFinderModel->getProjectId($category_id));
}
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class TaskFileAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class TaskFileAuthorization extends ProjectAuthorization
{
public function check($class, $method, $file_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->taskFileModel->getProjectId($file_id));
}
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace Kanboard\Api\Authorization;
/**
* Class TaskLinkAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class TaskLinkAuthorization extends ProjectAuthorization
{
public function check($class, $method, $task_link_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($class, $method, $this->taskLinkModel->getProjectId($task_link_id));
}
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Kanboard\Api\Authorization;
use JsonRPC\Exception\AccessDeniedException;
use Kanboard\Core\Base;
/**
* Class UserAuthorization
*
* @package Kanboard\Api\Authorization
* @author Frederic Guillot
*/
class UserAuthorization extends Base
{
public function check($class, $method)
{
if ($this->userSession->isLogged() && ! $this->apiAuthorization->isAllowed($class, $method, $this->userSession->getRole())) {
throw new AccessDeniedException('You are not allowed to access to this resource');
}
}
}

View File

@ -13,46 +13,8 @@ use Kanboard\Core\Base;
* @package Kanboard\Api\Middleware
* @author Frederic Guillot
*/
class AuthenticationApiMiddleware extends Base implements MiddlewareInterface
class AuthenticationMiddleware extends Base implements MiddlewareInterface
{
private $user_allowed_procedures = array(
'getMe',
'getMyDashboard',
'getMyActivityStream',
'createMyPrivateProject',
'getMyProjectsList',
'getMyProjects',
'getMyOverdueTasks',
);
private $both_allowed_procedures = array(
'getTimezone',
'getVersion',
'getDefaultTaskColor',
'getDefaultTaskColors',
'getColorList',
'getProjectById',
'getSubTask',
'getTask',
'getTaskByReference',
'getTimeSpent',
'getAllTasks',
'getAllSubTasks',
'hasTimer',
'logStartTime',
'logEndTime',
'openTask',
'closeTask',
'moveTaskPosition',
'createTask',
'createSubtask',
'updateTask',
'getBoard',
'getProjectActivity',
'getOverdueTasksByProject',
'searchTasks',
);
/**
* Execute Middleware
*
@ -68,11 +30,8 @@ class AuthenticationApiMiddleware extends Base implements MiddlewareInterface
$this->dispatcher->dispatch('app.bootstrap');
if ($this->isUserAuthenticated($username, $password)) {
$this->checkProcedurePermission(true, $procedureName);
$this->userSession->initialize($this->userModel->getByUsername($username));
} elseif ($this->isAppAuthenticated($username, $password)) {
$this->checkProcedurePermission(false, $procedureName);
} else {
} elseif (! $this->isAppAuthenticated($username, $password)) {
$this->logger->error('API authentication failure for '.$username);
throw new AuthenticationFailureException('Wrong credentials');
}
@ -120,18 +79,4 @@ class AuthenticationApiMiddleware extends Base implements MiddlewareInterface
return $this->configModel->get('api_token');
}
public function checkProcedurePermission($is_user, $procedure)
{
$is_both_procedure = in_array($procedure, $this->both_allowed_procedures);
$is_user_procedure = in_array($procedure, $this->user_allowed_procedures);
if ($is_user && ! $is_both_procedure && ! $is_user_procedure) {
throw new AccessDeniedException('Permission denied');
} elseif (! $is_user && ! $is_both_procedure && $is_user_procedure) {
throw new AccessDeniedException('Permission denied');
}
$this->logger->debug('API call: '.$procedure);
}
}

View File

@ -1,16 +1,17 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Core\Base;
use Kanboard\Api\Authorization\ActionAuthorization;
use Kanboard\Api\Authorization\ProjectAuthorization;
/**
* Action API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class ActionApi extends Base
class ActionProcedure extends BaseProcedure
{
public function getAvailableActions()
{
@ -29,16 +30,19 @@ class ActionApi extends Base
public function removeAction($action_id)
{
ActionAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeAction', $action_id);
return $this->actionModel->remove($action_id);
}
public function getActions($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getActions', $project_id);
return $this->actionModel->getAllByProject($project_id);
}
public function createAction($project_id, $event_name, $action_name, array $params)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createAction', $project_id);
$values = array(
'project_id' => $project_id,
'event_name' => $event_name,

View File

@ -1,16 +1,14 @@
<?php
namespace Kanboard\Api;
use Kanboard\Core\Base;
namespace Kanboard\Api\Procedure;
/**
* App API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class AppApi extends Base
class AppProcedure extends BaseProcedure
{
public function getTimezone()
{

View File

@ -1,30 +1,24 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use JsonRPC\Exception\AccessDeniedException;
use Kanboard\Api\Authorization\ProcedureAuthorization;
use Kanboard\Api\Authorization\UserAuthorization;
use Kanboard\Core\Base;
use ReflectionClass;
/**
* Base class
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
abstract class BaseApi extends Base
abstract class BaseProcedure extends Base
{
public function checkProjectPermission($project_id)
public function beforeProcedure($procedure)
{
if ($this->userSession->isLogged() && ! $this->projectPermissionModel->isUserAllowed($project_id, $this->userSession->getId())) {
throw new AccessDeniedException('Permission denied');
}
}
public function checkTaskPermission($task_id)
{
if ($this->userSession->isLogged()) {
$this->checkProjectPermission($this->taskFinderModel->getProjectId($task_id));
}
ProcedureAuthorization::getInstance($this->container)->check($procedure);
UserAuthorization::getInstance($this->container)->check($this->getClassName(), $procedure);
}
protected function formatTask($task)
@ -71,4 +65,21 @@ abstract class BaseApi extends Base
return $projects;
}
protected function filterValues(array $values)
{
foreach ($values as $key => $value) {
if (is_null($value)) {
unset($values[$key]);
}
}
return $values;
}
protected function getClassName()
{
$reflection = new ReflectionClass(get_called_class());
return $reflection->getShortName();
}
}

View File

@ -1,21 +1,22 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProjectAuthorization;
use Kanboard\Formatter\BoardFormatter;
/**
* Board API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class BoardApi extends BaseApi
class BoardProcedure extends BaseProcedure
{
public function getBoard($project_id)
{
$this->checkProjectPermission($project_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getBoard', $project_id);
return BoardFormatter::getInstance($this->container)
->withProjectId($project_id)
->withQuery($this->taskFinderModel->getExtendedQuery())

View File

@ -1,34 +1,40 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Core\Base;
use Kanboard\Api\Authorization\CategoryAuthorization;
use Kanboard\Api\Authorization\ProjectAuthorization;
/**
* Category API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class CategoryApi extends Base
class CategoryProcedure extends BaseProcedure
{
public function getCategory($category_id)
{
CategoryAuthorization::getInstance($this->container)->check($this->getClassName(), 'getCategory', $category_id);
return $this->categoryModel->getById($category_id);
}
public function getAllCategories($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllCategories', $project_id);
return $this->categoryModel->getAll($project_id);
}
public function removeCategory($category_id)
{
CategoryAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeCategory', $category_id);
return $this->categoryModel->remove($category_id);
}
public function createCategory($project_id, $name)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createCategory', $project_id);
$values = array(
'project_id' => $project_id,
'name' => $name,
@ -40,6 +46,8 @@ class CategoryApi extends Base
public function updateCategory($id, $name)
{
CategoryAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateCategory', $id);
$values = array(
'id' => $id,
'name' => $name,

View File

@ -1,42 +1,51 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ColumnAuthorization;
use Kanboard\Api\Authorization\ProjectAuthorization;
/**
* Column API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class ColumnApi extends BaseApi
class ColumnProcedure extends BaseProcedure
{
public function getColumns($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getColumns', $project_id);
return $this->columnModel->getAll($project_id);
}
public function getColumn($column_id)
{
ColumnAuthorization::getInstance($this->container)->check($this->getClassName(), 'getColumn', $column_id);
return $this->columnModel->getById($column_id);
}
public function updateColumn($column_id, $title, $task_limit = 0, $description = '')
{
ColumnAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateColumn', $column_id);
return $this->columnModel->update($column_id, $title, $task_limit, $description);
}
public function addColumn($project_id, $title, $task_limit = 0, $description = '')
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addColumn', $project_id);
return $this->columnModel->create($project_id, $title, $task_limit, $description);
}
public function removeColumn($column_id)
{
ColumnAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeColumn', $column_id);
return $this->columnModel->remove($column_id);
}
public function changeColumnPosition($project_id, $column_id, $position)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeColumnPosition', $project_id);
return $this->columnModel->changePosition($project_id, $column_id, $position);
}
}

View File

@ -1,34 +1,40 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Core\Base;
use Kanboard\Api\Authorization\CommentAuthorization;
use Kanboard\Api\Authorization\TaskAuthorization;
/**
* Comment API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class CommentApi extends Base
class CommentProcedure extends BaseProcedure
{
public function getComment($comment_id)
{
CommentAuthorization::getInstance($this->container)->check($this->getClassName(), 'getComment', $comment_id);
return $this->commentModel->getById($comment_id);
}
public function getAllComments($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllComments', $task_id);
return $this->commentModel->getAll($task_id);
}
public function removeComment($comment_id)
{
CommentAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeComment', $comment_id);
return $this->commentModel->remove($comment_id);
}
public function createComment($task_id, $user_id, $content, $reference = '')
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'createComment', $task_id);
$values = array(
'task_id' => $task_id,
'user_id' => $user_id,
@ -43,6 +49,8 @@ class CommentApi extends Base
public function updateComment($id, $content)
{
CommentAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateComment', $id);
$values = array(
'id' => $id,
'comment' => $content,

View File

@ -1,16 +1,14 @@
<?php
namespace Kanboard\Api;
use Kanboard\Core\Base;
namespace Kanboard\Api\Procedure;
/**
* Group Member API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class GroupMemberApi extends Base
class GroupMemberProcedure extends BaseProcedure
{
public function getMemberGroups($user_id)
{

View File

@ -1,16 +1,14 @@
<?php
namespace Kanboard\Api;
use Kanboard\Core\Base;
namespace Kanboard\Api\Procedure;
/**
* Group API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class GroupApi extends Base
class GroupProcedure extends BaseProcedure
{
public function createGroup($name, $external_id = '')
{

View File

@ -1,16 +1,14 @@
<?php
namespace Kanboard\Api;
use Kanboard\Core\Base;
namespace Kanboard\Api\Procedure;
/**
* Link API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class LinkApi extends Base
class LinkProcedure extends BaseProcedure
{
/**
* Get a link by id

View File

@ -1,16 +1,16 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Model\SubtaskModel;
/**
* Me API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class MeApi extends BaseApi
class MeProcedure extends BaseProcedure
{
public function getMe()
{

View File

@ -1,73 +1,69 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Core\Base;
use Kanboard\Api\Authorization\ProjectAuthorization;
use Kanboard\Core\Security\Role;
/**
* Project Permission API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class ProjectPermissionApi extends Base
class ProjectPermissionProcedure extends BaseProcedure
{
public function getProjectUsers($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectUsers', $project_id);
return $this->projectUserRoleModel->getAllUsers($project_id);
}
public function getAssignableUsers($project_id, $prepend_unassigned = false)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAssignableUsers', $project_id);
return $this->projectUserRoleModel->getAssignableUsersList($project_id, $prepend_unassigned);
}
public function addProjectUser($project_id, $user_id, $role = Role::PROJECT_MEMBER)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addProjectUser', $project_id);
return $this->projectUserRoleModel->addUser($project_id, $user_id, $role);
}
public function addProjectGroup($project_id, $group_id, $role = Role::PROJECT_MEMBER)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addProjectGroup', $project_id);
return $this->projectGroupRoleModel->addGroup($project_id, $group_id, $role);
}
public function removeProjectUser($project_id, $user_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeProjectUser', $project_id);
return $this->projectUserRoleModel->removeUser($project_id, $user_id);
}
public function removeProjectGroup($project_id, $group_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeProjectGroup', $project_id);
return $this->projectGroupRoleModel->removeGroup($project_id, $group_id);
}
public function changeProjectUserRole($project_id, $user_id, $role)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeProjectUserRole', $project_id);
return $this->projectUserRoleModel->changeUserRole($project_id, $user_id, $role);
}
public function changeProjectGroupRole($project_id, $group_id, $role)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeProjectGroupRole', $project_id);
return $this->projectGroupRoleModel->changeGroupRole($project_id, $group_id, $role);
}
// Deprecated
public function getMembers($project_id)
public function getProjectUserRole($project_id, $user_id)
{
return $this->getProjectUsers($project_id);
}
// Deprecated
public function revokeUser($project_id, $user_id)
{
return $this->removeProjectUser($project_id, $user_id);
}
// Deprecated
public function allowUser($project_id, $user_id)
{
return $this->addProjectUser($project_id, $user_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectUserRole', $project_id);
return $this->projectUserRoleModel->getUserRole($project_id, $user_id);
}
}

View File

@ -0,0 +1,113 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProjectAuthorization;
/**
* Project API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class ProjectProcedure extends BaseProcedure
{
public function getProjectById($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectById', $project_id);
return $this->formatProject($this->projectModel->getById($project_id));
}
public function getProjectByName($name)
{
$project = $this->projectModel->getByName($name);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectByName', $project['id']);
return $this->formatProject($project);
}
public function getProjectByIdentifier($identifier)
{
$project = $this->formatProject($this->projectModel->getByIdentifier($identifier));
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectByIdentifier', $project['id']);
return $this->formatProject($project);
}
public function getAllProjects()
{
return $this->formatProjects($this->projectModel->getAll());
}
public function removeProject($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeProject', $project_id);
return $this->projectModel->remove($project_id);
}
public function enableProject($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'enableProject', $project_id);
return $this->projectModel->enable($project_id);
}
public function disableProject($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'disableProject', $project_id);
return $this->projectModel->disable($project_id);
}
public function enableProjectPublicAccess($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'enableProjectPublicAccess', $project_id);
return $this->projectModel->enablePublicAccess($project_id);
}
public function disableProjectPublicAccess($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'disableProjectPublicAccess', $project_id);
return $this->projectModel->disablePublicAccess($project_id);
}
public function getProjectActivities(array $project_ids)
{
foreach ($project_ids as $project_id) {
ProjectAuthorization::getInstance($this->container)
->check($this->getClassName(), 'getProjectActivities', $project_id);
}
return $this->helper->projectActivity->getProjectsEvents($project_ids);
}
public function getProjectActivity($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectActivity', $project_id);
return $this->helper->projectActivity->getProjectEvents($project_id);
}
public function createProject($name, $description = null, $owner_id = 0, $identifier = null)
{
$values = $this->filterValues(array(
'name' => $name,
'description' => $description,
'identifier' => $identifier,
));
list($valid, ) = $this->projectValidator->validateCreation($values);
return $valid ? $this->projectModel->create($values, $owner_id, $this->userSession->isLogged()) : false;
}
public function updateProject($project_id, $name = null, $description = null, $owner_id = null, $identifier = null)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateProject', $project_id);
$values = $this->filterValues(array(
'id' => $project_id,
'name' => $name,
'description' => $description,
'owner_id' => $owner_id,
'identifier' => $identifier,
));
list($valid, ) = $this->projectValidator->validateModification($values);
return $valid && $this->projectModel->update($values);
}
}

View File

@ -1,34 +1,40 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Core\Base;
use Kanboard\Api\Authorization\SubtaskAuthorization;
use Kanboard\Api\Authorization\TaskAuthorization;
/**
* Subtask API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class SubtaskApi extends Base
class SubtaskProcedure extends BaseProcedure
{
public function getSubtask($subtask_id)
{
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSubtask', $subtask_id);
return $this->subtaskModel->getById($subtask_id);
}
public function getAllSubtasks($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllSubtasks', $task_id);
return $this->subtaskModel->getAll($task_id);
}
public function removeSubtask($subtask_id)
{
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeSubtask', $subtask_id);
return $this->subtaskModel->remove($subtask_id);
}
public function createSubtask($task_id, $title, $user_id = 0, $time_estimated = 0, $time_spent = 0, $status = 0)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'createSubtask', $task_id);
$values = array(
'title' => $title,
'task_id' => $task_id,
@ -44,6 +50,8 @@ class SubtaskApi extends Base
public function updateSubtask($id, $task_id, $title = null, $user_id = null, $time_estimated = null, $time_spent = null, $status = null)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateSubtask', $task_id);
$values = array(
'id' => $id,
'task_id' => $task_id,

View File

@ -0,0 +1,39 @@
<?php
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\SubtaskAuthorization;
/**
* Subtask Time Tracking API controller
*
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
* @author Nikolaos Georgakis
*/
class SubtaskTimeTrackingProcedure extends BaseProcedure
{
public function hasSubtaskTimer($subtask_id, $user_id)
{
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'hasSubtaskTimer', $subtask_id);
return $this->subtaskTimeTrackingModel->hasTimer($subtask_id, $user_id);
}
public function logSubtaskStartTime($subtask_id, $user_id)
{
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'logSubtaskStartTime', $subtask_id);
return $this->subtaskTimeTrackingModel->logStartTime($subtask_id, $user_id);
}
public function logSubtaskEndTime($subtask_id,$user_id)
{
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'logSubtaskEndTime', $subtask_id);
return $this->subtaskTimeTrackingModel->logEndTime($subtask_id, $user_id);
}
public function getSubtaskTimeSpent($subtask_id,$user_id)
{
SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSubtaskTimeSpent', $subtask_id);
return $this->subtaskTimeTrackingModel->getTimeSpent($subtask_id, $user_id);
}
}

View File

@ -1,34 +1,39 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Core\Base;
use Kanboard\Api\Authorization\ProjectAuthorization;
/**
* Swimlane API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class SwimlaneApi extends Base
class SwimlaneProcedure extends BaseProcedure
{
public function getActiveSwimlanes($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getActiveSwimlanes', $project_id);
return $this->swimlaneModel->getSwimlanes($project_id);
}
public function getAllSwimlanes($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllSwimlanes', $project_id);
return $this->swimlaneModel->getAll($project_id);
}
public function getSwimlaneById($swimlane_id)
{
return $this->swimlaneModel->getById($swimlane_id);
$swimlane = $this->swimlaneModel->getById($swimlane_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSwimlaneById', $swimlane['project_id']);
return $swimlane;
}
public function getSwimlaneByName($project_id, $name)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSwimlaneByName', $project_id);
return $this->swimlaneModel->getByName($project_id, $name);
}
@ -39,11 +44,13 @@ class SwimlaneApi extends Base
public function getDefaultSwimlane($project_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getDefaultSwimlane', $project_id);
return $this->swimlaneModel->getDefault($project_id);
}
public function addSwimlane($project_id, $name, $description = '')
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addSwimlane', $project_id);
return $this->swimlaneModel->create(array('project_id' => $project_id, 'name' => $name, 'description' => $description));
}
@ -60,21 +67,25 @@ class SwimlaneApi extends Base
public function removeSwimlane($project_id, $swimlane_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeSwimlane', $project_id);
return $this->swimlaneModel->remove($project_id, $swimlane_id);
}
public function disableSwimlane($project_id, $swimlane_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'disableSwimlane', $project_id);
return $this->swimlaneModel->disable($project_id, $swimlane_id);
}
public function enableSwimlane($project_id, $swimlane_id)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'enableSwimlane', $project_id);
return $this->swimlaneModel->enable($project_id, $swimlane_id);
}
public function changeSwimlanePosition($project_id, $swimlane_id, $position)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeSwimlanePosition', $project_id);
return $this->swimlaneModel->changePosition($project_id, $swimlane_id, $position);
}
}

View File

@ -1,29 +1,36 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProjectAuthorization;
use Kanboard\Api\Authorization\TaskAuthorization;
use Kanboard\Api\Authorization\TaskFileAuthorization;
use Kanboard\Core\ObjectStorage\ObjectStorageException;
/**
* File API controller
* Task File API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class FileApi extends BaseApi
class TaskFileProcedure extends BaseProcedure
{
public function getTaskFile($file_id)
{
TaskFileAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTaskFile', $file_id);
return $this->taskFileModel->getById($file_id);
}
public function getAllTaskFiles($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllTaskFiles', $task_id);
return $this->taskFileModel->getAll($task_id);
}
public function downloadTaskFile($file_id)
{
TaskFileAuthorization::getInstance($this->container)->check($this->getClassName(), 'downloadTaskFile', $file_id);
try {
$file = $this->taskFileModel->getById($file_id);
@ -33,12 +40,14 @@ class FileApi extends BaseApi
} catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
}
return '';
}
public function createTaskFile($project_id, $task_id, $filename, $blob)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createTaskFile', $project_id);
try {
return $this->taskFileModel->uploadContent($task_id, $filename, $blob);
} catch (ObjectStorageException $e) {
@ -49,43 +58,13 @@ class FileApi extends BaseApi
public function removeTaskFile($file_id)
{
TaskFileAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeTaskFile', $file_id);
return $this->taskFileModel->remove($file_id);
}
public function removeAllTaskFiles($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeAllTaskFiles', $task_id);
return $this->taskFileModel->removeAll($task_id);
}
// Deprecated procedures
public function getFile($file_id)
{
return $this->getTaskFile($file_id);
}
public function getAllFiles($task_id)
{
return $this->getAllTaskFiles($task_id);
}
public function downloadFile($file_id)
{
return $this->downloadTaskFile($file_id);
}
public function createFile($project_id, $task_id, $filename, $blob)
{
return $this->createTaskFile($project_id, $task_id, $filename, $blob);
}
public function removeFile($file_id)
{
return $this->removeTaskFile($file_id);
}
public function removeAllFiles($task_id)
{
return $this->removeAllTaskFiles($task_id);
}
}

View File

@ -1,16 +1,17 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Core\Base;
use Kanboard\Api\Authorization\TaskAuthorization;
use Kanboard\Api\Authorization\TaskLinkAuthorization;
/**
* TaskLink API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class TaskLinkApi extends Base
class TaskLinkProcedure extends BaseProcedure
{
/**
* Get a task link
@ -21,6 +22,7 @@ class TaskLinkApi extends Base
*/
public function getTaskLinkById($task_link_id)
{
TaskLinkAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTaskLinkById', $task_link_id);
return $this->taskLinkModel->getById($task_link_id);
}
@ -33,6 +35,7 @@ class TaskLinkApi extends Base
*/
public function getAllTaskLinks($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllTaskLinks', $task_id);
return $this->taskLinkModel->getAll($task_id);
}
@ -47,6 +50,7 @@ class TaskLinkApi extends Base
*/
public function createTaskLink($task_id, $opposite_task_id, $link_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'createTaskLink', $task_id);
return $this->taskLinkModel->create($task_id, $opposite_task_id, $link_id);
}
@ -62,6 +66,7 @@ class TaskLinkApi extends Base
*/
public function updateTaskLink($task_link_id, $task_id, $opposite_task_id, $link_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateTaskLink', $task_id);
return $this->taskLinkModel->update($task_link_id, $task_id, $opposite_task_id, $link_id);
}
@ -74,6 +79,7 @@ class TaskLinkApi extends Base
*/
public function removeTaskLink($task_link_id)
{
TaskLinkAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeTaskLink', $task_link_id);
return $this->taskLinkModel->remove($task_link_id);
}
}

View File

@ -1,39 +1,41 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Api\Authorization\ProjectAuthorization;
use Kanboard\Api\Authorization\TaskAuthorization;
use Kanboard\Filter\TaskProjectFilter;
use Kanboard\Model\TaskModel;
/**
* Task API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class TaskApi extends BaseApi
class TaskProcedure extends BaseProcedure
{
public function searchTasks($project_id, $query)
{
$this->checkProjectPermission($project_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'searchTasks', $project_id);
return $this->taskLexer->build($query)->withFilter(new TaskProjectFilter($project_id))->toArray();
}
public function getTask($task_id)
{
$this->checkTaskPermission($task_id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTask', $task_id);
return $this->formatTask($this->taskFinderModel->getById($task_id));
}
public function getTaskByReference($project_id, $reference)
{
$this->checkProjectPermission($project_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTaskByReference', $project_id);
return $this->formatTask($this->taskFinderModel->getByReference($project_id, $reference));
}
public function getAllTasks($project_id, $status_id = TaskModel::STATUS_OPEN)
{
$this->checkProjectPermission($project_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllTasks', $project_id);
return $this->formatTasks($this->taskFinderModel->getAll($project_id, $status_id));
}
@ -44,40 +46,43 @@ class TaskApi extends BaseApi
public function getOverdueTasksByProject($project_id)
{
$this->checkProjectPermission($project_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getOverdueTasksByProject', $project_id);
return $this->taskFinderModel->getOverdueTasksByProject($project_id);
}
public function openTask($task_id)
{
$this->checkTaskPermission($task_id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'openTask', $task_id);
return $this->taskStatusModel->open($task_id);
}
public function closeTask($task_id)
{
$this->checkTaskPermission($task_id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'closeTask', $task_id);
return $this->taskStatusModel->close($task_id);
}
public function removeTask($task_id)
{
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeTask', $task_id);
return $this->taskModel->remove($task_id);
}
public function moveTaskPosition($project_id, $task_id, $column_id, $position, $swimlane_id = 0)
{
$this->checkProjectPermission($project_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'moveTaskPosition', $project_id);
return $this->taskPositionModel->movePosition($project_id, $task_id, $column_id, $position, $swimlane_id);
}
public function moveTaskToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'moveTaskToProject', $project_id);
return $this->taskDuplicationModel->moveToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id);
}
public function duplicateTaskToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null)
{
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'duplicateTaskToProject', $project_id);
return $this->taskDuplicationModel->duplicateToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id);
}
@ -86,8 +91,8 @@ class TaskApi extends BaseApi
$recurrence_status = 0, $recurrence_trigger = 0, $recurrence_factor = 0, $recurrence_timeframe = 0,
$recurrence_basedate = 0, $reference = '')
{
$this->checkProjectPermission($project_id);
ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createTask', $project_id);
if ($owner_id !== 0 && ! $this->projectPermissionModel->isAssignable($project_id, $owner_id)) {
return false;
}
@ -127,8 +132,7 @@ class TaskApi extends BaseApi
$recurrence_status = null, $recurrence_trigger = null, $recurrence_factor = null,
$recurrence_timeframe = null, $recurrence_basedate = null, $reference = null)
{
$this->checkTaskPermission($id);
TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateTask', $id);
$project_id = $this->taskFinderModel->getProjectId($id);
if ($project_id === 0) {
@ -139,7 +143,7 @@ class TaskApi extends BaseApi
return false;
}
$values = array(
$values = $this->filterValues(array(
'id' => $id,
'title' => $title,
'color_id' => $color_id,
@ -155,13 +159,7 @@ class TaskApi extends BaseApi
'recurrence_basedate' => $recurrence_basedate,
'reference' => $reference,
'priority' => $priority,
);
foreach ($values as $key => $value) {
if (is_null($value)) {
unset($values[$key]);
}
}
));
list($valid) = $this->taskValidator->validateApiModification($values);
return $valid && $this->taskModificationModel->update($values);

View File

@ -1,8 +1,7 @@
<?php
namespace Kanboard\Api;
namespace Kanboard\Api\Procedure;
use Kanboard\Core\Base;
use LogicException;
use Kanboard\Core\Security\Role;
use Kanboard\Core\Ldap\Client as LdapClient;
@ -12,10 +11,10 @@ use Kanboard\Core\Ldap\User as LdapUser;
/**
* User API controller
*
* @package Kanboard\Api
* @package Kanboard\Api\Procedure
* @author Frederic Guillot
*/
class UserApi extends Base
class UserProcedure extends BaseProcedure
{
public function getUser($user_id)
{
@ -118,19 +117,13 @@ class UserApi extends Base
public function updateUser($id, $username = null, $name = null, $email = null, $role = null)
{
$values = array(
$values = $this->filterValues(array(
'id' => $id,
'username' => $username,
'name' => $name,
'email' => $email,
'role' => $role,
);
foreach ($values as $key => $value) {
if (is_null($value)) {
unset($values[$key]);
}
}
));
list($valid, ) = $this->userValidator->validateApiModification($values);
return $valid && $this->userModel->update($values);

View File

@ -1,87 +0,0 @@
<?php
namespace Kanboard\Api;
/**
* Project API controller
*
* @package Kanboard\Api
* @author Frederic Guillot
*/
class ProjectApi extends BaseApi
{
public function getProjectById($project_id)
{
$this->checkProjectPermission($project_id);
return $this->formatProject($this->projectModel->getById($project_id));
}
public function getProjectByName($name)
{
return $this->formatProject($this->projectModel->getByName($name));
}
public function getAllProjects()
{
return $this->formatProjects($this->projectModel->getAll());
}
public function removeProject($project_id)
{
return $this->projectModel->remove($project_id);
}
public function enableProject($project_id)
{
return $this->projectModel->enable($project_id);
}
public function disableProject($project_id)
{
return $this->projectModel->disable($project_id);
}
public function enableProjectPublicAccess($project_id)
{
return $this->projectModel->enablePublicAccess($project_id);
}
public function disableProjectPublicAccess($project_id)
{
return $this->projectModel->disablePublicAccess($project_id);
}
public function getProjectActivities(array $project_ids)
{
return $this->helper->projectActivity->getProjectsEvents($project_ids);
}
public function getProjectActivity($project_id)
{
$this->checkProjectPermission($project_id);
return $this->helper->projectActivity->getProjectEvents($project_id);
}
public function createProject($name, $description = null)
{
$values = array(
'name' => $name,
'description' => $description
);
list($valid, ) = $this->projectValidator->validateCreation($values);
return $valid ? $this->projectModel->create($values) : false;
}
public function updateProject($id, $name, $description = null)
{
$values = array(
'id' => $id,
'name' => $name,
'description' => $description
);
list($valid, ) = $this->projectValidator->validateModification($values);
return $valid && $this->projectModel->update($values);
}
}

View File

@ -1,34 +0,0 @@
<?php
namespace Kanboard\Api;
use Kanboard\Core\Base;
/**
* Subtask Time Tracking API controller
*
* @package api
* @author Nikolaos Georgakis
*/
class SubtaskTimeTrackingApi extends Base
{
public function hasTimer($subtask_id,$user_id)
{
return $this->subtaskTimeTrackingModel->hasTimer($subtask_id,$user_id);
}
public function logStartTime($subtask_id,$user_id)
{
return $this->subtaskTimeTrackingModel->logStartTime($subtask_id,$user_id);
}
public function logEndTime($subtask_id,$user_id)
{
return $this->subtaskTimeTrackingModel->logEndTime($subtask_id,$user_id);
}
public function getTimeSpent($subtask_id,$user_id)
{
return $this->subtaskTimeTrackingModel->getTimeSpent($subtask_id,$user_id);
}
}

View File

@ -35,8 +35,12 @@ use Pimple\Container;
* @property \Kanboard\Core\Security\AuthenticationManager $authenticationManager
* @property \Kanboard\Core\Security\AccessMap $applicationAccessMap
* @property \Kanboard\Core\Security\AccessMap $projectAccessMap
* @property \Kanboard\Core\Security\AccessMap $apiAccessMap
* @property \Kanboard\Core\Security\AccessMap $apiProjectAccessMap
* @property \Kanboard\Core\Security\Authorization $applicationAuthorization
* @property \Kanboard\Core\Security\Authorization $projectAuthorization
* @property \Kanboard\Core\Security\Authorization $apiAuthorization
* @property \Kanboard\Core\Security\Authorization $apiProjectAuthorization
* @property \Kanboard\Core\Security\Role $role
* @property \Kanboard\Core\Security\Token $token
* @property \Kanboard\Core\Session\FlashMessage $flash

View File

@ -85,6 +85,18 @@ class ActionModel extends Base
return $action;
}
/**
* Get the projectId by the actionId
*
* @access public
* @param integer $action_id
* @return integer
*/
public function getProjectId($action_id)
{
return $this->db->table(self::TABLE)->eq('id', $action_id)->findOneColumn('project_id') ?: 0;
}
/**
* Attach parameters to actions
*

View File

@ -55,6 +55,18 @@ class CategoryModel extends Base
return $this->db->table(self::TABLE)->eq('id', $category_id)->findOneColumn('name') ?: '';
}
/**
* Get the projectId by the category id
*
* @access public
* @param integer $category_id Category id
* @return integer
*/
public function getProjectId($category_id)
{
return $this->db->table(self::TABLE)->eq('id', $category_id)->findOneColumn('project_id') ?: 0;
}
/**
* Get a category id by the category name and project id
*

View File

@ -31,6 +31,18 @@ class ColumnModel extends Base
return $this->db->table(self::TABLE)->eq('id', $column_id)->findOne();
}
/**
* Get projectId by the columnId
*
* @access public
* @param integer $column_id Column id
* @return integer
*/
public function getProjectId($column_id)
{
return $this->db->table(self::TABLE)->eq('id', $column_id)->findOneColumn('project_id');
}
/**
* Get the first column id for a given project
*

View File

@ -29,6 +29,22 @@ class CommentModel extends Base
const EVENT_CREATE = 'comment.create';
const EVENT_USER_MENTION = 'comment.user.mention';
/**
* Get projectId from commentId
*
* @access public
* @param integer $comment_id
* @return integer
*/
public function getProjectId($comment_id)
{
return $this->db
->table(self::TABLE)
->eq(self::TABLE.'.id', $comment_id)
->join(TaskModel::TABLE, 'id', 'task_id')
->findOneColumn(TaskModel::TABLE . '.project_id') ?: 0;
}
/**
* Get all comments for a given task
*

View File

@ -51,6 +51,22 @@ class SubtaskModel extends Base
const EVENT_CREATE = 'subtask.create';
const EVENT_DELETE = 'subtask.delete';
/**
* Get projectId from subtaskId
*
* @access public
* @param integer $subtask_id
* @return integer
*/
public function getProjectId($subtask_id)
{
return $this->db
->table(self::TABLE)
->eq(self::TABLE.'.id', $subtask_id)
->join(TaskModel::TABLE, 'id', 'task_id')
->findOneColumn(TaskModel::TABLE . '.project_id') ?: 0;
}
/**
* Get available status
*

View File

@ -72,6 +72,22 @@ class TaskFileModel extends FileModel
return self::EVENT_CREATE;
}
/**
* Get projectId from fileId
*
* @access public
* @param integer $file_id
* @return integer
*/
public function getProjectId($file_id)
{
return $this->db
->table(self::TABLE)
->eq(self::TABLE.'.id', $file_id)
->join(TaskModel::TABLE, 'id', 'task_id')
->findOneColumn(TaskModel::TABLE . '.project_id') ?: 0;
}
/**
* Handle screenshot upload
*

View File

@ -28,6 +28,22 @@ class TaskLinkModel extends Base
*/
const EVENT_CREATE_UPDATE = 'tasklink.create_update';
/**
* Get projectId from $task_link_id
*
* @access public
* @param integer $task_link_id
* @return integer
*/
public function getProjectId($task_link_id)
{
return $this->db
->table(self::TABLE)
->eq(self::TABLE.'.id', $task_link_id)
->join(TaskModel::TABLE, 'id', 'task_id')
->findOneColumn(TaskModel::TABLE . '.project_id') ?: 0;
}
/**
* Get a task link
*

View File

@ -3,26 +3,26 @@
namespace Kanboard\ServiceProvider;
use JsonRPC\Server;
use Kanboard\Api\ActionApi;
use Kanboard\Api\AppApi;
use Kanboard\Api\BoardApi;
use Kanboard\Api\CategoryApi;
use Kanboard\Api\ColumnApi;
use Kanboard\Api\CommentApi;
use Kanboard\Api\FileApi;
use Kanboard\Api\GroupApi;
use Kanboard\Api\GroupMemberApi;
use Kanboard\Api\LinkApi;
use Kanboard\Api\MeApi;
use Kanboard\Api\Middleware\AuthenticationApiMiddleware;
use Kanboard\Api\ProjectApi;
use Kanboard\Api\ProjectPermissionApi;
use Kanboard\Api\SubtaskApi;
use Kanboard\Api\SubtaskTimeTrackingApi;
use Kanboard\Api\SwimlaneApi;
use Kanboard\Api\TaskApi;
use Kanboard\Api\TaskLinkApi;
use Kanboard\Api\UserApi;
use Kanboard\Api\Procedure\ActionProcedure;
use Kanboard\Api\Procedure\AppProcedure;
use Kanboard\Api\Procedure\BoardProcedure;
use Kanboard\Api\Procedure\CategoryProcedure;
use Kanboard\Api\Procedure\ColumnProcedure;
use Kanboard\Api\Procedure\CommentProcedure;
use Kanboard\Api\Procedure\TaskFileProcedure;
use Kanboard\Api\Procedure\GroupProcedure;
use Kanboard\Api\Procedure\GroupMemberProcedure;
use Kanboard\Api\Procedure\LinkProcedure;
use Kanboard\Api\Procedure\MeProcedure;
use Kanboard\Api\Middleware\AuthenticationMiddleware;
use Kanboard\Api\Procedure\ProjectProcedure;
use Kanboard\Api\Procedure\ProjectPermissionProcedure;
use Kanboard\Api\Procedure\SubtaskProcedure;
use Kanboard\Api\Procedure\SubtaskTimeTrackingProcedure;
use Kanboard\Api\Procedure\SwimlaneProcedure;
use Kanboard\Api\Procedure\TaskProcedure;
use Kanboard\Api\Procedure\TaskLinkProcedure;
use Kanboard\Api\Procedure\UserProcedure;
use Pimple\Container;
use Pimple\ServiceProviderInterface;
@ -45,31 +45,32 @@ class ApiProvider implements ServiceProviderInterface
$server = new Server();
$server->setAuthenticationHeader(API_AUTHENTICATION_HEADER);
$server->getMiddlewareHandler()
->withMiddleware(new AuthenticationApiMiddleware($container))
->withMiddleware(new AuthenticationMiddleware($container))
;
$server->getProcedureHandler()
->withObject(new MeApi($container))
->withObject(new ActionApi($container))
->withObject(new AppApi($container))
->withObject(new BoardApi($container))
->withObject(new ColumnApi($container))
->withObject(new CategoryApi($container))
->withObject(new CommentApi($container))
->withObject(new FileApi($container))
->withObject(new LinkApi($container))
->withObject(new ProjectApi($container))
->withObject(new ProjectPermissionApi($container))
->withObject(new SubtaskApi($container))
->withObject(new SubtaskTimeTrackingApi($container))
->withObject(new SwimlaneApi($container))
->withObject(new TaskApi($container))
->withObject(new TaskLinkApi($container))
->withObject(new UserApi($container))
->withObject(new GroupApi($container))
->withObject(new GroupMemberApi($container))
->withObject(new MeProcedure($container))
->withObject(new ActionProcedure($container))
->withObject(new AppProcedure($container))
->withObject(new BoardProcedure($container))
->withObject(new ColumnProcedure($container))
->withObject(new CategoryProcedure($container))
->withObject(new CommentProcedure($container))
->withObject(new TaskFileProcedure($container))
->withObject(new LinkProcedure($container))
->withObject(new ProjectProcedure($container))
->withObject(new ProjectPermissionProcedure($container))
->withObject(new SubtaskProcedure($container))
->withObject(new SubtaskTimeTrackingProcedure($container))
->withObject(new SwimlaneProcedure($container))
->withObject(new TaskProcedure($container))
->withObject(new TaskLinkProcedure($container))
->withObject(new UserProcedure($container))
->withObject(new GroupProcedure($container))
->withObject(new GroupMemberProcedure($container))
->withBeforeMethod('beforeProcedure')
;
$container['api'] = $server;
return $container;
}

View File

@ -46,9 +46,13 @@ class AuthenticationProvider implements ServiceProviderInterface
$container['projectAccessMap'] = $this->getProjectAccessMap();
$container['applicationAccessMap'] = $this->getApplicationAccessMap();
$container['apiAccessMap'] = $this->getApiAccessMap();
$container['apiProjectAccessMap'] = $this->getApiProjectAccessMap();
$container['projectAuthorization'] = new Authorization($container['projectAccessMap']);
$container['applicationAuthorization'] = new Authorization($container['applicationAccessMap']);
$container['apiAuthorization'] = new Authorization($container['apiAccessMap']);
$container['apiProjectAuthorization'] = new Authorization($container['apiProjectAccessMap']);
return $container;
}
@ -151,4 +155,57 @@ class AuthenticationProvider implements ServiceProviderInterface
return $acl;
}
/**
* Get ACL for the API
*
* @access public
* @return AccessMap
*/
public function getApiAccessMap()
{
$acl = new AccessMap;
$acl->setDefaultRole(Role::APP_USER);
$acl->setRoleHierarchy(Role::APP_ADMIN, array(Role::APP_MANAGER, Role::APP_USER, Role::APP_PUBLIC));
$acl->setRoleHierarchy(Role::APP_MANAGER, array(Role::APP_USER, Role::APP_PUBLIC));
$acl->add('UserProcedure', '*', Role::APP_ADMIN);
$acl->add('GroupMemberProcedure', '*', Role::APP_ADMIN);
$acl->add('GroupProcedure', '*', Role::APP_ADMIN);
$acl->add('LinkProcedure', '*', Role::APP_ADMIN);
$acl->add('TaskProcedure', array('getOverdueTasks'), Role::APP_ADMIN);
$acl->add('ProjectProcedure', array('getAllProjects'), Role::APP_ADMIN);
$acl->add('ProjectProcedure', array('createProject'), Role::APP_MANAGER);
return $acl;
}
/**
* Get ACL for the API
*
* @access public
* @return AccessMap
*/
public function getApiProjectAccessMap()
{
$acl = new AccessMap;
$acl->setDefaultRole(Role::PROJECT_VIEWER);
$acl->setRoleHierarchy(Role::PROJECT_MANAGER, array(Role::PROJECT_MEMBER, Role::PROJECT_VIEWER));
$acl->setRoleHierarchy(Role::PROJECT_MEMBER, array(Role::PROJECT_VIEWER));
$acl->add('ActionProcedure', array('removeAction', 'getActions', 'createAction'), Role::PROJECT_MANAGER);
$acl->add('CategoryProcedure', '*', Role::PROJECT_MANAGER);
$acl->add('ColumnProcedure', '*', Role::PROJECT_MANAGER);
$acl->add('CommentProcedure', array('removeComment', 'createComment', 'updateComment'), Role::PROJECT_MEMBER);
$acl->add('ProjectPermissionProcedure', '*', Role::PROJECT_MANAGER);
$acl->add('ProjectProcedure', array('updateProject', 'removeProject', 'enableProject', 'disableProject', 'enableProjectPublicAccess', 'disableProjectPublicAccess'), Role::PROJECT_MANAGER);
$acl->add('SubtaskProcedure', '*', Role::PROJECT_MEMBER);
$acl->add('SubtaskTimeTrackingProcedure', '*', Role::PROJECT_MEMBER);
$acl->add('SwimlaneProcedure', '*', Role::PROJECT_MANAGER);
$acl->add('TaskFileProcedure', '*', Role::PROJECT_MEMBER);
$acl->add('TaskLinkProcedure', '*', Role::PROJECT_MEMBER);
$acl->add('TaskProcedure', '*', Role::PROJECT_MEMBER);
return $acl;
}
}

View File

@ -28,7 +28,7 @@ class ProjectValidator extends BaseValidator
new Validators\Integer('priority_start', t('This value must be an integer')),
new Validators\Integer('priority_end', t('This value must be an integer')),
new Validators\Integer('is_active', t('This value must be an integer')),
new Validators\Required('name', t('The project name is required')),
new Validators\NotEmpty('name', t('This field cannot be empty')),
new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50),
new Validators\MaxLength('identifier', t('The maximum length is %d characters', 50), 50),
new Validators\MaxLength('start_date', t('The maximum length is %d characters', 10), 10),
@ -47,11 +47,15 @@ class ProjectValidator extends BaseValidator
*/
public function validateCreation(array $values)
{
$rules = array(
new Validators\Required('name', t('The project name is required')),
);
if (! empty($values['identifier'])) {
$values['identifier'] = strtoupper($values['identifier']);
}
$v = new Validator($values, $this->commonValidationRules());
$v = new Validator($values, array_merge($this->commonValidationRules(), $rules));
return array(
$v->execute(),

View File

@ -14,7 +14,7 @@
"discard-changes": true
},
"require" : {
"php" : ">=5.3.3",
"php" : ">=5.3.9",
"ext-gd" : "*",
"ext-mbstring" : "*",
"ext-hash" : "*",
@ -23,21 +23,21 @@
"ext-ctype" : "*",
"ext-filter" : "*",
"ext-session" : "*",
"christian-riesen/otp" : "1.4",
"eluceo/ical": "0.8.0",
"christian-riesen/otp" : "1.4.3",
"eluceo/ical": "0.10.1",
"erusev/parsedown" : "1.6.0",
"fguillot/json-rpc" : "1.2.0",
"fguillot/json-rpc" : "1.2.1",
"fguillot/picodb" : "1.0.12",
"fguillot/simpleLogger" : "1.0.1",
"fguillot/simple-validator" : "1.0.0",
"fguillot/simple-validator" : "1.0.1",
"fguillot/simple-queue" : "1.0.1",
"paragonie/random_compat": "@stable",
"pimple/pimple" : "~3.0",
"ramsey/array_column": "@stable",
"swiftmailer/swiftmailer" : "~5.4",
"symfony/console" : "~2.7",
"symfony/event-dispatcher" : "~2.7",
"gregwar/captcha": "1.*"
"paragonie/random_compat": "2.0.2",
"pimple/pimple" : "3.0.2",
"ramsey/array_column": "1.1.3",
"swiftmailer/swiftmailer" : "5.4.2",
"symfony/console" : "2.8.7",
"symfony/event-dispatcher" : "2.7.14",
"gregwar/captcha": "1.1.1"
},
"autoload" : {
"classmap" : ["app/"],
@ -50,9 +50,10 @@
]
},
"require-dev" : {
"symfony/yaml" : "2.1",
"symfony/stopwatch" : "~2.6",
"phpunit/phpunit" : "4.8.*",
"phpunit/phpunit-selenium": "^2.0"
"phpdocumentor/reflection-docblock": "2.0.4",
"symfony/yaml": "2.8.7",
"symfony/stopwatch" : "2.6.13",
"phpunit/phpunit" : "4.8.26",
"phpunit/phpunit-selenium": "2.0.2"
}
}

228
composer.lock generated
View File

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "2de2026649db7bc41653bef80f974c6a",
"content-hash": "ea8ef74f1f1cf53b9f96b7609d756873",
"hash": "ab5b2c960b3a6d9f93883606269085e0",
"content-hash": "bd5f17c3382d7f85e33a68023927704c",
"packages": [
{
"name": "christian-riesen/base32",
@ -63,22 +63,25 @@
},
{
"name": "christian-riesen/otp",
"version": "1.4",
"version": "1.4.3",
"source": {
"type": "git",
"url": "https://github.com/ChristianRiesen/otp.git",
"reference": "a209b8bbd975d96d6b5287f8658562061adef1f8"
"reference": "20a539ce6280eb029030f4e7caefd5709a75e1ad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ChristianRiesen/otp/zipball/a209b8bbd975d96d6b5287f8658562061adef1f8",
"reference": "a209b8bbd975d96d6b5287f8658562061adef1f8",
"url": "https://api.github.com/repos/ChristianRiesen/otp/zipball/20a539ce6280eb029030f4e7caefd5709a75e1ad",
"reference": "20a539ce6280eb029030f4e7caefd5709a75e1ad",
"shasum": ""
},
"require": {
"christian-riesen/base32": ">=1.0",
"php": ">=5.3.0"
},
"suggest": {
"paragonie/random_compat": "Optional polyfill for a more secure random generator for pre PHP7 versions"
},
"type": "library",
"autoload": {
"psr-0": {
@ -107,20 +110,20 @@
"rfc6238",
"totp"
],
"time": "2015-02-12 09:11:49"
"time": "2015-10-08 08:17:59"
},
{
"name": "eluceo/ical",
"version": "0.8.0",
"version": "0.10.1",
"source": {
"type": "git",
"url": "https://github.com/markuspoerschke/iCal.git",
"reference": "a291711851d1538e2726ffe95862aa5e340ddb9a"
"reference": "2dd99c12c0aa961c541380ab0c113135e14af33e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/markuspoerschke/iCal/zipball/a291711851d1538e2726ffe95862aa5e340ddb9a",
"reference": "a291711851d1538e2726ffe95862aa5e340ddb9a",
"url": "https://api.github.com/repos/markuspoerschke/iCal/zipball/2dd99c12c0aa961c541380ab0c113135e14af33e",
"reference": "2dd99c12c0aa961c541380ab0c113135e14af33e",
"shasum": ""
},
"require": {
@ -160,7 +163,7 @@
"ics",
"php calendar"
],
"time": "2015-07-12 18:19:30"
"time": "2016-06-09 09:08:55"
},
{
"name": "erusev/parsedown",
@ -203,16 +206,16 @@
},
{
"name": "fguillot/json-rpc",
"version": "v1.2.0",
"version": "v1.2.1",
"source": {
"type": "git",
"url": "https://github.com/fguillot/JsonRPC.git",
"reference": "b002320b10aa1eeb7aee83f7b703cd6a6e99ff78"
"reference": "d491bb549bfa11aff4c37abcea2ffb28c9523f69"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/b002320b10aa1eeb7aee83f7b703cd6a6e99ff78",
"reference": "b002320b10aa1eeb7aee83f7b703cd6a6e99ff78",
"url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/d491bb549bfa11aff4c37abcea2ffb28c9523f69",
"reference": "d491bb549bfa11aff4c37abcea2ffb28c9523f69",
"shasum": ""
},
"require": {
@ -238,7 +241,7 @@
],
"description": "Simple Json-RPC client/server library that just works",
"homepage": "https://github.com/fguillot/JsonRPC",
"time": "2016-05-29 13:06:36"
"time": "2016-06-25 23:11:10"
},
{
"name": "fguillot/picodb",
@ -331,16 +334,16 @@
},
{
"name": "fguillot/simple-validator",
"version": "1.0.0",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://github.com/fguillot/simpleValidator.git",
"reference": "9579993f3dd0f03053b28fec1e7b9990edc3947b"
"reference": "23b0a99c5f11ad74d05f8845feaafbcfd9223eda"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fguillot/simpleValidator/zipball/9579993f3dd0f03053b28fec1e7b9990edc3947b",
"reference": "9579993f3dd0f03053b28fec1e7b9990edc3947b",
"url": "https://api.github.com/repos/fguillot/simpleValidator/zipball/23b0a99c5f11ad74d05f8845feaafbcfd9223eda",
"reference": "23b0a99c5f11ad74d05f8845feaafbcfd9223eda",
"shasum": ""
},
"require": {
@ -363,7 +366,7 @@
],
"description": "Simple validator library",
"homepage": "https://github.com/fguillot/simpleValidator",
"time": "2015-08-29 00:44:37"
"time": "2016-06-26 15:09:26"
},
{
"name": "fguillot/simpleLogger",
@ -682,16 +685,16 @@
},
{
"name": "symfony/console",
"version": "v2.8.6",
"version": "v2.8.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "48221d3de4dc22d2cd57c97e8b9361821da86609"
"reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/48221d3de4dc22d2cd57c97e8b9361821da86609",
"reference": "48221d3de4dc22d2cd57c97e8b9361821da86609",
"url": "https://api.github.com/repos/symfony/console/zipball/5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3",
"reference": "5ac8bc9aa77bb2edf06af3a1bb6bc1020d23acd3",
"shasum": ""
},
"require": {
@ -738,20 +741,20 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2016-04-26 12:00:47"
"time": "2016-06-06 15:06:25"
},
{
"name": "symfony/event-dispatcher",
"version": "v2.8.6",
"version": "v2.7.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "a158f13992a3147d466af7a23b564ac719a4ddd8"
"reference": "d3e09ed1224503791f31b913d22196f65f9afed5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a158f13992a3147d466af7a23b564ac719a4ddd8",
"reference": "a158f13992a3147d466af7a23b564ac719a4ddd8",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d3e09ed1224503791f31b913d22196f65f9afed5",
"reference": "d3e09ed1224503791f31b913d22196f65f9afed5",
"shasum": ""
},
"require": {
@ -759,10 +762,10 @@
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~2.0,>=2.0.5|~3.0.0",
"symfony/dependency-injection": "~2.6|~3.0.0",
"symfony/expression-language": "~2.6|~3.0.0",
"symfony/stopwatch": "~2.3|~3.0.0"
"symfony/config": "~2.0,>=2.0.5",
"symfony/dependency-injection": "~2.6",
"symfony/expression-language": "~2.6",
"symfony/stopwatch": "~2.3"
},
"suggest": {
"symfony/dependency-injection": "",
@ -771,7 +774,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
"dev-master": "2.7-dev"
}
},
"autoload": {
@ -798,7 +801,7 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2016-05-03 18:59:18"
"time": "2016-06-06 11:03:51"
},
{
"name": "symfony/polyfill-mbstring",
@ -966,32 +969,32 @@
},
{
"name": "phpspec/prophecy",
"version": "v1.6.0",
"version": "v1.6.1",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "3c91bdf81797d725b14cb62906f9a4ce44235972"
"reference": "58a8137754bc24b25740d4281399a4a3596058e0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972",
"reference": "3c91bdf81797d725b14cb62906f9a4ce44235972",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0",
"reference": "58a8137754bc24b25740d4281399a4a3596058e0",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "~2.0",
"sebastian/comparator": "~1.1",
"sebastian/recursion-context": "~1.0"
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
"sebastian/comparator": "^1.1",
"sebastian/recursion-context": "^1.0"
},
"require-dev": {
"phpspec/phpspec": "~2.0"
"phpspec/phpspec": "^2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.5.x-dev"
"dev-master": "1.6.x-dev"
}
},
"autoload": {
@ -1024,7 +1027,7 @@
"spy",
"stub"
],
"time": "2016-02-15 07:46:21"
"time": "2016-06-07 08:13:47"
},
{
"name": "phpunit/php-code-coverage",
@ -1629,16 +1632,16 @@
},
{
"name": "sebastian/exporter",
"version": "1.2.1",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "7ae5513327cb536431847bcc0c10edba2701064e"
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e",
"reference": "7ae5513327cb536431847bcc0c10edba2701064e",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
"shasum": ""
},
"require": {
@ -1646,12 +1649,13 @@
"sebastian/recursion-context": "~1.0"
},
"require-dev": {
"ext-mbstring": "*",
"phpunit/phpunit": "~4.4"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
"dev-master": "1.3.x-dev"
}
},
"autoload": {
@ -1691,7 +1695,7 @@
"export",
"exporter"
],
"time": "2015-06-21 07:55:53"
"time": "2016-06-17 09:04:28"
},
{
"name": "sebastian/global-state",
@ -1834,16 +1838,66 @@
},
{
"name": "symfony/stopwatch",
"version": "v2.8.6",
"version": "v2.6.13",
"target-dir": "Symfony/Component/Stopwatch",
"source": {
"type": "git",
"url": "https://github.com/symfony/stopwatch.git",
"reference": "9e24824b2a9a16e17ab997f61d70bc03948e434e"
"reference": "a0d91f2f4e2c60bd78f13388aa68f9d7cab8c987"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/9e24824b2a9a16e17ab997f61d70bc03948e434e",
"reference": "9e24824b2a9a16e17ab997f61d70bc03948e434e",
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/a0d91f2f4e2c60bd78f13388aa68f9d7cab8c987",
"reference": "a0d91f2f4e2c60bd78f13388aa68f9d7cab8c987",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.6-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\Stopwatch\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Stopwatch Component",
"homepage": "https://symfony.com",
"time": "2015-07-01 18:23:01"
},
{
"name": "symfony/yaml",
"version": "v2.8.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/815fabf3f48c7d1df345a69d1ad1a88f59757b34",
"reference": "815fabf3f48c7d1df345a69d1ad1a88f59757b34",
"shasum": ""
},
"require": {
@ -1857,7 +1911,7 @@
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Stopwatch\\": ""
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
@ -1877,68 +1931,18 @@
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Stopwatch Component",
"homepage": "https://symfony.com",
"time": "2016-03-04 07:54:35"
},
{
"name": "symfony/yaml",
"version": "v2.1.0",
"target-dir": "Symfony/Component/Yaml",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "f18e004fc975707bb4695df1dbbe9b0d8c8b7715"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/f18e004fc975707bb4695df1dbbe9b0d8c8b7715",
"reference": "f18e004fc975707bb4695df1dbbe9b0d8c8b7715",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.1-dev"
}
},
"autoload": {
"psr-0": {
"Symfony\\Component\\Yaml": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Symfony Community",
"homepage": "http://symfony.com/contributors"
},
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Symfony Yaml Component",
"homepage": "http://symfony.com",
"time": "2012-08-22 13:48:41"
"homepage": "https://symfony.com",
"time": "2016-06-06 11:11:27"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"paragonie/random_compat": 0,
"ramsey/array_column": 0
},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=5.3.3",
"php": ">=5.3.9",
"ext-gd": "*",
"ext-mbstring": "*",
"ext-hash": "*",

View File

@ -1,48 +1,26 @@
API Authentication
==================
API endpoint
------------
URL: `https://YOUR_SERVER/jsonrpc.php`
Default method (HTTP Basic)
---------------------------
The API credentials are available on the settings page.
- API end-point: `https://YOUR_SERVER/jsonrpc.php`
If you want to use the "application api":
### Application credentials
- Username: `jsonrpc`
- Password: API token on the settings page
Otherwise for the "user api", just use the real username/passsword.
### User credentials
- Use the real username and password
The API use the [HTTP Basic Authentication Scheme described in the RFC2617](http://www.ietf.org/rfc/rfc2617.txt).
If there is an authentication error, you will receive the HTTP status code `401 Not Authorized`.
### Authorized User API procedures
- getMe
- getMyDashboard
- getMyActivityStream
- createMyPrivateProject
- getMyProjectsList
- getMyProjects
- getTimezone
- getVersion
- getDefaultTaskColor
- getDefaultTaskColors
- getColorList
- getProjectById
- getTask
- getTaskByReference
- getAllTasks
- openTask
- closeTask
- moveTaskPosition
- createTask
- updateTask
- getBoard
- getProjectActivity
- getMyOverdueTasks
Custom HTTP header
------------------
@ -64,3 +42,14 @@ curl \
-d '{"jsonrpc": "2.0", "method": "getAllProjects", "id": 1}' \
http://localhost/kanboard/jsonrpc.php
```
Authentication error
--------------------
If the credentials are wrong, you will receive a `401 Not Authorized` and the corresponding JSON response.
Authorization error
-------------------
If the connected user is not allowed to access to the resource, you will receive a `403 Forbidden`.

View File

@ -8,25 +8,25 @@ There are two types of API access:
### Application API
- Access to the API with the user "jsonrpc" and the token available in settings
- Access to the API with the user "jsonrpc" and the token available on the settings page
- Access to all procedures
- No permission checked
- There is no user session on the server
- No access to procedures that starts with "My..." (example: "getMe" or "getMyProjects")
- Example of possible clients: tools to migrate/import data, create tasks from another system, etc...
### User API
- Access to the API with the user credentials (username and password)
- Access to a restricted set of procedures
- The project permissions are checked
- Application role and project permissions are checked for each procedure
- A user session is created on the server
- Example of possible clients: mobile/desktop application, command line utility, etc...
- Example of possible clients: native mobile/desktop application, command line utility, etc...
Security
--------
- Always use HTTPS with a valid certificate
- If you make a mobile application, it's your job to store securely the user credentials on the device
- Always use HTTPS with a valid certificate (avoid clear text communication)
- If you make a mobile application, it's your responsability to store securely the user credentials on the device
- After 3 authentication failure on the user api, the end-user have to unlock his account by using the login form
- Two factor authentication is not yet available through the API

View File

@ -272,3 +272,36 @@ Response example:
"result": true
}
```
## getProjectUserRole
- Purpose: **Get the role of a user for a given project**
- Parameters:
- **project_id** (integer, required)
- **user_id** (integer, required)
- Result on success: **role name**
- Result on failure: **false**
Request example:
```json
{
"jsonrpc": "2.0",
"method": "getProjectUserRole",
"id": 2114673298,
"params": [
"2",
"3"
]
}
```
Response example:
```json
{
"jsonrpc": "2.0",
"id": 2114673298,
"result": "project-viewer"
}
```

View File

@ -7,6 +7,8 @@ API Project Procedures
- Parameters:
- **name** (string, required)
- **description** (string, optional)
- **owner_id** (integer, optional)
- **identifier** (string, optional)
- Result on success: **project_id**
- Result on failure: **false**
@ -183,9 +185,11 @@ Response example:
- Purpose: **Update a project**
- Parameters:
- **id** (integer, required)
- **name** (string, required)
- **project_id** (integer, required)
- **name** (string, optional)
- **description** (string, optional)
- **owner_id** (integer, optional)
- **identifier** (string, optional)
- Result on success: **true**
- Result on failure: **false**
@ -197,7 +201,7 @@ Request example:
"method": "updateProject",
"id": 1853996288,
"params": {
"id": 1,
"project_id": 1,
"name": "PHP client update"
}
}

View File

@ -51,7 +51,7 @@ Kanboard is pre-configured to work with Apache (URL rewriting).
| PHP Version |
|----------------|
| PHP >= 5.3.3 |
| PHP >= 5.3.9 |
| PHP 5.4 |
| PHP 5.5 |
| PHP 5.6 |

View File

@ -9,7 +9,7 @@ Requirements
------------
- Linux/Unix machine
- PHP cli
- PHP
- PHPUnit installed
- Mysql and Postgresql (optional)
- Selenium (optional)
@ -85,46 +85,37 @@ From your Kanboard directory, run the command `phpunit -c tests/units.postgres.x
Integration Tests
-----------------
Acceptance tests (also known as end-to-end tests and sometimes functional tests) allow us to test the actual functionality of the browser using Selenium and PHPUnit.
Integration tests are mainly used to test the API.
The test suites are making real HTTP calls to the application that run inside a container.
The PHPUnit config file is `tests/acceptance.xml`.
From your Kanboard directory, run the command `phpunit -c tests/units.sqlite.xml`.
### Requirements
Actually only the API calls are tested.
- PHP
- Composer
- Unix operating system (Mac OS or Linux)
- Docker
- Docker Compose
Real HTTP calls are made with those tests.
So a local instance of Kanboard is necessary and must listen on `http://localhost:8000/`.
### Running integration tests
All data will be removed/altered by the test suite.
Moreover the script will reset and set a new API key.
Integration tests are using Docker containers.
There are 3 different environment available to run tests against each supported database.
1. Start a local instance of Kanboard `php -S 127.0.0.1:8000`
2. Run the test suite from another terminal
The same method as above is used to run tests across different databases:
- Sqlite: `phpunit -c tests/integration.sqlite.xml`
- Mysql: `phpunit -c tests/integration.mysql.xml`
- Postgresql: `phpunit -c tests/integration.postgres.xml`
Example:
You can use these commands to run each test suite:
```bash
phpunit -c tests/integration.sqlite.xml
# Run tests with Sqlite
make integration-test-sqlite
PHPUnit 5.0.0 by Sebastian Bergmann and contributors.
# Run tests with Mysql
make integration-test-mysql
............................................................... 63 / 135 ( 46%)
............................................................... 126 / 135 ( 93%)
......... 135 / 135 (100%)
Time: 1.18 minutes, Memory: 14.75Mb
OK (135 tests, 526 assertions)
# Run tests with Postgres
make integration-test-postgres
```
Acceptance Tests
-----------------
----------------
Acceptance tests (also sometimes known as end-to-end tests, and functional tests) test the actual functionality of the UI in a browser using Selenium.

View File

@ -0,0 +1,12 @@
<?php
define('DB_DRIVER', 'mysql');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', 'kanboard');
define('DB_HOSTNAME', 'mysql');
define('DB_NAME', 'kanboard');
define('DEBUG', true);
define('LOG_DRIVER', 'stderr');
define('API_AUTHENTICATION_TOKEN', 'test');

View File

@ -0,0 +1,12 @@
<?php
define('DB_DRIVER', 'postgres');
define('DB_USERNAME', 'postgres');
define('DB_PASSWORD', 'postgres');
define('DB_HOSTNAME', 'postgres');
define('DB_NAME', 'kanboard');
define('DEBUG', true);
define('LOG_DRIVER', 'stderr');
define('API_AUTHENTICATION_TOKEN', 'test');

View File

@ -0,0 +1,8 @@
<?php
define('DB_DRIVER', 'sqlite');
define('DEBUG', true);
define('LOG_DRIVER', 'file');
define('API_AUTHENTICATION_TOKEN', 'test');

View File

@ -0,0 +1,24 @@
FROM ubuntu:16.04
RUN mkdir -p /var/lock/apache2 /var/run/apache2 /var/log/supervisor
RUN apt-get update -qq && \
apt-get install -y apache2 supervisor cron curl unzip \
libapache2-mod-php7.0 php7.0-cli php7.0-mbstring php7.0-xml php7.0-mysql php7.0-sqlite3 \
php7.0-opcache php7.0-json php7.0-pgsql php7.0-ldap php7.0-gd php7.0-zip && \
apt clean && \
echo "ServerName localhost" >> /etc/apache2/apache2.conf && \
sed -ri 's/AllowOverride None/AllowOverride All/g' /etc/apache2/apache2.conf && \
a2enmod rewrite && \
curl -sS https://getcomposer.org/installer | php -- --filename=/usr/local/bin/composer
COPY . /var/www/html
RUN chown -R www-data:www-data /var/www/html/data /var/www/html/plugins
COPY tests/docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY tests/configs /configs/
EXPOSE 80
ENTRYPOINT ["/var/www/html/tests/docker/entrypoint.sh"]

View File

@ -0,0 +1,27 @@
version: '2'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: "kanboard"
MYSQL_DATABASE: "kanboard"
MYSQL_USER: "kanboard"
MYSQL_PASSWORD: "kanboard"
ports:
- "3306:3306"
app:
build:
context: ../..
dockerfile: tests/docker/Dockerfile.xenial
ports:
- "8000:80"
depends_on:
- mysql
command: config-mysql
tests:
build:
context: ../..
dockerfile: tests/docker/Dockerfile.xenial
depends_on:
- app
command: integration-test-mysql

View File

@ -0,0 +1,26 @@
version: '2'
services:
postgres:
image: postgres:9.5
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: kanboard
ports:
- "5432:5432"
app:
build:
context: ../..
dockerfile: tests/docker/Dockerfile.xenial
ports:
- "8000:80"
depends_on:
- postgres
command: config-postgres
tests:
build:
context: ../..
dockerfile: tests/docker/Dockerfile.xenial
depends_on:
- app
command: integration-test-postgres

View File

@ -0,0 +1,16 @@
version: '2'
services:
app:
build:
context: ../..
dockerfile: tests/docker/Dockerfile.xenial
ports:
- "8000:80"
command: config-sqlite
tests:
build:
context: ../..
dockerfile: tests/docker/Dockerfile.xenial
depends_on:
- app
command: integration-test-sqlite

33
tests/docker/entrypoint.sh Executable file
View File

@ -0,0 +1,33 @@
#!/usr/bin/env bash
function wait_schema_creation() {
curl -s http://app/login > /dev/null
sleep $1
}
case "$1" in
"config-sqlite")
cp /configs/config.sqlite.php /var/www/html/config.php
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
;;
"config-postgres")
cp /configs/config.postgres.php /var/www/html/config.php
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
;;
"config-mysql")
cp /configs/config.mysql.php /var/www/html/config.php
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
;;
"integration-test-sqlite")
wait_schema_creation 1
/var/www/html/vendor/phpunit/phpunit/phpunit -c /var/www/html/tests/integration.sqlite.xml
;;
"integration-test-postgres")
wait_schema_creation 5
/var/www/html/vendor/phpunit/phpunit/phpunit -c /var/www/html/tests/integration.postgres.xml
;;
"integration-test-mysql")
wait_schema_creation 15
/var/www/html/vendor/phpunit/phpunit/phpunit -c /var/www/html/tests/integration.mysql.xml
;;
esac

View File

@ -0,0 +1,6 @@
[supervisord]
nodaemon=true
[program:apache2]
command=/bin/bash -c "source /etc/apache2/envvars && exec /usr/sbin/apache2 -DFOREGROUND"
autorestart=true

View File

@ -5,16 +5,8 @@
</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="" />
<const name="DB_PORT" value="" />
<const name="DB_SSL_KEY" value="" />
<const name="DB_SSL_CA" value="" />
<const name="DB_SSL_CERT" value="" />
<const name="BASE_URL" value="http://app/" />
<const name="API_URL" value="http://app/jsonrpc.php" />
<const name="API_KEY" value="test" />
</php>
</phpunit>

View File

@ -5,13 +5,8 @@
</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" />
<const name="DB_PORT" value="" />
<const name="BASE_URL" value="http://app/" />
<const name="API_URL" value="http://app/jsonrpc.php" />
<const name="API_KEY" value="test" />
</php>
</phpunit>
</phpunit>

View File

@ -5,9 +5,8 @@
</testsuite>
</testsuites>
<php>
<const name="API_URL" value="http://127.0.0.1:8000/jsonrpc.php" />
<const name="API_KEY" value="19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929" />
<const name="DB_DRIVER" value="sqlite" />
<const name="DB_FILENAME" value="data/db.sqlite" />
<const name="BASE_URL" value="http://app/" />
<const name="API_URL" value="http://app/jsonrpc.php" />
<const name="API_KEY" value="test" />
</php>
</phpunit>
</phpunit>

View File

@ -0,0 +1,66 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class ActionProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My project to test actions';
public function testGetAvailableActions()
{
$actions = $this->app->getAvailableActions();
$this->assertNotEmpty($actions);
$this->assertInternalType('array', $actions);
$this->assertArrayHasKey('\Kanboard\Action\TaskCloseColumn', $actions);
}
public function testGetAvailableActionEvents()
{
$events = $this->app->getAvailableActionEvents();
$this->assertNotEmpty($events);
$this->assertInternalType('array', $events);
$this->assertArrayHasKey('task.move.column', $events);
}
public function testGetCompatibleActionEvents()
{
$events = $this->app->getCompatibleActionEvents('\Kanboard\Action\TaskCloseColumn');
$this->assertNotEmpty($events);
$this->assertInternalType('array', $events);
$this->assertArrayHasKey('task.move.column', $events);
}
public function testCRUD()
{
$this->assertCreateTeamProject();
$this->assertCreateAction();
$this->assertGetActions();
$this->assertRemoveAction();
}
public function assertCreateAction()
{
$actionId = $this->app->createAction($this->projectId, 'task.move.column', '\Kanboard\Action\TaskCloseColumn', array('column_id' => 1));
$this->assertNotFalse($actionId);
$this->assertTrue($actionId > 0);
}
public function assertGetActions()
{
$actions = $this->app->getActions($this->projectId);
$this->assertNotEmpty($actions);
$this->assertInternalType('array', $actions);
$this->assertArrayHasKey('id', $actions[0]);
$this->assertArrayHasKey('project_id', $actions[0]);
$this->assertArrayHasKey('event_name', $actions[0]);
$this->assertArrayHasKey('action_name', $actions[0]);
$this->assertArrayHasKey('params', $actions[0]);
$this->assertArrayHasKey('column_id', $actions[0]['params']);
}
public function assertRemoveAction()
{
$actionId = $this->app->createAction($this->projectId, 'task.move.column', '\Kanboard\Action\TaskCloseColumn', array('column_id' => 1));
$this->assertTrue($this->app->removeAction($actionId));
}
}

View File

@ -1,928 +0,0 @@
<?php
require_once __DIR__.'/../../vendor/autoload.php';
class Api extends PHPUnit_Framework_TestCase
{
private $client = null;
public static function setUpBeforeClass()
{
if (DB_DRIVER === 'sqlite') {
@unlink(DB_FILENAME);
} elseif (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;
} elseif (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;
}
$service = new Kanboard\ServiceProvider\DatabaseProvider;
$db = $service->getInstance();
$db->table('settings')->eq('option', 'api_token')->update(array('value' => API_KEY));
$db->table('settings')->eq('option', 'application_timezone')->update(array('value' => 'Europe/Paris'));
$db->closeConnection();
}
public function setUp()
{
$this->client = new JsonRPC\Client(API_URL);
$this->client->authentication('jsonrpc', API_KEY);
// $this->client->debug = true;
}
private function getTaskId()
{
$tasks = $this->client->getAllTasks(1, 1);
$this->assertNotEmpty($tasks);
return $tasks[0]['id'];
}
public function testRemoveAll()
{
$projects = $this->client->getAllProjects();
if ($projects) {
foreach ($projects as $project) {
$this->assertEquals('http://127.0.0.1:8000/?controller=BoardViewController&action=show&project_id='.$project['id'], $project['url']['board']);
$this->assertEquals('http://127.0.0.1:8000/?controller=CalendarController&action=show&project_id='.$project['id'], $project['url']['calendar']);
$this->assertEquals('http://127.0.0.1:8000/?controller=TaskListController&action=show&project_id='.$project['id'], $project['url']['list']);
$this->assertTrue($this->client->removeProject($project['id']));
}
}
}
public function testCreateProject()
{
$project_id = $this->client->createProject('API test');
$this->assertNotFalse($project_id);
$this->assertInternalType('int', $project_id);
}
public function testGetProjectById()
{
$project = $this->client->getProjectById(1);
$this->assertNotEmpty($project);
$this->assertEquals(1, $project['id']);
$this->assertEquals('http://127.0.0.1:8000/?controller=BoardViewController&action=show&project_id='.$project['id'], $project['url']['board']);
$this->assertEquals('http://127.0.0.1:8000/?controller=CalendarController&action=show&project_id='.$project['id'], $project['url']['calendar']);
$this->assertEquals('http://127.0.0.1:8000/?controller=TaskListController&action=show&project_id='.$project['id'], $project['url']['list']);
}
public function testGetProjectByName()
{
$project = $this->client->getProjectByName('API test');
$this->assertNotEmpty($project);
$this->assertEquals(1, $project['id']);
$this->assertEquals('http://127.0.0.1:8000/?controller=BoardViewController&action=show&project_id='.$project['id'], $project['url']['board']);
$this->assertEquals('http://127.0.0.1:8000/?controller=CalendarController&action=show&project_id='.$project['id'], $project['url']['calendar']);
$this->assertEquals('http://127.0.0.1:8000/?controller=TaskListController&action=show&project_id='.$project['id'], $project['url']['list']);
$project = $this->client->getProjectByName(array('name' => 'API test'));
$this->assertNotEmpty($project);
$this->assertEquals(1, $project['id']);
$project = $this->client->getProjectByName('None');
$this->assertEmpty($project);
$this->assertNull($project);
}
public function testGetAllProjects()
{
$projects = $this->client->getAllProjects();
$this->assertNotEmpty($projects);
foreach ($projects as $project) {
$this->assertEquals('http://127.0.0.1:8000/?controller=BoardViewController&action=show&project_id='.$project['id'], $project['url']['board']);
$this->assertEquals('http://127.0.0.1:8000/?controller=CalendarController&action=show&project_id='.$project['id'], $project['url']['calendar']);
$this->assertEquals('http://127.0.0.1:8000/?controller=TaskListController&action=show&project_id='.$project['id'], $project['url']['list']);
}
}
public function testUpdateProject()
{
$project = $this->client->getProjectById(1);
$this->assertNotEmpty($project);
$this->assertTrue($this->client->execute('updateProject', array('id' => 1, 'name' => 'API test 2')));
$project = $this->client->getProjectById(1);
$this->assertEquals('API test 2', $project['name']);
$this->assertTrue($this->client->execute('updateProject', array('id' => 1, 'name' => 'API test', 'description' => 'test')));
$project = $this->client->getProjectById(1);
$this->assertEquals('API test', $project['name']);
$this->assertEquals('test', $project['description']);
}
public function testDisableProject()
{
$this->assertTrue($this->client->disableProject(1));
$project = $this->client->getProjectById(1);
$this->assertNotEmpty($project);
$this->assertEquals(0, $project['is_active']);
}
public function testEnableProject()
{
$this->assertTrue($this->client->enableProject(1));
$project = $this->client->getProjectById(1);
$this->assertNotEmpty($project);
$this->assertEquals(1, $project['is_active']);
}
public function testEnableProjectPublicAccess()
{
$this->assertTrue($this->client->enableProjectPublicAccess(1));
$project = $this->client->getProjectById(1);
$this->assertNotEmpty($project);
$this->assertEquals(1, $project['is_public']);
$this->assertNotEmpty($project['token']);
}
public function testDisableProjectPublicAccess()
{
$this->assertTrue($this->client->disableProjectPublicAccess(1));
$project = $this->client->getProjectById(1);
$this->assertNotEmpty($project);
$this->assertEquals(0, $project['is_public']);
$this->assertEmpty($project['token']);
}
public function testgetProjectActivities()
{
$activities = $this->client->getProjectActivities(array('project_ids' => array(1)));
$this->assertInternalType('array', $activities);
$this->assertCount(0, $activities);
}
public function testgetProjectActivity()
{
$activities = $this->client->getProjectActivity(1);
$this->assertInternalType('array', $activities);
$this->assertCount(0, $activities);
}
public function testCreateTaskWithWrongMember()
{
$task = array(
'title' => 'Task #1',
'color_id' => 'blue',
'owner_id' => 1,
'project_id' => 1,
'column_id' => 2,
);
$task_id = $this->client->createTask($task);
$this->assertFalse($task_id);
}
public function testGetAllowedUsers()
{
$users = $this->client->getMembers(1);
$this->assertNotFalse($users);
$this->assertEquals(array(), $users);
}
public function testAddMember()
{
$this->assertTrue($this->client->allowUser(1, 1));
}
public function testCreateTask()
{
$task = array(
'title' => 'Task #1',
'color_id' => 'blue',
'owner_id' => 1,
'project_id' => 1,
'column_id' => 2,
);
$task_id = $this->client->createTask($task);
$this->assertNotFalse($task_id);
$this->assertInternalType('int', $task_id);
$this->assertTrue($task_id > 0);
}
/**
* @expectedException InvalidArgumentException
*/
public function testCreateTaskWithBadParams()
{
$task = array(
'title' => 'Task #1',
'color_id' => 'blue',
'owner_id' => 1,
);
$this->client->createTask($task);
}
public function testGetTask()
{
$task = $this->client->getTask(1);
$this->assertNotFalse($task);
$this->assertTrue(is_array($task));
$this->assertEquals('Task #1', $task['title']);
$this->assertEquals('http://127.0.0.1:8000/?controller=TaskViewController&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'], $task['url']);
}
public function testGetAllTasks()
{
$tasks = $this->client->getAllTasks(1, 1);
$this->assertNotFalse($tasks);
$this->assertTrue(is_array($tasks));
$this->assertEquals('Task #1', $tasks[0]['title']);
$this->assertEquals('http://127.0.0.1:8000/?controller=TaskViewController&action=show&task_id='.$tasks[0]['id'].'&project_id='.$tasks[0]['project_id'], $tasks[0]['url']);
$tasks = $this->client->getAllTasks(2, 0);
$this->assertNotFalse($tasks);
$this->assertTrue(is_array($tasks));
$this->assertEmpty($tasks);
}
public function testMoveTaskSwimlane()
{
$task_id = $this->getTaskId();
$task = $this->client->getTask($task_id);
$this->assertNotFalse($task);
$this->assertTrue(is_array($task));
$this->assertEquals(1, $task['position']);
$this->assertEquals(2, $task['column_id']);
$this->assertEquals(0, $task['swimlane_id']);
$moved_timestamp = $task['date_moved'];
sleep(1);
$this->assertTrue($this->client->moveTaskPosition(1, $task_id, 4, 1, 2));
$task = $this->client->getTask($task_id);
$this->assertNotFalse($task);
$this->assertTrue(is_array($task));
$this->assertEquals(1, $task['position']);
$this->assertEquals(4, $task['column_id']);
$this->assertEquals(2, $task['swimlane_id']);
$this->assertNotEquals($moved_timestamp, $task['date_moved']);
}
public function testUpdateTask()
{
$task = $this->client->getTask(1);
$values = array();
$values['id'] = $task['id'];
$values['color_id'] = 'green';
$values['description'] = 'test';
$values['date_due'] = '';
$this->assertTrue($this->client->execute('updateTask', $values));
}
public function testRemoveTask()
{
$this->assertTrue($this->client->removeTask(1));
}
public function testRemoveUsers()
{
$users = $this->client->getAllUsers();
$this->assertNotFalse($users);
$this->assertNotEmpty($users);
foreach ($users as $user) {
if ($user['id'] > 1) {
$this->assertTrue($this->client->removeUser($user['id']));
}
}
}
public function testCreateUser()
{
$user = array(
'username' => 'toto',
'name' => 'Toto',
'password' => '123456',
);
$user_id = $this->client->execute('createUser', $user);
$this->assertNotFalse($user_id);
$this->assertInternalType('int', $user_id);
$this->assertTrue($user_id > 0);
}
public function testCreateManagerUser()
{
$user = array(
'username' => 'manager',
'name' => 'Manager',
'password' => '123456',
'role' => 'app-manager'
);
$user_id = $this->client->execute('createUser', $user);
$this->assertNotFalse($user_id);
$this->assertInternalType('int', $user_id);
$this->assertTrue($user_id > 0);
}
/**
* @expectedException InvalidArgumentException
*/
public function testCreateUserWithBadParams()
{
$user = array(
'name' => 'Titi',
'password' => '123456',
);
$this->assertNull($this->client->execute('createUser', $user));
}
public function testGetUser()
{
$user = $this->client->getUser(2);
$this->assertNotFalse($user);
$this->assertTrue(is_array($user));
$this->assertEquals('toto', $user['username']);
$user = $this->client->getUser(3);
$this->assertNotEmpty($user);
$this->assertEquals('app-manager', $user['role']);
$this->assertNull($this->client->getUser(2222));
}
public function testGetUserByName()
{
$user = $this->client->getUserByName('toto');
$this->assertNotFalse($user);
$this->assertTrue(is_array($user));
$this->assertEquals(2, $user['id']);
$user = $this->client->getUserByName('manager');
$this->assertNotEmpty($user);
$this->assertEquals('app-manager', $user['role']);
$this->assertNull($this->client->getUserByName('nonexistantusername'));
}
public function testUpdateUser()
{
$user = array();
$user['id'] = 2;
$user['username'] = 'titi';
$user['name'] = 'Titi';
$this->assertTrue($this->client->execute('updateUser', $user));
$user = $this->client->getUser(2);
$this->assertNotFalse($user);
$this->assertTrue(is_array($user));
$this->assertEquals('titi', $user['username']);
$this->assertEquals('Titi', $user['name']);
$user = array();
$user['id'] = 2;
$user['email'] = 'titi@localhost';
$this->assertTrue($this->client->execute('updateUser', $user));
$user = $this->client->getUser(2);
$this->assertNotFalse($user);
$this->assertTrue(is_array($user));
$this->assertEquals('titi@localhost', $user['email']);
}
public function testAllowedUser()
{
$this->assertTrue($this->client->allowUser(1, 2));
$users = $this->client->getMembers(1);
$this->assertNotFalse($users);
$this->assertEquals(array(1 => 'admin', 2 => 'Titi'), $users);
}
public function testRevokeUser()
{
$this->assertTrue($this->client->revokeUser(1, 2));
$users = $this->client->getMembers(1);
$this->assertNotFalse($users);
$this->assertEquals(array(1 => 'admin'), $users);
}
public function testCreateComment()
{
$task = array(
'title' => 'Task with comment',
'color_id' => 'red',
'owner_id' => 1,
'project_id' => 1,
'column_id' => 1,
);
$this->assertNotFalse($this->client->execute('createTask', $task));
$tasks = $this->client->getAllTasks(1, 1);
$this->assertNotEmpty($tasks);
$this->assertEquals(1, count($tasks));
$comment = array(
'task_id' => $tasks[0]['id'],
'user_id' => 2,
'content' => 'boo',
);
$comment_id = $this->client->execute('createComment', $comment);
$this->assertNotFalse($comment_id);
$this->assertInternalType('int', $comment_id);
$this->assertTrue($comment_id > 0);
}
public function testGetComment()
{
$comment = $this->client->getComment(1);
$this->assertNotFalse($comment);
$this->assertNotEmpty($comment);
$this->assertEquals(2, $comment['user_id']);
$this->assertEquals('boo', $comment['comment']);
}
public function testUpdateComment()
{
$comment = array();
$comment['id'] = 1;
$comment['content'] = 'test';
$this->assertTrue($this->client->execute('updateComment', $comment));
$comment = $this->client->getComment(1);
$this->assertEquals('test', $comment['comment']);
}
public function testGetAllComments()
{
$task_id = $this->getTaskId();
$comment = array(
'task_id' => $task_id,
'user_id' => 1,
'content' => 'blabla',
);
$comment_id = $this->client->createComment($comment);
$this->assertNotFalse($comment_id);
$this->assertInternalType('int', $comment_id);
$this->assertTrue($comment_id > 0);
$comments = $this->client->getAllComments($task_id);
$this->assertNotFalse($comments);
$this->assertNotEmpty($comments);
$this->assertTrue(is_array($comments));
$this->assertEquals(2, count($comments));
}
public function testRemoveComment()
{
$task_id = $this->getTaskId();
$comments = $this->client->getAllComments($task_id);
$this->assertNotFalse($comments);
$this->assertNotEmpty($comments);
$this->assertTrue(is_array($comments));
foreach ($comments as $comment) {
$this->assertTrue($this->client->removeComment($comment['id']));
}
$comments = $this->client->getAllComments($task_id);
$this->assertNotFalse($comments);
$this->assertEmpty($comments);
$this->assertTrue(is_array($comments));
}
public function testCreateSubtask()
{
$subtask = array(
'task_id' => $this->getTaskId(),
'title' => 'subtask #1',
);
$subtask_id = $this->client->createSubtask($subtask);
$this->assertNotFalse($subtask_id);
$this->assertInternalType('int', $subtask_id);
$this->assertTrue($subtask_id > 0);
}
public function testGetSubtask()
{
$subtask = $this->client->getSubtask(1);
$this->assertNotFalse($subtask);
$this->assertNotEmpty($subtask);
$this->assertEquals($this->getTaskId(), $subtask['task_id']);
$this->assertEquals(0, $subtask['user_id']);
$this->assertEquals('subtask #1', $subtask['title']);
}
public function testUpdateSubtask()
{
$subtask = array();
$subtask['id'] = 1;
$subtask['task_id'] = $this->getTaskId();
$subtask['title'] = 'test';
$this->assertTrue($this->client->execute('updateSubtask', $subtask));
$subtask = $this->client->getSubtask(1);
$this->assertEquals('test', $subtask['title']);
}
public function testGetAllSubtasks()
{
$subtask = array(
'task_id' => $this->getTaskId(),
'user_id' => 2,
'title' => 'Subtask #2',
);
$this->assertNotFalse($this->client->execute('createSubtask', $subtask));
$subtasks = $this->client->getAllSubtasks($this->getTaskId());
$this->assertNotFalse($subtasks);
$this->assertNotEmpty($subtasks);
$this->assertTrue(is_array($subtasks));
$this->assertEquals(2, count($subtasks));
}
public function testRemoveSubtask()
{
$this->assertTrue($this->client->removeSubtask(1));
$subtasks = $this->client->getAllSubtasks($this->getTaskId());
$this->assertNotFalse($subtasks);
$this->assertNotEmpty($subtasks);
$this->assertTrue(is_array($subtasks));
$this->assertEquals(1, count($subtasks));
}
public function testMoveTaskPosition()
{
$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']);
$this->assertEquals(3, $task['column_id']);
}
public function testCategoryCreation()
{
$category = array(
'name' => 'Category',
'project_id' => 1,
);
$cat_id = $this->client->execute('createCategory', $category);
$this->assertNotFalse($cat_id);
$this->assertInternalType('int', $cat_id);
$this->assertTrue($cat_id > 0);
// Duplicate
$category = array(
'name' => 'Category',
'project_id' => 1,
);
$this->assertFalse($this->client->execute('createCategory', $category));
}
/**
* @expectedException InvalidArgumentException
*/
public function testCategoryCreationWithBadParams()
{
// Missing project id
$category = array(
'name' => 'Category',
);
$this->assertNull($this->client->execute('createCategory', $category));
}
public function testCategoryRead()
{
$category = $this->client->getCategory(1);
$this->assertTrue(is_array($category));
$this->assertNotEmpty($category);
$this->assertEquals(1, $category['id']);
$this->assertEquals('Category', $category['name']);
$this->assertEquals(1, $category['project_id']);
}
public function testGetAllCategories()
{
$categories = $this->client->getAllCategories(1);
$this->assertNotEmpty($categories);
$this->assertNotFalse($categories);
$this->assertTrue(is_array($categories));
$this->assertEquals(1, count($categories));
$this->assertEquals(1, $categories[0]['id']);
$this->assertEquals('Category', $categories[0]['name']);
$this->assertEquals(1, $categories[0]['project_id']);
}
public function testCategoryUpdate()
{
$category = array(
'id' => 1,
'name' => 'Renamed category',
);
$this->assertTrue($this->client->execute('updateCategory', $category));
$category = $this->client->getCategory(1);
$this->assertTrue(is_array($category));
$this->assertNotEmpty($category);
$this->assertEquals(1, $category['id']);
$this->assertEquals('Renamed category', $category['name']);
$this->assertEquals(1, $category['project_id']);
}
public function testCategoryRemove()
{
$this->assertTrue($this->client->removeCategory(1));
$this->assertFalse($this->client->removeCategory(1));
$this->assertFalse($this->client->removeCategory(1111));
}
public function testGetAvailableActions()
{
$actions = $this->client->getAvailableActions();
$this->assertNotEmpty($actions);
$this->assertInternalType('array', $actions);
$this->assertArrayHasKey('\Kanboard\Action\TaskCloseColumn', $actions);
}
public function testGetAvailableActionEvents()
{
$events = $this->client->getAvailableActionEvents();
$this->assertNotEmpty($events);
$this->assertInternalType('array', $events);
$this->assertArrayHasKey('task.move.column', $events);
}
public function testGetCompatibleActionEvents()
{
$events = $this->client->getCompatibleActionEvents('\Kanboard\Action\TaskCloseColumn');
$this->assertNotEmpty($events);
$this->assertInternalType('array', $events);
$this->assertArrayHasKey('task.move.column', $events);
}
public function testCreateAction()
{
$action_id = $this->client->createAction(1, 'task.move.column', '\Kanboard\Action\TaskCloseColumn', array('column_id' => 1));
$this->assertNotFalse($action_id);
$this->assertEquals(1, $action_id);
}
public function testGetActions()
{
$actions = $this->client->getActions(1);
$this->assertNotEmpty($actions);
$this->assertInternalType('array', $actions);
$this->assertCount(1, $actions);
$this->assertArrayHasKey('id', $actions[0]);
$this->assertArrayHasKey('project_id', $actions[0]);
$this->assertArrayHasKey('event_name', $actions[0]);
$this->assertArrayHasKey('action_name', $actions[0]);
$this->assertArrayHasKey('params', $actions[0]);
$this->assertArrayHasKey('column_id', $actions[0]['params']);
}
public function testRemoveAction()
{
$this->assertTrue($this->client->removeAction(1));
$actions = $this->client->getActions(1);
$this->assertEmpty($actions);
$this->assertCount(0, $actions);
}
public function testGetAllLinks()
{
$links = $this->client->getAllLinks();
$this->assertNotEmpty($links);
$this->assertArrayHasKey('id', $links[0]);
$this->assertArrayHasKey('label', $links[0]);
$this->assertArrayHasKey('opposite_id', $links[0]);
}
public function testGetOppositeLink()
{
$link = $this->client->getOppositeLinkId(1);
$this->assertEquals(1, $link);
$link = $this->client->getOppositeLinkId(2);
$this->assertEquals(3, $link);
}
public function testGetLinkByLabel()
{
$link = $this->client->getLinkByLabel('blocks');
$this->assertNotEmpty($link);
$this->assertEquals(2, $link['id']);
$this->assertEquals(3, $link['opposite_id']);
}
public function testGetLinkById()
{
$link = $this->client->getLinkById(4);
$this->assertNotEmpty($link);
$this->assertEquals(4, $link['id']);
$this->assertEquals(5, $link['opposite_id']);
$this->assertEquals('duplicates', $link['label']);
}
public function testCreateLink()
{
$link_id = $this->client->createLink(array('label' => 'test'));
$this->assertNotFalse($link_id);
$this->assertInternalType('int', $link_id);
$link_id = $this->client->createLink(array('label' => 'foo', 'opposite_label' => 'bar'));
$this->assertNotFalse($link_id);
$this->assertInternalType('int', $link_id);
}
public function testUpdateLink()
{
$link1 = $this->client->getLinkByLabel('bar');
$this->assertNotEmpty($link1);
$link2 = $this->client->getLinkByLabel('test');
$this->assertNotEmpty($link2);
$this->assertNotFalse($this->client->updateLink($link1['id'], $link2['id'], 'boo'));
$link = $this->client->getLinkById($link1['id']);
$this->assertNotEmpty($link);
$this->assertEquals($link2['id'], $link['opposite_id']);
$this->assertEquals('boo', $link['label']);
$this->assertTrue($this->client->removeLink($link1['id']));
}
public function testCreateTaskLink()
{
$task_id1 = $this->client->createTask(array('project_id' => 1, 'title' => 'A'));
$this->assertNotFalse($task_id1);
$task_id2 = $this->client->createTask(array('project_id' => 1, 'title' => 'B'));
$this->assertNotFalse($task_id2);
$task_id3 = $this->client->createTask(array('project_id' => 1, 'title' => 'C'));
$this->assertNotFalse($task_id3);
$task_link_id = $this->client->createTaskLink($task_id1, $task_id2, 1);
$this->assertNotFalse($task_link_id);
$task_link = $this->client->getTaskLinkById($task_link_id);
$this->assertNotEmpty($task_link);
$this->assertEquals($task_id1, $task_link['task_id']);
$this->assertEquals($task_id2, $task_link['opposite_task_id']);
$this->assertEquals(1, $task_link['link_id']);
$task_links = $this->client->getAllTaskLinks($task_id1);
$this->assertNotEmpty($task_links);
$this->assertCount(1, $task_links);
$this->assertTrue($this->client->updateTaskLink($task_link_id, $task_id1, $task_id3, 2));
$task_link = $this->client->getTaskLinkById($task_link_id);
$this->assertNotEmpty($task_link);
$this->assertEquals($task_id1, $task_link['task_id']);
$this->assertEquals($task_id3, $task_link['opposite_task_id']);
$this->assertEquals(2, $task_link['link_id']);
$this->assertTrue($this->client->removeTaskLink($task_link_id));
$this->assertEmpty($this->client->getAllTaskLinks($task_id1));
}
public function testCreateFile()
{
$this->assertNotFalse($this->client->createFile(1, $this->getTaskId(), 'My file', base64_encode('plain text file')));
}
public function testGetAllFiles()
{
$files = $this->client->getAllFiles(array('task_id' => $this->getTaskId()));
$this->assertNotEmpty($files);
$this->assertCount(1, $files);
$this->assertEquals('My file', $files[0]['name']);
$file = $this->client->getFile($files[0]['id']);
$this->assertNotEmpty($file);
$this->assertEquals('My file', $file['name']);
$content = $this->client->downloadFile($file['id']);
$this->assertNotEmpty($content);
$this->assertEquals('plain text file', base64_decode($content));
$content = $this->client->downloadFile(1234567);
$this->assertEmpty($content);
$this->assertTrue($this->client->removeFile($file['id']));
$this->assertEmpty($this->client->getAllFiles(1));
}
public function testRemoveAllFiles()
{
$this->assertNotFalse($this->client->createFile(1, $this->getTaskId(), 'My file 1', base64_encode('plain text file')));
$this->assertNotFalse($this->client->createFile(1, $this->getTaskId(), 'My file 2', base64_encode('plain text file')));
$files = $this->client->getAllFiles(array('task_id' => $this->getTaskId()));
$this->assertNotEmpty($files);
$this->assertCount(2, $files);
$this->assertTrue($this->client->removeAllFiles(array('task_id' => $this->getTaskId())));
$files = $this->client->getAllFiles(array('task_id' => $this->getTaskId()));
$this->assertEmpty($files);
}
public function testCreateTaskWithReference()
{
$task = array(
'title' => 'Task with external ticket number',
'reference' => 'TICKET-1234',
'project_id' => 1,
'description' => '[Link to my ticket](http://my-ticketing-system/1234)',
);
$task_id = $this->client->createTask($task);
$this->assertNotFalse($task_id);
$this->assertInternalType('int', $task_id);
$this->assertTrue($task_id > 0);
}
public function testGetTaskByReference()
{
$task = $this->client->getTaskByReference(array('project_id' => 1, 'reference' => 'TICKET-1234'));
$this->assertNotEmpty($task);
$this->assertEquals('Task with external ticket number', $task['title']);
$this->assertEquals('TICKET-1234', $task['reference']);
$this->assertEquals('http://127.0.0.1:8000/?controller=TaskViewController&action=show&task_id='.$task['id'].'&project_id='.$task['project_id'], $task['url']);
}
public function testCreateOverdueTask()
{
$this->assertNotFalse($this->client->createTask(array(
'title' => 'overdue task',
'project_id' => 1,
'date_due' => date('Y-m-d', strtotime('-2days')),
)));
}
public function testGetOverdueTasksByProject()
{
$tasks = $this->client->getOverdueTasksByProject(1);
$this->assertNotEmpty($tasks);
$this->assertCount(1, $tasks);
$this->assertEquals('overdue task', $tasks[0]['title']);
$this->assertEquals('API test', $tasks[0]['project_name']);
}
public function testGetOverdueTasks()
{
$tasks = $this->client->getOverdueTasks();
$this->assertNotEmpty($tasks);
$this->assertCount(1, $tasks);
$this->assertEquals('overdue task', $tasks[0]['title']);
$this->assertEquals('API test', $tasks[0]['project_name']);
}
}

View File

@ -1,8 +1,8 @@
<?php
require_once __DIR__.'/Base.php';
require_once __DIR__.'/BaseProcedureTest.php';
class AppTest extends Base
class AppProcedureTest extends BaseProcedureTest
{
public function testGetTimezone()
{
@ -31,4 +31,24 @@ class AppTest extends Base
$this->assertEquals('Project Member', $roles['project-member']);
$this->assertEquals('Project Viewer', $roles['project-viewer']);
}
public function testGetDefaultColor()
{
$this->assertEquals('yellow', $this->user->getDefaultTaskColor());
}
public function testGetDefaultColors()
{
$colors = $this->user->getDefaultTaskColors();
$this->assertNotEmpty($colors);
$this->assertArrayHasKey('red', $colors);
}
public function testGetColorList()
{
$colors = $this->user->getColorList();
$this->assertNotEmpty($colors);
$this->assertArrayHasKey('red', $colors);
$this->assertEquals('Red', $colors['red']);
}
}

View File

@ -1,62 +0,0 @@
<?php
require_once __DIR__.'/../../vendor/autoload.php';
abstract class Base extends PHPUnit_Framework_TestCase
{
protected $app = null;
protected $admin = null;
protected $user = null;
public static function setUpBeforeClass()
{
if (DB_DRIVER === 'sqlite') {
@unlink(DB_FILENAME);
} elseif (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;
} elseif (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;
}
$service = new Kanboard\ServiceProvider\DatabaseProvider;
$db = $service->getInstance();
$db->table('settings')->eq('option', 'api_token')->update(array('value' => API_KEY));
$db->closeConnection();
}
public function setUp()
{
$this->app = new JsonRPC\Client(API_URL);
$this->app->authentication('jsonrpc', API_KEY);
$this->app->getHttpClient()->withDebug();
$this->admin = new JsonRPC\Client(API_URL);
$this->admin->authentication('admin', 'admin');
$this->admin->getHttpClient()->withDebug();
$this->user = new JsonRPC\Client(API_URL);
$this->user->authentication('user', 'password');
$this->user->getHttpClient()->withDebug();
}
protected function getProjectId()
{
$projects = $this->app->getAllProjects();
$this->assertNotEmpty($projects);
return $projects[0]['id'];
}
protected function getGroupId()
{
$groups = $this->app->getAllGroups();
$this->assertNotEmpty($groups);
return $groups[0]['id'];
}
}

View File

@ -0,0 +1,122 @@
<?php
require_once __DIR__.'/../../vendor/autoload.php';
abstract class BaseProcedureTest extends PHPUnit_Framework_TestCase
{
protected $app = null;
protected $admin = null;
protected $manager = null;
protected $user = null;
protected $adminUserId = 0;
protected $managerUserId = 0;
protected $userUserId = 0;
protected $projectName = '';
protected $projectId = 0;
protected $taskTitle = 'My task';
protected $taskId = 0;
protected $groupName1 = 'My Group A';
protected $groupName2 = 'My Group B';
protected $groupId1;
protected $groupId2;
protected $username = 'test-user';
protected $userId;
public function setUp()
{
$this->setUpAppClient();
$this->setUpAdminUser();
$this->setUpManagerUser();
$this->setUpStandardUser();
}
public function setUpAppClient()
{
$this->app = new JsonRPC\Client(API_URL);
$this->app->authentication('jsonrpc', API_KEY);
$this->app->getHttpClient()->withDebug()->withTimeout(10);
}
public function setUpAdminUser()
{
$this->adminUserId = $this->getUserId('superuser');
if (! $this->adminUserId) {
$this->adminUserId = $this->app->createUser('superuser', 'password', 'Admin User', 'user@localhost', 'app-admin');
$this->assertNotFalse($this->adminUserId);
}
$this->admin = new JsonRPC\Client(API_URL);
$this->admin->authentication('superuser', 'password');
$this->admin->getHttpClient()->withDebug();
}
public function setUpManagerUser()
{
$this->managerUserId = $this->getUserId('manager');
if (! $this->managerUserId) {
$this->managerUserId = $this->app->createUser('manager', 'password', 'Manager User', 'user@localhost', 'app-manager');
$this->assertNotFalse($this->managerUserId);
}
$this->manager = new JsonRPC\Client(API_URL);
$this->manager->authentication('manager', 'password');
$this->manager->getHttpClient()->withDebug();
}
public function setUpStandardUser()
{
$this->userUserId = $this->getUserId('user');
if (! $this->userUserId) {
$this->userUserId = $this->app->createUser('user', 'password', 'Standard User', 'user@localhost', 'app-user');
$this->assertNotFalse($this->userUserId);
}
$this->user = new JsonRPC\Client(API_URL);
$this->user->authentication('user', 'password');
$this->user->getHttpClient()->withDebug();
}
public function getUserId($username)
{
$user = $this->app->getUserByName($username);
if (! empty($user)) {
return $user['id'];
}
return 0;
}
public function assertCreateTeamProject()
{
$this->projectId = $this->app->createProject($this->projectName, 'Description');
$this->assertNotFalse($this->projectId);
}
public function assertCreateUser()
{
$this->userId = $this->app->createUser($this->username, 'password');
$this->assertNotFalse($this->userId);
}
public function assertCreateGroups()
{
$this->groupId1 = $this->app->createGroup($this->groupName1);
$this->groupId2 = $this->app->createGroup($this->groupName2, 'External ID');
$this->assertNotFalse($this->groupId1);
$this->assertNotFalse($this->groupId2);
}
public function assertCreateTask()
{
$this->taskId = $this->app->createTask(array('title' => $this->taskTitle, 'project_id' => $this->projectId));
$this->assertNotFalse($this->taskId);
}
}

View File

@ -0,0 +1,25 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class BoardProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My project to test board';
public function testAll()
{
$this->assertCreateTeamProject();
$this->assertGetBoard();
}
public function assertGetBoard()
{
$board = $this->app->getBoard($this->projectId);
$this->assertNotNull($board);
$this->assertCount(1, $board);
$this->assertEquals('Default swimlane', $board[0]['name']);
$this->assertCount(4, $board[0]['columns']);
$this->assertEquals('Ready', $board[0]['columns'][1]['title']);
}
}

View File

@ -1,21 +0,0 @@
<?php
require_once __DIR__.'/Base.php';
class BoardTest extends Base
{
public function testCreateProject()
{
$this->assertEquals(1, $this->app->createProject('A project'));
}
public function testGetBoard()
{
$board = $this->app->getBoard(1);
$this->assertCount(1, $board);
$this->assertEquals('Default swimlane', $board[0]['name']);
$this->assertCount(4, $board[0]['columns']);
$this->assertEquals('Ready', $board[0]['columns'][1]['title']);
}
}

View File

@ -0,0 +1,76 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class CategoryProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My project to test categories';
private $categoryId = 0;
public function testAll()
{
$this->assertCreateTeamProject();
$this->assertCreateCategory();
$this->assertThatCategoriesAreUnique();
$this->assertGetCategory();
$this->assertGetAllCategories();
$this->assertCategoryUpdate();
$this->assertRemoveCategory();
}
public function assertCreateCategory()
{
$this->categoryId = $this->app->createCategory(array(
'name' => 'Category',
'project_id' => $this->projectId,
));
$this->assertNotFalse($this->categoryId);
}
public function assertThatCategoriesAreUnique()
{
$this->assertFalse($this->app->execute('createCategory', array(
'name' => 'Category',
'project_id' => $this->projectId,
)));
}
public function assertGetCategory()
{
$category = $this->app->getCategory($this->categoryId);
$this->assertInternalType('array', $category);
$this->assertEquals($this->categoryId, $category['id']);
$this->assertEquals('Category', $category['name']);
$this->assertEquals($this->projectId, $category['project_id']);
}
public function assertGetAllCategories()
{
$categories = $this->app->getAllCategories($this->projectId);
$this->assertCount(1, $categories);
$this->assertEquals($this->categoryId, $categories[0]['id']);
$this->assertEquals('Category', $categories[0]['name']);
$this->assertEquals($this->projectId, $categories[0]['project_id']);
}
public function assertCategoryUpdate()
{
$this->assertTrue($this->app->execute('updateCategory', array(
'id' => $this->categoryId,
'name' => 'Renamed category',
)));
$category = $this->app->getCategory($this->categoryId);
$this->assertEquals('Renamed category', $category['name']);
}
public function assertRemoveCategory()
{
$this->assertTrue($this->app->removeCategory($this->categoryId));
$this->assertFalse($this->app->removeCategory($this->categoryId));
$this->assertFalse($this->app->removeCategory(1111));
}
}

View File

@ -0,0 +1,69 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class ColumnProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My project to test columns';
private $columns = array();
public function testAll()
{
$this->assertCreateTeamProject();
$this->assertGetColumns();
$this->assertUpdateColumn();
$this->assertAddColumn();
$this->assertRemoveColumn();
$this->assertChangeColumnPosition();
}
public function assertGetColumns()
{
$this->columns = $this->app->getColumns($this->projectId);
$this->assertCount(4, $this->columns);
$this->assertEquals('Done', $this->columns[3]['title']);
}
public function assertUpdateColumn()
{
$this->assertTrue($this->app->updateColumn($this->columns[3]['id'], 'Another column', 2));
$this->columns = $this->app->getColumns($this->projectId);
$this->assertEquals('Another column', $this->columns[3]['title']);
$this->assertEquals(2, $this->columns[3]['task_limit']);
}
public function assertAddColumn()
{
$column_id = $this->app->addColumn($this->projectId, 'New column');
$this->assertNotFalse($column_id);
$this->assertTrue($column_id > 0);
$this->columns = $this->app->getColumns($this->projectId);
$this->assertCount(5, $this->columns);
$this->assertEquals('New column', $this->columns[4]['title']);
}
public function assertRemoveColumn()
{
$this->assertTrue($this->app->removeColumn($this->columns[3]['id']));
$this->columns = $this->app->getColumns($this->projectId);
$this->assertCount(4, $this->columns);
}
public function assertChangeColumnPosition()
{
$this->assertTrue($this->app->changeColumnPosition($this->projectId, $this->columns[0]['id'], 3));
$this->columns = $this->app->getColumns($this->projectId);
$this->assertEquals('Ready', $this->columns[0]['title']);
$this->assertEquals(1, $this->columns[0]['position']);
$this->assertEquals('Work in progress', $this->columns[1]['title']);
$this->assertEquals(2, $this->columns[1]['position']);
$this->assertEquals('Backlog', $this->columns[2]['title']);
$this->assertEquals(3, $this->columns[2]['position']);
$this->assertEquals('New column', $this->columns[3]['title']);
$this->assertEquals(4, $this->columns[3]['position']);
}
}

View File

@ -1,65 +0,0 @@
<?php
require_once __DIR__.'/Base.php';
class ColumnTest extends Base
{
public function testCreateProject()
{
$this->assertEquals(1, $this->app->createProject('A project'));
}
public function testGetColumns()
{
$columns = $this->app->getColumns($this->getProjectId());
$this->assertCount(4, $columns);
$this->assertEquals('Done', $columns[3]['title']);
}
public function testUpdateColumn()
{
$this->assertTrue($this->app->updateColumn(4, 'Boo', 2));
$columns = $this->app->getColumns($this->getProjectId());
$this->assertEquals('Boo', $columns[3]['title']);
$this->assertEquals(2, $columns[3]['task_limit']);
}
public function testAddColumn()
{
$column_id = $this->app->addColumn($this->getProjectId(), 'New column');
$this->assertNotFalse($column_id);
$this->assertInternalType('int', $column_id);
$this->assertTrue($column_id > 0);
$columns = $this->app->getColumns($this->getProjectId());
$this->assertCount(5, $columns);
$this->assertEquals('New column', $columns[4]['title']);
}
public function testRemoveColumn()
{
$this->assertTrue($this->app->removeColumn(5));
$columns = $this->app->getColumns($this->getProjectId());
$this->assertCount(4, $columns);
}
public function testChangeColumnPosition()
{
$this->assertTrue($this->app->changeColumnPosition($this->getProjectId(), 1, 3));
$columns = $this->app->getColumns($this->getProjectId());
$this->assertCount(4, $columns);
$this->assertEquals('Ready', $columns[0]['title']);
$this->assertEquals(1, $columns[0]['position']);
$this->assertEquals('Work in progress', $columns[1]['title']);
$this->assertEquals(2, $columns[1]['position']);
$this->assertEquals('Backlog', $columns[2]['title']);
$this->assertEquals(3, $columns[2]['position']);
$this->assertEquals('Boo', $columns[3]['title']);
$this->assertEquals(4, $columns[3]['position']);
}
}

View File

@ -0,0 +1,63 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class CommentProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My project to test comments';
private $commentId = 0;
public function testAll()
{
$this->assertCreateTeamProject();
$this->assertCreateTask();
$this->assertCreateComment();
$this->assertUpdateComment();
$this->assertGetAllComments();
$this->assertRemoveComment();
}
public function assertCreateComment()
{
$this->commentId = $this->app->execute('createComment', array(
'task_id' => $this->taskId,
'user_id' => 1,
'content' => 'foobar',
));
$this->assertNotFalse($this->commentId);
}
public function assertGetComment()
{
$comment = $this->app->getComment($this->commentId);
$this->assertNotFalse($comment);
$this->assertNotEmpty($comment);
$this->assertEquals(1, $comment['user_id']);
$this->assertEquals('foobar', $comment['comment']);
}
public function assertUpdateComment()
{
$this->assertTrue($this->app->execute('updateComment', array(
'id' => $this->commentId,
'content' => 'test',
)));
$comment = $this->app->getComment($this->commentId);
$this->assertEquals('test', $comment['comment']);
}
public function assertGetAllComments()
{
$comments = $this->app->getAllComments($this->taskId);
$this->assertCount(1, $comments);
$this->assertEquals('test', $comments[0]['comment']);
}
public function assertRemoveComment()
{
$this->assertTrue($this->app->removeComment($this->commentId));
$this->assertFalse($this->app->removeComment($this->commentId));
}
}

View File

@ -0,0 +1,53 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class GroupMemberProcedureTest extends BaseProcedureTest
{
protected $username = 'user-group-member';
protected $groupName1 = 'My group member A';
protected $groupName2 = 'My group member B';
public function testAll()
{
$this->assertCreateGroups();
$this->assertCreateUser();
$this->assertAddMember();
$this->assertGetMembers();
$this->assertIsGroupMember();
$this->assertGetGroups();
$this->assertRemove();
}
public function assertAddMember()
{
$this->assertTrue($this->app->addGroupMember($this->groupId1, $this->userId));
}
public function assertGetMembers()
{
$members = $this->app->getGroupMembers($this->groupId1);
$this->assertCount(1, $members);
$this->assertEquals($this->username, $members[0]['username']);
}
public function assertIsGroupMember()
{
$this->assertTrue($this->app->isGroupMember($this->groupId1, $this->userId));
$this->assertFalse($this->app->isGroupMember($this->groupId1, $this->adminUserId));
}
public function assertGetGroups()
{
$groups = $this->app->getMemberGroups($this->userId);
$this->assertCount(1, $groups);
$this->assertEquals($this->groupId1, $groups[0]['id']);
$this->assertEquals($this->groupName1, $groups[0]['name']);
}
public function assertRemove()
{
$this->assertTrue($this->app->removeGroupMember($this->groupId1, $this->userId));
$this->assertFalse($this->app->isGroupMember($this->groupId1, $this->userId));
}
}

View File

@ -1,47 +0,0 @@
<?php
require_once __DIR__.'/Base.php';
class GroupMemberTest extends Base
{
public function testAddMember()
{
$this->assertNotFalse($this->app->createGroup('My Group A'));
$this->assertNotFalse($this->app->createGroup('My Group B'));
$groupId = $this->getGroupId();
$this->assertTrue($this->app->addGroupMember($groupId, 1));
}
public function testGetMembers()
{
$groups = $this->app->getAllGroups();
$members = $this->app->getGroupMembers($groups[0]['id']);
$this->assertCount(1, $members);
$this->assertEquals('admin', $members[0]['username']);
$this->assertSame(array(), $this->app->getGroupMembers($groups[1]['id']));
}
public function testIsGroupMember()
{
$groupId = $this->getGroupId();
$this->assertTrue($this->app->isGroupMember($groupId, 1));
$this->assertFalse($this->app->isGroupMember($groupId, 2));
}
public function testGetGroups()
{
$groups = $this->app->getMemberGroups(1);
$this->assertCount(1, $groups);
$this->assertEquals(1, $groups[0]['id']);
$this->assertEquals('My Group A', $groups[0]['name']);
}
public function testRemove()
{
$groupId = $this->getGroupId();
$this->assertTrue($this->app->removeGroupMember($groupId, 1));
$this->assertFalse($this->app->isGroupMember($groupId, 1));
}
}

View File

@ -0,0 +1,50 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class GroupProcedureTest extends BaseProcedureTest
{
public function testAll()
{
$this->assertCreateGroups();
$this->assertGetAllGroups();
$this->assertGetGroup();
$this->assertUpdateGroup();
$this->assertRemove();
}
public function assertGetAllGroups()
{
$groups = $this->app->getAllGroups();
$this->assertNotEmpty($groups);
$this->assertArrayHasKey('name', $groups[0]);
$this->assertArrayHasKey('external_id', $groups[0]);
}
public function assertGetGroup()
{
$group = $this->app->getGroup($this->groupId1);
$this->assertNotEmpty($group);
$this->assertEquals($this->groupName1, $group['name']);
$this->assertEquals('', $group['external_id']);
}
public function assertUpdateGroup()
{
$this->assertTrue($this->app->updateGroup(array(
'group_id' => $this->groupId2,
'name' => 'My Group C',
'external_id' => 'something else',
)));
$group = $this->app->getGroup($this->groupId2);
$this->assertNotEmpty($group);
$this->assertEquals('My Group C', $group['name']);
$this->assertEquals('something else', $group['external_id']);
}
public function assertRemove()
{
$this->assertTrue($this->app->removeGroup($this->groupId1));
}
}

View File

@ -1,48 +0,0 @@
<?php
require_once __DIR__.'/Base.php';
class GroupTest extends Base
{
public function testCreateGroup()
{
$this->assertNotFalse($this->app->createGroup('My Group A'));
$this->assertNotFalse($this->app->createGroup('My Group B', '1234'));
}
public function testGetter()
{
$groups = $this->app->getAllGroups();
$this->assertCount(2, $groups);
$this->assertEquals('My Group A', $groups[0]['name']);
$this->assertEquals('', $groups[0]['external_id']);
$this->assertEquals('My Group B', $groups[1]['name']);
$this->assertEquals('1234', $groups[1]['external_id']);
$group = $this->app->getGroup($groups[0]['id']);
$this->assertNotEmpty($group);
$this->assertEquals('My Group A', $group['name']);
$this->assertEquals('', $group['external_id']);
}
public function testUpdate()
{
$groups = $this->app->getAllGroups();
$this->assertTrue($this->app->updateGroup(array('group_id' => $groups[0]['id'], 'name' => 'ABC', 'external_id' => 'something')));
$this->assertTrue($this->app->updateGroup(array('group_id' => $groups[1]['id'], 'external_id' => '')));
$groups = $this->app->getAllGroups();
$this->assertEquals('ABC', $groups[0]['name']);
$this->assertEquals('something', $groups[0]['external_id']);
$this->assertEquals('', $groups[1]['external_id']);
}
public function testRemove()
{
$groups = $this->app->getAllGroups();
$this->assertTrue($this->app->removeGroup($groups[0]['id']));
$this->assertTrue($this->app->removeGroup($groups[1]['id']));
$this->assertSame(array(), $this->app->getAllGroups());
}
}

View File

@ -0,0 +1,70 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class LinkProcedureTest extends BaseProcedureTest
{
public function testGetAllLinks()
{
$links = $this->app->getAllLinks();
$this->assertNotEmpty($links);
$this->assertArrayHasKey('id', $links[0]);
$this->assertArrayHasKey('label', $links[0]);
$this->assertArrayHasKey('opposite_id', $links[0]);
}
public function testGetOppositeLink()
{
$link = $this->app->getOppositeLinkId(1);
$this->assertEquals(1, $link);
$link = $this->app->getOppositeLinkId(2);
$this->assertEquals(3, $link);
}
public function testGetLinkByLabel()
{
$link = $this->app->getLinkByLabel('blocks');
$this->assertNotEmpty($link);
$this->assertEquals(2, $link['id']);
$this->assertEquals(3, $link['opposite_id']);
}
public function testGetLinkById()
{
$link = $this->app->getLinkById(4);
$this->assertNotEmpty($link);
$this->assertEquals(4, $link['id']);
$this->assertEquals(5, $link['opposite_id']);
$this->assertEquals('duplicates', $link['label']);
}
public function testCreateLink()
{
$link_id = $this->app->createLink(array('label' => 'test'));
$this->assertNotFalse($link_id);
$this->assertInternalType('int', $link_id);
$link_id = $this->app->createLink(array('label' => 'foo', 'opposite_label' => 'bar'));
$this->assertNotFalse($link_id);
$this->assertInternalType('int', $link_id);
}
public function testUpdateLink()
{
$link1 = $this->app->getLinkByLabel('bar');
$this->assertNotEmpty($link1);
$link2 = $this->app->getLinkByLabel('test');
$this->assertNotEmpty($link2);
$this->assertNotFalse($this->app->updateLink($link1['id'], $link2['id'], 'my link'));
$link = $this->app->getLinkById($link1['id']);
$this->assertNotEmpty($link);
$this->assertEquals($link2['id'], $link['opposite_id']);
$this->assertEquals('my link', $link['label']);
$this->assertTrue($this->app->removeLink($link1['id']));
}
}

View File

@ -0,0 +1,68 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class MeProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My private project';
public function testAll()
{
$this->assertGetMe();
$this->assertCreateMyPrivateProject();
$this->assertGetMyProjectsList();
$this->assertGetMyProjects();
$this->assertCreateTask();
$this->assertGetMyDashboard();
$this->assertGetMyActivityStream();
}
public function assertGetMe()
{
$profile = $this->user->getMe();
$this->assertEquals('user', $profile['username']);
$this->assertEquals('app-user', $profile['role']);
}
public function assertCreateMyPrivateProject()
{
$this->projectId = $this->user->createMyPrivateProject($this->projectName);
$this->assertNotFalse($this->projectId);
}
public function assertGetMyProjectsList()
{
$projects = $this->user->getMyProjectsList();
$this->assertNotEmpty($projects);
$this->assertEquals($this->projectName, $projects[$this->projectId]);
}
public function assertGetMyProjects()
{
$projects = $this->user->getMyProjects();
$this->assertNotEmpty($projects);
}
public function assertCreateTask()
{
$taskId = $this->user->createTask(array('title' => 'My task', 'project_id' => $this->projectId, 'owner_id' => $this->userUserId));
$this->assertNotFalse($taskId);
}
public function assertGetMyDashboard()
{
$dashboard = $this->user->getMyDashboard();
$this->assertNotEmpty($dashboard);
$this->assertArrayHasKey('projects', $dashboard);
$this->assertArrayHasKey('tasks', $dashboard);
$this->assertArrayHasKey('subtasks', $dashboard);
$this->assertNotEmpty($dashboard['projects']);
$this->assertNotEmpty($dashboard['tasks']);
}
public function assertGetMyActivityStream()
{
$activity = $this->user->getMyActivityStream();
$this->assertNotEmpty($activity);
}
}

View File

@ -1,247 +0,0 @@
<?php
require_once __DIR__.'/Base.php';
class MeTest extends Base
{
public function testCreateProject()
{
$this->assertEquals(1, $this->app->createProject('team project'));
}
public function testCreateUser()
{
$this->assertEquals(2, $this->app->createUser('user', 'password'));
}
/**
* @expectedException JsonRPC\Exception\AccessDeniedException
*/
public function testNotAllowedAppProcedure()
{
$this->app->getMe();
}
/**
* @expectedException JsonRPC\Exception\AccessDeniedException
*/
public function testNotAllowedUserProcedure()
{
$this->user->getAllProjects();
}
/**
* @expectedException JsonRPC\Exception\AccessDeniedException
*/
public function testNotAllowedProjectForUser()
{
$this->user->getProjectById(1);
}
public function testAllowedProjectForAdmin()
{
$this->assertNotEmpty($this->admin->getProjectById(1));
}
public function testGetTimezone()
{
$this->assertEquals('UTC', $this->user->getTimezone());
}
public function testGetVersion()
{
$this->assertEquals('master', $this->user->getVersion());
}
public function testGetDefaultColor()
{
$this->assertEquals('yellow', $this->user->getDefaultTaskColor());
}
public function testGetDefaultColors()
{
$colors = $this->user->getDefaultTaskColors();
$this->assertNotEmpty($colors);
$this->assertArrayHasKey('red', $colors);
}
public function testGetColorList()
{
$colors = $this->user->getColorList();
$this->assertNotEmpty($colors);
$this->assertArrayHasKey('red', $colors);
$this->assertEquals('Red', $colors['red']);
}
public function testGetMe()
{
$profile = $this->user->getMe();
$this->assertNotEmpty($profile);
$this->assertEquals(2, $profile['id']);
$this->assertEquals('user', $profile['username']);
}
public function testCreateMyPrivateProject()
{
$this->assertEquals(2, $this->user->createMyPrivateProject('my project'));
}
public function testGetMyProjectsList()
{
$projects = $this->user->getMyProjectsList();
$this->assertNotEmpty($projects);
$this->assertArrayNotHasKey(1, $projects);
$this->assertArrayHasKey(2, $projects);
$this->assertEquals('my project', $projects[2]);
}
public function testGetMyProjects()
{
$projects = $this->user->getMyProjects();
$this->assertNotEmpty($projects);
$this->assertCount(1, $projects);
$this->assertEquals(2, $projects[0]['id']);
$this->assertEquals('my project', $projects[0]['name']);
$this->assertNotEmpty($projects[0]['url']['calendar']);
$this->assertNotEmpty($projects[0]['url']['board']);
$this->assertNotEmpty($projects[0]['url']['list']);
}
public function testGetProjectById()
{
$project = $this->user->getProjectById(2);
$this->assertNotEmpty($project);
$this->assertEquals('my project', $project['name']);
$this->assertEquals(1, $project['is_private']);
}
public function testCreateTask()
{
$this->assertEquals(1, $this->user->createTask('my user title', 2));
$this->assertEquals(2, $this->admin->createTask('my admin title', 1));
}
public function testCreateTaskWithWrongMember()
{
$this->assertFalse($this->user->createTask(array('title' => 'something', 'project_id' => 2, 'owner_id' => 1)));
$this->assertFalse($this->app->createTask(array('title' => 'something', 'project_id' => 1, 'owner_id' => 2)));
}
public function testGetTask()
{
$task = $this->user->getTask(1);
$this->assertNotEmpty($task);
$this->assertEquals('my user title', $task['title']);
$this->assertEquals('yellow', $task['color_id']);
$this->assertArrayHasKey('color', $task);
$this->assertArrayHasKey('name', $task['color']);
$this->assertArrayHasKey('border', $task['color']);
$this->assertArrayHasKey('background', $task['color']);
}
/**
* @expectedException JsonRPC\Exception\AccessDeniedException
*/
public function testGetAdminTask()
{
$this->user->getTask(2);
}
/**
* @expectedException JsonRPC\Exception\AccessDeniedException
*/
public function testGetProjectActivityDenied()
{
$this->user->getProjectActivity(1);
}
public function testGetProjectActivityAllowed()
{
$activity = $this->user->getProjectActivity(2);
$this->assertNotEmpty($activity);
}
public function testGetMyActivityStream()
{
$activity = $this->user->getMyActivityStream();
$this->assertNotEmpty($activity);
}
public function testCloseTask()
{
$this->assertTrue($this->user->closeTask(1));
}
public function testOpenTask()
{
$this->assertTrue($this->user->openTask(1));
}
public function testMoveTaskPosition()
{
$this->assertTrue($this->user->moveTaskPosition(2, 1, 2, 1));
}
public function testUpdateTaskWithWrongMember()
{
$this->assertFalse($this->user->updateTask(array('id' => 1, 'title' => 'new title', 'reference' => 'test', 'owner_id' => 1)));
}
public function testUpdateTask()
{
$this->assertTrue($this->user->updateTask(array('id' => 1, 'title' => 'new title', 'reference' => 'test', 'owner_id' => 2)));
}
public function testGetbyReference()
{
$task = $this->user->getTaskByReference(2, 'test');
$this->assertNotEmpty($task);
$this->assertEquals('new title', $task['title']);
$this->assertEquals(2, $task['column_id']);
$this->assertEquals(1, $task['position']);
}
public function testGetMyDashboard()
{
$dashboard = $this->user->getMyDashboard();
$this->assertNotEmpty($dashboard);
$this->assertArrayHasKey('projects', $dashboard);
$this->assertArrayHasKey('tasks', $dashboard);
$this->assertArrayHasKey('subtasks', $dashboard);
$this->assertNotEmpty($dashboard['projects']);
$this->assertNotEmpty($dashboard['tasks']);
}
public function testGetBoard()
{
$this->assertNotEmpty($this->user->getBoard(2));
}
public function testCreateOverdueTask()
{
$this->assertNotFalse($this->user->createTask(array(
'title' => 'overdue task',
'project_id' => 2,
'date_due' => date('Y-m-d', strtotime('-2days')),
'owner_id' => 2,
)));
}
public function testGetMyOverdueTasks()
{
$tasks = $this->user->getMyOverdueTasks();
$this->assertNotEmpty($tasks);
$this->assertCount(1, $tasks);
$this->assertEquals('overdue task', $tasks[0]['title']);
$this->assertEquals('my project', $tasks[0]['project_name']);
}
public function testGetOverdueTasksByProject()
{
$tasks = $this->user->getOverdueTasksByProject(2);
$this->assertNotEmpty($tasks);
$this->assertCount(1, $tasks);
$this->assertEquals('overdue task', $tasks[0]['title']);
$this->assertEquals('my project', $tasks[0]['project_name']);
}
}

View File

@ -0,0 +1,43 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class OverdueTaskProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My project to test overdue tasks';
public function testAll()
{
$this->assertCreateTeamProject();
$this->assertCreateOverdueTask();
$this->assertGetOverdueTasksByProject();
$this->assertGetOverdueTasks();
}
public function assertCreateOverdueTask()
{
$this->assertNotFalse($this->app->createTask(array(
'title' => 'overdue task',
'project_id' => $this->projectId,
'date_due' => date('Y-m-d', strtotime('-2days')),
)));
}
public function assertGetOverdueTasksByProject()
{
$tasks = $this->app->getOverdueTasksByProject($this->projectId);
$this->assertNotEmpty($tasks);
$this->assertCount(1, $tasks);
$this->assertEquals('overdue task', $tasks[0]['title']);
$this->assertEquals($this->projectName, $tasks[0]['project_name']);
}
public function assertGetOverdueTasks()
{
$tasks = $this->app->getOverdueTasks();
$this->assertNotEmpty($tasks);
$this->assertCount(1, $tasks);
$this->assertEquals('overdue task', $tasks[0]['title']);
$this->assertEquals($this->projectName, $tasks[0]['project_name']);
}
}

View File

@ -0,0 +1,306 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class ProcedureAuthorizationTest extends BaseProcedureTest
{
public function testApiCredentialDoNotHaveAccessToUserCredentialProcedure()
{
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->app->getMe();
}
public function testUserCredentialDoNotHaveAccessToAdminProcedures()
{
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->getUser(1);
}
public function testManagerCredentialDoNotHaveAccessToAdminProcedures()
{
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->getAllProjects();
}
public function testUserCredentialDoNotHaveAccessToManagerProcedures()
{
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->createProject('Team project creation are only for app managers');
}
public function testAppManagerCanCreateTeamProject()
{
$this->assertNotFalse($this->manager->createProject('Team project created by app manager'));
}
public function testAdminManagerCanCreateTeamProject()
{
$projectId = $this->admin->createProject('Team project created by admin');
$this->assertNotFalse($projectId);
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->assertNotNull($this->manager->getProjectById($projectId));
}
public function testProjectManagerCanUpdateHisProject()
{
$projectId = $this->manager->createProject(array(
'name' => 'Team project can be updated',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$this->assertEquals('project-manager', $this->app->getProjectUserRole($projectId, $this->managerUserId));
$this->assertNotNull($this->manager->getProjectById($projectId));
$this->assertTrue($this->manager->updateProject($projectId, 'My team project have been updated'));
}
public function testProjectAuthorizationForbidden()
{
$projectId = $this->manager->createProject('A team project without members');
$this->assertNotFalse($projectId);
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->getProjectById($projectId);
}
public function testProjectAuthorizationGranted()
{
$projectId = $this->manager->createProject(array(
'name' => 'A team project with members',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$this->assertTrue($this->manager->addProjectUser($projectId, $this->userUserId));
$this->assertNotNull($this->user->getProjectById($projectId));
}
public function testActionAuthorizationForbidden()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$actionId = $this->manager->createAction($projectId, 'task.move.column', '\Kanboard\Action\TaskCloseColumn', array('column_id' => 1));
$this->assertNotFalse($actionId);
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->removeAction($projectId);
}
public function testActionAuthorizationForbiddenBecauseNotProjectManager()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$actionId = $this->manager->createAction($projectId, 'task.move.column', '\Kanboard\Action\TaskCloseColumn', array('column_id' => 1));
$this->assertNotFalse($actionId);
$this->assertTrue($this->manager->addProjectUser($projectId, $this->userUserId, 'project-member'));
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->removeAction($actionId);
}
public function testActionAuthorizationGranted()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$actionId = $this->manager->createAction($projectId, 'task.move.column', '\Kanboard\Action\TaskCloseColumn', array('column_id' => 1));
$this->assertNotFalse($actionId);
$this->assertTrue($this->manager->addProjectUser($projectId, $this->userUserId, 'project-manager'));
$this->assertTrue($this->user->removeAction($actionId));
}
public function testCategoryAuthorizationForbidden()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$categoryId = $this->manager->createCategory($projectId, 'Test');
$this->assertNotFalse($categoryId);
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->removeCategory($categoryId);
}
public function testCategoryAuthorizationForbiddenBecauseNotProjectManager()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$categoryId = $this->manager->createCategory($projectId, 'Test');
$this->assertNotFalse($categoryId);
$this->assertTrue($this->manager->addProjectUser($projectId, $this->userUserId, 'project-member'));
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->removeCategory($categoryId);
}
public function testCategoryAuthorizationGranted()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$categoryId = $this->manager->createCategory($projectId, 'Test');
$this->assertNotFalse($categoryId);
$this->assertTrue($this->manager->addProjectUser($projectId, $this->userUserId, 'project-manager'));
$this->assertTrue($this->user->removeCategory($categoryId));
}
public function testColumnAuthorizationForbidden()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$columnId = $this->manager->addColumn($projectId, 'Test');
$this->assertNotFalse($columnId);
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->removeColumn($columnId);
}
public function testColumnAuthorizationForbiddenBecauseNotProjectManager()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$columnId = $this->manager->addColumn($projectId, 'Test');
$this->assertNotFalse($columnId);
$this->assertTrue($this->manager->addProjectUser($projectId, $this->userUserId, 'project-member'));
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->removeColumn($columnId);
}
public function testColumnAuthorizationGranted()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$columnId = $this->manager->addColumn($projectId, 'Test');
$this->assertNotFalse($columnId);
$this->assertTrue($this->manager->addProjectUser($projectId, $this->userUserId, 'project-manager'));
$this->assertTrue($this->user->removeColumn($columnId));
}
public function testCommentAuthorizationForbidden()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$this->assertTrue($this->manager->addProjectUser($projectId, $this->userUserId, 'project-viewer'));
$taskId = $this->manager->createTask('My Task', $projectId);
$this->assertNotFalse($taskId);
$commentId = $this->manager->createComment($taskId, $this->userUserId, 'My comment');
$this->assertNotFalse($commentId);
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->updateComment($commentId, 'something else');
}
public function testCommentAuthorizationGranted()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$this->assertTrue($this->manager->addProjectUser($projectId, $this->userUserId, 'project-member'));
$taskId = $this->user->createTask('My Task', $projectId);
$this->assertNotFalse($taskId);
$commentId = $this->user->createComment($taskId, $this->userUserId, 'My comment');
$this->assertNotFalse($commentId);
$this->assertTrue($this->user->updateComment($commentId, 'something else'));
}
public function testSubtaskAuthorizationForbidden()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$this->assertTrue($this->manager->addProjectUser($projectId, $this->userUserId, 'project-viewer'));
$taskId = $this->manager->createTask('My Task', $projectId);
$this->assertNotFalse($taskId);
$subtaskId = $this->manager->createSubtask($taskId, 'My subtask');
$this->assertNotFalse($subtaskId);
$this->setExpectedException('JsonRPC\Exception\AccessDeniedException');
$this->user->removeSubtask($subtaskId);
}
public function testSubtaskAuthorizationGranted()
{
$projectId = $this->manager->createProject(array(
'name' => 'Test Project',
'owner_id' => $this->managerUserId,
));
$this->assertNotFalse($projectId);
$this->assertTrue($this->manager->addProjectUser($projectId, $this->userUserId, 'project-member'));
$taskId = $this->user->createTask('My Task', $projectId);
$this->assertNotFalse($taskId);
$subtaskId = $this->manager->createSubtask($taskId, 'My subtask');
$this->assertNotFalse($subtaskId);
$this->assertTrue($this->user->removeSubtask($subtaskId));
}
}

View File

@ -0,0 +1,89 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class ProjectPermissionProcedureTest extends BaseProcedureTest
{
protected $projectName = 'Project with permission';
protected $username = 'user-project-permission';
protected $groupName1 = 'My group A for project permission';
protected $groupName2 = 'My group B for project permission';
public function testAll()
{
$this->assertCreateTeamProject();
$this->assertCreateGroups();
$this->assertCreateUser();
$this->assertAddProjectUser();
$this->assertGetProjectUsers();
$this->assertGetAssignableUsers();
$this->assertChangeProjectUserRole();
$this->assertRemoveProjectUser();
$this->assertAddProjectGroup();
$this->assertGetProjectUsers();
$this->assertGetAssignableUsers();
$this->assertChangeProjectGroupRole();
$this->assertRemoveProjectGroup();
}
public function assertAddProjectUser()
{
$this->assertTrue($this->app->addProjectUser($this->projectId, $this->userId));
}
public function assertGetProjectUsers()
{
$members = $this->app->getProjectUsers($this->projectId);
$this->assertCount(1, $members);
$this->assertArrayHasKey($this->userId, $members);
$this->assertEquals($this->username, $members[$this->userId]);
}
public function assertGetAssignableUsers()
{
$members = $this->app->getAssignableUsers($this->projectId);
$this->assertCount(1, $members);
$this->assertArrayHasKey($this->userId, $members);
$this->assertEquals($this->username, $members[$this->userId]);
}
public function assertChangeProjectUserRole()
{
$this->assertTrue($this->app->changeProjectUserRole($this->projectId, $this->userId, 'project-viewer'));
$members = $this->app->getAssignableUsers($this->projectId);
$this->assertCount(0, $members);
}
public function assertRemoveProjectUser()
{
$this->assertTrue($this->app->removeProjectUser($this->projectId, $this->userId));
$members = $this->app->getProjectUsers($this->projectId);
$this->assertCount(0, $members);
}
public function assertAddProjectGroup()
{
$this->assertTrue($this->app->addGroupMember($this->groupId1, $this->userId));
$this->assertTrue($this->app->addProjectGroup($this->projectId, $this->groupId1));
}
public function assertChangeProjectGroupRole()
{
$this->assertTrue($this->app->changeProjectGroupRole($this->projectId, $this->groupId1, 'project-viewer'));
$members = $this->app->getAssignableUsers($this->projectId);
$this->assertCount(0, $members);
}
public function assertRemoveProjectGroup()
{
$this->assertTrue($this->app->removeProjectGroup($this->projectId, $this->groupId1));
$members = $this->app->getProjectUsers($this->projectId);
$this->assertCount(0, $members);
}
}

View File

@ -1,64 +0,0 @@
<?php
require_once __DIR__.'/Base.php';
class ProjectPermissionTest extends Base
{
public function testGetProjectUsers()
{
$this->assertNotFalse($this->app->createProject('Test'));
$this->assertNotFalse($this->app->createGroup('Test'));
$projectId = $this->getProjectId();
$groupId = $this->getGroupId();
$this->assertTrue($this->app->addGroupMember($projectId, $groupId));
$this->assertSame(array(), $this->app->getProjectUsers($projectId));
}
public function testProjectUser()
{
$projectId = $this->getProjectId();
$this->assertTrue($this->app->addProjectUser($projectId, 1));
$users = $this->app->getProjectUsers($projectId);
$this->assertCount(1, $users);
$this->assertEquals('admin', $users[1]);
$users = $this->app->getAssignableUsers($projectId);
$this->assertCount(1, $users);
$this->assertEquals('admin', $users[1]);
$this->assertTrue($this->app->changeProjectUserRole($projectId, 1, 'project-viewer'));
$users = $this->app->getAssignableUsers($projectId);
$this->assertCount(0, $users);
$this->assertTrue($this->app->removeProjectUser($projectId, 1));
$this->assertSame(array(), $this->app->getProjectUsers($projectId));
}
public function testProjectGroup()
{
$projectId = $this->getProjectId();
$groupId = $this->getGroupId();
$this->assertTrue($this->app->addProjectGroup($projectId, $groupId));
$users = $this->app->getProjectUsers($projectId);
$this->assertCount(1, $users);
$this->assertEquals('admin', $users[1]);
$users = $this->app->getAssignableUsers($projectId);
$this->assertCount(1, $users);
$this->assertEquals('admin', $users[1]);
$this->assertTrue($this->app->changeProjectGroupRole($projectId, $groupId, 'project-viewer'));
$users = $this->app->getAssignableUsers($projectId);
$this->assertCount(0, $users);
$this->assertTrue($this->app->removeProjectGroup($projectId, 1));
$this->assertSame(array(), $this->app->getProjectUsers($projectId));
}
}

View File

@ -0,0 +1,119 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class ProjectProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My team project';
public function testAll()
{
$this->assertCreateTeamProject();
$this->assertGetProjectById();
$this->assertGetProjectByName();
$this->assertGetAllProjects();
$this->assertUpdateProject();
$this->assertUpdateProjectIdentifier();
$this->assertCreateProjectWithIdentifier();
$this->assertGetProjectActivity();
$this->assertGetProjectsActivity();
$this->assertEnableDisableProject();
$this->assertEnableDisablePublicAccess();
$this->assertRemoveProject();
}
public function assertGetProjectById()
{
$project = $this->app->getProjectById($this->projectId);
$this->assertNotNull($project);
$this->assertEquals($this->projectName, $project['name']);
$this->assertEquals('Description', $project['description']);
}
public function assertGetProjectByName()
{
$project = $this->app->getProjectByName($this->projectName);
$this->assertNotNull($project);
$this->assertEquals($this->projectId, $project['id']);
$this->assertEquals($this->projectName, $project['name']);
$this->assertEquals('Description', $project['description']);
}
public function assertGetAllProjects()
{
$projects = $this->app->getAllProjects();
$this->assertNotEmpty($projects);
}
public function assertGetProjectActivity()
{
$activities = $this->app->getProjectActivity($this->projectId);
$this->assertInternalType('array', $activities);
$this->assertCount(0, $activities);
}
public function assertGetProjectsActivity()
{
$activities = $this->app->getProjectActivities(array('project_ids' => array($this->projectId)));
$this->assertInternalType('array', $activities);
$this->assertCount(0, $activities);
}
public function assertUpdateProject()
{
$this->assertTrue($this->app->updateProject(array('project_id' => $this->projectId, 'name' => 'test', 'description' => 'test')));
$project = $this->app->getProjectById($this->projectId);
$this->assertNotNull($project);
$this->assertEquals('test', $project['name']);
$this->assertEquals('test', $project['description']);
$this->assertTrue($this->app->updateProject(array('project_id' => $this->projectId, 'name' => $this->projectName)));
}
public function assertUpdateProjectIdentifier()
{
$this->assertTrue($this->app->updateProject(array(
'project_id' => $this->projectId,
'identifier' => 'MYPROJECT',
)));
$project = $this->app->getProjectById($this->projectId);
$this->assertNotNull($project);
$this->assertEquals($this->projectName, $project['name']);
$this->assertEquals('MYPROJECT', $project['identifier']);
}
public function assertCreateProjectWithIdentifier()
{
$projectId = $this->app->createProject(array(
'name' => 'My project with an identifier',
'identifier' => 'MYPROJECTWITHIDENTIFIER',
));
$this->assertNotFalse($projectId);
$project = $this->app->getProjectByIdentifier('MYPROJECTWITHIDENTIFIER');
$this->assertEquals($projectId, $project['id']);
$this->assertEquals('My project with an identifier', $project['name']);
$this->assertEquals('MYPROJECTWITHIDENTIFIER', $project['identifier']);
}
public function assertEnableDisableProject()
{
$this->assertTrue($this->app->disableProject($this->projectId));
$this->assertTrue($this->app->enableProject($this->projectId));
}
public function assertEnableDisablePublicAccess()
{
$this->assertTrue($this->app->disableProjectPublicAccess($this->projectId));
$this->assertTrue($this->app->enableProjectPublicAccess($this->projectId));
}
public function assertRemoveProject()
{
$this->assertTrue($this->app->removeProject($this->projectId));
$this->assertNull($this->app->getProjectById($this->projectId));
}
}

View File

@ -0,0 +1,64 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class SubtaskProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My project to test subtasks';
private $subtaskId = 0;
public function testAll()
{
$this->assertCreateTeamProject();
$this->assertCreateTask();
$this->assertCreateSubtask();
$this->assertGetSubtask();
$this->assertUpdateSubtask();
$this->assertGetAllSubtasks();
$this->assertRemoveSubtask();
}
public function assertCreateSubtask()
{
$this->subtaskId = $this->app->createSubtask(array(
'task_id' => $this->taskId,
'title' => 'subtask #1',
));
$this->assertNotFalse($this->subtaskId);
}
public function assertGetSubtask()
{
$subtask = $this->app->getSubtask($this->subtaskId);
$this->assertEquals($this->taskId, $subtask['task_id']);
$this->assertEquals('subtask #1', $subtask['title']);
}
public function assertUpdateSubtask()
{
$this->assertTrue($this->app->execute('updateSubtask', array(
'id' => $this->subtaskId,
'task_id' => $this->taskId,
'title' => 'test',
)));
$subtask = $this->app->getSubtask($this->subtaskId);
$this->assertEquals('test', $subtask['title']);
}
public function assertGetAllSubtasks()
{
$subtasks = $this->app->getAllSubtasks($this->taskId);
$this->assertCount(1, $subtasks);
$this->assertEquals('test', $subtasks[0]['title']);
}
public function assertRemoveSubtask()
{
$this->assertTrue($this->app->removeSubtask($this->subtaskId));
$subtasks = $this->app->getAllSubtasks($this->taskId);
$this->assertCount(0, $subtasks);
}
}

View File

@ -0,0 +1,93 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class SwimlaneProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My project to test swimlanes';
private $swimlaneId = 0;
public function testAll()
{
$this->assertCreateTeamProject();
}
public function assertGetDefaultSwimlane()
{
$swimlane = $this->app->getDefaultSwimlane($this->projectId);
$this->assertNotEmpty($swimlane);
$this->assertEquals('Default swimlane', $swimlane['default_swimlane']);
}
public function assertAddSwimlane()
{
$this->swimlaneId = $this->app->addSwimlane($this->projectId, 'Swimlane 1');
$this->assertNotFalse($this->swimlaneId);
$this->assertNotFalse($this->app->addSwimlane($this->projectId, 'Swimlane 2'));
}
public function assertGetSwimlane()
{
$swimlane = $this->app->getSwimlane($this->swimlaneId);
$this->assertInternalType('array', $swimlane);
$this->assertEquals('Swimlane 1', $swimlane['name']);
}
public function assertUpdateSwimlane()
{
$this->assertTrue($this->app->updateSwimlane($this->swimlaneId, 'Another swimlane'));
$swimlane = $this->app->getSwimlaneById($this->swimlaneId);
$this->assertEquals('Another swimlane', $swimlane['name']);
}
public function assertDisableSwimlane()
{
$this->assertTrue($this->app->disableSwimlane($this->projectId, $this->swimlaneId));
$swimlane = $this->app->getSwimlaneById($this->swimlaneId);
$this->assertEquals(0, $swimlane['is_active']);
}
public function assertEnableSwimlane()
{
$this->assertTrue($this->app->enableSwimlane($this->projectId, $this->swimlaneId));
$swimlane = $this->app->getSwimlaneById($this->swimlaneId);
$this->assertEquals(1, $swimlane['is_active']);
}
public function assertGetAllSwimlanes()
{
$swimlanes = $this->app->getAllSwimlanes($this->projectId);
$this->assertCount(2, $swimlanes);
$this->assertEquals('Another swimlane', $swimlanes[0]['name']);
$this->assertEquals('Swimlane 2', $swimlanes[1]['name']);
}
public function assertGetActiveSwimlane()
{
$this->assertTrue($this->app->disableSwimlane($this->projectId, $this->swimlaneId));
$swimlanes = $this->app->getActiveSwimlanes($this->projectId);
$this->assertCount(2, $swimlanes);
$this->assertEquals('Default swimlane', $swimlanes[0]['name']);
$this->assertEquals('Swimlane 2', $swimlanes[1]['name']);
}
public function assertRemoveSwimlane()
{
$this->assertTrue($this->app->removeSwimlane($this->projectId, $this->swimlaneId));
}
public function assertChangePosition()
{
$swimlaneId1 = $this->app->addSwimlane($this->projectId, 'Swimlane A');
$this->assertNotFalse($this->app->addSwimlane($this->projectId, 'Swimlane B'));
$swimlanes = $this->app->getAllSwimlanes($this->projectId);
$this->assertCount(3, $swimlanes);
$this->assertTrue($this->app->changeSwimlanePosition($this->projectId, $swimlaneId1, 3));
}
}

View File

@ -1,103 +0,0 @@
<?php
require_once __DIR__.'/Base.php';
class SwimlaneTest extends Base
{
public function testCreateProject()
{
$this->assertEquals(1, $this->app->createProject('A project'));
}
public function testGetDefaultSwimlane()
{
$swimlane = $this->app->getDefaultSwimlane(1);
$this->assertNotEmpty($swimlane);
$this->assertEquals('Default swimlane', $swimlane['default_swimlane']);
}
public function testAddSwimlane()
{
$swimlane_id = $this->app->addSwimlane(1, 'Swimlane 1');
$this->assertNotFalse($swimlane_id);
$this->assertInternalType('int', $swimlane_id);
$swimlane = $this->app->getSwimlaneById($swimlane_id);
$this->assertNotEmpty($swimlane);
$this->assertInternalType('array', $swimlane);
$this->assertEquals('Swimlane 1', $swimlane['name']);
}
public function testGetSwimlane()
{
$swimlane = $this->app->getSwimlane(1);
$this->assertInternalType('array', $swimlane);
$this->assertEquals('Swimlane 1', $swimlane['name']);
}
public function testUpdateSwimlane()
{
$swimlane = $this->app->getSwimlaneByName(1, 'Swimlane 1');
$this->assertInternalType('array', $swimlane);
$this->assertEquals(1, $swimlane['id']);
$this->assertEquals('Swimlane 1', $swimlane['name']);
$this->assertTrue($this->app->updateSwimlane($swimlane['id'], 'Another swimlane'));
$swimlane = $this->app->getSwimlaneById($swimlane['id']);
$this->assertEquals('Another swimlane', $swimlane['name']);
}
public function testDisableSwimlane()
{
$this->assertTrue($this->app->disableSwimlane(1, 1));
$swimlane = $this->app->getSwimlaneById(1);
$this->assertEquals(0, $swimlane['is_active']);
}
public function testEnableSwimlane()
{
$this->assertTrue($this->app->enableSwimlane(1, 1));
$swimlane = $this->app->getSwimlaneById(1);
$this->assertEquals(1, $swimlane['is_active']);
}
public function testGetAllSwimlanes()
{
$this->assertNotFalse($this->app->addSwimlane(1, 'Swimlane A'));
$swimlanes = $this->app->getAllSwimlanes(1);
$this->assertCount(2, $swimlanes);
$this->assertEquals('Another swimlane', $swimlanes[0]['name']);
$this->assertEquals('Swimlane A', $swimlanes[1]['name']);
}
public function testGetActiveSwimlane()
{
$this->assertTrue($this->app->disableSwimlane(1, 1));
$swimlanes = $this->app->getActiveSwimlanes(1);
$this->assertCount(2, $swimlanes);
$this->assertEquals('Default swimlane', $swimlanes[0]['name']);
$this->assertEquals('Swimlane A', $swimlanes[1]['name']);
}
public function testRemoveSwimlane()
{
$this->assertTrue($this->app->removeSwimlane(1, 2));
}
public function testChangePosition()
{
$this->assertNotFalse($this->app->addSwimlane(1, 'Swimlane 1'));
$this->assertNotFalse($this->app->addSwimlane(1, 'Swimlane 2'));
$swimlanes = $this->app->getAllSwimlanes(1);
$this->assertCount(3, $swimlanes);
$this->assertTrue($this->app->changeSwimlanePosition(1, 1, 3));
$this->assertFalse($this->app->changeSwimlanePosition(1, 1, 6));
}
}

View File

@ -0,0 +1,67 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class TaskFileProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My project to test task files';
protected $fileId;
public function testAll()
{
$this->assertCreateTeamProject();
$this->assertCreateTask();
$this->assertCreateTaskFile();
$this->assertGetTaskFile();
$this->assertDownloadTaskFile();
$this->assertGetAllFiles();
$this->assertRemoveTaskFile();
$this->assertRemoveAllTaskFiles();
}
public function assertCreateTaskFile()
{
$this->fileId = $this->app->createTaskFile(1, $this->taskId, 'My file', base64_encode('plain text file'));
$this->assertNotFalse($this->fileId);
}
public function assertGetTaskFile()
{
$file = $this->app->getTaskFile($this->fileId);
$this->assertNotEmpty($file);
$this->assertEquals('My file', $file['name']);
}
public function assertDownloadTaskFile()
{
$content = $this->app->downloadTaskFile($this->fileId);
$this->assertNotEmpty($content);
$this->assertEquals('plain text file', base64_decode($content));
}
public function assertGetAllFiles()
{
$files = $this->app->getAllTaskFiles(array('task_id' => $this->taskId));
$this->assertCount(1, $files);
$this->assertEquals('My file', $files[0]['name']);
}
public function assertRemoveTaskFile()
{
$this->assertTrue($this->app->removeTaskFile($this->fileId));
$files = $this->app->getAllTaskFiles(array('task_id' => $this->taskId));
$this->assertEmpty($files);
}
public function assertRemoveAllTaskFiles()
{
$this->assertCreateTaskFile();
$this->assertCreateTaskFile();
$this->assertTrue($this->app->removeAllTaskFiles($this->taskId));
$files = $this->app->getAllTaskFiles(array('task_id' => $this->taskId));
$this->assertEmpty($files);
}
}

View File

@ -0,0 +1,68 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class TaskLinkProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My project to test task links';
protected $taskLinkId;
protected $taskId1;
protected $taskId2;
public function testAll()
{
$this->assertCreateTeamProject();
$this->taskId1 = $this->app->createTask(array('project_id' => $this->projectId, 'title' => 'Task 1'));
$this->taskId2 = $this->app->createTask(array('project_id' => $this->projectId, 'title' => 'Task 2'));
$this->assertNotFalse($this->taskId1);
$this->assertNotFalse($this->taskId2);
$this->assertCreateTaskLink();
$this->assertGetTaskLink();
$this->assertGetAllTaskLinks();
$this->assertUpdateTaskLink();
$this->assertRemoveTaskLink();
}
public function assertCreateTaskLink()
{
$this->taskLinkId = $this->app->createTaskLink($this->taskId1, $this->taskId2, 1);
$this->assertNotFalse($this->taskLinkId);
}
public function assertGetTaskLink()
{
$link = $this->app->getTaskLinkById($this->taskLinkId);
$this->assertNotNull($link);
$this->assertEquals($this->taskId1, $link['task_id']);
$this->assertEquals($this->taskId2, $link['opposite_task_id']);
$this->assertEquals(1, $link['link_id']);
}
public function assertGetAllTaskLinks()
{
$links = $this->app->getAllTaskLinks($this->taskId2);
$this->assertCount(1, $links);
}
public function assertUpdateTaskLink()
{
$this->assertTrue($this->app->updateTaskLink($this->taskLinkId, $this->taskId1, $this->taskId2, 3));
$link = $this->app->getTaskLinkById($this->taskLinkId);
$this->assertNotNull($link);
$this->assertEquals($this->taskId1, $link['task_id']);
$this->assertEquals($this->taskId2, $link['opposite_task_id']);
$this->assertEquals(3, $link['link_id']);
}
public function assertRemoveTaskLink()
{
$this->assertTrue($this->app->removeTaskLink($this->taskLinkId));
$links = $this->app->getAllTaskLinks($this->taskId2);
$this->assertCount(0, $links);
}
}

View File

@ -0,0 +1,55 @@
<?php
require_once __DIR__.'/BaseProcedureTest.php';
class TaskProcedureTest extends BaseProcedureTest
{
protected $projectName = 'My project to test tasks';
public function testAll()
{
$this->assertCreateTeamProject();
$this->assertCreateTask();
$this->assertUpdateTask();
$this->assertGetTaskById();
$this->assertGetTaskByReference();
$this->assertGetAllTasks();
$this->assertOpenCloseTask();
}
public function assertUpdateTask()
{
$this->assertTrue($this->app->updateTask(array('id' => $this->taskId, 'color_id' => 'red')));
}
public function assertGetTaskById()
{
$task = $this->app->getTask($this->taskId);
$this->assertNotNull($task);
$this->assertEquals('red', $task['color_id']);
$this->assertEquals($this->taskTitle, $task['title']);
}
public function assertGetTaskByReference()
{
$taskId = $this->app->createTask(array('title' => 'task with reference', 'project_id' => $this->projectId, 'reference' => 'test'));
$this->assertNotFalse($taskId);
$task = $this->app->getTaskByReference($this->projectId, 'test');
$this->assertNotNull($task);
$this->assertEquals($taskId, $task['id']);
}
public function assertGetAllTasks()
{
$tasks = $this->app->getAllTasks($this->projectId);
$this->assertInternalType('array', $tasks);
$this->assertNotEmpty($tasks);
}
public function assertOpenCloseTask()
{
$this->assertTrue($this->app->closeTask($this->taskId));
$this->assertTrue($this->app->openTask($this->taskId));
}
}

Some files were not shown because too many files have changed in this diff Show More