First API implementation

This commit is contained in:
Frédéric Guillot
2014-06-20 15:41:05 -03:00
parent efdc959c55
commit 7c5b900bd8
28 changed files with 1285 additions and 63 deletions

View File

@@ -99,7 +99,7 @@ class Board extends Base
foreach (array('title', 'task_limit') as $field) { foreach (array('title', 'task_limit') as $field) {
foreach ($values[$field] as $column_id => $field_value) { foreach ($values[$field] as $column_id => $field_value) {
$this->db->table(self::TABLE)->eq('id', $column_id)->update(array($field => $field_value)); $this->updateColumn($column_id, array($field => $field_value));
} }
} }
@@ -108,6 +108,19 @@ class Board extends Base
return true; return true;
} }
/**
* Update a column
*
* @access public
* @param integer $column_id Column id
* @param array $values Form values
* @return boolean
*/
public function updateColumn($column_id, array $values)
{
return $this->db->table(self::TABLE)->eq('id', $column_id)->update($values);
}
/** /**
* Move a column down, increment the column position value * Move a column down, increment the column position value
* *

View File

@@ -61,6 +61,21 @@ class Category extends Base
return $prepend + $listing; return $prepend + $listing;
} }
/**
* Return all categories for a given project
*
* @access public
* @param integer $project_id Project id
* @return array
*/
public function getAll($project_id)
{
return $this->db->table(self::TABLE)
->eq('project_id', $project_id)
->asc('name')
->findAll();
}
/** /**
* Create a category * Create a category
* *

View File

@@ -197,6 +197,18 @@ class Project extends Base
return $this->db->table(self::TABLE)->eq('id', $project_id)->findOne(); return $this->db->table(self::TABLE)->eq('id', $project_id)->findOne();
} }
/**
* Get a project by the name
*
* @access public
* @param string $project_name Project name
* @return array
*/
public function getByName($project_name)
{
return $this->db->table(self::TABLE)->eq('name', $project_name)->findOne();
}
/** /**
* Fetch project data by using the token * Fetch project data by using the token
* *
@@ -505,7 +517,8 @@ class Project extends Base
new Validators\Integer('id', t('This value must be an integer')), new Validators\Integer('id', t('This value must be an integer')),
new Validators\Required('name', t('The project name is required')), new Validators\Required('name', t('The project name is required')),
new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50), new Validators\MaxLength('name', t('The maximum length is %d characters', 50), 50),
new Validators\Unique('name', t('This project must be unique'), $this->db->getConnection(), self::TABLE) new Validators\Unique('name', t('This project must be unique'), $this->db->getConnection(), self::TABLE),
new Validators\Integer('is_active', t('This value must be an integer'))
)); ));
return array( return array(

View File

@@ -108,6 +108,23 @@ class Task extends Base
} }
} }
/**
* Count all tasks for a given project and status
*
* @access public
* @param integer $project_id Project id
* @param array $status List of status id
* @return array
*/
public function getAll($project_id, array $status = array(self::STATUS_OPEN, self::STATUS_CLOSED))
{
return $this->db
->table(self::TABLE)
->eq('project_id', $project_id)
->in('is_active', $status)
->findAll();
}
/** /**
* Count all tasks for a given project and status * Count all tasks for a given project and status
* *

View File

@@ -135,7 +135,7 @@ class User extends Base
$result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values); $result = $this->db->table(self::TABLE)->eq('id', $values['id'])->update($values);
if ($_SESSION['user']['id'] == $values['id']) { if (session_id() !== '' && $_SESSION['user']['id'] == $values['id']) {
$this->updateSession(); $this->updateSession();
} }

View File

@@ -2,7 +2,12 @@
namespace Schema; namespace Schema;
const VERSION = 18; const VERSION = 19;
function version_19($pdo)
{
$pdo->exec("ALTER TABLE config ADD COLUMN api_token VARCHAR(255) DEFAULT '".\Core\Security::generateToken()."'");
}
function version_18($pdo) function version_18($pdo)
{ {

View File

@@ -2,7 +2,12 @@
namespace Schema; namespace Schema;
const VERSION = 18; const VERSION = 19;
function version_19($pdo)
{
$pdo->exec("ALTER TABLE config ADD COLUMN api_token TEXT DEFAULT '".\Core\Security::generateToken()."'");
}
function version_18($pdo) function version_18($pdo)
{ {

View File

@@ -46,6 +46,10 @@
<?= t('Webhooks token:') ?> <?= t('Webhooks token:') ?>
<strong><?= Helper\escape($values['webhooks_token']) ?></strong> <strong><?= Helper\escape($values['webhooks_token']) ?></strong>
</li> </li>
<li>
<?= t('API token:') ?>
<strong><?= Helper\escape($values['api_token']) ?></strong>
</li>
<?php if (DB_DRIVER === 'sqlite'): ?> <?php if (DB_DRIVER === 'sqlite'): ?>
<li> <li>
<?= t('Database size:') ?> <?= t('Database size:') ?>

238
jsonrpc.php Normal file
View File

@@ -0,0 +1,238 @@
<?php
require __DIR__.'/app/common.php';
require __DIR__.'/vendor/JsonRPC/Server.php';
use JsonRPC\Server;
use Model\Project;
use Model\Task;
use Model\User;
use Model\Config;
use Model\Category;
use Model\Comment;
use Model\Subtask;
use Model\Board;
use Model\Action;
$config = new Config($registry->shared('db'), $registry->shared('event'));
$project = new Project($registry->shared('db'), $registry->shared('event'));
$task = new Task($registry->shared('db'), $registry->shared('event'));
$user = new User($registry->shared('db'), $registry->shared('event'));
$category = new Category($registry->shared('db'), $registry->shared('event'));
$comment = new Comment($registry->shared('db'), $registry->shared('event'));
$subtask = new Subtask($registry->shared('db'), $registry->shared('event'));
$board = new Board($registry->shared('db'), $registry->shared('event'));
$action = new Action($registry->shared('db'), $registry->shared('event'));
$action->attachEvents();
$project->attachEvents();
$server = new Server;
$server->authentication(array('jsonrpc' => $config->get('api_token')));
/**
* Project procedures
*/
$server->register('createProject', function($name) use ($project) {
$values = array('name' => $name);
list($valid,) = $project->validateCreation($values);
return $valid && $project->create($values);
});
$server->register('getProjectById', function($project_id) use ($project) {
return $project->getById($project_id);
});
$server->register('getProjectByName', function($name) use ($project) {
return $project->getByName($name);
});
$server->register('getAllProjects', function() use ($project) {
return $project->getAll();
});
$server->register('updateProject', function(array $values) use ($project) {
list($valid,) = $project->validateModification($values);
return $valid && $project->update($values);
});
$server->register('removeProject', function($project_id) use ($project) {
return $project->remove($project_id);
});
$server->register('getBoard', function($project_id) use ($board) {
return $board->get($project_id);
});
$server->register('getColumns', function($project_id) use ($board) {
return $board->getColumns($project_id);
});
$server->register('moveColumnUp', function($project_id, $column_id) use ($board) {
return $board->moveUp($project_id, $column_id);
});
$server->register('moveColumnDown', function($project_id, $column_id) use ($board) {
return $board->moveDown($project_id, $column_id);
});
$server->register('updateColumn', function($column_id, array $values) use ($board) {
return $board->updateColumn($column_id, $values);
});
$server->register('addColumn', function($project_id, array $values) use ($board) {
$values += array('project_id' => $project_id);
return $board->add($values);
});
$server->register('removeColumn', function($column_id) use ($board) {
return $board->removeColumn($column_id);
});
$server->register('getAllowedUsers', function($project_id) use ($project) {
return $project->getUsersList($project_id, false, false);
});
$server->register('revokeUser', function($project_id, $user_id) use ($project) {
return $project->revokeUser($project_id, $user_id);
});
$server->register('allowUser', function($project_id, $user_id) use ($project) {
return $project->allowUser($project_id, $user_id);
});
/**
* Task procedures
*/
$server->register('createTask', function(array $values) use ($task) {
list($valid,) = $task->validateCreation($values);
return $valid && $task->create($values) !== false;
});
$server->register('getTask', function($task_id) use ($task) {
return $task->getById($task_id);
});
$server->register('getAllTasks', function($project_id, array $status) use ($task) {
return $task->getAll($project_id, $status);
});
$server->register('updateTask', function($values) use ($task) {
list($valid,) = $task->validateModification($values);
return $valid && $task->update($values);
});
$server->register('removeTask', function($task_id) use ($task) {
return $task->remove($task_id);
});
/**
* User procedures
*/
$server->register('createUser', function(array $values) use ($user) {
list($valid,) = $user->validateCreation($values);
return $valid && $user->create($values);
});
$server->register('getUser', function($user_id) use ($user) {
return $user->getById($user_id);
});
$server->register('getAllUsers', function() use ($user) {
return $user->getAll();
});
$server->register('updateUser', function($values) use ($user) {
list($valid,) = $user->validateModification($values);
return $valid && $user->update($values);
});
$server->register('removeUser', function($user_id) use ($user) {
return $user->remove($user_id);
});
/**
* Category procedures
*/
$server->register('createCategory', function(array $values) use ($category) {
list($valid,) = $category->validateCreation($values);
return $valid && $category->create($values);
});
$server->register('getCategory', function($category_id) use ($category) {
return $category->getById($category_id);
});
$server->register('getAllCategories', function($project_id) use ($category) {
return $category->getAll($project_id);
});
$server->register('updateCategory', function($values) use ($category) {
list($valid,) = $category->validateModification($values);
return $valid && $category->update($values);
});
$server->register('removeCategory', function($category_id) use ($category) {
return $category->remove($category_id);
});
/**
* Comments procedures
*/
$server->register('createComment', function(array $values) use ($comment) {
list($valid,) = $comment->validateCreation($values);
return $valid && $comment->create($values);
});
$server->register('getComment', function($comment_id) use ($comment) {
return $comment->getById($comment_id);
});
$server->register('getAllComments', function($task_id) use ($comment) {
return $comment->getAll($task_id);
});
$server->register('updateComment', function($values) use ($comment) {
list($valid,) = $comment->validateModification($values);
return $valid && $comment->update($values);
});
$server->register('removeComment', function($comment_id) use ($comment) {
return $comment->remove($comment_id);
});
/**
* Subtask procedures
*/
$server->register('createSubtask', function(array $values) use ($subtask) {
list($valid,) = $subtask->validate($values);
return $valid && $subtask->create($values);
});
$server->register('getSubtask', function($subtask_id) use ($subtask) {
return $subtask->getById($subtask_id);
});
$server->register('getAllSubtasks', function($task_id) use ($subtask) {
return $subtask->getAll($task_id);
});
$server->register('updateSubtask', function($values) use ($subtask) {
list($valid,) = $subtask->validate($values);
return $valid && $subtask->update($values);
});
$server->register('removeSubtask', function($subtask_id) use ($subtask) {
return $subtask->remove($subtask_id);
});
/**
* Parse incoming requests
*/
echo $server->execute();

