summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/Model/Link.php4
-rw-r--r--app/Model/TaskLink.php2
-rw-r--r--docs/api-json-rpc.markdown477
-rw-r--r--tests/functionals.mysql.xml2
-rw-r--r--tests/functionals.postgres.xml2
-rw-r--r--tests/functionals/ApiTest.php113
6 files changed, 585 insertions, 15 deletions
diff --git a/app/Model/Link.php b/app/Model/Link.php
index b26a01e4..e0e5184e 100644
--- a/app/Model/Link.php
+++ b/app/Model/Link.php
@@ -125,7 +125,7 @@ class Link extends Base
$label_id = $this->db->getConnection()->getLastId();
- if ($opposite_label !== '') {
+ if (! empty($opposite_label)) {
$this->db
->table(self::TABLE)
@@ -144,7 +144,7 @@ class Link extends Base
$this->db->closeTransaction();
- return $label_id;
+ return (int) $label_id;
}
/**
diff --git a/app/Model/TaskLink.php b/app/Model/TaskLink.php
index 7b696afc..251460c9 100644
--- a/app/Model/TaskLink.php
+++ b/app/Model/TaskLink.php
@@ -144,7 +144,7 @@ class TaskLink extends Base
$this->db->closeTransaction();
- return $task_link_id;
+ return (int) $task_link_id;
}
/**
diff --git a/docs/api-json-rpc.markdown b/docs/api-json-rpc.markdown
index d8fe896d..89010cef 100644
--- a/docs/api-json-rpc.markdown
+++ b/docs/api-json-rpc.markdown
@@ -2830,7 +2830,6 @@ Response example:
}
```
-
### createSubtask
- Purpose: **Create a new subtask**
@@ -2876,6 +2875,8 @@ Response example:
- Result on success: **subtask properties**
- Result on failure: **null**
+Request example:
+
```json
{
"jsonrpc": "2.0",
@@ -2913,6 +2914,8 @@ Response example:
- Result on success: **List of subtasks**
- Result on failure: **false**
+Request example:
+
```json
{
"jsonrpc": "2.0",
@@ -2961,7 +2964,7 @@ Response example:
- Result on success: **true**
- Result on failure: **false**
-Request examples:
+Request example:
```json
{
@@ -2996,6 +2999,8 @@ Response example:
- Result on success: **true**
- Result on failure: **false**
+Request example:
+
```json
{
"jsonrpc": "2.0",
@@ -3016,3 +3021,471 @@ Response example:
"result": true
}
```
+
+### getAllLinks
+
+- Purpose: **Get the list of possible relations between tasks**
+- Parameters: none
+- Result on success: **List of links**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getAllLinks",
+ "id": 113057196
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 113057196,
+ "result": [
+ {
+ "id": "1",
+ "label": "relates to",
+ "opposite_id": "0"
+ },
+ {
+ "id": "2",
+ "label": "blocks",
+ "opposite_id": "3"
+ },
+ {
+ "id": "3",
+ "label": "is blocked by",
+ "opposite_id": "2"
+ },
+ {
+ "id": "4",
+ "label": "duplicates",
+ "opposite_id": "5"
+ },
+ {
+ "id": "5",
+ "label": "is duplicated by",
+ "opposite_id": "4"
+ },
+ {
+ "id": "6",
+ "label": "is a child of",
+ "opposite_id": "7"
+ },
+ {
+ "id": "7",
+ "label": "is a parent of",
+ "opposite_id": "6"
+ },
+ {
+ "id": "8",
+ "label": "targets milestone",
+ "opposite_id": "9"
+ },
+ {
+ "id": "9",
+ "label": "is a milestone of",
+ "opposite_id": "8"
+ },
+ {
+ "id": "10",
+ "label": "fixes",
+ "opposite_id": "11"
+ },
+ {
+ "id": "11",
+ "label": "is fixed by",
+ "opposite_id": "10"
+ }
+ ]
+}
+```
+
+### getOppositeLinkId
+
+- Purpose: **Get the opposite link id of a task link**
+- Parameters:
+ - **link_id** (integer, required)
+- Result on success: **link_id**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getOppositeLinkId",
+ "id": 407062448,
+ "params": [
+ 2
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 407062448,
+ "result": "3"
+}
+```
+
+### getLinkByLabel
+
+- Purpose: **Get a link by label**
+- Parameters:
+ - **label** (integer, required)
+- Result on success: **link properties**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getLinkByLabel",
+ "id": 1796123316,
+ "params": [
+ "blocks"
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1796123316,
+ "result": {
+ "id": "2",
+ "label": "blocks",
+ "opposite_id": "3"
+ }
+}
+```
+
+### getLinkById
+
+- Purpose: **Get a link by id**
+- Parameters:
+ - **link_id** (integer, required)
+- Result on success: **link properties**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getLinkById",
+ "id": 1190238402,
+ "params": [
+ 4
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1190238402,
+ "result": {
+ "id": "4",
+ "label": "duplicates",
+ "opposite_id": "5"
+ }
+}
+```
+
+### createLink
+
+- Purpose: **Create a new task relation**
+- Parameters:
+ - **label** (integer, required)
+ - **opposite_label** (integer, optional)
+- Result on success: **link_id**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "createLink",
+ "id": 1040237496,
+ "params": [
+ "foo",
+ "bar"
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 1040237496,
+ "result": 13
+}
+```
+
+### updateLink
+
+- Purpose: **Update a link**
+- Parameters:
+ - **link_id** (integer, required)
+ - **opposite_link_id** (integer, required)
+ - **label** (string, required)
+- Result on success: **true**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "updateLink",
+ "id": 2110446926,
+ "params": [
+ "14",
+ "12",
+ "boo"
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 2110446926,
+ "result": true
+}
+```
+
+### removeLink
+
+- Purpose: **Remove a link**
+- Parameters:
+ - **link_id** (integer, required)
+- Result on success: **true**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "removeLink",
+ "id": 2136522739,
+ "params": [
+ "14"
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 2136522739,
+ "result": true
+}
+```
+
+### createTaskLink
+
+- Purpose: **Create a link between two tasks**
+- Parameters:
+ - **task_id** (integer, required)
+ - **opposite_task_id** (integer, required)
+ - **link_id** (integer, required)
+- Result on success: **task_link_id**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "createTaskLink",
+ "id": 509742912,
+ "params": [
+ 2,
+ 3,
+ 1
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 509742912,
+ "result": 1
+}
+```
+
+### updateTaskLink
+
+- Purpose: **Update task link**
+- Parameters:
+ - **task_link_id** (integer, required)
+ - **task_id** (integer, required)
+ - **opposite_task_id** (integer, required)
+ - **link_id** (integer, required)
+- Result on success: **true**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "updateTaskLink",
+ "id": 669037109,
+ "params": [
+ 1,
+ 2,
+ 4,
+ 2
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 669037109,
+ "result": true
+}
+```
+
+### getTaskLinkById
+
+- Purpose: **Get a task link**
+- Parameters:
+ - **task_link_id** (integer, required)
+- Result on success: **task link properties**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getTaskLinkById",
+ "id": 809885202,
+ "params": [
+ 1
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 809885202,
+ "result": {
+ "id": "1",
+ "link_id": "1",
+ "task_id": "2",
+ "opposite_task_id": "3"
+ }
+}
+```
+
+### getAllTaskLinks
+
+- Purpose: **Get all links related to a task**
+- Parameters:
+ - **task_id** (integer, required)
+- Result on success: **list of task link**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getAllTaskLinks",
+ "id": 810848359,
+ "params": [
+ 2
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 810848359,
+ "result": [
+ {
+ "id": "1",
+ "task_id": "3",
+ "label": "relates to",
+ "title": "B",
+ "is_active": "1",
+ "project_id": "1",
+ "task_time_spent": "0",
+ "task_time_estimated": "0",
+ "task_assignee_id": "0",
+ "task_assignee_username": null,
+ "task_assignee_name": null,
+ "column_title": "Backlog"
+ }
+ ]
+}
+```
+
+### removeTaskLink
+
+- Purpose: **Remove a link between two tasks**
+- Parameters:
+ - **task_link_id** (integer, required)
+- Result on success: **true**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "removeTaskLink",
+ "id": 473028226,
+ "params": [
+ 1
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 473028226,
+ "result": true
+}
+```
diff --git a/tests/functionals.mysql.xml b/tests/functionals.mysql.xml
index f5c3e16a..61cb05df 100644
--- a/tests/functionals.mysql.xml
+++ b/tests/functionals.mysql.xml
@@ -12,6 +12,6 @@
<const name="DB_HOSTNAME" value="localhost" />
<const name="DB_USERNAME" value="root" />
<const name="DB_PASSWORD" value="" />
- <const name="DB_PORT" value="3306" />
+ <const name="DB_PORT" value="" />
</php>
</phpunit> \ No newline at end of file
diff --git a/tests/functionals.postgres.xml b/tests/functionals.postgres.xml
index 40fcef00..eb83d157 100644
--- a/tests/functionals.postgres.xml
+++ b/tests/functionals.postgres.xml
@@ -12,6 +12,6 @@
<const name="DB_HOSTNAME" value="localhost" />
<const name="DB_USERNAME" value="postgres" />
<const name="DB_PASSWORD" value="postgres" />
- <const name="DB_PORT" value="5432" />
+ <const name="DB_PORT" value="" />
</php>
</phpunit> \ No newline at end of file
diff --git a/tests/functionals/ApiTest.php b/tests/functionals/ApiTest.php
index 7b7a2bed..4ab2db99 100644
--- a/tests/functionals/ApiTest.php
+++ b/tests/functionals/ApiTest.php
@@ -4,25 +4,24 @@ require_once __DIR__.'/../../vendor/autoload.php';
class Api extends PHPUnit_Framework_TestCase
{
- private $client;
+ private $client = null;
public static function setUpBeforeClass()
{
if (DB_DRIVER === 'sqlite') {
@unlink(DB_FILENAME);
- $pdo = new PDO('sqlite:'.DB_FILENAME);
}
else if (DB_DRIVER === 'mysql') {
$pdo = new PDO('mysql:host='.DB_HOSTNAME, DB_USERNAME, DB_PASSWORD);
$pdo->exec('DROP DATABASE '.DB_NAME);
$pdo->exec('CREATE DATABASE '.DB_NAME);
- $pdo = new PDO('mysql:host='.DB_HOSTNAME.';dbname='.DB_NAME, DB_USERNAME, DB_PASSWORD);
+ $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 = new PDO('pgsql:host='.DB_HOSTNAME.';dbname='.DB_NAME, DB_USERNAME, DB_PASSWORD);
+ $pdo = null;
}
$service = new ServiceProvider\DatabaseProvider;
@@ -31,15 +30,13 @@ class Api extends PHPUnit_Framework_TestCase
$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();
-
- $pdo = null;
}
public function setUp()
{
$this->client = new JsonRPC\Client(API_URL);
$this->client->authentication('jsonrpc', API_KEY);
- // $this->client->debug = true;
+ $this->client->debug = true;
}
private function getTaskId()
@@ -837,4 +834,104 @@ class Api extends PHPUnit_Framework_TestCase
$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));
+ }
+} \ No newline at end of file