summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2015-05-23 21:44:33 -0400
committerFrederic Guillot <fred@kanboard.net>2015-05-23 21:44:33 -0400
commite32f26d048249b84166542d6442efdf202ff44fd (patch)
tree1868c5e83cec5ea8b821ad8a2036543aa37e5adb
parentc9ba525bab06eff76b1d5fb8701848d0e3990122 (diff)
API refactoring
-rw-r--r--app/Api/Action.php98
-rw-r--r--app/Api/App.php22
-rw-r--r--app/Api/Base.php81
-rw-r--r--app/Api/Board.php52
-rw-r--r--app/Api/Category.php49
-rw-r--r--app/Api/Comment.php51
-rw-r--r--app/Api/Link.php111
-rw-r--r--app/Api/Project.php85
-rw-r--r--app/Api/ProjectPermission.php27
-rw-r--r--app/Api/Subtask.php64
-rw-r--r--app/Api/Swimlane.php77
-rw-r--r--app/Api/Task.php113
-rw-r--r--app/Api/TaskLink.php77
-rw-r--r--app/Api/User.php88
-rw-r--r--app/Model/Link.php46
-rw-r--r--app/Model/Swimlane.php2
-rw-r--r--composer.json20
-rw-r--r--composer.lock22
-rw-r--r--docs/api-json-rpc.markdown345
-rw-r--r--jsonrpc.php449
-rw-r--r--tests/functionals.mysql.xml1
-rw-r--r--tests/functionals.postgres.xml1
-rw-r--r--tests/functionals/ApiTest.php228
-rw-r--r--tests/units/LinkTest.php8
24 files changed, 1515 insertions, 602 deletions
diff --git a/app/Api/Action.php b/app/Api/Action.php
new file mode 100644
index 00000000..6187b776
--- /dev/null
+++ b/app/Api/Action.php
@@ -0,0 +1,98 @@
+<?php
+
+namespace Api;
+
+/**
+ * Action API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class Action extends Base
+{
+ public function getAvailableActions()
+ {
+ return $this->action->getAvailableActions();
+ }
+
+ public function getAvailableActionEvents()
+ {
+ return $this->action->getAvailableEvents();
+ }
+
+ public function getCompatibleActionEvents($action_name)
+ {
+ return $this->action->getCompatibleEvents($action_name);
+ }
+
+ public function removeAction($action_id)
+ {
+ return $this->action->remove($action_id);
+ }
+
+ public function getActions($project_id)
+ {
+ $actions = $this->action->getAllByProject($project_id);
+
+ foreach ($actions as $index => $action) {
+
+ $params = array();
+
+ foreach($action['params'] as $param) {
+ $params[$param['name']] = $param['value'];
+ }
+
+ $actions[$index]['params'] = $params;
+ }
+
+ return $actions;
+ }
+
+ public function createAction($project_id, $event_name, $action_name, $params)
+ {
+ $values = array(
+ 'project_id' => $project_id,
+ 'event_name' => $event_name,
+ 'action_name' => $action_name,
+ 'params' => $params,
+ );
+
+ list($valid,) = $this->action->validateCreation($values);
+
+ if (! $valid) {
+ return false;
+ }
+
+ // Check if the action exists
+ $actions = $this->action->getAvailableActions();
+
+ if (! isset($actions[$action_name])) {
+ return false;
+ }
+
+ // Check the event
+ $action = $this->action->load($action_name, $project_id, $event_name);
+
+ if (! in_array($event_name, $action->getCompatibleEvents())) {
+ return false;
+ }
+
+ $required_params = $action->getActionRequiredParameters();
+
+ // Check missing parameters
+ foreach($required_params as $param => $value) {
+ if (! isset($params[$param])) {
+ return false;
+ }
+ }
+
+ // Check extra parameters
+ foreach($params as $param => $value) {
+ if (! isset($required_params[$param])) {
+ return false;
+ }
+ }
+
+ return $this->action->create($values);
+ }
+}
diff --git a/app/Api/App.php b/app/Api/App.php
new file mode 100644
index 00000000..2fc32e91
--- /dev/null
+++ b/app/Api/App.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Api;
+
+/**
+ * App API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class App extends Base
+{
+ public function getTimezone()
+ {
+ return $this->config->get('application_timezone');
+ }
+
+ public function getVersion()
+ {
+ return APP_VERSION;
+ }
+}
diff --git a/app/Api/Base.php b/app/Api/Base.php
new file mode 100644
index 00000000..e9494b58
--- /dev/null
+++ b/app/Api/Base.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace Api;
+
+use Pimple\Container;
+use JsonRPC\AuthenticationFailure;
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Base class
+ *
+ * @package api
+ * @author Frederic Guillot
+ *
+ * @property \Model\Board $board
+ * @property \Model\Config $config
+ * @property \Model\Comment $comment
+ * @property \Model\LastLogin $lastLogin
+ * @property \Model\Notification $notification
+ * @property \Model\Project $project
+ * @property \Model\ProjectPermission $projectPermission
+ * @property \Model\ProjectActivity $projectActivity
+ * @property \Model\ProjectAnalytic $projectAnalytic
+ * @property \Model\ProjectDailySummary $projectDailySummary
+ * @property \Model\Subtask $subtask
+ * @property \Model\Task $task
+ * @property \Model\TaskDuplication $taskDuplication
+ * @property \Model\TaskExport $taskExport
+ * @property \Model\TaskFinder $taskFinder
+ */
+abstract class Base
+{
+ /**
+ * Container instance
+ *
+ * @access protected
+ * @var \Pimple\Container
+ */
+ protected $container;
+
+ /**
+ * Constructor
+ *
+ * @access public
+ * @param \Pimple\Container $container
+ */
+ public function __construct(Container $container)
+ {
+ $this->container = $container;
+ }
+
+ /**
+ * Load automatically models
+ *
+ * @access public
+ * @param string $name Model name
+ * @return mixed
+ */
+ public function __get($name)
+ {
+ return $this->container[$name];
+ }
+
+ /**
+ * 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);
+
+ if (! ($username === 'jsonrpc' && $password === $this->config->get('api_token'))) {
+ throw new AuthenticationFailure('Wrond credentials');
+ }
+ }
+}
diff --git a/app/Api/Board.php b/app/Api/Board.php
new file mode 100644
index 00000000..163131b6
--- /dev/null
+++ b/app/Api/Board.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace Api;
+
+/**
+ * Board API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class Board extends Base
+{
+ public function getBoard($project_id)
+ {
+ return $this->board->getBoard($project_id);
+ }
+
+ public function getColumns($project_id)
+ {
+ return $this->board->getColumns($project_id);
+ }
+
+ public function getColumn($column_id)
+ {
+ return $this->board->getColumn($column_id);
+ }
+
+ public function moveColumnUp($project_id, $column_id)
+ {
+ return $this->board->moveUp($project_id, $column_id);
+ }
+
+ public function moveColumnDown($project_id, $column_id)
+ {
+ return $this->board->moveDown($project_id, $column_id);
+ }
+
+ public function updateColumn($column_id, $title, $task_limit = 0, $description = '')
+ {
+ return $this->board->updateColumn($column_id, $title, $task_limit, $description);
+ }
+
+ public function addColumn($project_id, $title, $task_limit = 0, $description = '')
+ {
+ return $this->board->addColumn($project_id, $title, $task_limit, $description);
+ }
+
+ public function removeColumn($column_id)
+ {
+ return $this->board->removeColumn($column_id);
+ }
+}
diff --git a/app/Api/Category.php b/app/Api/Category.php
new file mode 100644
index 00000000..f457ddf1
--- /dev/null
+++ b/app/Api/Category.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Api;
+
+/**
+ * Category API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class Category extends Base
+{
+ public function getCategory($category_id)
+ {
+ return $this->category->getById($category_id);
+ }
+
+ public function getAllCategories($project_id)
+ {
+ return $this->category->getAll($project_id);
+ }
+
+ public function removeCategory($category_id)
+ {
+ return $this->category->remove($category_id);
+ }
+
+ public function createCategory($project_id, $name)
+ {
+ $values = array(
+ 'project_id' => $project_id,
+ 'name' => $name,
+ );
+
+ list($valid,) = $this->category->validateCreation($values);
+ return $valid ? $this->category->create($values) : false;
+ }
+
+ public function updateCategory($id, $name)
+ {
+ $values = array(
+ 'id' => $id,
+ 'name' => $name,
+ );
+
+ list($valid,) = $this->category->validateModification($values);
+ return $valid && $this->category->update($values);
+ }
+}
diff --git a/app/Api/Comment.php b/app/Api/Comment.php
new file mode 100644
index 00000000..19b84383
--- /dev/null
+++ b/app/Api/Comment.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace Api;
+
+/**
+ * Comment API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class Comment extends Base
+{
+ public function getComment($comment_id)
+ {
+ return $this->comment->getById($comment_id);
+ }
+
+ public function getAllComments($task_id)
+ {
+ return $this->comment->getAll($task_id);
+ }
+
+ public function removeComment($comment_id)
+ {
+ return $this->comment->remove($comment_id);
+ }
+
+ public function createComment($task_id, $user_id, $content)
+ {
+ $values = array(
+ 'task_id' => $task_id,
+ 'user_id' => $user_id,
+ 'comment' => $content,
+ );
+
+ list($valid,) = $this->comment->validateCreation($values);
+
+ return $valid ? $this->comment->create($values) : false;
+ }
+
+ public function updateComment($id, $content)
+ {
+ $values = array(
+ 'id' => $id,
+ 'comment' => $content,
+ );
+
+ list($valid,) = $this->comment->validateModification($values);
+ return $valid && $this->comment->update($values);
+ }
+}
diff --git a/app/Api/Link.php b/app/Api/Link.php
new file mode 100644
index 00000000..b9084784
--- /dev/null
+++ b/app/Api/Link.php
@@ -0,0 +1,111 @@
+<?php
+
+namespace Api;
+
+/**
+ * Link API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class Link extends Base
+{
+ /**
+ * Get a link by id
+ *
+ * @access public
+ * @param integer $link_id Link id
+ * @return array
+ */
+ public function getLinkById($link_id)
+ {
+ return $this->link->getById($link_id);
+ }
+
+ /**
+ * Get a link by name
+ *
+ * @access public
+ * @param string $label
+ * @return array
+ */
+ public function getLinkByLabel($label)
+ {
+ return $this->link->getByLabel($label);
+ }
+
+ /**
+ * Get the opposite link id
+ *
+ * @access public
+ * @param integer $link_id Link id
+ * @return integer
+ */
+ public function getOppositeLinkId($link_id)
+ {
+ return $this->link->getOppositeLinkId($link_id);
+ }
+
+ /**
+ * Get all links
+ *
+ * @access public
+ * @return array
+ */
+ public function getAllLinks()
+ {
+ return $this->link->getAll();
+ }
+
+ /**
+ * Create a new link label
+ *
+ * @access public
+ * @param string $label
+ * @param string $opposite_label
+ * @return boolean|integer
+ */
+ public function createLink($label, $opposite_label = '')
+ {
+ $values = array(
+ 'label' => $label,
+ 'opposite_label' => $opposite_label,
+ );
+
+ list($valid,) = $this->link->validateCreation($values);
+ return $valid ? $this->link->create($label, $opposite_label) : false;
+ }
+
+ /**
+ * Update a link
+ *
+ * @access public
+ * @param integer $link_id
+ * @param integer $opposite_link_id
+ * @param string $label
+ * @return boolean
+ */
+ public function updateLink($link_id, $opposite_link_id, $label)
+ {
+ $values = array(
+ 'id' => $link_id,
+ 'opposite_id' => $opposite_link_id,
+ 'label' => $label,
+ );
+
+ list($valid,) = $this->link->validateModification($values);
+ return $valid && $this->link->update($values);
+ }
+
+ /**
+ * Remove a link a the relation to its opposite
+ *
+ * @access public
+ * @param integer $link_id
+ * @return boolean
+ */
+ public function removeLink($link_id)
+ {
+ return $this->link->remove($link_id);
+ }
+}
diff --git a/app/Api/Project.php b/app/Api/Project.php
new file mode 100644
index 00000000..2451cd9c
--- /dev/null
+++ b/app/Api/Project.php
@@ -0,0 +1,85 @@
+<?php
+
+namespace Api;
+
+/**
+ * Project API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class Project extends Base
+{
+ public function getProjectById($project_id)
+ {
+ return $this->project->getById($project_id);
+ }
+
+ public function getProjectByName($name)
+ {
+ return $this->project->getByName($name);
+ }
+
+ public function getAllProjects()
+ {
+ return $this->project->getAll();
+ }
+
+ public function removeProject($project_id)
+ {
+ return $this->project->remove($project_id);
+ }
+
+ public function enableProject($project_id)
+ {
+ return $this->project->enable($project_id);
+ }
+
+ public function disableProject($project_id)
+ {
+ return $this->project->disable($project_id);
+ }
+
+ public function enableProjectPublicAccess($project_id)
+ {
+ return $this->project->enablePublicAccess($project_id);
+ }
+
+ public function disableProjectPublicAccess($project_id)
+ {
+ return $this->project->disablePublicAccess($project_id);
+ }
+
+ public function getProjectActivities(array $project_ids)
+ {
+ return $this->projectActivity->getProjects($project_ids);
+ }
+
+ public function getProjectActivity($project_id)
+ {
+ return $this->projectActivity->getProject($project_id);
+ }
+
+ public function createProject($name, $description = null)
+ {
+ $values = array(
+ 'name' => $name,
+ 'description' => $description
+ );
+
+ list($valid,) = $this->project->validateCreation($values);
+ return $valid ? $this->project->create($values) : false;
+ }
+
+ public function updateProject($id, $name, $description = null)
+ {
+ $values = array(
+ 'id' => $id,
+ 'name' => $name,
+ 'description' => $description
+ );
+
+ list($valid,) = $this->project->validateModification($values);
+ return $valid && $this->project->update($values);
+ }
+}
diff --git a/app/Api/ProjectPermission.php b/app/Api/ProjectPermission.php
new file mode 100644
index 00000000..a31faf3d
--- /dev/null
+++ b/app/Api/ProjectPermission.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Api;
+
+/**
+ * ProjectPermission API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class ProjectPermission extends Base
+{
+ public function getMembers($project_id)
+ {
+ return $this->projectPermission->getMembers($project_id);
+ }
+
+ public function revokeUser($project_id, $user_id)
+ {
+ return $this->projectPermission->revokeMember($project_id, $user_id);
+ }
+
+ public function allowUser($project_id, $user_id)
+ {
+ return $this->projectPermission->addMember($project_id, $user_id);
+ }
+}
diff --git a/app/Api/Subtask.php b/app/Api/Subtask.php
new file mode 100644
index 00000000..2e6c30f2
--- /dev/null
+++ b/app/Api/Subtask.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Api;
+
+/**
+ * Subtask API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class Subtask extends Base
+{
+ public function getSubtask($subtask_id)
+ {
+ return $this->subtask->getById($subtask_id);
+ }
+
+ public function getAllSubtasks($task_id)
+ {
+ return $this->subtask->getAll($task_id);
+ }
+
+ public function removeSubtask($subtask_id)
+ {
+ return $this->subtask->remove($subtask_id);
+ }
+
+ public function createSubtask($task_id, $title, $user_id = 0, $time_estimated = 0, $time_spent = 0, $status = 0)
+ {
+ $values = array(
+ 'title' => $title,
+ 'task_id' => $task_id,
+ 'user_id' => $user_id,
+ 'time_estimated' => $time_estimated,
+ 'time_spent' => $time_spent,
+ 'status' => $status,
+ );
+
+ list($valid,) = $this->subtask->validateCreation($values);
+ return $valid ? $this->subtask->create($values) : false;
+ }
+
+ public function updateSubtask($id, $task_id, $title = null, $user_id = null, $time_estimated = null, $time_spent = null, $status = null)
+ {
+ $values = array(
+ 'id' => $id,
+ 'task_id' => $task_id,
+ 'title' => $title,
+ 'user_id' => $user_id,
+ 'time_estimated' => $time_estimated,
+ 'time_spent' => $time_spent,
+ 'status' => $status,
+ );
+
+ foreach ($values as $key => $value) {
+ if (is_null($value)) {
+ unset($values[$key]);
+ }
+ }
+
+ list($valid,) = $this->subtask->validateApiModification($values);
+ return $valid && $this->subtask->update($values);
+ }
+}
diff --git a/app/Api/Swimlane.php b/app/Api/Swimlane.php
new file mode 100644
index 00000000..322b0805
--- /dev/null
+++ b/app/Api/Swimlane.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Api;
+
+/**
+ * Swimlane API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class Swimlane extends Base
+{
+ public function getActiveSwimlanes($project_id)
+ {
+ return $this->swimlane->getSwimlanes($project_id);
+ }
+
+ public function getAllSwimlanes($project_id)
+ {
+ return $this->swimlane->getAll($project_id);
+ }
+
+ public function getSwimlaneById($swimlane_id)
+ {
+ return $this->swimlane->getById($swimlane_id);
+ }
+
+ public function getSwimlaneByName($project_id, $name)
+ {
+ return $this->swimlane->getByName($project_id, $name);
+ }
+
+ public function getSwimlane($swimlane_id)
+ {
+ return $this->swimlane->getById($swimlane_id);
+ }
+
+ public function getDefaultSwimlane($project_id)
+ {
+ return $this->swimlane->getDefault($project_id);
+ }
+
+ public function addSwimlane($project_id, $name)
+ {
+ return $this->swimlane->create($project_id, $name);
+ }
+
+ public function updateSwimlane($swimlane_id, $name)
+ {
+ return $this->swimlane->rename($swimlane_id, $name);
+ }
+
+ public function removeSwimlane($project_id, $swimlane_id)
+ {
+ return $this->swimlane->remove($project_id, $swimlane_id);
+ }
+
+ public function disableSwimlane($project_id, $swimlane_id)
+ {
+ return $this->swimlane->disable($project_id, $swimlane_id);
+ }
+
+ public function enableSwimlane($project_id, $swimlane_id)
+ {
+ return $this->swimlane->enable($project_id, $swimlane_id);
+ }
+
+ public function moveSwimlaneUp($project_id, $swimlane_id)
+ {
+ return $this->swimlane->moveUp($project_id, $swimlane_id);
+ }
+
+ public function moveSwimlaneDown($project_id, $swimlane_id)
+ {
+ return $this->swimlane->moveDown($project_id, $swimlane_id);
+ }
+}
diff --git a/app/Api/Task.php b/app/Api/Task.php
new file mode 100644
index 00000000..c98b24a6
--- /dev/null
+++ b/app/Api/Task.php
@@ -0,0 +1,113 @@
+<?php
+
+namespace Api;
+
+use Model\Task as TaskModel;
+
+/**
+ * Task API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class Task extends Base
+{
+ public function getTask($task_id)
+ {
+ return $this->taskFinder->getById($task_id);
+ }
+
+ public function getAllTasks($project_id, $status_id = TaskModel::STATUS_OPEN)
+ {
+ return $this->taskFinder->getAll($project_id, $status_id);
+ }
+
+ public function getOverdueTasks()
+ {
+ return $this->taskFinder->getOverdueTasks();
+ }
+
+ public function openTask($task_id)
+ {
+ return $this->taskStatus->open($task_id);
+ }
+
+ public function closeTask($task_id)
+ {
+ return $this->taskStatus->close($task_id);
+ }
+
+ public function removeTask($task_id)
+ {
+ return $this->task->remove($task_id);
+ }
+
+ public function moveTaskPosition($project_id, $task_id, $column_id, $position, $swimlane_id = 0)
+ {
+ return $this->taskPosition->movePosition($project_id, $task_id, $column_id, $position, $swimlane_id);
+ }
+
+ public function createTask($title, $project_id, $color_id = '', $column_id = 0, $owner_id = 0, $creator_id = 0,
+ $date_due = '', $description = '', $category_id = 0, $score = 0, $swimlane_id = 0,
+ $recurrence_status = 0, $recurrence_trigger = 0, $recurrence_factor = 0, $recurrence_timeframe = 0,
+ $recurrence_basedate = 0)
+ {
+ $values = array(
+ 'title' => $title,
+ 'project_id' => $project_id,
+ 'color_id' => $color_id,
+ 'column_id' => $column_id,
+ 'owner_id' => $owner_id,
+ 'creator_id' => $creator_id,
+ 'date_due' => $date_due,
+ 'description' => $description,
+ 'category_id' => $category_id,
+ 'score' => $score,
+ 'swimlane_id' => $swimlane_id,
+ 'recurrence_status' => $recurrence_status,
+ 'recurrence_trigger' => $recurrence_trigger,
+ 'recurrence_factor' => $recurrence_factor,
+ 'recurrence_timeframe' => $recurrence_timeframe,
+ 'recurrence_basedate' => $recurrence_basedate,
+ );
+
+ list($valid,) = $this->taskValidator->validateCreation($values);
+
+ return $valid ? $this->taskCreation->create($values) : false;
+ }
+
+ public function updateTask($id, $title = null, $project_id = null, $color_id = null, $column_id = null, $owner_id = null,
+ $creator_id = null, $date_due = null, $description = null, $category_id = null, $score = null,
+ $swimlane_id = null, $recurrence_status = null, $recurrence_trigger = null, $recurrence_factor = null,
+ $recurrence_timeframe = null, $recurrence_basedate = null)
+ {
+ $values = array(
+ 'id' => $id,
+ 'title' => $title,
+ 'project_id' => $project_id,
+ 'color_id' => $color_id,
+ 'column_id' => $column_id,
+ 'owner_id' => $owner_id,
+ 'creator_id' => $creator_id,
+ 'date_due' => $date_due,
+ 'description' => $description,
+ 'category_id' => $category_id,
+ 'score' => $score,
+ 'swimlane_id' => $swimlane_id,
+ 'recurrence_status' => $recurrence_status,
+ 'recurrence_trigger' => $recurrence_trigger,
+ 'recurrence_factor' => $recurrence_factor,
+ 'recurrence_timeframe' => $recurrence_timeframe,
+ 'recurrence_basedate' => $recurrence_basedate,
+ );
+
+ foreach ($values as $key => $value) {
+ if (is_null($value)) {
+ unset($values[$key]);
+ }
+ }
+
+ list($valid) = $this->taskValidator->validateApiModification($values);
+ return $valid && $this->taskModification->update($values);
+ }
+}
diff --git a/app/Api/TaskLink.php b/app/Api/TaskLink.php
new file mode 100644
index 00000000..c3e1a83c
--- /dev/null
+++ b/app/Api/TaskLink.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Api;
+
+/**
+ * TaskLink API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class TaskLink extends Base
+{
+ /**
+ * Get a task link
+ *
+ * @access public
+ * @param integer $task_link_id Task link id
+ * @return array
+ */
+ public function getTaskLinkById($task_link_id)
+ {
+ return $this->taskLink->getById($task_link_id);
+ }
+
+ /**
+ * Get all links attached to a task
+ *
+ * @access public
+ * @param integer $task_id Task id
+ * @return array
+ */
+ public function getAllTaskLinks($task_id)
+ {
+ return $this->taskLink->getAll($task_id);
+ }
+
+ /**
+ * Create a new link
+ *
+ * @access public
+ * @param integer $task_id Task id
+ * @param integer $opposite_task_id Opposite task id
+ * @param integer $link_id Link id
+ * @return integer Task link id
+ */
+ public function createTaskLink($task_id, $opposite_task_id, $link_id)
+ {
+ return $this->taskLink->create($task_id, $opposite_task_id, $link_id);
+ }
+
+ /**
+ * Update a task link
+ *
+ * @access public
+ * @param integer $task_link_id Task link id
+ * @param integer $task_id Task id
+ * @param integer $opposite_task_id Opposite task id
+ * @param integer $link_id Link id
+ * @return boolean
+ */
+ public function updateTaskLink($task_link_id, $task_id, $opposite_task_id, $link_id)
+ {
+ return $this->taskLink->update($task_link_id, $task_id, $opposite_task_id, $link_id);
+ }
+
+ /**
+ * Remove a link between two tasks
+ *
+ * @access public
+ * @param integer $task_link_id
+ * @return boolean
+ */
+ public function removeTaskLink($task_link_id)
+ {
+ return $this->taskLink->remove($task_link_id);
+ }
+}
diff --git a/app/Api/User.php b/app/Api/User.php
new file mode 100644
index 00000000..166ef2c1
--- /dev/null
+++ b/app/Api/User.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace Api;
+
+use Auth\Ldap;
+
+/**
+ * User API controller
+ *
+ * @package api
+ * @author Frederic Guillot
+ */
+class User extends Base
+{
+ public function getUser($user_id)
+ {
+ return $this->user->getById($user_id);
+ }
+
+ public function getAllUsers()
+ {
+ return $this->user->getAll();
+ }
+
+ public function removeUser($user_id)
+ {
+ return $this->user->remove($user_id);
+ }
+
+ public function createUser($username, $password, $name = '', $email = '', $is_admin = 0, $default_project_id = 0)
+ {
+ $values = array(
+ 'username' => $username,
+ 'password' => $password,
+ 'confirmation' => $password,
+ 'name' => $name,
+ 'email' => $email,
+ 'is_admin' => $is_admin,
+ 'default_project_id' => $default_project_id,
+ );
+
+ list($valid,) = $this->user->validateCreation($values);
+
+ return $valid ? $this->user->create($values) : false;
+ }
+
+ public function createLdapUser($username = '', $email = '', $is_admin = 0, $default_project_id = 0)
+ {
+ $ldap = new Ldap($this->container);
+ $user = $ldap->lookup($username, $email);
+
+ if (! $user) {
+ return false;
+ }
+
+ $values = array(
+ 'username' => $user['username'],
+ 'name' => $user['name'],
+ 'email' => $user['email'],
+ 'is_ldap_user' => 1,
+ 'is_admin' => $is_admin,
+ 'default_project_id' => $default_project_id,
+ );
+
+ return $this->user->create($values);
+ }
+
+ public function updateUser($id, $username = null, $name = null, $email = null, $is_admin = null, $default_project_id = null)
+ {
+ $values = array(
+ 'id' => $id,
+ 'username' => $username,
+ 'name' => $name,
+ 'email' => $email,
+ 'is_admin' => $is_admin,
+ 'default_project_id' => $default_project_id,
+ );
+
+ foreach ($values as $key => $value) {
+ if (is_null($value)) {
+ unset($values[$key]);
+ }
+ }
+
+ list($valid,) = $this->user->validateApiModification($values);
+ return $valid && $this->user->update($values);
+ }
+}
diff --git a/app/Model/Link.php b/app/Model/Link.php
index 42b8382c..b26a01e4 100644
--- a/app/Model/Link.php
+++ b/app/Model/Link.php
@@ -112,7 +112,7 @@ class Link extends Base
* @access public
* @param string $label
* @param string $opposite_label
- * @return boolean
+ * @return boolean|integer
*/
public function create($label, $opposite_label = '')
{
@@ -123,38 +123,28 @@ class Link extends Base
return false;
}
+ $label_id = $this->db->getConnection()->getLastId();
+
if ($opposite_label !== '') {
- $this->createOpposite($opposite_label);
+
+ $this->db
+ ->table(self::TABLE)
+ ->insert(array(
+ 'label' => $opposite_label,
+ 'opposite_id' => $label_id,
+ ));
+
+ $this->db
+ ->table(self::TABLE)
+ ->eq('id', $label_id)
+ ->update(array(
+ 'opposite_id' => $this->db->getConnection()->getLastId()
+ ));
}
$this->db->closeTransaction();
- return true;
- }
-
- /**
- * Create the opposite label (executed inside create() method)
- *
- * @access private
- * @param string $label
- */
- private function createOpposite($label)
- {
- $label_id = $this->db->getConnection()->getLastId();
-
- $this->db
- ->table(self::TABLE)
- ->insert(array(
- 'label' => $label,
- 'opposite_id' => $label_id,
- ));
-
- $this->db
- ->table(self::TABLE)
- ->eq('id', $label_id)
- ->update(array(
- 'opposite_id' => $this->db->getConnection()->getLastId()
- ));
+ return $label_id;
}
/**
diff --git a/app/Model/Swimlane.php b/app/Model/Swimlane.php
index cfd6d4a7..3b78a406 100644
--- a/app/Model/Swimlane.php
+++ b/app/Model/Swimlane.php
@@ -87,7 +87,7 @@ class Swimlane extends Base
return $this->db->table(self::TABLE)
->eq('project_id', $project_id)
->eq('name', $name)
- ->findAll();
+ ->findOne();
}
/**
diff --git a/composer.json b/composer.json
index c1381c02..b330aa73 100644
--- a/composer.json
+++ b/composer.json
@@ -3,20 +3,20 @@
"php" : ">=5.3",
"ext-mbstring" : "*",
"ext-gd" : "*",
- "fguillot/simple-validator" : "dev-master",
- "swiftmailer/swiftmailer" : "@stable",
- "fguillot/json-rpc" : "0.0.1",
- "fguillot/picodb" : "dev-master",
+ "christian-riesen/otp" : "1.4",
+ "eluceo/ical": "*",
"erusev/parsedown" : "1.5.1",
+ "fabiang/xmpp" : "0.6.1",
+ "fguillot/json-rpc" : "0.0.3",
+ "fguillot/picodb" : "0.0.3",
+ "fguillot/simpleLogger" : "0.0.1",
+ "fguillot/simple-validator" : "0.0.3",
"lusitanian/oauth" : "0.3.5",
+ "nickcernis/html-to-markdown" : "2.2.1",
"pimple/pimple" : "~3.0",
+ "swiftmailer/swiftmailer" : "@stable",
"symfony/console" : "@stable",
- "symfony/event-dispatcher" : "~2.6",
- "fguillot/simpleLogger" : "0.0.1",
- "christian-riesen/otp" : "1.4",
- "nickcernis/html-to-markdown" : "2.2.1",
- "fabiang/xmpp" : "0.6.1",
- "eluceo/ical": "*"
+ "symfony/event-dispatcher" : "~2.6"
},
"autoload" : {
"psr-0" : {
diff --git a/composer.lock b/composer.lock
index cebfcbbc..11f1e0f6 100644
--- a/composer.lock
+++ b/composer.lock
@@ -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": "d5e3dbbd2a1a260e2d0bfa0750d11754",
+ "hash": "3610e6ed82392eda9699a9332158c12e",
"packages": [
{
"name": "christian-riesen/base32",
@@ -260,16 +260,16 @@
},
{
"name": "fguillot/json-rpc",
- "version": "v0.0.1",
+ "version": "v0.0.3",
"source": {
"type": "git",
"url": "https://github.com/fguillot/JsonRPC.git",
- "reference": "86e8339205616ad9b09d581957cc084a99c0ed27"
+ "reference": "ef2f1aa1c07f0e3e8878c53b3a5fc81daedbebb8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/86e8339205616ad9b09d581957cc084a99c0ed27",
- "reference": "86e8339205616ad9b09d581957cc084a99c0ed27",
+ "url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/ef2f1aa1c07f0e3e8878c53b3a5fc81daedbebb8",
+ "reference": "ef2f1aa1c07f0e3e8878c53b3a5fc81daedbebb8",
"shasum": ""
},
"require": {
@@ -283,7 +283,7 @@
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "Unlicense"
+ "MIT"
],
"authors": [
{
@@ -291,13 +291,13 @@
"homepage": "http://fredericguillot.com"
}
],
- "description": "A simple Json-RPC client/server library that just works",
+ "description": "Simple Json-RPC client/server library that just works",
"homepage": "https://github.com/fguillot/JsonRPC",
- "time": "2014-11-22 20:32:14"
+ "time": "2015-05-20 15:08:40"
},
{
"name": "fguillot/picodb",
- "version": "dev-master",
+ "version": "v0.0.3",
"source": {
"type": "git",
"url": "https://github.com/fguillot/picoDb.git",
@@ -334,7 +334,7 @@
},
{
"name": "fguillot/simple-validator",
- "version": "dev-master",
+ "version": "v0.0.3",
"source": {
"type": "git",
"url": "https://github.com/fguillot/simpleValidator.git",
@@ -822,9 +822,7 @@
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
- "fguillot/simple-validator": 20,
"swiftmailer/swiftmailer": 0,
- "fguillot/picodb": 20,
"symfony/console": 0
},
"prefer-stable": false,
diff --git a/docs/api-json-rpc.markdown b/docs/api-json-rpc.markdown
index 8250b1c4..d8fe896d 100644
--- a/docs/api-json-rpc.markdown
+++ b/docs/api-json-rpc.markdown
@@ -360,9 +360,6 @@ Response example:
- Parameters:
- **id** (integer, required)
- **name** (string, required)
- - **is_active** (integer, optional)
- - **token** (string, optional)
- - **is_public** (integer, optional)
- **description** (string, optional)
- Result on success: **true**
- Result on failure: **false**
@@ -548,13 +545,31 @@ Response example:
### getProjectActivity
+- Purpose: **Get activity stream for a project**
+- Parameters:
+ - **project_id** (integer, required)
+- Result on success: **List of events**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getProjectActivity",
+ "id": 942472945,
+ "params": [
+ "project_id": 1
+ ]
+}
+```
+
+### getProjectActivities
+
- Purpose: **Get Activityfeed for Project(s)**
- Parameters:
- **project_ids** (integer array, required)
- - **limit** (integer, optional)
- - **start** (timestamp, optional)
- - **end** (timestamp, optional)
-- Result on success: **true**
+- Result on success: **List of events**
- Result on failure: **false**
Request example:
@@ -562,7 +577,7 @@ Request example:
```json
{
"jsonrpc": "2.0",
- "method": "getProjectActivity",
+ "method": "getProjectActivities",
"id": 942472945,
"params": [
"project_ids": [1,2]
@@ -1086,12 +1101,47 @@ Response example:
}
```
-### getSwimlanes
+### getDefaultSwimlane
-- Purpose: **Get the list of enabled swimlanes of a project**
+- Purpose: **Get the default swimlane for a project**
- Parameters:
- **project_id** (integer, required)
-- Result on success: **swimlane properties**
+- Result on success: **true**
+- Result on failure: **false**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getDefaultSwimlane",
+ "id": 898774713,
+ "params": [
+ 1
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 898774713,
+ "result": {
+ "id": "1",
+ "default_swimlane": "Default swimlane",
+ "show_default_swimlane": "1"
+ }
+}
+```
+
+### getActiveSwimlanes
+
+- Purpose: **Get the list of enabled swimlanes of a project (include default swimlane if enabled)**
+- Parameters:
+ - **project_id** (integer, required)
+- Result on success: **List of swimlanes**
- Result on failure: **null**
Request example:
@@ -1099,10 +1149,10 @@ Request example:
```json
{
"jsonrpc": "2.0",
- "method": "getSwimlanes",
- "id": 1242049935,
+ "method": "getActiveSwimlanes",
+ "id": 934789422,
"params": [
- 2
+ 1
]
}
```
@@ -1112,26 +1162,26 @@ Response example:
```json
{
"jsonrpc": "2.0",
- "id": 1242049935,
+ "id": 934789422,
"result": [
{
- "id": "0",
- "name": "Default"
+ "id": 0,
+ "name": "Default swimlane"
},
{
"id": "2",
- "name": "Version 7.0"
- },
+ "name": "Swimlane A"
+ }
]
}
```
### getAllSwimlanes
-- Purpose: **Get the list of all swimlanes of a project**
+- Purpose: **Get the list of all swimlanes of a project (enabled or disabled) and sorted by position**
- Parameters:
- **project_id** (integer, required)
-- Result on success: **swimlane properties**
+- Result on success: **List of swimlanes**
- Result on failure: **null**
Request example:
@@ -1140,9 +1190,9 @@ Request example:
{
"jsonrpc": "2.0",
"method": "getAllSwimlanes",
- "id": 1242049935,
+ "id": 509791576,
"params": [
- 2
+ 1
]
}
```
@@ -1152,25 +1202,21 @@ Response example:
```json
{
"jsonrpc": "2.0",
- "id": 1242049935,
+ "id": 509791576,
"result": [
{
- "id": "0",
- "name": "Default"
- },
- {
- "id": "3",
- "name": "Version 1.0",
- "is_active": "0",
- "position": 1,
- "project_id": 2
+ "id": "1",
+ "name": "Another swimlane",
+ "position": "1",
+ "is_active": "1",
+ "project_id": "1"
},
{
"id": "2",
- "name": "Version 7.0",
+ "name": "Swimlane A",
+ "position": "2",
"is_active": "1",
- "position": 2,
- "project_id": 2
+ "project_id": "1"
}
]
}
@@ -1178,7 +1224,81 @@ Response example:
### getSwimlane
-- Purpose: **Get the a swimlane**
+- Purpose: **Get the a swimlane by id**
+- Parameters:
+ - **swimlane_id** (integer, required)
+- Result on success: **swimlane properties**
+- Result on failure: **null**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getSwimlane",
+ "id": 131071870,
+ "params": [
+ 1
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 131071870,
+ "result": {
+ "id": "1",
+ "name": "Swimlane 1",
+ "position": "1",
+ "is_active": "1",
+ "project_id": "1"
+ }
+}
+```
+
+### getSwimlaneById
+
+- Purpose: **Get the a swimlane by id**
+- Parameters:
+ - **swimlane_id** (integer, required)
+- Result on success: **swimlane properties**
+- Result on failure: **null**
+
+Request example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "method": "getSwimlaneById",
+ "id": 131071870,
+ "params": [
+ 1
+ ]
+}
+```
+
+Response example:
+
+```json
+{
+ "jsonrpc": "2.0",
+ "id": 131071870,
+ "result": {
+ "id": "1",
+ "name": "Swimlane 1",
+ "position": "1",
+ "is_active": "1",
+ "project_id": "1"
+ }
+}
+```
+
+### getSwimlaneByName
+
+- Purpose: **Get the a swimlane by name**
- Parameters:
- **project_id** (integer, required)
- **name** (string, required)
@@ -1190,11 +1310,11 @@ Request example:
```json
{
"jsonrpc": "2.0",
- "method": "getSwimlane",
- "id": 1242049935,
+ "method": "getSwimlaneByName",
+ "id": 824623567,
"params": [
- 2,
- "Version 1.0"
+ 1,
+ "Swimlane 1"
]
}
```
@@ -1204,13 +1324,13 @@ Response example:
```json
{
"jsonrpc": "2.0",
- "id": 1242049935,
+ "id": 824623567,
"result": {
- "id": "3",
- "name": "Version 1.0",
- "is_active": "0",
- "position": 2,
- "project_id": 2
+ "id": "1",
+ "name": "Swimlane 1",
+ "position": "1",
+ "is_active": "1",
+ "project_id": "1"
}
}
```
@@ -1296,10 +1416,10 @@ Request example:
{
"jsonrpc": "2.0",
"method": "updateSwimlane",
- "id": 480740641,
+ "id": 87102426,
"params": [
- 2,
- "Version 4.1"
+ "1",
+ "Another swimlane"
]
}
```
@@ -1309,7 +1429,7 @@ Response example:
```json
{
"jsonrpc": "2.0",
- "id": 480740641,
+ "id": 87102426,
"result": true
}
```
@@ -1329,10 +1449,10 @@ Request example:
{
"jsonrpc": "2.0",
"method": "addSwimlane",
- "id": 638544704,
+ "id": 849940086,
"params": [
1,
- "Version 1.0"
+ "Swimlane 1"
]
}
```
@@ -1342,8 +1462,8 @@ Response example:
```json
{
"jsonrpc": "2.0",
- "id": 638544704,
- "result": 5
+ "id": 849940086,
+ "result": 1
}
```
@@ -1448,7 +1568,7 @@ Response example:
### getAvailableActions
-- Purpose: **Get list of available actions**
+- Purpose: **Get list of available automatic actions**
- Parameters: none
- Result on success: **list of actions**
- Result on failure: **false**
@@ -1459,7 +1579,7 @@ Request example:
{
"jsonrpc": "2.0",
"method": "getAvailableActions",
- "id": 1433237746,
+ "id": 1217735483
}
```
@@ -1468,30 +1588,33 @@ Response example:
```json
{
"jsonrpc": "2.0",
- "id": 1433237746,
+ "id": 1217735483,
"result": {
- "TaskLogMoveAnotherColumn" : "Add a comment logging moving the task between columns",
- "TaskAssignColorColumn" : "Assign a color when the task is moved to a specific column",
- "TaskAssignColorUser" : "Assign a color to a specific user",
- "TaskAssignCategoryColor" : "Assign automatically a category based on a color",
- "TaskAssignColorCategory" : "Assign automatically a color based on a category",
- "TaskAssignSpecificUser" : "Assign the task to a specific user",
- "TaskAssignCurrentUser" : "Assign the task to the person who does the action",
- "TaskAssignUser" : "Change the assignee based on an external username",
- "TaskAssignCategoryLabel" : "Change the category based on an external label",
- "TaskClose" : "Close a task",
- "CommentCreation" : "Create a comment from an external provider",
- "TaskCreation" : "Create a task from an external provider",
- "TaskDuplicateAnotherProject" : "Duplicate the task to another project",
- "TaskMoveAnotherProject" : "Move the task to another project",
- "TaskOpen" : "Open a task"
+ "TaskLogMoveAnotherColumn": "Add a comment logging moving the task between columns",
+ "TaskAssignColorUser": "Assign a color to a specific user",
+ "TaskAssignColorColumn": "Assign a color when the task is moved to a specific column",
+ "TaskAssignCategoryColor": "Assign automatically a category based on a color",
+ "TaskAssignColorCategory": "Assign automatically a color based on a category",
+ "TaskAssignSpecificUser": "Assign the task to a specific user",
+ "TaskAssignCurrentUser": "Assign the task to the person who does the action",
+ "TaskUpdateStartDate": "Automatically update the start date",
+ "TaskAssignUser": "Change the assignee based on an external username",
+ "TaskAssignCategoryLabel": "Change the category based on an external label",
+ "TaskClose": "Close a task",
+ "CommentCreation": "Create a comment from an external provider",
+ "TaskCreation": "Create a task from an external provider",
+ "TaskDuplicateAnotherProject": "Duplicate the task to another project",
+ "TaskMoveColumnAssigned": "Move the task to another column when assigned to a user",
+ "TaskMoveColumnUnAssigned": "Move the task to another column when assignee is cleared",
+ "TaskMoveAnotherProject": "Move the task to another project",
+ "TaskOpen": "Open a task"
}
}
```
-### getAvailableEvents
+### getAvailableActionEvents
-- Purpose: **Get list of available events**
+- Purpose: **Get list of available events for actions**
- Parameters: none
- Result on success: **list of events**
- Result on failure: **false**
@@ -1501,8 +1624,8 @@ Request example:
```json
{
"jsonrpc": "2.0",
- "method": "getAvailableEvents",
- "id": 1433237746,
+ "method": "getAvailableActionEvents",
+ "id": 2116665643
}
```
@@ -1511,31 +1634,31 @@ Response example:
```json
{
"jsonrpc": "2.0",
- "id": 1433237746,
+ "id": 2116665643,
"result": {
- "bitbucket.webhook.commit" : "Bitbucket commit received",
- "task.close" : "Closing a task",
- "github.webhook.commit" : "Github commit received",
- "github.webhook.issue.assignee" : "Github issue assignee change",
- "github.webhook.issue.closed" : "Github issue closed",
- "github.webhook.issue.commented" : "Github issue comment created",
- "github.webhook.issue.label" : "Github issue label change",
- "github.webhook.issue.opened" : "Github issue opened",
- "github.webhook.issue.reopened" : "Github issue reopened",
- "gitlab.webhook.commit" : "Gitlab commit received",
- "gitlab.webhook.issue.closed" : "Gitlab issue closed",
- "gitlab.webhook.issue.opened" : "Gitlab issue opened",
- "task.move.column" : "Move a task to another column",
- "task.open" : "Open a closed task",
- "task.assignee_change" : "Task assignee change",
- "task.create" : "Task creation",
- "task.create_update" : "Task creation or modification",
- "task.update" : "Task modification"
+ "bitbucket.webhook.commit": "Bitbucket commit received",
+ "task.close": "Closing a task",
+ "github.webhook.commit": "Github commit received",
+ "github.webhook.issue.assignee": "Github issue assignee change",
+ "github.webhook.issue.closed": "Github issue closed",
+ "github.webhook.issue.commented": "Github issue comment created",
+ "github.webhook.issue.label": "Github issue label change",
+ "github.webhook.issue.opened": "Github issue opened",
+ "github.webhook.issue.reopened": "Github issue reopened",
+ "gitlab.webhook.commit": "Gitlab commit received",
+ "gitlab.webhook.issue.closed": "Gitlab issue closed",
+ "gitlab.webhook.issue.opened": "Gitlab issue opened",
+ "task.move.column": "Move a task to another column",
+ "task.open": "Open a closed task",
+ "task.assignee_change": "Task assignee change",
+ "task.create": "Task creation",
+ "task.create_update": "Task creation or modification",
+ "task.update": "Task modification"
}
}
```
-### getCompatibleEvents
+### getCompatibleActionEvents
- Purpose: **Get list of events compatible with an action**
- Parameters:
@@ -1548,10 +1671,10 @@ Request example:
```json
{
"jsonrpc": "2.0",
- "method": "getCompatibleEvents",
- "id": 1433237746,
+ "method": "getCompatibleActionEvents",
+ "id": 899370297,
"params": [
- "TaskAssignSpecificUser"
+ "TaskClose"
]
}
```
@@ -1561,10 +1684,14 @@ Response example:
```json
{
"jsonrpc": "2.0",
- "id": 1433237746,
+ "id": 899370297,
"result": {
- "task.move.column" : "Move a task to another column",
- "task.create_update" : "Task creation or modification",
+ "bitbucket.webhook.commit": "Bitbucket commit received",
+ "github.webhook.commit": "Github commit received",
+ "github.webhook.issue.closed": "Github issue closed",
+ "gitlab.webhook.commit": "Gitlab commit received",
+ "gitlab.webhook.issue.closed": "Gitlab issue closed",
+ "task.move.column": "Move a task to another column"
}
}
```
@@ -1574,7 +1701,7 @@ Response example:
- Purpose: **Get list of actions for a project**
- Parameters:
- **project_id** (integer, required)
-- Result on success: **list of actions info**
+- Result on success: **list of actions properties**
- Result on failure: **false**
Request example:
@@ -1618,7 +1745,7 @@ Response example:
- **project_id** (integer, required)
- **event_name** (string, required)
- **action_name** (string, required)
- - **params** (list of string pairs, required)
+ - **params** (key/value parameters, required)
- Result on success: **action_id**
- Result on failure: **false**
@@ -1664,10 +1791,10 @@ Request example:
```json
{
"jsonrpc": "2.0",
- "method": "getAvailableEvents",
- "id": 1433237746,
+ "method": "removeAction",
+ "id": 1510741671,
"params": [
- "2",
+ 1
]
}
```
@@ -1677,7 +1804,7 @@ Response example:
```json
{
"jsonrpc": "2.0",
- "id": 1433237746,
+ "id": 1510741671,
"result": true
}
```
diff --git a/jsonrpc.php b/jsonrpc.php
index e5c000c0..b6ec8291 100644
--- a/jsonrpc.php
+++ b/jsonrpc.php
@@ -2,441 +2,20 @@
require __DIR__.'/app/common.php';
-use Symfony\Component\EventDispatcher\Event;
-
-$container['dispatcher']->dispatch('api.bootstrap', new Event);
-
$server = new JsonRPC\Server;
-$server->authentication(array('jsonrpc' => $container['config']->get('api_token')));
-
-/**
- * Project procedures
- */
-$server->bind('getProjectById', $container['project'], 'getById');
-$server->bind('getProjectByName', $container['project'], 'getByName');
-$server->bind('getAllProjects', $container['project'], 'getAll');
-$server->bind('removeProject', $container['project'], 'remove');
-$server->bind('enableProject', $container['project'], 'enable');
-$server->bind('disableProject', $container['project'], 'disable');
-$server->bind('enableProjectPublicAccess', $container['project'], 'enablePublicAccess');
-$server->bind('disableProjectPublicAccess', $container['project'], 'disablePublicAccess');
-$server->bind('getProjectActivity', $container['projectActivity'], 'getProjects');
-
-$server->register('createProject', function($name, $description = null) use ($container) {
- $values = array(
- 'name' => $name,
- 'description' => $description
- );
- list($valid,) = $container['project']->validateCreation($values);
- return $valid ? $container['project']->create($values) : false;
-});
-
-$server->register('updateProject', function($id, $name, $is_active = null, $is_public = null, $token = null, $description = null) use ($container) {
-
- $values = array(
- 'id' => $id,
- 'name' => $name,
- 'is_active' => $is_active,
- 'is_public' => $is_public,
- 'token' => $token,
- 'description' => $description
- );
-
- foreach ($values as $key => $value) {
- if (is_null($value)) {
- unset($values[$key]);
- }
- }
-
- list($valid,) = $container['project']->validateModification($values);
- return $valid && $container['project']->update($values);
-});
-
-/**
- * Board procedures
- */
-$server->bind('getBoard', $container['board'], 'getBoard');
-$server->bind('getColumns', $container['board'], 'getColumns');
-$server->bind('getColumn', $container['board'], 'getColumn');
-$server->bind('moveColumnUp', $container['board'], 'moveUp');
-$server->bind('moveColumnDown', $container['board'], 'moveDown');
-$server->bind('updateColumn', $container['board'], 'updateColumn');
-$server->bind('addColumn', $container['board'], 'addColumn');
-$server->bind('removeColumn', $container['board'], 'removeColumn');
-
-/**
- * Swimlane procedures
- */
-$server->bind('getSwimlanes', $container['swimlane'], 'getSwimlanes');
-$server->bind('getAllSwimlanes', $container['swimlane'], 'getAll');
-$server->bind('getSwimlane', $container['swimlane'], 'getByName');
-$server->bind('addSwimlane', $container['swimlane'], 'create');
-$server->bind('updateSwimlane', $container['swimlane'], 'rename');
-$server->bind('removeSwimlane', $container['swimlane'], 'remove');
-$server->bind('disableSwimlane', $container['swimlane'], 'disable');
-$server->bind('enableSwimlane', $container['swimlane'], 'enable');
-$server->bind('moveSwimlaneUp', $container['swimlane'], 'moveUp');
-$server->bind('moveSwimlaneDown', $container['swimlane'], 'moveDown');
-
-/**
- * Actions procedures
- */
-$server->bind('getAvailableActions', $container['action'], 'getAvailableActions');
-$server->bind('getAvailableEvents', $container['action'], 'getAvailableEvents');
-$server->bind('getCompatibleEvents', $container['action'], 'getCompatibleEvents');
-$server->bind('removeAction', $container['action'], 'remove');
-
-$server->register('getActions', function($project_id) use ($container) {
- $actions = $container['action']->getAllByProject($project_id);
-
- foreach ($actions as $index => $action) {
- $params = array();
-
- foreach($action['params'] as $param) {
- $params[$param['name']] = $param['value'];
- }
-
- $actions[$index]['params'] = $params;
- }
-
- return $actions;
-});
-
-$server->register('createAction', function($project_id, $event_name, $action_name, $params) use ($container) {
-
- $values = array(
- 'project_id' => $project_id,
- 'event_name' => $event_name,
- 'action_name' => $action_name,
- 'params' => $params,
- );
-
- list($valid,) = $container['action']->validateCreation($values);
-
- if (! $valid) {
- return false;
- }
-
- // Check the action exists
- $actions = $container['action']->getAvailableActions();
-
- if (! isset($actions[$action_name])) {
- return false;
- }
-
- // Check the event
- $action = $container['action']->load($action_name, $project_id, $event_name);
-
- if (! in_array($event_name, $action->getCompatibleEvents())) {
- return false;
- }
-
- $required_params = $action->getActionRequiredParameters();
-
- // Check missing parameters
- foreach($required_params as $param => $value) {
- if (! isset($params[$param])) {
- return false;
- }
- }
-
- // Check extra parameters
- foreach($params as $param => $value) {
- if (! isset($required_params[$param])) {
- return false;
- }
- }
-
- return $container['action']->create($values);
-});
-
-
-/**
- * Project permissions procedures
- */
-$server->bind('getMembers', $container['projectPermission'], 'getMembers');
-$server->bind('revokeUser', $container['projectPermission'], 'revokeMember');
-$server->bind('allowUser', $container['projectPermission'], 'addMember');
-
-/**
- * Task procedures
- */
-$server->bind('getTask', $container['taskFinder'], 'getById');
-$server->bind('getAllTasks', $container['taskFinder'], 'getAll');
-$server->bind('getOverdueTasks', $container['taskFinder'], 'getOverdueTasks');
-$server->bind('openTask', $container['taskStatus'], 'open');
-$server->bind('closeTask', $container['taskStatus'], 'close');
-$server->bind('removeTask', $container['task'], 'remove');
-$server->bind('moveTaskPosition', $container['taskPosition'], 'movePosition');
-
-$server->register('createTask', function($title, $project_id, $color_id = '', $column_id = 0, $owner_id = 0, $creator_id = 0, $date_due = '', $description = '', $category_id = 0, $score = 0, $swimlane_id = 0, $recurrence_status = 0, $recurrence_trigger = 0, $recurrence_factor = 0, $recurrence_timeframe = 0, $recurrence_basedate = 0) use ($container) {
-
- $values = array(
- 'title' => $title,
- 'project_id' => $project_id,
- 'color_id' => $color_id,
- 'column_id' => $column_id,
- 'owner_id' => $owner_id,
- 'creator_id' => $creator_id,
- 'date_due' => $date_due,
- 'description' => $description,
- 'category_id' => $category_id,
- 'score' => $score,
- 'swimlane_id' => $swimlane_id,
- 'recurrence_status' => $recurrence_status,
- 'recurrence_trigger' => $recurrence_trigger,
- 'recurrence_factor' => $recurrence_factor,
- 'recurrence_timeframe' => $recurrence_timeframe,
- 'recurrence_basedate' => $recurrence_basedate,
- );
-
- list($valid,) = $container['taskValidator']->validateCreation($values);
-
- if (! $valid) {
- return false;
- }
-
- return $container['taskCreation']->create($values);
-});
-
-$server->register('updateTask', function($id, $title = null, $project_id = null, $color_id = null, $column_id = null, $owner_id = null, $creator_id = null, $date_due = null, $description = null, $category_id = null, $score = null, $swimlane_id = null, $recurrence_status = null, $recurrence_trigger = null, $recurrence_factor = null, $recurrence_timeframe = null, $recurrence_basedate = null) use ($container) {
-
- $values = array(
- 'id' => $id,
- 'title' => $title,
- 'project_id' => $project_id,
- 'color_id' => $color_id,
- 'column_id' => $column_id,
- 'owner_id' => $owner_id,
- 'creator_id' => $creator_id,
- 'date_due' => $date_due,
- 'description' => $description,
- 'category_id' => $category_id,
- 'score' => $score,
- 'swimlane_id' => $swimlane_id,
- 'recurrence_status' => $recurrence_status,
- 'recurrence_trigger' => $recurrence_trigger,
- 'recurrence_factor' => $recurrence_factor,
- 'recurrence_timeframe' => $recurrence_timeframe,
- 'recurrence_basedate' => $recurrence_basedate,
- );
-
- foreach ($values as $key => $value) {
- if (is_null($value)) {
- unset($values[$key]);
- }
- }
-
- list($valid) = $container['taskValidator']->validateApiModification($values);
- return $valid && $container['taskModification']->update($values);
-});
-
-
-/**
- * User procedures
- */
-$server->bind('getUser', $container['user'], 'getById');
-$server->bind('getAllUsers', $container['user'], 'getAll');
-$server->bind('removeUser', $container['user'], 'remove');
-
-$server->register('createUser', function($username, $password, $name = '', $email = '', $is_admin = 0, $default_project_id = 0) use ($container) {
-
- $values = array(
- 'username' => $username,
- 'password' => $password,
- 'confirmation' => $password,
- 'name' => $name,
- 'email' => $email,
- 'is_admin' => $is_admin,
- 'default_project_id' => $default_project_id,
- );
-
- list($valid,) = $container['user']->validateCreation($values);
-
- if (! $valid) {
- return false;
- }
-
- return $container['user']->create($values);
-});
-
-$server->register('createLdapUser', function($username = '', $email = '', $is_admin = 0, $default_project_id = 0) use ($container) {
-
- $ldap = new Auth\Ldap($container);
- $user = $ldap->lookup($username, $email);
-
- if (! $user) {
- return false;
- }
-
- $values = array(
- 'username' => $user['username'],
- 'name' => $user['name'],
- 'email' => $user['email'],
- 'is_ldap_user' => 1,
- 'is_admin' => $is_admin,
- 'default_project_id' => $default_project_id,
- );
-
- return $container['user']->create($values);
-});
-
-$server->register('updateUser', function($id, $username = null, $name = null, $email = null, $is_admin = null, $default_project_id = null) use ($container) {
-
- $values = array(
- 'id' => $id,
- 'username' => $username,
- 'name' => $name,
- 'email' => $email,
- 'is_admin' => $is_admin,
- 'default_project_id' => $default_project_id,
- );
-
- foreach ($values as $key => $value) {
- if (is_null($value)) {
- unset($values[$key]);
- }
- }
-
- list($valid,) = $container['user']->validateApiModification($values);
- return $valid && $container['user']->update($values);
-});
-
-/**
- * Category procedures
- */
-$server->bind('getCategory', $container['category'], 'getById');
-$server->bind('getAllCategories', $container['category'], 'getAll');
-$server->bind('removeCategory', $container['category'], 'remove');
-
-$server->register('createCategory', function($project_id, $name) use ($container) {
-
- $values = array(
- 'project_id' => $project_id,
- 'name' => $name,
- );
-
- list($valid,) = $container['category']->validateCreation($values);
-
- if (! $valid) {
- return false;
- }
-
- return $container['category']->create($values);
-});
-
-$server->register('updateCategory', function($id, $name) use ($container) {
-
- $values = array(
- 'id' => $id,
- 'name' => $name,
- );
-
- list($valid,) = $container['category']->validateModification($values);
- return $valid && $container['category']->update($values);
-});
-
-/**
- * Comments procedures
- */
-$server->bind('getComment', $container['comment'], 'getById');
-$server->bind('getAllComments', $container['comment'], 'getAll');
-$server->bind('removeComment', $container['comment'], 'remove');
-
-$server->register('createComment', function($task_id, $user_id, $content) use ($container) {
-
- $values = array(
- 'task_id' => $task_id,
- 'user_id' => $user_id,
- 'comment' => $content,
- );
-
- list($valid,) = $container['comment']->validateCreation($values);
-
- if (! $valid) {
- return false;
- }
-
- return $container['comment']->create($values);
-});
-
-$server->register('updateComment', function($id, $content) use ($container) {
-
- $values = array(
- 'id' => $id,
- 'comment' => $content,
- );
-
- list($valid,) = $container['comment']->validateModification($values);
- return $valid && $container['comment']->update($values);
-});
-
-/**
- * Subtask procedures
- */
-$server->bind('getSubtask', $container['subtask'], 'getById');
-$server->bind('getAllSubtasks', $container['subtask'], 'getAll');
-$server->bind('removeSubtask', $container['subtask'], 'remove');
-
-$server->register('createSubtask', function($task_id, $title, $user_id = 0, $time_estimated = 0, $time_spent = 0, $status = 0) use ($container) {
-
- $values = array(
- 'title' => $title,
- 'task_id' => $task_id,
- 'user_id' => $user_id,
- 'time_estimated' => $time_estimated,
- 'time_spent' => $time_spent,
- 'status' => $status,
- );
-
- foreach ($values as $key => $value) {
- if (is_null($value)) {
- unset($values[$key]);
- }
- }
- list($valid,) = $container['subtask']->validateCreation($values);
-
- if (! $valid) {
- return false;
- }
-
- return $container['subtask']->create($values);
-});
-
-$server->register('updateSubtask', function($id, $task_id, $title = null, $user_id = null, $time_estimated = null, $time_spent = null, $status = null) use ($container) {
-
- $values = array(
- 'id' => $id,
- 'task_id' => $task_id,
- 'title' => $title,
- 'user_id' => $user_id,
- 'time_estimated' => $time_estimated,
- 'time_spent' => $time_spent,
- 'status' => $status,
- );
-
- foreach ($values as $key => $value) {
- if (is_null($value)) {
- unset($values[$key]);
- }
- }
-
- list($valid,) = $container['subtask']->validateApiModification($values);
- return $valid && $container['subtask']->update($values);
-});
-
-/**
- * Application procedures
- */
-$server->register('getTimezone', function() use ($container) {
- return $container['config']->get('application_timezone');
-});
-
-$server->register('getVersion', function() use ($container) {
- return APP_VERSION;
-});
+$server->before('authentication');
+$server->attach(new Api\Action($container));
+$server->attach(new Api\App($container));
+$server->attach(new Api\Board($container));
+$server->attach(new Api\Category($container));
+$server->attach(new Api\Comment($container));
+$server->attach(new Api\Link($container));
+$server->attach(new Api\Project($container));
+$server->attach(new Api\ProjectPermission($container));
+$server->attach(new Api\Subtask($container));
+$server->attach(new Api\Swimlane($container));
+$server->attach(new Api\Task($container));
+$server->attach(new Api\TaskLink($container));
+$server->attach(new Api\User($container));
-/**
- * Parse incoming requests
- */
echo $server->execute();
diff --git a/tests/functionals.mysql.xml b/tests/functionals.mysql.xml
index f667cafa..f5c3e16a 100644
--- a/tests/functionals.mysql.xml
+++ b/tests/functionals.mysql.xml
@@ -12,5 +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" />
</php>
</phpunit> \ No newline at end of file
diff --git a/tests/functionals.postgres.xml b/tests/functionals.postgres.xml
index 38904d1a..40fcef00 100644
--- a/tests/functionals.postgres.xml
+++ b/tests/functionals.postgres.xml
@@ -12,5 +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" />
</php>
</phpunit> \ No newline at end of file
diff --git a/tests/functionals/ApiTest.php b/tests/functionals/ApiTest.php
index 9fdfd1ba..7b7a2bed 100644
--- a/tests/functionals/ApiTest.php
+++ b/tests/functionals/ApiTest.php
@@ -105,19 +105,66 @@ class Api extends PHPUnit_Framework_TestCase
{
$project = $this->client->getProjectById(1);
$this->assertNotEmpty($project);
- $this->assertTrue($this->client->execute('updateProject', array('id' => 1, 'name' => 'API test 2', 'is_active' => 0)));
+ $this->assertTrue($this->client->execute('updateProject', array('id' => 1, 'name' => 'API test 2')));
$project = $this->client->getProjectById(1);
$this->assertEquals('API test 2', $project['name']);
- $this->assertEquals(0, $project['is_active']);
- $this->assertTrue($this->client->execute('updateProject', array('id' => 1, 'name' => 'API test', 'is_active' => 1)));
+ $this->assertTrue($this->client->execute('updateProject', array('id' => 1, 'name' => 'API test', 'description' => 'test')));
$project = $this->client->getProjectById(1);
$this->assertEquals('API test', $project['name']);
+ $this->assertEquals('test', $project['description']);
+ }
+
+ public function testDisableProject()
+ {
+ $this->assertTrue($this->client->disableProject(1));
+ $project = $this->client->getProjectById(1);
+ $this->assertNotEmpty($project);
+ $this->assertEquals(0, $project['is_active']);
+ }
+
+ public function testEnableProject()
+ {
+ $this->assertTrue($this->client->enableProject(1));
+ $project = $this->client->getProjectById(1);
+ $this->assertNotEmpty($project);
$this->assertEquals(1, $project['is_active']);
}
+ public function testEnableProjectPublicAccess()
+ {
+ $this->assertTrue($this->client->enableProjectPublicAccess(1));
+ $project = $this->client->getProjectById(1);
+ $this->assertNotEmpty($project);
+ $this->assertEquals(1, $project['is_public']);
+ $this->assertNotEmpty($project['token']);
+ }
+
+ public function testDisableProjectPublicAccess()
+ {
+ $this->assertTrue($this->client->disableProjectPublicAccess(1));
+ $project = $this->client->getProjectById(1);
+ $this->assertNotEmpty($project);
+ $this->assertEquals(0, $project['is_public']);
+ $this->assertEmpty($project['token']);
+ }
+
+ public function testgetProjectActivities()
+ {
+ $activities = $this->client->getProjectActivities(array('project_ids' => array(1)));
+ $this->assertInternalType('array', $activities);
+ $this->assertCount(0, $activities);
+ }
+
+ public function testgetProjectActivity()
+ {
+ $activities = $this->client->getProjectActivity(1);
+ $this->assertInternalType('array', $activities);
+ $this->assertCount(0, $activities);
+ }
+
public function testGetBoard()
{
$board = $this->client->getBoard(1);
@@ -188,6 +235,127 @@ class Api extends PHPUnit_Framework_TestCase
$this->assertEquals(4, count($columns));
}
+ public function testGetDefaultSwimlane()
+ {
+ $swimlane = $this->client->getDefaultSwimlane(1);
+ $this->assertNotEmpty($swimlane);
+ $this->assertEquals('Default swimlane', $swimlane['default_swimlane']);
+ }
+
+ public function testAddSwimlane()
+ {
+ $swimlane_id = $this->client->addSwimlane(1, 'Swimlane 1');
+ $this->assertNotFalse($swimlane_id);
+ $this->assertInternalType('int', $swimlane_id);
+
+ $swimlane = $this->client->getSwimlaneById($swimlane_id);
+ $this->assertNotEmpty($swimlane);
+ $this->assertInternalType('array', $swimlane);
+ $this->assertEquals('Swimlane 1', $swimlane['name']);
+ }
+
+ public function testGetSwimlane()
+ {
+ $swimlane = $this->client->getSwimlane(1);
+ $this->assertNotEmpty($swimlane);
+ $this->assertInternalType('array', $swimlane);
+ $this->assertEquals('Swimlane 1', $swimlane['name']);
+ }
+
+ public function testUpdateSwimlane()
+ {
+ $swimlane = $this->client->getSwimlaneByName(1, 'Swimlane 1');
+ $this->assertNotEmpty($swimlane);
+ $this->assertInternalType('array', $swimlane);
+ $this->assertEquals(1, $swimlane['id']);
+ $this->assertEquals('Swimlane 1', $swimlane['name']);
+
+ $this->assertTrue($this->client->updateSwimlane($swimlane['id'], 'Another swimlane'));
+
+ $swimlane = $this->client->getSwimlaneById($swimlane['id']);
+ $this->assertNotEmpty($swimlane);
+ $this->assertEquals('Another swimlane', $swimlane['name']);
+ }
+
+ public function testDisableSwimlane()
+ {
+ $this->assertTrue($this->client->disableSwimlane(1, 1));
+
+ $swimlane = $this->client->getSwimlaneById(1);
+ $this->assertNotEmpty($swimlane);
+ $this->assertEquals(0, $swimlane['is_active']);
+ }
+
+ public function testEnableSwimlane()
+ {
+ $this->assertTrue($this->client->enableSwimlane(1, 1));
+
+ $swimlane = $this->client->getSwimlaneById(1);
+ $this->assertNotEmpty($swimlane);
+ $this->assertEquals(1, $swimlane['is_active']);
+ }
+
+ public function testGetAllSwimlanes()
+ {
+ $this->assertNotFalse($this->client->addSwimlane(1, 'Swimlane A'));
+
+ $swimlanes = $this->client->getAllSwimlanes(1);
+ $this->assertNotEmpty($swimlanes);
+ $this->assertCount(2, $swimlanes);
+ $this->assertEquals('Another swimlane', $swimlanes[0]['name']);
+ $this->assertEquals('Swimlane A', $swimlanes[1]['name']);
+ }
+
+ public function testGetActiveSwimlane()
+ {
+ $this->assertTrue($this->client->disableSwimlane(1, 1));
+
+ $swimlanes = $this->client->getActiveSwimlanes(1);
+ $this->assertNotEmpty($swimlanes);
+ $this->assertCount(2, $swimlanes);
+ $this->assertEquals('Default swimlane', $swimlanes[0]['name']);
+ $this->assertEquals('Swimlane A', $swimlanes[1]['name']);
+ }
+
+ public function testMoveSwimlaneUp()
+ {
+ $this->assertTrue($this->client->enableSwimlane(1, 1));
+ $this->assertTrue($this->client->moveSwimlaneUp(1, 1));
+
+ $swimlanes = $this->client->getActiveSwimlanes(1);
+ $this->assertNotEmpty($swimlanes);
+ $this->assertCount(3, $swimlanes);
+ $this->assertEquals('Default swimlane', $swimlanes[0]['name']);
+ $this->assertEquals('Another swimlane', $swimlanes[1]['name']);
+ $this->assertEquals('Swimlane A', $swimlanes[2]['name']);
+
+ $this->assertTrue($this->client->moveSwimlaneUp(1, 2));
+
+ $swimlanes = $this->client->getActiveSwimlanes(1);
+ $this->assertNotEmpty($swimlanes);
+ $this->assertCount(3, $swimlanes);
+ $this->assertEquals('Default swimlane', $swimlanes[0]['name']);
+ $this->assertEquals('Swimlane A', $swimlanes[1]['name']);
+ $this->assertEquals('Another swimlane', $swimlanes[2]['name']);
+ }
+
+ public function testMoveSwimlaneDown()
+ {
+ $this->assertTrue($this->client->moveSwimlaneDown(1, 2));
+
+ $swimlanes = $this->client->getActiveSwimlanes(1);
+ $this->assertNotEmpty($swimlanes);
+ $this->assertCount(3, $swimlanes);
+ $this->assertEquals('Default swimlane', $swimlanes[0]['name']);
+ $this->assertEquals('Another swimlane', $swimlanes[1]['name']);
+ $this->assertEquals('Swimlane A', $swimlanes[2]['name']);
+ }
+
+ public function testRemoveSwimlane()
+ {
+ $this->assertTrue($this->client->removeSwimlane(1, 2));
+ }
+
public function testCreateTask()
{
$task = array(
@@ -615,4 +783,58 @@ class Api extends PHPUnit_Framework_TestCase
$this->assertFalse($this->client->removeCategory(1));
$this->assertFalse($this->client->removeCategory(1111));
}
+
+ public function testGetAvailableActions()
+ {
+ $actions = $this->client->getAvailableActions();
+ $this->assertNotEmpty($actions);
+ $this->assertInternalType('array', $actions);
+ $this->assertArrayHasKey('TaskLogMoveAnotherColumn', $actions);
+ }
+
+ public function testGetAvailableActionEvents()
+ {
+ $events = $this->client->getAvailableActionEvents();
+ $this->assertNotEmpty($events);
+ $this->assertInternalType('array', $events);
+ $this->assertArrayHasKey('task.move.column', $events);
+ }
+
+ public function testGetCompatibleActionEvents()
+ {
+ $events = $this->client->getCompatibleActionEvents('TaskClose');
+ $this->assertNotEmpty($events);
+ $this->assertInternalType('array', $events);
+ $this->assertArrayHasKey('task.move.column', $events);
+ }
+
+ public function testCreateAction()
+ {
+ $action_id = $this->client->createAction(1, 'task.move.column', 'TaskClose', array('column_id' => 1));
+ $this->assertNotFalse($action_id);
+ $this->assertEquals(1, $action_id);
+ }
+
+ public function testGetActions()
+ {
+ $actions = $this->client->getActions(1);
+ $this->assertNotEmpty($actions);
+ $this->assertInternalType('array', $actions);
+ $this->assertCount(1, $actions);
+ $this->assertArrayHasKey('id', $actions[0]);
+ $this->assertArrayHasKey('project_id', $actions[0]);
+ $this->assertArrayHasKey('event_name', $actions[0]);
+ $this->assertArrayHasKey('action_name', $actions[0]);
+ $this->assertArrayHasKey('params', $actions[0]);
+ $this->assertArrayHasKey('column_id', $actions[0]['params']);
+ }
+
+ public function testRemoveAction()
+ {
+ $this->assertTrue($this->client->removeAction(1));
+
+ $actions = $this->client->getActions(1);
+ $this->assertEmpty($actions);
+ $this->assertCount(0, $actions);
+ }
}
diff --git a/tests/units/LinkTest.php b/tests/units/LinkTest.php
index 076e1b3b..45e9796c 100644
--- a/tests/units/LinkTest.php
+++ b/tests/units/LinkTest.php
@@ -10,9 +10,9 @@ class LinkTest extends Base
{
$l = new Link($this->container);
- $this->assertTrue($l->create('Link A'));
+ $this->assertNotFalse($l->create('Link A'));
$this->assertFalse($l->create('Link A'));
- $this->assertTrue($l->create('Link B', 'Link C'));
+ $this->assertNotFalse($l->create('Link B', 'Link C'));
$links = $l->getAll();
$this->assertNotEmpty($links);
@@ -40,8 +40,8 @@ class LinkTest extends Base
{
$l = new Link($this->container);
- $this->assertTrue($l->create('Link A'));
- $this->assertTrue($l->create('Link B', 'Link C'));
+ $this->assertNotFalse($l->create('Link A'));
+ $this->assertNotFalse($l->create('Link B', 'Link C'));
$this->assertEquals(1, $l->getOppositeLinkId(1));
$this->assertEquals(3, $l->getOppositeLinkId(2));