View File

@@ -1,7 +1,7 @@
<phpunit> <phpunit>
<testsuites> <testsuites>
<testsuite name="Kanboard"> <testsuite name="Kanboard">
<directory>tests</directory> <directory>tests/units</directory>
</testsuite> </testsuite>
</testsuites> </testsuites>
</phpunit> </phpunit>

20
scripts/api-client.php Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env php
<?php
require 'vendor/JsonRPC/Client.php';
if ($argc !== 3) {
die('Usage: '.$argv[0].' <url> <token>'.PHP_EOL);
}
$client = new JsonRPC\Client($argv[1], 5, true);
$client->authentication('jsonrpc', $argv[2]);
$client->createProject('Test API');
$r = $client->getAllProjects();
var_dump($r);

View File

@@ -1,57 +0,0 @@
<?php
if (version_compare(PHP_VERSION, '5.5.0', '<')) {
require __DIR__.'/../vendor/password.php';
}
require_once __DIR__.'/../app/Core/Security.php';
require_once __DIR__.'/../vendor/PicoDb/Database.php';
require_once __DIR__.'/../app/Schema/Sqlite.php';
require_once __DIR__.'/../app/Core/Listener.php';
require_once __DIR__.'/../app/Core/Event.php';
require_once __DIR__.'/../app/Core/Translator.php';
require_once __DIR__.'/../app/translator.php';
require_once __DIR__.'/../app/Model/Base.php';
require_once __DIR__.'/../app/Model/Task.php';
require_once __DIR__.'/../app/Model/Acl.php';
require_once __DIR__.'/../app/Model/Comment.php';
require_once __DIR__.'/../app/Model/Project.php';
require_once __DIR__.'/../app/Model/User.php';
require_once __DIR__.'/../app/Model/Board.php';
require_once __DIR__.'/../app/Model/Action.php';
require_once __DIR__.'/../app/Model/Category.php';
require_once __DIR__.'/../app/Action/Base.php';
require_once __DIR__.'/../app/Action/TaskClose.php';
require_once __DIR__.'/../app/Action/TaskAssignSpecificUser.php';
require_once __DIR__.'/../app/Action/TaskAssignColorUser.php';
require_once __DIR__.'/../app/Action/TaskAssignColorCategory.php';
require_once __DIR__.'/../app/Action/TaskAssignCurrentUser.php';
require_once __DIR__.'/../app/Action/TaskDuplicateAnotherProject.php';
abstract class Base extends PHPUnit_Framework_TestCase
{
public function setUp()
{
$this->db = $this->getDbConnection();
$this->event = new \Core\Event;
}
public function getDbConnection()
{
$db = new \PicoDb\Database(array(
'driver' => 'sqlite',
'filename' => ':memory:'
));
if ($db->schema()->check(\Schema\VERSION)) {
return $db;
}
else {
die('Unable to migrate database schema!');
}
}
}

View File

@@ -0,0 +1,417 @@
<?php
require_once __DIR__.'/../../vendor/JsonRPC/Client.php';
class Api extends PHPUnit_Framework_TestCase
{
const URL = 'http://localhost:8000/jsonrpc.php';
const KEY = '19ffd9709d03ce50675c3a43d1c49c1ac207f4bc45f06c5b2701fbdf8929';
private $client;
public function setUp()
{
$this->client = new JsonRPC\Client(self::URL, 5, true);
$this->client->authentication('jsonrpc', self::KEY);
$pdo = new PDO('sqlite:data/db.sqlite');
$pdo->exec('UPDATE config SET api_token="'.self::KEY.'"');
}
public function testRemoveAll()
{
$projects = $this->client->getAllProjects();
if ($projects) {
foreach ($projects as $project) {
$this->client->removeProject($project['id']);
}
}
}
public function testCreateProject()
{
$this->assertTrue($this->client->createProject('API test'));
}
public function testGetProjectById()
{
$project = $this->client->getProjectById(1);
$this->assertNotEmpty($project);
$this->assertEquals(1, $project['id']);
}
public function testUpdateProject()
{
$project = $this->client->getProjectById(1);
$this->assertNotEmpty($project);
$this->assertTrue($this->client->updateProject(array('id' => 1, 'name' => 'API test 2', 'is_active' => 0)));
$project = $this->client->getProjectById(1);
$this->assertEquals('API test 2', $project['name']);
$this->assertEquals(0, $project['is_active']);
$this->assertTrue($this->client->updateProject(array('id' => 1, 'name' => 'API test', 'is_active' => 1)));
$project = $this->client->getProjectById(1);
$this->assertEquals('API test', $project['name']);
$this->assertEquals(1, $project['is_active']);
}
public function testGetBoard()
{
$board = $this->client->getBoard(1);
$this->assertTrue(is_array($board));
$this->assertEquals(4, count($board));
}
public function testGetColumns()
{
$columns = $this->client->getColumns(1);
$this->assertTrue(is_array($columns));
$this->assertEquals(4, count($columns));
$this->assertEquals('Done', $columns[3]['title']);
}
public function testMoveColumnUp()
{
$this->assertTrue($this->client->moveColumnUp(1, 4));
$columns = $this->client->getColumns(1);
$this->assertTrue(is_array($columns));
$this->assertEquals('Done', $columns[2]['title']);
$this->assertEquals('Work in progress', $columns[3]['title']);
}
public function testMoveColumnDown()
{
$this->assertTrue($this->client->moveColumnDown(1, 4));
$columns = $this->client->getColumns(1);
$this->assertTrue(is_array($columns));
$this->assertEquals('Work in progress', $columns[2]['title']);
$this->assertEquals('Done', $columns[3]['title']);
}
public function testUpdateColumn()
{
$this->assertTrue($this->client->updateColumn(4, array('title' => 'Boo', 'task_limit' => 2)));
$columns = $this->client->getColumns(1);
$this->assertTrue(is_array($columns));
$this->assertEquals('Boo', $columns[3]['title']);
$this->assertEquals(2, $columns[3]['task_limit']);
}
public function testAddColumn()
{
$this->assertTrue($this->client->addColumn(1, array('title' => 'New column')));
$columns = $this->client->getColumns(1);
$this->assertTrue(is_array($columns));
$this->assertEquals(5, count($columns));
$this->assertEquals('New column', $columns[4]['title']);
}
public function testRemoveColumn()
{
$this->assertTrue($this->client->removeColumn(5));
$columns = $this->client->getColumns(1);
$this->assertTrue(is_array($columns));
$this->assertEquals(4, count($columns));
}
public function testCreateTask()
{
$task = array(
'title' => 'Task #1',
'color_id' => 'blue',
'owner_id' => 1,
'project_id' => 1,
'column_id' => 2,
);
$this->assertTrue($this->client->createTask($task));
$task = array(
'title' => 'Task #1',
'color_id' => 'blue',
'owner_id' => 1,
);
$this->assertFalse($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']);
}
public function testGetAllTasks()
{
$tasks = $this->client->getAllTasks(1, array(1));
$this->assertNotFalse($tasks);
$this->assertTrue(is_array($tasks));
$this->assertEquals('Task #1', $tasks[0]['title']);
$tasks = $this->client->getAllTasks(2, array(1, 2));
$this->assertNotFalse($tasks);
$this->assertTrue(is_array($tasks));
$this->assertEmpty($tasks);
}
public function testUpdateTask()
{
$task = $this->client->getTask(1);
$task['color_id'] = 'green';
$task['column_id'] = 1;
$task['description'] = 'test';
$this->assertTrue($this->client->updateTask($task));
}
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',
'confirmation' => '123456',
);
$this->assertTrue($this->client->createUser($user));
$user = array(
'username' => 'titi',
'name' => 'Titi',
'password' => '123456',
'confirmation' => '789',
);
$this->assertFalse($this->client->createUser($user));
}
public function testGetUser()
{
$user = $this->client->getUser(2);
$this->assertNotFalse($user);
$this->assertTrue(is_array($user));
$this->assertEquals('toto', $user['username']);
}
public function testUpdateUser()
{
$user = $this->client->getUser(2);
$user['username'] = 'titi';
$user['name'] = 'Titi';
unset($user['password']);
$this->assertTrue($this->client->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']);
}
public function testGetAllowedUsers()
{
$users = $this->client->getAllowedUsers(1);
$this->assertNotFalse($users);
$this->assertEquals(array(1 => 'admin', 2 => 'titi'), $users);
}
public function testAllowedUser()
{
$this->assertTrue($this->client->allowUser(1, 2));
$users = $this->client->getAllowedUsers(1);
$this->assertNotFalse($users);
$this->assertEquals(array(2 => 'titi'), $users);
}
public function testRevokeUser()
{
$this->assertTrue($this->client->revokeUser(1, 2));
$users = $this->client->getAllowedUsers(1);
$this->assertNotFalse($users);
$this->assertEquals(array(1 => 'admin', 2 => 'titi'), $users);
}
public function testCreateComment()
{
$task = array(
'title' => 'Task with comment',
'color_id' => 'red',
'owner_id' => 1,
'project_id' => 1,
'column_id' => 1,
);
$this->assertTrue($this->client->createTask($task));
$comment = array(
'task_id' => 1,
'user_id' => 2,
'comment' => 'boo',
);
$this->assertTrue($this->client->createComment($comment));
}
public function testGetComment()
{
$comment = $this->client->getComment(1);
$this->assertNotFalse($comment);
$this->assertNotEmpty($comment);
$this->assertEquals(1, $comment['task_id']);
$this->assertEquals(2, $comment['user_id']);
$this->assertEquals('boo', $comment['comment']);
}
public function testUpdateComment()
{
$comment = $this->client->getComment(1);
$comment['comment'] = 'test';
$this->assertTrue($this->client->updateComment($comment));
$comment = $this->client->getComment(1);
$this->assertEquals('test', $comment['comment']);
}
public function testGetAllComments()
{
$comment = array(
'task_id' => 1,
'user_id' => 1,
'comment' => 'blabla',
);
$this->assertTrue($this->client->createComment($comment));
$comments = $this->client->getAllComments(1);
$this->assertNotFalse($comments);
$this->assertNotEmpty($comments);
$this->assertTrue(is_array($comments));
$this->assertEquals(2, count($comments));
}
public function testRemoveComment()
{
$this->assertTrue($this->client->removeComment(1));
$comments = $this->client->getAllComments(1);
$this->assertNotFalse($comments);
$this->assertNotEmpty($comments);
$this->assertTrue(is_array($comments));
$this->assertEquals(1, count($comments));
}
public function testCreateSubtask()
{
$subtask = array(
'task_id' => 1,
'title' => 'subtask #1',
);
$this->assertTrue($this->client->createSubtask($subtask));
}
public function testGetSubtask()
{
$subtask = $this->client->getSubtask(1);
$this->assertNotFalse($subtask);
$this->assertNotEmpty($subtask);
$this->assertEquals(1, $subtask['task_id']);
$this->assertEquals(0, $subtask['user_id']);
$this->assertEquals('subtask #1', $subtask['title']);
}
public function testUpdateSubtask()
{
$subtask = $this->client->getSubtask(1);
$subtask['title'] = 'test';
$this->assertTrue($this->client->updateSubtask($subtask));
$subtask = $this->client->getSubtask(1);
$this->assertEquals('test', $subtask['title']);
}
public function testGetAllSubtasks()
{
$subtask = array(
'task_id' => 1,
'user_id' => 2,
'title' => 'Subtask #2',
);
$this->assertTrue($this->client->createSubtask($subtask));
$subtasks = $this->client->getAllSubtasks(1);
$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(1);
$this->assertNotFalse($subtasks);
$this->assertNotEmpty($subtasks);
$this->assertTrue(is_array($subtasks));
$this->assertEquals(1, count($subtasks));
}
/*
public function testAutomaticActions()
{
$task = array(
'title' => 'Task #1',
'color_id' => 'blue',
'owner_id' => 0,
'project_id' => 1,
'column_id' => 1,
);
$this->assertTrue($this->client->createTask($task));
$tasks = $this->client->getAllTasks(1, array(1));
$task = $tasks[count($tasks) - 1];
$task['column_id'] = 3;
$this->assertTrue($this->client->updateTask($task));
}*/
}

