Add first draft of the user api
This commit is contained in:
parent
2eeb58ae03
commit
f595fb2786
|
|
@ -8,7 +8,7 @@ namespace Api;
|
|||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Action extends Base
|
||||
class Action extends \Core\Base
|
||||
{
|
||||
public function getAvailableActions()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Api;
|
|||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class App extends Base
|
||||
class App extends \Core\Base
|
||||
{
|
||||
public function getTimezone()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace Api;
|
||||
|
||||
use JsonRPC\AuthenticationFailure;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
/**
|
||||
* Base class
|
||||
*
|
||||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Auth extends Base
|
||||
{
|
||||
/**
|
||||
* Check api credentials
|
||||
*
|
||||
* @access public
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
*/
|
||||
public function checkCredentials($username, $password, $class, $method)
|
||||
{
|
||||
$this->container['dispatcher']->dispatch('api.bootstrap', new Event);
|
||||
|
||||
if ($username !== 'jsonrpc' && $this->authentication->authenticate($username, $password)) {
|
||||
$this->checkProcedurePermission(true, $method);
|
||||
$this->userSession->refresh($this->user->getByUsername($username));
|
||||
}
|
||||
else if ($username === 'jsonrpc' && $password === $this->config->get('api_token')) {
|
||||
$this->checkProcedurePermission(false, $method);
|
||||
}
|
||||
else {
|
||||
throw new AuthenticationFailure('Wrong credentials');
|
||||
}
|
||||
}
|
||||
}
|
||||
106
app/Api/Base.php
106
app/Api/Base.php
|
|
@ -3,7 +3,7 @@
|
|||
namespace Api;
|
||||
|
||||
use JsonRPC\AuthenticationFailure;
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use JsonRPC\AccessDeniedException;
|
||||
|
||||
/**
|
||||
* Base class
|
||||
|
|
@ -13,21 +13,97 @@ use Symfony\Component\EventDispatcher\Event;
|
|||
*/
|
||||
abstract class Base extends \Core\Base
|
||||
{
|
||||
/**
|
||||
* Check api credentials
|
||||
*
|
||||
* @access public
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param string $class
|
||||
* @param string $method
|
||||
*/
|
||||
public function authentication($username, $password, $class, $method)
|
||||
{
|
||||
$this->container['dispatcher']->dispatch('api.bootstrap', new Event);
|
||||
private $user_allowed_procedures = array(
|
||||
'getMe',
|
||||
'getMyDashboard',
|
||||
'getMyActivityStream',
|
||||
'createMyPrivateProject',
|
||||
'getMyProjectsList',
|
||||
);
|
||||
|
||||
if (! ($username === 'jsonrpc' && $password === $this->config->get('api_token'))) {
|
||||
throw new AuthenticationFailure('Wrong credentials');
|
||||
private $both_allowed_procedures = array(
|
||||
'getTimezone',
|
||||
'getVersion',
|
||||
'getProjectById',
|
||||
'getTask',
|
||||
'getTaskByReference',
|
||||
'getAllTasks',
|
||||
'openTask',
|
||||
'closeTask',
|
||||
'moveTaskPosition',
|
||||
'createTask',
|
||||
'updateTask',
|
||||
'getBoard',
|
||||
);
|
||||
|
||||
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');
|
||||
}
|
||||
else if (! $is_user && ! $is_both_procedure && $is_user_procedure) {
|
||||
throw new AccessDeniedException('Permission denied');
|
||||
}
|
||||
}
|
||||
|
||||
public function checkProjectPermission($project_id)
|
||||
{
|
||||
if ($this->userSession->isLogged() && ! $this->projectPermission->isUserAllowed($project_id, $this->userSession->getId())) {
|
||||
throw new AccessDeniedException('Permission denied');
|
||||
}
|
||||
}
|
||||
|
||||
public function checkTaskPermission($task_id)
|
||||
{
|
||||
if ($this->userSession->isLogged()) {
|
||||
$this->checkProjectPermission($this->taskFinder->getProjectId($task_id));
|
||||
}
|
||||
}
|
||||
|
||||
protected function formatTask($task)
|
||||
{
|
||||
if (! empty($task)) {
|
||||
$task['url'] = $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), '', true);
|
||||
}
|
||||
|
||||
return $task;
|
||||
}
|
||||
|
||||
protected function formatTasks($tasks)
|
||||
{
|
||||
if (! empty($tasks)) {
|
||||
foreach ($tasks as &$task) {
|
||||
$task = $this->formatTask($task);
|
||||
}
|
||||
}
|
||||
|
||||
return $tasks;
|
||||
}
|
||||
|
||||
protected function formatProject($project)
|
||||
{
|
||||
if (! empty($project)) {
|
||||
$project['url'] = array(
|
||||
'board' => $this->helper->url->to('board', 'show', array('project_id' => $project['id']), '', true),
|
||||
'calendar' => $this->helper->url->to('calendar', 'show', array('project_id' => $project['id']), '', true),
|
||||
'list' => $this->helper->url->to('listing', 'show', array('project_id' => $project['id']), '', true),
|
||||
);
|
||||
}
|
||||
|
||||
return $project;
|
||||
}
|
||||
|
||||
protected function formatProjects($projects)
|
||||
{
|
||||
if (! empty($projects)) {
|
||||
foreach ($projects as &$project) {
|
||||
$project = $this->formatProject($project);
|
||||
}
|
||||
}
|
||||
|
||||
return $projects;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ class Board extends Base
|
|||
{
|
||||
public function getBoard($project_id)
|
||||
{
|
||||
$this->checkProjectPermission($project_id);
|
||||
return $this->board->getBoard($project_id);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Api;
|
|||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Category extends Base
|
||||
class Category extends \Core\Base
|
||||
{
|
||||
public function getCategory($category_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Api;
|
|||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Comment extends Base
|
||||
class Comment extends \Core\Base
|
||||
{
|
||||
public function getComment($comment_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Api;
|
|||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class File extends Base
|
||||
class File extends \Core\Base
|
||||
{
|
||||
public function getFile($file_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Api;
|
|||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Link extends Base
|
||||
class Link extends \Core\Base
|
||||
{
|
||||
/**
|
||||
* Get a link by id
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Api;
|
||||
|
||||
use Model\Subtask as SubtaskModel;
|
||||
use Model\Task as TaskModel;
|
||||
|
||||
/**
|
||||
* Me API controller
|
||||
*
|
||||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Me extends Base
|
||||
{
|
||||
public function getMe()
|
||||
{
|
||||
return $this->session['user'];
|
||||
}
|
||||
|
||||
public function getMyDashboard()
|
||||
{
|
||||
$user_id = $this->userSession->getId();
|
||||
$projects = $this->project->getQueryColumnStats($this->projectPermission->getActiveMemberProjectIds($user_id))->findAll();
|
||||
$tasks = $this->taskFinder->getUserQuery($user_id)->findAll();
|
||||
|
||||
return array(
|
||||
'projects' => $this->formatProjects($projects),
|
||||
'tasks' => $this->formatTasks($tasks),
|
||||
'subtasks' => $this->subtask->getUserQuery($user_id, array(SubTaskModel::STATUS_TODO, SubtaskModel::STATUS_INPROGRESS))->findAll(),
|
||||
);
|
||||
}
|
||||
|
||||
public function getMyActivityStream()
|
||||
{
|
||||
return $this->projectActivity->getProjects($this->projectPermission->getActiveMemberProjectIds($this->userSession->getId()), 100);
|
||||
}
|
||||
|
||||
public function createMyPrivateProject($name, $description = null)
|
||||
{
|
||||
$values = array(
|
||||
'name' => $name,
|
||||
'description' => $description,
|
||||
'is_private' => 1,
|
||||
);
|
||||
|
||||
list($valid,) = $this->project->validateCreation($values);
|
||||
return $valid ? $this->project->create($values, $this->userSession->getId(), true) : false;
|
||||
}
|
||||
|
||||
public function getMyProjectsList()
|
||||
{
|
||||
return $this->projectPermission->getMemberProjects($this->userSession->getId());
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ class Project extends Base
|
|||
{
|
||||
public function getProjectById($project_id)
|
||||
{
|
||||
$this->checkProjectPermission($project_id);
|
||||
return $this->formatProject($this->project->getById($project_id));
|
||||
}
|
||||
|
||||
|
|
@ -82,28 +83,4 @@ class Project extends Base
|
|||
list($valid,) = $this->project->validateModification($values);
|
||||
return $valid && $this->project->update($values);
|
||||
}
|
||||
|
||||
private function formatProject($project)
|
||||
{
|
||||
if (! empty($project)) {
|
||||
$project['url'] = array(
|
||||
'board' => $this->helper->url->to('board', 'show', array('project_id' => $project['id']), '', true),
|
||||
'calendar' => $this->helper->url->to('calendar', 'show', array('project_id' => $project['id']), '', true),
|
||||
'list' => $this->helper->url->to('listing', 'show', array('project_id' => $project['id']), '', true),
|
||||
);
|
||||
}
|
||||
|
||||
return $project;
|
||||
}
|
||||
|
||||
private function formatProjects($projects)
|
||||
{
|
||||
if (! empty($projects)) {
|
||||
foreach ($projects as &$project) {
|
||||
$project = $this->formatProject($project);
|
||||
}
|
||||
}
|
||||
|
||||
return $projects;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Api;
|
|||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class ProjectPermission extends Base
|
||||
class ProjectPermission extends \Core\Base
|
||||
{
|
||||
public function getMembers($project_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Api;
|
|||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Subtask extends Base
|
||||
class Subtask extends \Core\Base
|
||||
{
|
||||
public function getSubtask($subtask_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Api;
|
|||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Swimlane extends Base
|
||||
class Swimlane extends \Core\Base
|
||||
{
|
||||
public function getActiveSwimlanes($project_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,16 +14,19 @@ class Task extends Base
|
|||
{
|
||||
public function getTask($task_id)
|
||||
{
|
||||
$this->checkTaskPermission($task_id);
|
||||
return $this->formatTask($this->taskFinder->getById($task_id));
|
||||
}
|
||||
|
||||
public function getTaskByReference($project_id, $reference)
|
||||
{
|
||||
$this->checkProjectPermission($project_id);
|
||||
return $this->formatTask($this->taskFinder->getByReference($project_id, $reference));
|
||||
}
|
||||
|
||||
public function getAllTasks($project_id, $status_id = TaskModel::STATUS_OPEN)
|
||||
{
|
||||
$this->checkProjectPermission($project_id);
|
||||
return $this->formatTasks($this->taskFinder->getAll($project_id, $status_id));
|
||||
}
|
||||
|
||||
|
|
@ -34,11 +37,13 @@ class Task extends Base
|
|||
|
||||
public function openTask($task_id)
|
||||
{
|
||||
$this->checkTaskPermission($task_id);
|
||||
return $this->taskStatus->open($task_id);
|
||||
}
|
||||
|
||||
public function closeTask($task_id)
|
||||
{
|
||||
$this->checkTaskPermission($task_id);
|
||||
return $this->taskStatus->close($task_id);
|
||||
}
|
||||
|
||||
|
|
@ -49,6 +54,7 @@ class Task extends Base
|
|||
|
||||
public function moveTaskPosition($project_id, $task_id, $column_id, $position, $swimlane_id = 0)
|
||||
{
|
||||
$this->checkProjectPermission($project_id);
|
||||
return $this->taskPosition->movePosition($project_id, $task_id, $column_id, $position, $swimlane_id);
|
||||
}
|
||||
|
||||
|
|
@ -57,6 +63,8 @@ class Task extends Base
|
|||
$recurrence_status = 0, $recurrence_trigger = 0, $recurrence_factor = 0, $recurrence_timeframe = 0,
|
||||
$recurrence_basedate = 0, $reference = '')
|
||||
{
|
||||
$this->checkProjectPermission($project_id);
|
||||
|
||||
$values = array(
|
||||
'title' => $title,
|
||||
'project_id' => $project_id,
|
||||
|
|
@ -87,6 +95,8 @@ class Task extends Base
|
|||
$recurrence_status = null, $recurrence_trigger = null, $recurrence_factor = null,
|
||||
$recurrence_timeframe = null, $recurrence_basedate = null, $reference = null)
|
||||
{
|
||||
$this->checkTaskPermission($id);
|
||||
|
||||
$values = array(
|
||||
'id' => $id,
|
||||
'title' => $title,
|
||||
|
|
@ -115,24 +125,4 @@ class Task extends Base
|
|||
list($valid) = $this->taskValidator->validateApiModification($values);
|
||||
return $valid && $this->taskModification->update($values);
|
||||
}
|
||||
|
||||
private function formatTask($task)
|
||||
{
|
||||
if (! empty($task)) {
|
||||
$task['url'] = $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), '', true);
|
||||
}
|
||||
|
||||
return $task;
|
||||
}
|
||||
|
||||
private function formatTasks($tasks)
|
||||
{
|
||||
if (! empty($tasks)) {
|
||||
foreach ($tasks as &$task) {
|
||||
$task = $this->formatTask($task);
|
||||
}
|
||||
}
|
||||
|
||||
return $tasks;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Api;
|
|||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class TaskLink extends Base
|
||||
class TaskLink extends \Core\Base
|
||||
{
|
||||
/**
|
||||
* Get a task link
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use Auth\Ldap;
|
|||
* @package api
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class User extends Base
|
||||
class User extends \Core\Base
|
||||
{
|
||||
public function getUser($user_id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"eluceo/ical": "*",
|
||||
"erusev/parsedown" : "1.5.3",
|
||||
"fabiang/xmpp" : "0.6.1",
|
||||
"fguillot/json-rpc" : "1.0.0",
|
||||
"fguillot/json-rpc" : "dev-master",
|
||||
"fguillot/picodb" : "1.0.0",
|
||||
"fguillot/simpleLogger" : "0.0.2",
|
||||
"fguillot/simple-validator" : "0.0.3",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "305f839bfc9c4acb5d9357e1174c42da",
|
||||
"hash": "1c0cc116db3d03c38df0f0efa59e9df7",
|
||||
"packages": [
|
||||
{
|
||||
"name": "christian-riesen/base32",
|
||||
|
|
@ -260,16 +260,16 @@
|
|||
},
|
||||
{
|
||||
"name": "fguillot/json-rpc",
|
||||
"version": "v1.0.0",
|
||||
"version": "dev-master",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fguillot/JsonRPC.git",
|
||||
"reference": "5a11f1414780a200f09b78d20ab72b5cee4faa95"
|
||||
"reference": "050f046b1cae99210ae2fe64618831d3961f5bd9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/5a11f1414780a200f09b78d20ab72b5cee4faa95",
|
||||
"reference": "5a11f1414780a200f09b78d20ab72b5cee4faa95",
|
||||
"url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/050f046b1cae99210ae2fe64618831d3961f5bd9",
|
||||
"reference": "050f046b1cae99210ae2fe64618831d3961f5bd9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -292,7 +292,7 @@
|
|||
],
|
||||
"description": "Simple Json-RPC client/server library that just works",
|
||||
"homepage": "https://github.com/fguillot/JsonRPC",
|
||||
"time": "2015-07-01 19:50:31"
|
||||
"time": "2015-07-29 20:56:20"
|
||||
},
|
||||
{
|
||||
"name": "fguillot/picodb",
|
||||
|
|
@ -757,6 +757,7 @@
|
|||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"fguillot/json-rpc": 20,
|
||||
"swiftmailer/swiftmailer": 0,
|
||||
"symfony/console": 0
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,34 @@
|
|||
Json-RPC API
|
||||
============
|
||||
|
||||
User and application API
|
||||
------------------------
|
||||
|
||||
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 all procedures
|
||||
- No permission checked
|
||||
- There is no user session on the server
|
||||
- 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
|
||||
- A user session is created on the server
|
||||
- Example of possible clients: 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
|
||||
- Two factor authentication is not yet available through the API
|
||||
|
||||
Protocol
|
||||
--------
|
||||
|
||||
|
|
@ -20,12 +48,37 @@ Authentication
|
|||
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":
|
||||
|
||||
- Username: `jsonrpc`
|
||||
- Password: API token on the settings page
|
||||
|
||||
Otherwise for the "user api", just use the real username/passsword.
|
||||
|
||||
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
|
||||
- getTimezone
|
||||
- getVersion
|
||||
- getProjectById
|
||||
- getTask
|
||||
- getTaskByReference
|
||||
- getAllTasks
|
||||
- openTask
|
||||
- closeTask
|
||||
- moveTaskPosition
|
||||
- createTask
|
||||
- updateTask
|
||||
- getBoard
|
||||
|
||||
### Custom HTTP header
|
||||
|
||||
You can use an alternative HTTP header for the authentication if your server have a very specific configuration.
|
||||
|
|
@ -3831,3 +3884,293 @@ Response example:
|
|||
"result": true
|
||||
}
|
||||
```
|
||||
|
||||
### getMe
|
||||
|
||||
- Purpose: **Get logged user session**
|
||||
- Parameters: None
|
||||
- Result on success: **user session data**
|
||||
- Result on failure: **false**
|
||||
|
||||
Request example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getMe",
|
||||
"id": 1718627783
|
||||
}
|
||||
```
|
||||
|
||||
Response example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1718627783,
|
||||
"result": {
|
||||
"id": 2,
|
||||
"username": "user",
|
||||
"is_admin": false,
|
||||
"is_ldap_user": false,
|
||||
"name": "",
|
||||
"email": "",
|
||||
"google_id": null,
|
||||
"github_id": null,
|
||||
"notifications_enabled": "0",
|
||||
"timezone": null,
|
||||
"language": null,
|
||||
"disable_login_form": "0",
|
||||
"twofactor_activated": false,
|
||||
"twofactor_secret": null,
|
||||
"token": "",
|
||||
"notifications_filter": "4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### getMyDashboard
|
||||
|
||||
- Purpose: **Get the dashboard of the logged user without pagination**
|
||||
- Parameters: None
|
||||
- Result on success: **Dashboard information**
|
||||
- Result on failure: **false**
|
||||
|
||||
Request example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getMyDashboard",
|
||||
"id": 447898718
|
||||
}
|
||||
```
|
||||
|
||||
Response example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1563664593,
|
||||
"result": {
|
||||
"projects": [
|
||||
{
|
||||
"id": "2",
|
||||
"name": "my project",
|
||||
"is_active": "1",
|
||||
"token": "",
|
||||
"last_modified": "1438205337",
|
||||
"is_public": "0",
|
||||
"is_private": "1",
|
||||
"is_everybody_allowed": "0",
|
||||
"default_swimlane": "Default swimlane",
|
||||
"show_default_swimlane": "1",
|
||||
"description": null,
|
||||
"identifier": "",
|
||||
"columns": [
|
||||
{
|
||||
"id": "5",
|
||||
"title": "Backlog",
|
||||
"position": "1",
|
||||
"project_id": "2",
|
||||
"task_limit": "0",
|
||||
"description": "",
|
||||
"nb_tasks": 0
|
||||
},
|
||||
{
|
||||
"id": "6",
|
||||
"title": "Ready",
|
||||
"position": "2",
|
||||
"project_id": "2",
|
||||
"task_limit": "0",
|
||||
"description": "",
|
||||
"nb_tasks": 0
|
||||
},
|
||||
{
|
||||
"id": "7",
|
||||
"title": "Work in progress",
|
||||
"position": "3",
|
||||
"project_id": "2",
|
||||
"task_limit": "0",
|
||||
"description": "",
|
||||
"nb_tasks": 0
|
||||
},
|
||||
{
|
||||
"id": "8",
|
||||
"title": "Done",
|
||||
"position": "4",
|
||||
"project_id": "2",
|
||||
"task_limit": "0",
|
||||
"description": "",
|
||||
"nb_tasks": 0
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"board": "http:\/\/127.0.0.1:8000\/?controller=board&action=show&project_id=2",
|
||||
"calendar": "http:\/\/127.0.0.1:8000\/?controller=calendar&action=show&project_id=2",
|
||||
"list": "http:\/\/127.0.0.1:8000\/?controller=listing&action=show&project_id=2"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tasks": [
|
||||
{
|
||||
"id": "1",
|
||||
"title": "new title",
|
||||
"date_due": "0",
|
||||
"date_creation": "1438205336",
|
||||
"project_id": "2",
|
||||
"color_id": "yellow",
|
||||
"time_spent": "0",
|
||||
"time_estimated": "0",
|
||||
"project_name": "my project",
|
||||
"url": "http:\/\/127.0.0.1:8000\/?controller=task&action=show&task_id=1&project_id=2"
|
||||
}
|
||||
],
|
||||
"subtasks": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### getMyActivityStream
|
||||
|
||||
- Purpose: **Get the last 100 events for the logged user**
|
||||
- Parameters: None
|
||||
- Result on success: **List of events**
|
||||
- Result on failure: **false**
|
||||
|
||||
Request example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getMyActivityStream",
|
||||
"id": 1132562181
|
||||
}
|
||||
```
|
||||
|
||||
Response example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1132562181,
|
||||
"result": [
|
||||
{
|
||||
"id": "1",
|
||||
"date_creation": "1438205054",
|
||||
"event_name": "task.create",
|
||||
"creator_id": "2",
|
||||
"project_id": "2",
|
||||
"task_id": "1",
|
||||
"author_username": "user",
|
||||
"author_name": "",
|
||||
"email": "",
|
||||
"task": {
|
||||
"id": "1",
|
||||
"reference": "",
|
||||
"title": "my user title",
|
||||
"description": "",
|
||||
"date_creation": "1438205054",
|
||||
"date_completed": null,
|
||||
"date_modification": "1438205054",
|
||||
"date_due": "0",
|
||||
"date_started": null,
|
||||
"time_estimated": "0",
|
||||
"time_spent": "0",
|
||||
"color_id": "yellow",
|
||||
"project_id": "2",
|
||||
"column_id": "5",
|
||||
"owner_id": "0",
|
||||
"creator_id": "2",
|
||||
"position": "1",
|
||||
"is_active": "1",
|
||||
"score": "0",
|
||||
"category_id": "0",
|
||||
"swimlane_id": "0",
|
||||
"date_moved": "1438205054",
|
||||
"recurrence_status": "0",
|
||||
"recurrence_trigger": "0",
|
||||
"recurrence_factor": "0",
|
||||
"recurrence_timeframe": "0",
|
||||
"recurrence_basedate": "0",
|
||||
"recurrence_parent": null,
|
||||
"recurrence_child": null,
|
||||
"category_name": null,
|
||||
"swimlane_name": null,
|
||||
"project_name": "my project",
|
||||
"default_swimlane": "Default swimlane",
|
||||
"column_title": "Backlog",
|
||||
"assignee_username": null,
|
||||
"assignee_name": null,
|
||||
"creator_username": "user",
|
||||
"creator_name": ""
|
||||
},
|
||||
"changes": [],
|
||||
"author": "user",
|
||||
"event_title": "user created the task #1",
|
||||
"event_content": "\n<p class=\"activity-title\">\n user created the task <a href=\"\/?controller=task&action=show&task_id=1&project_id=2\" class=\"\" title=\"\" >#1<\/a><\/p>\n<p class=\"activity-description\">\n <em>my user title<\/em>\n<\/p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### createMyPrivateProject
|
||||
|
||||
- Purpose: **Create a private project for the logged user**
|
||||
- Parameters:
|
||||
- **name** (string, required)
|
||||
- **description** (string, optional)
|
||||
- Result on success: **project_id**
|
||||
- Result on failure: **false**
|
||||
|
||||
Request example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "createMyPrivateProject",
|
||||
"id": 1271580569,
|
||||
"params": [
|
||||
"my project"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Response example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1271580569,
|
||||
"result": 2
|
||||
}
|
||||
```
|
||||
|
||||
### getMyProjectsList
|
||||
|
||||
- Purpose: **Get projects of the connected user**
|
||||
- Parameters: None
|
||||
- Result on success: **dictionary of project_id => project_name**
|
||||
- Result on failure: **false**
|
||||
|
||||
Request example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "getMyProjectsList",
|
||||
"id": 987834805
|
||||
}
|
||||
```
|
||||
|
||||
Response example:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 987834805,
|
||||
"result": {
|
||||
"2": "my project"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ require __DIR__.'/app/common.php';
|
|||
|
||||
$server = new JsonRPC\Server;
|
||||
$server->setAuthenticationHeader(API_AUTHENTICATION_HEADER);
|
||||
$server->before('authentication');
|
||||
$server->before(array(new Api\Auth($container), 'checkCredentials'));
|
||||
|
||||
$server->attach(new Api\Me($container));
|
||||
$server->attach(new Api\Action($container));
|
||||
$server->attach(new Api\App($container));
|
||||
$server->attach(new Api\Board($container));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,200 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__.'/../../vendor/autoload.php';
|
||||
|
||||
class UserApi extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $app = null;
|
||||
private $admin = null;
|
||||
private $user = null;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
if (DB_DRIVER === 'sqlite') {
|
||||
@unlink(DB_FILENAME);
|
||||
}
|
||||
else if (DB_DRIVER === 'mysql') {
|
||||
$pdo = new PDO('mysql:host='.DB_HOSTNAME, DB_USERNAME, DB_PASSWORD);
|
||||
$pdo->exec('DROP DATABASE '.DB_NAME);
|
||||
$pdo->exec('CREATE DATABASE '.DB_NAME);
|
||||
$pdo = null;
|
||||
}
|
||||
else if (DB_DRIVER === 'postgres') {
|
||||
$pdo = new PDO('pgsql:host='.DB_HOSTNAME, DB_USERNAME, DB_PASSWORD);
|
||||
$pdo->exec('DROP DATABASE '.DB_NAME);
|
||||
$pdo->exec('CREATE DATABASE '.DB_NAME.' WITH OWNER '.DB_USERNAME);
|
||||
$pdo = null;
|
||||
}
|
||||
|
||||
$service = new 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->debug = true;
|
||||
|
||||
$this->admin = new JsonRPC\Client(API_URL);
|
||||
$this->admin->authentication('admin', 'admin');
|
||||
$this->admin->debug = true;
|
||||
|
||||
$this->user = new JsonRPC\Client(API_URL);
|
||||
$this->user->authentication('user', 'password');
|
||||
$this->user->debug = true;
|
||||
}
|
||||
|
||||
public function testCreateProject()
|
||||
{
|
||||
$this->assertEquals(1, $this->app->createProject('team project'));
|
||||
}
|
||||
|
||||
public function testCreateUser()
|
||||
{
|
||||
$this->assertEquals(2, $this->app->createUser('user', 'password'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException JsonRPC\AccessDeniedException
|
||||
*/
|
||||
public function testNotAllowedAppProcedure()
|
||||
{
|
||||
$this->app->getMe();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException JsonRPC\AccessDeniedException
|
||||
*/
|
||||
public function testNotAllowedUserProcedure()
|
||||
{
|
||||
$this->user->getAllProjects();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException JsonRPC\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 testGetMe()
|
||||
{
|
||||
$profile = $this->user->getMe();
|
||||
$this->assertNotEmpty($profile);
|
||||
$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 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 testGetTask()
|
||||
{
|
||||
$task = $this->user->getTask(1);
|
||||
$this->assertNotEmpty($task);
|
||||
$this->assertEquals('my user title', $task['title']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException JsonRPC\AccessDeniedException
|
||||
*/
|
||||
public function testGetAdminTask()
|
||||
{
|
||||
$this->user->getTask(2);
|
||||
}
|
||||
|
||||
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 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));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue