Add first draft of the user api

This commit is contained in:
Frederic Guillot 2015-07-29 17:42:48 -04:00
parent 2eeb58ae03
commit f595fb2786
22 changed files with 763 additions and 78 deletions

View File

@ -8,7 +8,7 @@ namespace Api;
* @package api
* @author Frederic Guillot
*/
class Action extends Base
class Action extends \Core\Base
{
public function getAvailableActions()
{

View File

@ -8,7 +8,7 @@ namespace Api;
* @package api
* @author Frederic Guillot
*/
class App extends Base
class App extends \Core\Base
{
public function getTimezone()
{

40
app/Api/Auth.php Normal file
View File

@ -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');
}
}
}

View File

@ -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;
}
}

View File

@ -12,6 +12,7 @@ class Board extends Base
{
public function getBoard($project_id)
{
$this->checkProjectPermission($project_id);
return $this->board->getBoard($project_id);
}

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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

55
app/Api/Me.php Normal file
View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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;
}
}

View File

@ -8,7 +8,7 @@ namespace Api;
* @package api
* @author Frederic Guillot
*/
class TaskLink extends Base
class TaskLink extends \Core\Base
{
/**
* Get a task link

View File

@ -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)
{

View File

@ -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",

13
composer.lock generated
View File

@ -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
},

View File

@ -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&amp;action=show&amp;task_id=1&amp;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"
}
}
```

View File

@ -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));

View File

@ -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));
}
}