57
tests/units/Base.php Normal file
View File

@@ -0,0 +1,57 @@
<?php
if (version_compare(PHP_VERSION, '5.5.0', '<')) {
require __DIR__.'/../../vendor/password.php';
}
require_once __DIR__.'/../../app/Core/Security.php';
require_once __DIR__.'/../../vendor/PicoDb/Database.php';
require_once __DIR__.'/../../app/Schema/Sqlite.php';
require_once __DIR__.'/../../app/Core/Listener.php';
require_once __DIR__.'/../../app/Core/Event.php';
require_once __DIR__.'/../../app/Core/Translator.php';
require_once __DIR__.'/../../app/translator.php';
require_once __DIR__.'/../../app/Model/Base.php';
require_once __DIR__.'/../../app/Model/Task.php';
require_once __DIR__.'/../../app/Model/Acl.php';
require_once __DIR__.'/../../app/Model/Comment.php';
require_once __DIR__.'/../../app/Model/Project.php';
require_once __DIR__.'/../../app/Model/User.php';
require_once __DIR__.'/../../app/Model/Board.php';
require_once __DIR__.'/../../app/Model/Action.php';
require_once __DIR__.'/../../app/Model/Category.php';
require_once __DIR__.'/../../app/Action/Base.php';
require_once __DIR__.'/../../app/Action/TaskClose.php';
require_once __DIR__.'/../../app/Action/TaskAssignSpecificUser.php';
require_once __DIR__.'/../../app/Action/TaskAssignColorUser.php';
require_once __DIR__.'/../../app/Action/TaskAssignColorCategory.php';
require_once __DIR__.'/../../app/Action/TaskAssignCurrentUser.php';
require_once __DIR__.'/../../app/Action/TaskDuplicateAnotherProject.php';
abstract class Base extends PHPUnit_Framework_TestCase
{
public function setUp()
{
$this->db = $this->getDbConnection();
$this->event = new \Core\Event;
}
public function getDbConnection()
{
$db = new \PicoDb\Database(array(
'driver' => 'sqlite',
'filename' => ':memory:'
));
if ($db->schema()->check(\Schema\VERSION)) {
return $db;
}
else {
die('Unable to migrate database schema!');
}
}
}

