diff options
Diffstat (limited to 'app/Api/Procedure')
20 files changed, 1522 insertions, 0 deletions
diff --git a/app/Api/Procedure/ActionProcedure.php b/app/Api/Procedure/ActionProcedure.php new file mode 100644 index 00000000..4043dbb9 --- /dev/null +++ b/app/Api/Procedure/ActionProcedure.php @@ -0,0 +1,91 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\ActionAuthorization; +use Kanboard\Api\Authorization\ProjectAuthorization; + +/** + * Action API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class ActionProcedure extends BaseProcedure +{ + public function getAvailableActions() + { + return $this->actionManager->getAvailableActions(); + } + + public function getAvailableActionEvents() + { + return $this->eventManager->getAll(); + } + + public function getCompatibleActionEvents($action_name) + { + return $this->actionManager->getCompatibleEvents($action_name); + } + + public function removeAction($action_id) + { + ActionAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeAction', $action_id); + return $this->actionModel->remove($action_id); + } + + public function getActions($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getActions', $project_id); + return $this->actionModel->getAllByProject($project_id); + } + + public function createAction($project_id, $event_name, $action_name, array $params) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createAction', $project_id); + $values = array( + 'project_id' => $project_id, + 'event_name' => $event_name, + 'action_name' => $action_name, + 'params' => $params, + ); + + list($valid, ) = $this->actionValidator->validateCreation($values); + + if (! $valid) { + return false; + } + + // Check if the action exists + $actions = $this->actionManager->getAvailableActions(); + + if (! isset($actions[$action_name])) { + return false; + } + + // Check the event + $action = $this->actionManager->getAction($action_name); + + if (! in_array($event_name, $action->getEvents())) { + 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->actionModel->create($values); + } +} diff --git a/app/Api/Procedure/AppProcedure.php b/app/Api/Procedure/AppProcedure.php new file mode 100644 index 00000000..60af4a60 --- /dev/null +++ b/app/Api/Procedure/AppProcedure.php @@ -0,0 +1,47 @@ +<?php + +namespace Kanboard\Api\Procedure; + +/** + * App API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class AppProcedure extends BaseProcedure +{ + public function getTimezone() + { + return $this->timezoneModel->getCurrentTimezone(); + } + + public function getVersion() + { + return APP_VERSION; + } + + public function getDefaultTaskColor() + { + return $this->colorModel->getDefaultColor(); + } + + public function getDefaultTaskColors() + { + return $this->colorModel->getDefaultColors(); + } + + public function getColorList() + { + return $this->colorModel->getList(); + } + + public function getApplicationRoles() + { + return $this->role->getApplicationRoles(); + } + + public function getProjectRoles() + { + return $this->role->getProjectRoles(); + } +} diff --git a/app/Api/Procedure/BaseProcedure.php b/app/Api/Procedure/BaseProcedure.php new file mode 100644 index 00000000..0aa43428 --- /dev/null +++ b/app/Api/Procedure/BaseProcedure.php @@ -0,0 +1,86 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use JsonRPC\Exception\AccessDeniedException; +use Kanboard\Api\Authorization\ProcedureAuthorization; +use Kanboard\Api\Authorization\UserAuthorization; +use Kanboard\Core\Base; +use ReflectionClass; + +/** + * Base class + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +abstract class BaseProcedure extends Base +{ + public function beforeProcedure($procedure) + { + ProcedureAuthorization::getInstance($this->container)->check($procedure); + UserAuthorization::getInstance($this->container)->check($this->getClassName(), $procedure); + } + + protected function formatTask($task) + { + if (! empty($task)) { + $task['url'] = $this->helper->url->to('TaskViewController', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), '', true); + $task['color'] = $this->colorModel->getColorProperties($task['color_id']); + } + + 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('BoardViewController', 'show', array('project_id' => $project['id']), '', true), + 'calendar' => $this->helper->url->to('CalendarController', 'show', array('project_id' => $project['id']), '', true), + 'list' => $this->helper->url->to('TaskListController', '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; + } + + protected function filterValues(array $values) + { + foreach ($values as $key => $value) { + if (is_null($value)) { + unset($values[$key]); + } + } + + return $values; + } + + protected function getClassName() + { + $reflection = new ReflectionClass(get_called_class()); + return $reflection->getShortName(); + } +} diff --git a/app/Api/Procedure/BoardProcedure.php b/app/Api/Procedure/BoardProcedure.php new file mode 100644 index 00000000..674b5466 --- /dev/null +++ b/app/Api/Procedure/BoardProcedure.php @@ -0,0 +1,25 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\ProjectAuthorization; +use Kanboard\Formatter\BoardFormatter; + +/** + * Board API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class BoardProcedure extends BaseProcedure +{ + public function getBoard($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getBoard', $project_id); + + return BoardFormatter::getInstance($this->container) + ->withProjectId($project_id) + ->withQuery($this->taskFinderModel->getExtendedQuery()) + ->format(); + } +} diff --git a/app/Api/Procedure/CategoryProcedure.php b/app/Api/Procedure/CategoryProcedure.php new file mode 100644 index 00000000..3ebbd908 --- /dev/null +++ b/app/Api/Procedure/CategoryProcedure.php @@ -0,0 +1,59 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\CategoryAuthorization; +use Kanboard\Api\Authorization\ProjectAuthorization; + +/** + * Category API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class CategoryProcedure extends BaseProcedure +{ + public function getCategory($category_id) + { + CategoryAuthorization::getInstance($this->container)->check($this->getClassName(), 'getCategory', $category_id); + return $this->categoryModel->getById($category_id); + } + + public function getAllCategories($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllCategories', $project_id); + return $this->categoryModel->getAll($project_id); + } + + public function removeCategory($category_id) + { + CategoryAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeCategory', $category_id); + return $this->categoryModel->remove($category_id); + } + + public function createCategory($project_id, $name) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createCategory', $project_id); + + $values = array( + 'project_id' => $project_id, + 'name' => $name, + ); + + list($valid, ) = $this->categoryValidator->validateCreation($values); + return $valid ? $this->categoryModel->create($values) : false; + } + + public function updateCategory($id, $name) + { + CategoryAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateCategory', $id); + + $values = array( + 'id' => $id, + 'name' => $name, + ); + + list($valid, ) = $this->categoryValidator->validateModification($values); + return $valid && $this->categoryModel->update($values); + } +} diff --git a/app/Api/Procedure/ColumnProcedure.php b/app/Api/Procedure/ColumnProcedure.php new file mode 100644 index 00000000..ab9d173b --- /dev/null +++ b/app/Api/Procedure/ColumnProcedure.php @@ -0,0 +1,51 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\ColumnAuthorization; +use Kanboard\Api\Authorization\ProjectAuthorization; + +/** + * Column API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class ColumnProcedure extends BaseProcedure +{ + public function getColumns($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getColumns', $project_id); + return $this->columnModel->getAll($project_id); + } + + public function getColumn($column_id) + { + ColumnAuthorization::getInstance($this->container)->check($this->getClassName(), 'getColumn', $column_id); + return $this->columnModel->getById($column_id); + } + + public function updateColumn($column_id, $title, $task_limit = 0, $description = '') + { + ColumnAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateColumn', $column_id); + return $this->columnModel->update($column_id, $title, $task_limit, $description); + } + + public function addColumn($project_id, $title, $task_limit = 0, $description = '') + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addColumn', $project_id); + return $this->columnModel->create($project_id, $title, $task_limit, $description); + } + + public function removeColumn($column_id) + { + ColumnAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeColumn', $column_id); + return $this->columnModel->remove($column_id); + } + + public function changeColumnPosition($project_id, $column_id, $position) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeColumnPosition', $project_id); + return $this->columnModel->changePosition($project_id, $column_id, $position); + } +} diff --git a/app/Api/Procedure/CommentProcedure.php b/app/Api/Procedure/CommentProcedure.php new file mode 100644 index 00000000..019a49bb --- /dev/null +++ b/app/Api/Procedure/CommentProcedure.php @@ -0,0 +1,62 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\CommentAuthorization; +use Kanboard\Api\Authorization\TaskAuthorization; + +/** + * Comment API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class CommentProcedure extends BaseProcedure +{ + public function getComment($comment_id) + { + CommentAuthorization::getInstance($this->container)->check($this->getClassName(), 'getComment', $comment_id); + return $this->commentModel->getById($comment_id); + } + + public function getAllComments($task_id) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllComments', $task_id); + return $this->commentModel->getAll($task_id); + } + + public function removeComment($comment_id) + { + CommentAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeComment', $comment_id); + return $this->commentModel->remove($comment_id); + } + + public function createComment($task_id, $user_id, $content, $reference = '') + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'createComment', $task_id); + + $values = array( + 'task_id' => $task_id, + 'user_id' => $user_id, + 'comment' => $content, + 'reference' => $reference, + ); + + list($valid, ) = $this->commentValidator->validateCreation($values); + + return $valid ? $this->commentModel->create($values) : false; + } + + public function updateComment($id, $content) + { + CommentAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateComment', $id); + + $values = array( + 'id' => $id, + 'comment' => $content, + ); + + list($valid, ) = $this->commentValidator->validateModification($values); + return $valid && $this->commentModel->update($values); + } +} diff --git a/app/Api/Procedure/GroupMemberProcedure.php b/app/Api/Procedure/GroupMemberProcedure.php new file mode 100644 index 00000000..081d6ac8 --- /dev/null +++ b/app/Api/Procedure/GroupMemberProcedure.php @@ -0,0 +1,37 @@ +<?php + +namespace Kanboard\Api\Procedure; + +/** + * Group Member API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class GroupMemberProcedure extends BaseProcedure +{ + public function getMemberGroups($user_id) + { + return $this->groupMemberModel->getGroups($user_id); + } + + public function getGroupMembers($group_id) + { + return $this->groupMemberModel->getMembers($group_id); + } + + public function addGroupMember($group_id, $user_id) + { + return $this->groupMemberModel->addUser($group_id, $user_id); + } + + public function removeGroupMember($group_id, $user_id) + { + return $this->groupMemberModel->removeUser($group_id, $user_id); + } + + public function isGroupMember($group_id, $user_id) + { + return $this->groupMemberModel->isMember($group_id, $user_id); + } +} diff --git a/app/Api/Procedure/GroupProcedure.php b/app/Api/Procedure/GroupProcedure.php new file mode 100644 index 00000000..804940a2 --- /dev/null +++ b/app/Api/Procedure/GroupProcedure.php @@ -0,0 +1,49 @@ +<?php + +namespace Kanboard\Api\Procedure; + +/** + * Group API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class GroupProcedure extends BaseProcedure +{ + public function createGroup($name, $external_id = '') + { + return $this->groupModel->create($name, $external_id); + } + + public function updateGroup($group_id, $name = null, $external_id = null) + { + $values = array( + 'id' => $group_id, + 'name' => $name, + 'external_id' => $external_id, + ); + + foreach ($values as $key => $value) { + if (is_null($value)) { + unset($values[$key]); + } + } + + return $this->groupModel->update($values); + } + + public function removeGroup($group_id) + { + return $this->groupModel->remove($group_id); + } + + public function getGroup($group_id) + { + return $this->groupModel->getById($group_id); + } + + public function getAllGroups() + { + return $this->groupModel->getAll(); + } +} diff --git a/app/Api/Procedure/LinkProcedure.php b/app/Api/Procedure/LinkProcedure.php new file mode 100644 index 00000000..b4cecf3a --- /dev/null +++ b/app/Api/Procedure/LinkProcedure.php @@ -0,0 +1,111 @@ +<?php + +namespace Kanboard\Api\Procedure; + +/** + * Link API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class LinkProcedure extends BaseProcedure +{ + /** + * Get a link by id + * + * @access public + * @param integer $link_id Link id + * @return array + */ + public function getLinkById($link_id) + { + return $this->linkModel->getById($link_id); + } + + /** + * Get a link by name + * + * @access public + * @param string $label + * @return array + */ + public function getLinkByLabel($label) + { + return $this->linkModel->getByLabel($label); + } + + /** + * Get the opposite link id + * + * @access public + * @param integer $link_id Link id + * @return integer + */ + public function getOppositeLinkId($link_id) + { + return $this->linkModel->getOppositeLinkId($link_id); + } + + /** + * Get all links + * + * @access public + * @return array + */ + public function getAllLinks() + { + return $this->linkModel->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->linkValidator->validateCreation($values); + return $valid ? $this->linkModel->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->linkValidator->validateModification($values); + return $valid && $this->linkModel->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->linkModel->remove($link_id); + } +} diff --git a/app/Api/Procedure/MeProcedure.php b/app/Api/Procedure/MeProcedure.php new file mode 100644 index 00000000..e59e6522 --- /dev/null +++ b/app/Api/Procedure/MeProcedure.php @@ -0,0 +1,72 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Model\SubtaskModel; + +/** + * Me API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class MeProcedure extends BaseProcedure +{ + public function getMe() + { + return $this->sessionStorage->user; + } + + public function getMyDashboard() + { + $user_id = $this->userSession->getId(); + $projects = $this->projectModel->getQueryColumnStats($this->projectPermissionModel->getActiveProjectIds($user_id))->findAll(); + $tasks = $this->taskFinderModel->getUserQuery($user_id)->findAll(); + + return array( + 'projects' => $this->formatProjects($projects), + 'tasks' => $this->formatTasks($tasks), + 'subtasks' => $this->subtaskModel->getUserQuery($user_id, array(SubtaskModel::STATUS_TODO, SubtaskModel::STATUS_INPROGRESS))->findAll(), + ); + } + + public function getMyActivityStream() + { + $project_ids = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId()); + return $this->helper->projectActivity->getProjectsEvents($project_ids, 100); + } + + public function createMyPrivateProject($name, $description = null) + { + if ($this->configModel->get('disable_private_project', 0) == 1) { + return false; + } + + $values = array( + 'name' => $name, + 'description' => $description, + 'is_private' => 1, + ); + + list($valid, ) = $this->projectValidator->validateCreation($values); + return $valid ? $this->projectModel->create($values, $this->userSession->getId(), true) : false; + } + + public function getMyProjectsList() + { + return $this->projectUserRoleModel->getProjectsByUser($this->userSession->getId()); + } + + public function getMyOverdueTasks() + { + return $this->taskFinderModel->getOverdueTasksByUser($this->userSession->getId()); + } + + public function getMyProjects() + { + $project_ids = $this->projectPermissionModel->getActiveProjectIds($this->userSession->getId()); + $projects = $this->projectModel->getAllByIds($project_ids); + + return $this->formatProjects($projects); + } +} diff --git a/app/Api/Procedure/ProjectPermissionProcedure.php b/app/Api/Procedure/ProjectPermissionProcedure.php new file mode 100644 index 00000000..e22e1d62 --- /dev/null +++ b/app/Api/Procedure/ProjectPermissionProcedure.php @@ -0,0 +1,69 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\ProjectAuthorization; +use Kanboard\Core\Security\Role; + +/** + * Project Permission API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class ProjectPermissionProcedure extends BaseProcedure +{ + public function getProjectUsers($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectUsers', $project_id); + return $this->projectUserRoleModel->getAllUsers($project_id); + } + + public function getAssignableUsers($project_id, $prepend_unassigned = false) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAssignableUsers', $project_id); + return $this->projectUserRoleModel->getAssignableUsersList($project_id, $prepend_unassigned); + } + + public function addProjectUser($project_id, $user_id, $role = Role::PROJECT_MEMBER) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addProjectUser', $project_id); + return $this->projectUserRoleModel->addUser($project_id, $user_id, $role); + } + + public function addProjectGroup($project_id, $group_id, $role = Role::PROJECT_MEMBER) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addProjectGroup', $project_id); + return $this->projectGroupRoleModel->addGroup($project_id, $group_id, $role); + } + + public function removeProjectUser($project_id, $user_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeProjectUser', $project_id); + return $this->projectUserRoleModel->removeUser($project_id, $user_id); + } + + public function removeProjectGroup($project_id, $group_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeProjectGroup', $project_id); + return $this->projectGroupRoleModel->removeGroup($project_id, $group_id); + } + + public function changeProjectUserRole($project_id, $user_id, $role) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeProjectUserRole', $project_id); + return $this->projectUserRoleModel->changeUserRole($project_id, $user_id, $role); + } + + public function changeProjectGroupRole($project_id, $group_id, $role) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeProjectGroupRole', $project_id); + return $this->projectGroupRoleModel->changeGroupRole($project_id, $group_id, $role); + } + + public function getProjectUserRole($project_id, $user_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectUserRole', $project_id); + return $this->projectUserRoleModel->getUserRole($project_id, $user_id); + } +} diff --git a/app/Api/Procedure/ProjectProcedure.php b/app/Api/Procedure/ProjectProcedure.php new file mode 100644 index 00000000..9187f221 --- /dev/null +++ b/app/Api/Procedure/ProjectProcedure.php @@ -0,0 +1,106 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\ProjectAuthorization; + +/** + * Project API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class ProjectProcedure extends BaseProcedure +{ + public function getProjectById($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectById', $project_id); + return $this->formatProject($this->projectModel->getById($project_id)); + } + + public function getProjectByName($name) + { + $project = $this->projectModel->getByName($name); + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectByName', $project['id']); + return $this->formatProject($project); + } + + public function getAllProjects() + { + return $this->formatProjects($this->projectModel->getAll()); + } + + public function removeProject($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeProject', $project_id); + return $this->projectModel->remove($project_id); + } + + public function enableProject($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'enableProject', $project_id); + return $this->projectModel->enable($project_id); + } + + public function disableProject($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'disableProject', $project_id); + return $this->projectModel->disable($project_id); + } + + public function enableProjectPublicAccess($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'enableProjectPublicAccess', $project_id); + return $this->projectModel->enablePublicAccess($project_id); + } + + public function disableProjectPublicAccess($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'disableProjectPublicAccess', $project_id); + return $this->projectModel->disablePublicAccess($project_id); + } + + public function getProjectActivities(array $project_ids) + { + foreach ($project_ids as $project_id) { + ProjectAuthorization::getInstance($this->container) + ->check($this->getClassName(), 'getProjectActivities', $project_id); + } + + return $this->helper->projectActivity->getProjectsEvents($project_ids); + } + + public function getProjectActivity($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getProjectActivity', $project_id); + return $this->helper->projectActivity->getProjectEvents($project_id); + } + + public function createProject($name, $description = null, $owner_id = 0, $identifier = null) + { + $values = array( + 'name' => $name, + 'description' => $description, + 'identifier' => $identifier, + ); + + list($valid, ) = $this->projectValidator->validateCreation($values); + return $valid ? $this->projectModel->create($values, $owner_id, $this->userSession->isLogged()) : false; + } + + public function updateProject($project_id, $name, $description = null, $owner_id = null, $identifier = null) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateProject', $project_id); + + $values = $this->filterValues(array( + 'id' => $project_id, + 'name' => $name, + 'description' => $description, + 'owner_id' => $owner_id, + 'identifier' => $identifier, + )); + + list($valid, ) = $this->projectValidator->validateModification($values); + return $valid && $this->projectModel->update($values); + } +} diff --git a/app/Api/Procedure/SubtaskProcedure.php b/app/Api/Procedure/SubtaskProcedure.php new file mode 100644 index 00000000..e2400912 --- /dev/null +++ b/app/Api/Procedure/SubtaskProcedure.php @@ -0,0 +1,74 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\SubtaskAuthorization; +use Kanboard\Api\Authorization\TaskAuthorization; + +/** + * Subtask API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class SubtaskProcedure extends BaseProcedure +{ + public function getSubtask($subtask_id) + { + SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSubtask', $subtask_id); + return $this->subtaskModel->getById($subtask_id); + } + + public function getAllSubtasks($task_id) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllSubtasks', $task_id); + return $this->subtaskModel->getAll($task_id); + } + + public function removeSubtask($subtask_id) + { + SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeSubtask', $subtask_id); + return $this->subtaskModel->remove($subtask_id); + } + + public function createSubtask($task_id, $title, $user_id = 0, $time_estimated = 0, $time_spent = 0, $status = 0) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'createSubtask', $task_id); + + $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->subtaskValidator->validateCreation($values); + return $valid ? $this->subtaskModel->create($values) : false; + } + + public function updateSubtask($id, $task_id, $title = null, $user_id = null, $time_estimated = null, $time_spent = null, $status = null) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateSubtask', $task_id); + + $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->subtaskValidator->validateApiModification($values); + return $valid && $this->subtaskModel->update($values); + } +} diff --git a/app/Api/Procedure/SubtaskTimeTrackingProcedure.php b/app/Api/Procedure/SubtaskTimeTrackingProcedure.php new file mode 100644 index 00000000..5d1988d6 --- /dev/null +++ b/app/Api/Procedure/SubtaskTimeTrackingProcedure.php @@ -0,0 +1,39 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\SubtaskAuthorization; + +/** + * Subtask Time Tracking API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + * @author Nikolaos Georgakis + */ +class SubtaskTimeTrackingProcedure extends BaseProcedure +{ + public function hasSubtaskTimer($subtask_id, $user_id) + { + SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'hasSubtaskTimer', $subtask_id); + return $this->subtaskTimeTrackingModel->hasTimer($subtask_id, $user_id); + } + + public function logSubtaskStartTime($subtask_id, $user_id) + { + SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'logSubtaskStartTime', $subtask_id); + return $this->subtaskTimeTrackingModel->logStartTime($subtask_id, $user_id); + } + + public function logSubtaskEndTime($subtask_id,$user_id) + { + SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'logSubtaskEndTime', $subtask_id); + return $this->subtaskTimeTrackingModel->logEndTime($subtask_id, $user_id); + } + + public function getSubtaskTimeSpent($subtask_id,$user_id) + { + SubtaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSubtaskTimeSpent', $subtask_id); + return $this->subtaskTimeTrackingModel->getTimeSpent($subtask_id, $user_id); + } +} diff --git a/app/Api/Procedure/SwimlaneProcedure.php b/app/Api/Procedure/SwimlaneProcedure.php new file mode 100644 index 00000000..9b7d181d --- /dev/null +++ b/app/Api/Procedure/SwimlaneProcedure.php @@ -0,0 +1,91 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\ProjectAuthorization; + +/** + * Swimlane API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class SwimlaneProcedure extends BaseProcedure +{ + public function getActiveSwimlanes($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getActiveSwimlanes', $project_id); + return $this->swimlaneModel->getSwimlanes($project_id); + } + + public function getAllSwimlanes($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllSwimlanes', $project_id); + return $this->swimlaneModel->getAll($project_id); + } + + public function getSwimlaneById($swimlane_id) + { + $swimlane = $this->swimlaneModel->getById($swimlane_id); + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSwimlaneById', $swimlane['project_id']); + return $swimlane; + } + + public function getSwimlaneByName($project_id, $name) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getSwimlaneByName', $project_id); + return $this->swimlaneModel->getByName($project_id, $name); + } + + public function getSwimlane($swimlane_id) + { + return $this->swimlaneModel->getById($swimlane_id); + } + + public function getDefaultSwimlane($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getDefaultSwimlane', $project_id); + return $this->swimlaneModel->getDefault($project_id); + } + + public function addSwimlane($project_id, $name, $description = '') + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'addSwimlane', $project_id); + return $this->swimlaneModel->create(array('project_id' => $project_id, 'name' => $name, 'description' => $description)); + } + + public function updateSwimlane($swimlane_id, $name, $description = null) + { + $values = array('id' => $swimlane_id, 'name' => $name); + + if (!is_null($description)) { + $values['description'] = $description; + } + + return $this->swimlaneModel->update($values); + } + + public function removeSwimlane($project_id, $swimlane_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeSwimlane', $project_id); + return $this->swimlaneModel->remove($project_id, $swimlane_id); + } + + public function disableSwimlane($project_id, $swimlane_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'disableSwimlane', $project_id); + return $this->swimlaneModel->disable($project_id, $swimlane_id); + } + + public function enableSwimlane($project_id, $swimlane_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'enableSwimlane', $project_id); + return $this->swimlaneModel->enable($project_id, $swimlane_id); + } + + public function changeSwimlanePosition($project_id, $swimlane_id, $position) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'changeSwimlanePosition', $project_id); + return $this->swimlaneModel->changePosition($project_id, $swimlane_id, $position); + } +} diff --git a/app/Api/Procedure/TaskFileProcedure.php b/app/Api/Procedure/TaskFileProcedure.php new file mode 100644 index 00000000..5aa7ea0b --- /dev/null +++ b/app/Api/Procedure/TaskFileProcedure.php @@ -0,0 +1,70 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\ProjectAuthorization; +use Kanboard\Api\Authorization\TaskAuthorization; +use Kanboard\Api\Authorization\TaskFileAuthorization; +use Kanboard\Core\ObjectStorage\ObjectStorageException; + +/** + * Task File API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class TaskFileProcedure extends BaseProcedure +{ + public function getTaskFile($file_id) + { + TaskFileAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTaskFile', $file_id); + return $this->taskFileModel->getById($file_id); + } + + public function getAllTaskFiles($task_id) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllTaskFiles', $task_id); + return $this->taskFileModel->getAll($task_id); + } + + public function downloadTaskFile($file_id) + { + TaskFileAuthorization::getInstance($this->container)->check($this->getClassName(), 'downloadTaskFile', $file_id); + + try { + $file = $this->taskFileModel->getById($file_id); + + if (! empty($file)) { + return base64_encode($this->objectStorage->get($file['path'])); + } + } catch (ObjectStorageException $e) { + $this->logger->error($e->getMessage()); + } + + return ''; + } + + public function createTaskFile($project_id, $task_id, $filename, $blob) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createTaskFile', $project_id); + + try { + return $this->taskFileModel->uploadContent($task_id, $filename, $blob); + } catch (ObjectStorageException $e) { + $this->logger->error($e->getMessage()); + return false; + } + } + + public function removeTaskFile($file_id) + { + TaskFileAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeTaskFile', $file_id); + return $this->taskFileModel->remove($file_id); + } + + public function removeAllTaskFiles($task_id) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeAllTaskFiles', $task_id); + return $this->taskFileModel->removeAll($task_id); + } +} diff --git a/app/Api/Procedure/TaskLinkProcedure.php b/app/Api/Procedure/TaskLinkProcedure.php new file mode 100644 index 00000000..375266fb --- /dev/null +++ b/app/Api/Procedure/TaskLinkProcedure.php @@ -0,0 +1,85 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\TaskAuthorization; +use Kanboard\Api\Authorization\TaskLinkAuthorization; + +/** + * TaskLink API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class TaskLinkProcedure extends BaseProcedure +{ + /** + * Get a task link + * + * @access public + * @param integer $task_link_id Task link id + * @return array + */ + public function getTaskLinkById($task_link_id) + { + TaskLinkAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTaskLinkById', $task_link_id); + return $this->taskLinkModel->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) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllTaskLinks', $task_id); + return $this->taskLinkModel->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) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'createTaskLink', $task_id); + return $this->taskLinkModel->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) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateTaskLink', $task_id); + return $this->taskLinkModel->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) + { + TaskLinkAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeTaskLink', $task_link_id); + return $this->taskLinkModel->remove($task_link_id); + } +} diff --git a/app/Api/Procedure/TaskProcedure.php b/app/Api/Procedure/TaskProcedure.php new file mode 100644 index 00000000..2d29a4ef --- /dev/null +++ b/app/Api/Procedure/TaskProcedure.php @@ -0,0 +1,167 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use Kanboard\Api\Authorization\ProjectAuthorization; +use Kanboard\Api\Authorization\TaskAuthorization; +use Kanboard\Filter\TaskProjectFilter; +use Kanboard\Model\TaskModel; + +/** + * Task API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class TaskProcedure extends BaseProcedure +{ + public function searchTasks($project_id, $query) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'searchTasks', $project_id); + return $this->taskLexer->build($query)->withFilter(new TaskProjectFilter($project_id))->toArray(); + } + + public function getTask($task_id) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTask', $task_id); + return $this->formatTask($this->taskFinderModel->getById($task_id)); + } + + public function getTaskByReference($project_id, $reference) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getTaskByReference', $project_id); + return $this->formatTask($this->taskFinderModel->getByReference($project_id, $reference)); + } + + public function getAllTasks($project_id, $status_id = TaskModel::STATUS_OPEN) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getAllTasks', $project_id); + return $this->formatTasks($this->taskFinderModel->getAll($project_id, $status_id)); + } + + public function getOverdueTasks() + { + return $this->taskFinderModel->getOverdueTasks(); + } + + public function getOverdueTasksByProject($project_id) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'getOverdueTasksByProject', $project_id); + return $this->taskFinderModel->getOverdueTasksByProject($project_id); + } + + public function openTask($task_id) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'openTask', $task_id); + return $this->taskStatusModel->open($task_id); + } + + public function closeTask($task_id) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'closeTask', $task_id); + return $this->taskStatusModel->close($task_id); + } + + public function removeTask($task_id) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'removeTask', $task_id); + return $this->taskModel->remove($task_id); + } + + public function moveTaskPosition($project_id, $task_id, $column_id, $position, $swimlane_id = 0) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'moveTaskPosition', $project_id); + return $this->taskPositionModel->movePosition($project_id, $task_id, $column_id, $position, $swimlane_id); + } + + public function moveTaskToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'moveTaskToProject', $project_id); + return $this->taskDuplicationModel->moveToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_id); + } + + public function duplicateTaskToProject($task_id, $project_id, $swimlane_id = null, $column_id = null, $category_id = null, $owner_id = null) + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'duplicateTaskToProject', $project_id); + return $this->taskDuplicationModel->duplicateToProject($task_id, $project_id, $swimlane_id, $column_id, $category_id, $owner_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, $priority = 0, + $recurrence_status = 0, $recurrence_trigger = 0, $recurrence_factor = 0, $recurrence_timeframe = 0, + $recurrence_basedate = 0, $reference = '') + { + ProjectAuthorization::getInstance($this->container)->check($this->getClassName(), 'createTask', $project_id); + + if ($owner_id !== 0 && ! $this->projectPermissionModel->isAssignable($project_id, $owner_id)) { + return false; + } + + if ($this->userSession->isLogged()) { + $creator_id = $this->userSession->getId(); + } + + $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, + 'reference' => $reference, + 'priority' => $priority, + ); + + list($valid, ) = $this->taskValidator->validateCreation($values); + + return $valid ? $this->taskCreationModel->create($values) : false; + } + + public function updateTask($id, $title = null, $color_id = null, $owner_id = null, + $date_due = null, $description = null, $category_id = null, $score = null, $priority = null, + $recurrence_status = null, $recurrence_trigger = null, $recurrence_factor = null, + $recurrence_timeframe = null, $recurrence_basedate = null, $reference = null) + { + TaskAuthorization::getInstance($this->container)->check($this->getClassName(), 'updateTask', $id); + $project_id = $this->taskFinderModel->getProjectId($id); + + if ($project_id === 0) { + return false; + } + + if ($owner_id !== null && $owner_id != 0 && ! $this->projectPermissionModel->isAssignable($project_id, $owner_id)) { + return false; + } + + $values = $this->filterValues(array( + 'id' => $id, + 'title' => $title, + 'color_id' => $color_id, + 'owner_id' => $owner_id, + 'date_due' => $date_due, + 'description' => $description, + 'category_id' => $category_id, + 'score' => $score, + 'recurrence_status' => $recurrence_status, + 'recurrence_trigger' => $recurrence_trigger, + 'recurrence_factor' => $recurrence_factor, + 'recurrence_timeframe' => $recurrence_timeframe, + 'recurrence_basedate' => $recurrence_basedate, + 'reference' => $reference, + 'priority' => $priority, + )); + + list($valid) = $this->taskValidator->validateApiModification($values); + return $valid && $this->taskModificationModel->update($values); + } +} diff --git a/app/Api/Procedure/UserProcedure.php b/app/Api/Procedure/UserProcedure.php new file mode 100644 index 00000000..145f85bf --- /dev/null +++ b/app/Api/Procedure/UserProcedure.php @@ -0,0 +1,131 @@ +<?php + +namespace Kanboard\Api\Procedure; + +use LogicException; +use Kanboard\Core\Security\Role; +use Kanboard\Core\Ldap\Client as LdapClient; +use Kanboard\Core\Ldap\ClientException as LdapException; +use Kanboard\Core\Ldap\User as LdapUser; + +/** + * User API controller + * + * @package Kanboard\Api\Procedure + * @author Frederic Guillot + */ +class UserProcedure extends BaseProcedure +{ + public function getUser($user_id) + { + return $this->userModel->getById($user_id); + } + + public function getUserByName($username) + { + return $this->userModel->getByUsername($username); + } + + public function getAllUsers() + { + return $this->userModel->getAll(); + } + + public function removeUser($user_id) + { + return $this->userModel->remove($user_id); + } + + public function disableUser($user_id) + { + return $this->userModel->disable($user_id); + } + + public function enableUser($user_id) + { + return $this->userModel->enable($user_id); + } + + public function isActiveUser($user_id) + { + return $this->userModel->isActive($user_id); + } + + public function createUser($username, $password, $name = '', $email = '', $role = Role::APP_USER) + { + $values = array( + 'username' => $username, + 'password' => $password, + 'confirmation' => $password, + 'name' => $name, + 'email' => $email, + 'role' => $role, + ); + + list($valid, ) = $this->userValidator->validateCreation($values); + return $valid ? $this->userModel->create($values) : false; + } + + /** + * Create LDAP user in the database + * + * Only "anonymous" and "proxy" LDAP authentication are supported by this method + * + * User information will be fetched from the LDAP server + * + * @access public + * @param string $username + * @return bool|int + */ + public function createLdapUser($username) + { + if (LDAP_BIND_TYPE === 'user') { + $this->logger->error('LDAP authentication "user" is not supported by this API call'); + return false; + } + + try { + + $ldap = LdapClient::connect(); + $ldap->setLogger($this->logger); + $user = LdapUser::getUser($ldap, $username); + + if ($user === null) { + $this->logger->info('User not found in LDAP server'); + return false; + } + + if ($user->getUsername() === '') { + throw new LogicException('Username not found in LDAP profile, check the parameter LDAP_USER_ATTRIBUTE_USERNAME'); + } + + $values = array( + 'username' => $user->getUsername(), + 'name' => $user->getName(), + 'email' => $user->getEmail(), + 'role' => $user->getRole(), + 'is_ldap_user' => 1, + ); + + return $this->userModel->create($values); + + } catch (LdapException $e) { + $this->logger->error($e->getMessage()); + return false; + } + } + + public function updateUser($id, $username = null, $name = null, $email = null, $role = null) + { + $values = $this->filterValues(array( + 'id' => $id, + 'username' => $username, + 'name' => $name, + 'email' => $email, + 'role' => $role, + )); + + list($valid, ) = $this->userValidator->validateApiModification($values); + return $valid && $this->userModel->update($values); + } +} |