174
vendor/JsonRPC/Client.php vendored Normal file
View File

@@ -0,0 +1,174 @@
<?php
namespace JsonRPC;
/**
* JsonRPC client class
*
* @package JsonRPC
* @author Frderic Guillot
* @license Unlicense http://unlicense.org/
*/
class Client
{
/**
* URL of the server
*
* @access private
* @var string
*/
private $url;
/**
* HTTP client timeout
*
* @access private
* @var integer
*/
private $timeout;
/**
* Debug flag
*
* @access private
* @var bool
*/
private $debug;
/**
* Username for authentication
*
* @access private
* @var string
*/
private $username;
/**
* Password for authentication
*
* @access private
* @var string
*/
private $password;
/**
* Default HTTP headers to send to the server
*
* @access private
* @var array
*/
private $headers = array(
'Connection: close',
'Content-Type: application/json',
'Accept: application/json'
);
/**
* Constructor
*
* @access public
* @param string $url Server URL
* @param integer $timeout Server URL
* @param bool $debug Debug flag
* @param array $headers Custom HTTP headers
*/
public function __construct($url, $timeout = 5, $debug = false, $headers = array())
{
$this->url = $url;
$this->timeout = $timeout;
$this->debug = $debug;
$this->headers = array_merge($this->headers, $headers);
}
/**
* Automatic mapping of procedures
*
* @access public
* @param string $method Procedure name
* @param array $params Procedure arguments
* @return mixed
*/
public function __call($method, $params)
{
return $this->execute($method, $params);
}
/**
* Set authentication parameters
*
* @access public
* @param string $username Username
* @param string $password Password
*/
public function authentication($username, $password)
{
$this->username = $username;
$this->password = $password;
}
/**
* Execute
*
* @access public
* @param string $procedure Procedure name
* @param array $params Procedure arguments
* @return mixed
*/
public function execute($procedure, array $params = array())
{
$id = mt_rand();
$payload = array(
'jsonrpc' => '2.0',
'method' => $procedure,
'id' => $id
);
if (! empty($params)) {
$payload['params'] = $params;
}
$result = $this->doRequest($payload);
if (isset($result['id']) && $result['id'] == $id && array_key_exists('result', $result)) {
return $result['result'];
}
else if ($this->debug && isset($result['error'])) {
print_r($result['error']);
}
return null;
}
/**
* Do the HTTP request
*
* @access public
* @param string $payload Data to send
*/
public function doRequest($payload)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeout);
curl_setopt($ch, CURLOPT_USERAGENT, 'JSON-RPC PHP Client');
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
if ($this->username && $this->password) {
curl_setopt($ch, CURLOPT_USERPWD, $this->username.':'.$this->password);
}
$result = curl_exec($ch);
$response = json_decode($result, true);
curl_close($ch);
return is_array($response) ? $response : array();
}
}

301
vendor/JsonRPC/Server.php vendored Normal file
View File

@@ -0,0 +1,301 @@
<?php
namespace JsonRPC;
use ReflectionFunction;
use Closure;
/**
* JsonRPC server class
*
* @package JsonRPC
* @author Frderic Guillot
* @license Unlicense http://unlicense.org/
*/
class Server
{
/**
* Data received from the client
*
* @access private
* @var string
*/
private $payload;
/**
* List of procedures
*
* @static
* @access private
* @var array
*/
static private $procedures = array();
/**
* Constructor
*
* @access public
* @param string $payload Client data
*/
public function __construct($payload = '')
{
$this->payload = $payload;
}
/**
* IP based client restrictions
*
* Return an HTTP error 403 if the client is not allowed
*
* @access public
* @param array $hosts List of hosts
*/
public function allowHosts(array $hosts) {
if (! in_array($_SERVER['REMOTE_ADDR'], $hosts)) {
header('Content-Type: application/json');
header('HTTP/1.0 403 Forbidden');
echo '["Access Forbidden"]';
exit;
}
}
/**
* HTTP Basic authentication
*
* Return an HTTP error 401 if the client is not allowed
*
* @access public
* @param array $users Map of username/password
*/
public function authentication(array $users)
{
// OVH workaround
if (isset($_SERVER['REMOTE_USER'])) {
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['REMOTE_USER'], 6)));
}
if (! isset($_SERVER['PHP_AUTH_USER']) ||
! isset($users[$_SERVER['PHP_AUTH_USER']]) ||
$users[$_SERVER['PHP_AUTH_USER']] !== $_SERVER['PHP_AUTH_PW']) {
header('WWW-Authenticate: Basic realm="JsonRPC"');
header('Content-Type: application/json');
header('HTTP/1.0 401 Unauthorized');
echo '["Authentication failed"]';
exit;
}
}
/**
* Register a new procedure
*
* @access public
* @param string $name Procedure name
* @param closure $callback Callback
*/
public function register($name, Closure $callback)
{
self::$procedures[$name] = $callback;
}
/**
* Unregister a procedure
*
* @access public
* @param string $name Procedure name
*/
public function unregister($name)
{
if (isset(self::$procedures[$name])) {
unset(self::$procedures[$name]);
}
}
/**
* Unregister all procedures
*
* @access public
*/
public function unregisterAll()
{
self::$procedures = array();
}
/**
* Return the response to the client
*
* @access public
* @param array $data Data to send to the client
* @param array $payload Incoming data
* @return string
*/
public function getResponse(array $data, array $payload = array())
{
if (! array_key_exists('id', $payload)) {
return '';
}
$response = array(
'jsonrpc' => '2.0',
'id' => $payload['id']
);
$response = array_merge($response, $data);
@header('Content-Type: application/json');
return json_encode($response);
}
/**
* Map arguments to the procedure
*
* @access public
* @param array $request_params Incoming arguments
* @param array $method_params Procedure arguments
* @param array $params Arguments to pass to the callback
* @return bool
*/
public function mapParameters(array $request_params, array $method_params, array &$params)
{
// Positional parameters
if (array_keys($request_params) === range(0, count($request_params) - 1)) {
if (count($request_params) !== count($method_params)) return false;
$params = $request_params;
return true;
}
// Named parameters
foreach ($method_params as $p) {
$name = $p->getName();
if (isset($request_params[$name])) {
$params[$name] = $request_params[$name];
}
else if ($p->isDefaultValueAvailable()) {
continue;
}
else {
return false;
}
}
return true;
}
/**
* Parse incoming requests
*
* @access public
* @return string
*/
public function execute()
{
// Parse payload
if (empty($this->payload)) {
$this->payload = file_get_contents('php://input');
}
if (is_string($this->payload)) {
$this->payload = json_decode($this->payload, true);
}
// Check JSON format
if (! is_array($this->payload)) {
return $this->getResponse(array(
'error' => array(
'code' => -32700,
'message' => 'Parse error'
)),
array('id' => null)
);
}
// Handle batch request
if (array_keys($this->payload) === range(0, count($this->payload) - 1)) {
$responses = array();
foreach ($this->payload as $payload) {
if (! is_array($payload)) {
$responses[] = $this->getResponse(array(
'error' => array(
'code' => -32600,
'message' => 'Invalid Request'
)),
array('id' => null)
);
}
else {
$server = new Server($payload);
$response = $server->execute();
if ($response) $responses[] = $response;
}
}
return empty($responses) ? '' : '['.implode(',', $responses).']';
}
// Check JSON-RPC format
if (! isset($this->payload['jsonrpc']) ||
! isset($this->payload['method']) ||
! is_string($this->payload['method']) ||
$this->payload['jsonrpc'] !== '2.0' ||
(isset($this->payload['params']) && ! is_array($this->payload['params']))) {
return $this->getResponse(array(
'error' => array(
'code' => -32600,
'message' => 'Invalid Request'
)),
array('id' => null)
);
}
// Procedure not found
if (! isset(self::$procedures[$this->payload['method']])) {
return $this->getResponse(array(
'error' => array(
'code' => -32601,
'message' => 'Method not found'
)),
$this->payload
);
}
$callback = self::$procedures[$this->payload['method']];
$params = array();
$reflection = new ReflectionFunction($callback);
if (isset($this->payload['params'])) {
$parameters = $reflection->getParameters();
if (! $this->mapParameters($this->payload['params'], $parameters, $params)) {
return $this->getResponse(array(
'error' => array(
'code' => -32602,
'message' => 'Invalid params'
)),
$this->payload
);
}
}
$result = $reflection->invokeArgs($params);
return $this->getResponse(array('result' => $result), $this->payload);
}
}