diff --git a/appinfo/routes.php b/appinfo/routes.php index 90dffb520..dd55fb408 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -3,6 +3,7 @@ * @copyright Copyright (c) 2016 Julius Härtl * * @author Julius Härtl + * @author Ryan Fletcher * * @license GNU AGPL version 3 or any later version * @@ -76,5 +77,43 @@ ['name' => 'label#update', 'url' => '/labels/{labelId}', 'verb' => 'PUT'], ['name' => 'label#delete', 'url' => '/labels/{labelId}', 'verb' => 'DELETE'], + // api + ['name' => 'board_api#index', 'url' => '/api/v1.0/boards', 'verb' => 'GET'], + ['name' => 'board_api#get', 'url' => '/api/v1.0/boards/{boardId}', 'verb' => 'GET'], + ['name' => 'board_api#create', 'url' => '/api/v1.0/boards', 'verb' => 'POST'], + ['name' => 'board_api#delete', 'url' => '/api/v1.0/boards/{boardId}', 'verb' => 'DELETE'], + ['name' => 'board_api#update', 'url' => '/api/v1.0/boards/{boardId}', 'verb' => 'PUT'], + ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/boards/{boardId}/undo_delete', 'verb' => 'POST'], + + ['name' => 'stack_api#index', 'url' => '/api/v1.0/boards/{boardId}/stacks', 'verb' => 'GET'], + ['name' => 'stack_api#getArchived', 'url' => '/api/v1.0/boards/{boardId}/stacks/archived', 'verb' => 'GET'], + ['name' => 'stack_api#get', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}', 'verb' => 'GET'], + ['name' => 'stack_api#create', 'url' => '/api/v1.0/boards/{boardId}/stacks', 'verb' => 'POST'], + ['name' => 'stack_api#update', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}', 'verb' => 'PUT'], + ['name' => 'stack_api#delete', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}', 'verb' => 'DELETE'], + + ['name' => 'card_api#get', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'GET'], + ['name' => 'card_api#create', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards', 'verb' => 'POST'], + ['name' => 'card_api#update', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'PUT'], + ['name' => 'card_api#assignLabel', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/assignLabel', 'verb' => 'PUT'], + ['name' => 'card_api#removeLabel', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/removeLabel', 'verb' => 'PUT'], + ['name' => 'card_api#assignUser', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/assignUser', 'verb' => 'PUT'], + ['name' => 'card_api#unassignUser', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/unassignUser', 'verb' => 'PUT'], + ['name' => 'card_api#reorder', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/reorder', 'verb' => 'PUT'], + ['name' => 'card_api#delete', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'DELETE'], + + ['name' => 'label_api#get', 'url' => '/api/v1.0/boards/{boardId}/labels/{labelId}', 'verb' => 'GET'], + ['name' => 'label_api#create', 'url' => '/api/v1.0/boards/{boardId}/labels', 'verb' => 'POST'], + ['name' => 'label_api#update', 'url' => '/api/v1.0/boards/{boardId}/labels/{labelId}', 'verb' => 'PUT'], + ['name' => 'label_api#delete', 'url' => '/api/v1.0/boards/{boardId}/labels/{labelId}', 'verb' => 'DELETE'], + + ['name' => 'attachment_api#getAll', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments', 'verb' => 'GET'], + ['name' => 'attachment_api#display', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}', 'verb' => 'GET'], + ['name' => 'attachment_api#create', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments', 'verb' => 'POST'], + ['name' => 'attachment_api#update', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}', 'verb' => 'PUT'], + ['name' => 'attachment_api#delete', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}', 'verb' => 'DELETE'], + ['name' => 'attachment_api#restore', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/attachments/{attachmentId}/restore', 'verb' => 'PUT'], + + ['name' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}','verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ] ]; diff --git a/lib/BadRequestException.php b/lib/BadRequestException.php new file mode 100644 index 000000000..b3ffb98c1 --- /dev/null +++ b/lib/BadRequestException.php @@ -0,0 +1,36 @@ + + * + * @author Ryan Fletcher + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Deck; + +use OCP\AppFramework\Http; +class BadRequestException extends StatusException { + + public function __construct($message) { + parent::__construct($message); + } + + public function getStatus() { + return HTTP::STATUS_BAD_REQUEST; + } +} \ No newline at end of file diff --git a/lib/Controller/AttachmentApiController.php b/lib/Controller/AttachmentApiController.php new file mode 100644 index 000000000..8e82739a0 --- /dev/null +++ b/lib/Controller/AttachmentApiController.php @@ -0,0 +1,105 @@ + + * + * @author Ryan Fletcher + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\Deck\Controller; + +use OCP\AppFramework\ApiController; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; +use OCA\Deck\Service\AttachmentService; + +class AttachmentApiController extends ApiController { + + private $attachmentService; + + public function __construct($appName, IRequest $request, AttachmentService $attachmentService) { + parent::__construct($appName, $request); + $this->attachmentService = $attachmentService; + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + */ + public function getAll() { + $attachment = $this->attachmentService->findAll($this->request->getParam('cardId')); + return new DataResponse($attachment, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + */ + public function display() { + $attachment = $this->attachmentService->display($this->request->getParam('cardId'), $this->request->getParam('attachmentId')); + return new DataResponse($attachment, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + */ + public function create($type, $data) { + $attachment = $this->attachmentService->create($this->request->getParam('cardId'), $type, $data); + return new DataResponse($attachment, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + */ + public function update($data) { + $attachment = $this->attachmentService->update($this->request->getParam('cardId'), $this->request->getParam('attachmentId'), $data); + return new DataResponse($attachment, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + */ + public function delete() { + $attachment = $this->attachmentService->delete($this->request->getParam('cardId'), $this->request->getParam('attachmentId')); + return new DataResponse($attachment, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + */ + public function restore() { + $attachment = $this->attachmentService->restore($this->request->getParam('cardId'), $this->request->getParam('attachmentId')); + return new DataResponse($attachment, HTTP::STATUS_OK); + } +} \ No newline at end of file diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php new file mode 100644 index 000000000..d45644eef --- /dev/null +++ b/lib/Controller/BoardApiController.php @@ -0,0 +1,137 @@ + + * + * @author Steven R. Baker + * @author Ryan Fletcher + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Deck\Controller; + +use OCP\AppFramework\ApiController; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; + +use OCA\Deck\Service\BoardService; + +/** + * Class BoardApiController + * + * @package OCA\Deck\Controller + */ +class BoardApiController extends ApiController { + + private $service; + + /** + * @param string $appName + * @param IRequest $request + * @param BoardService $service + * @param $userId + */ + public function __construct($appName, IRequest $request, BoardService $service, $userId) { + parent::__construct($appName, $request); + $this->service = $service; + $this->userId = $userId; + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Return all of the boards that the current user has access to. + */ + public function index() { + $boards = $this->service->findAll(); + return new DataResponse($boards, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * + * Return the board specified by $this->request->getParam('boardId'). + */ + public function get() { + $board = $this->service->find($this->request->getParam('boardId')); + return new DataResponse($board, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $color + * + * Create a board with the specified title and color. + */ + public function create($title, $color) { + $board = $this->service->create($title, $this->userId, $color); + return new DataResponse($board, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $color + * @params $archived + * + * Update a board with the specified boardId, title and color, and archived state. + */ + public function update($title, $color, $archived = false) { + $board = $this->service->update($this->request->getParam('boardId'), $title, $color, $archived); + return new DataResponse($board, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * + * Delete the board specified by $boardId. Return the board that was deleted. + */ + public function delete() { + $board = $this->service->delete($this->request->getParam('boardId')); + return new DataResponse($board, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * + * Undo the deletion of the board specified by $boardId. + */ + public function undoDelete() { + $board = $this->service->deleteUndo($this->request->getParam('boardId')); + return new DataResponse($board, HTTP::STATUS_OK); + } + +} diff --git a/lib/Controller/BoardController.php b/lib/Controller/BoardController.php index 0ecd044b1..6cb65ff01 100644 --- a/lib/Controller/BoardController.php +++ b/lib/Controller/BoardController.php @@ -35,40 +35,20 @@ class BoardController extends ApiController { private $userId; private $boardService; - private $userManager; - private $groupManager; private $permissionService; - private $userInfo; - public function __construct($appName, IRequest $request, IUserManager $userManager, IGroupManager $groupManager, BoardService $boardService, PermissionService $permissionService, $userId) { + public function __construct($appName, IRequest $request, BoardService $boardService, PermissionService $permissionService, $userId) { parent::__construct($appName, $request); $this->userId = $userId; - $this->userManager = $userManager; - $this->groupManager = $groupManager; $this->boardService = $boardService; $this->permissionService = $permissionService; - $this->userInfo = $this->getBoardPrerequisites(); - } - - /** - * TODO: move to boardservice - * @return array - */ - private function getBoardPrerequisites() { - $groups = $this->groupManager->getUserGroupIds( - $this->userManager->get($this->userId) - ); - return [ - 'user' => $this->userId, - 'groups' => $groups - ]; } /** * @NoAdminRequired */ public function index() { - return $this->boardService->findAll($this->userInfo); + return $this->boardService->findAll(); } /** diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php new file mode 100644 index 000000000..5aa45d0f6 --- /dev/null +++ b/lib/Controller/CardApiController.php @@ -0,0 +1,158 @@ + + * + * @author Ryan Fletcher + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + namespace OCA\Deck\Controller; + + use OCP\AppFramework\ApiController; + use OCP\AppFramework\Http; + use OCP\AppFramework\Http\DataResponse; + use OCP\IRequest; + use OCA\Deck\Service\CardService; + + /** + * Class BoardApiController + * + * @package OCA\Deck\Controller + */ +class CardApiController extends ApiController { + private $cardService; + private $userId; + + /** + * @param string $appName + * @param IRequest $request + * @param CardService $cardService + * @param $userId + */ + public function __construct($appName, IRequest $request, CardService $cardService, $userId) { + parent::__construct($appName, $request); + $this->cardService = $cardService; + $this->userId = $userId; + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Get a specific card. + */ + public function get() { + $card = $this->cardService->find($this->request->getParam('cardId')); + return new DataResponse($card, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $type + * @params $order + * + * Get a specific card. + */ + public function create($title, $type = 'plain', $order = 999) { + $card = $this->cardService->create($title, $this->request->getParam('stackId'), $type, $order, $this->userId); + return new DataResponse($card, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * + * Update a card + */ + public function update($title, $type, $order = 0, $description = '', $owner, $duedate = null) { + $card = $this->cardService->update($this->request->getParam('cardId'), $title, $this->request->getParam('stackId'), $type, $order, $description, $owner, $duedate, 0); + return new DataResponse($card, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Delete a specific card. + */ + public function delete() { + $card = $this->cardService->delete($this->request->getParam('cardId')); + return new DataResponse($card, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Assign a label to a card. + */ + public function assignLabel($labelId) { + $card = $this->cardService->assignLabel($this->request->getParam('cardId'), $labelId); + return new DataResponse($card, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Assign a label to a card. + */ + public function removeLabel($labelId) { + $card = $this->cardService->removeLabel($this->request->getParam('cardId'), $labelId); + return new DataResponse($card, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Unassign a label to a card. + */ + public function unassignUser($userId) { + $card = $this->cardService->unassignUser($this->request->getParam('cardId'), $userId); + return new DataResponse($card, HTTP::STATUS_OK); + } + + public function assignUser($userId) { + $card = $this->cardService->assignUser($this->request->getParam('cardId'), $userId);; + return new DataResponse($card, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Unassign a label to a card. + */ + public function reorder($stackId, $order) { + $card = $this->cardService->reorder($this->request->getParam('cardId'), $stackId, $order); + return new DataResponse($card, HTTP::STATUS_OK); + } +} \ No newline at end of file diff --git a/lib/Controller/LabelApiController.php b/lib/Controller/LabelApiController.php new file mode 100644 index 000000000..87f729d8b --- /dev/null +++ b/lib/Controller/LabelApiController.php @@ -0,0 +1,107 @@ + + * + * @author Ryan Fletcher + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Deck\Controller; + +use OCP\AppFramework\ApiController; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; +use OCA\Deck\Service\LabelService; +use OCA\Deck\Controller\Helper\ApiHelper; + + /** + * Class BoardApiController + * + * @package OCA\Deck\Controller + */ +class LabelApiController extends ApiController { + + private $labelService; + private $userId; + + /** + * @param string $appName + * @param IRequest $request + * @param LabelService $labelService + * @param $userId + */ + public function __construct($appName, IRequest $request, LabelService $labelService, $userId) { + parent::__construct($appName, $request); + $this->labelService = $labelService; + $this->userId = $userId; + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Get a specific label. + */ + public function get() { + $label = $this->labelService->find($this->request->getParam('labelId')); + return new DataResponse($label, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $color + * Create a new label + */ + public function create($title, $color) { + $label = $this->labelService->create($title, $color, $this->request->getParam('boardId')); + return new DataResponse($label, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $color + * Update a specific label + */ + public function update($title, $color) { + $label = $this->labelService->update($this->request->getParam('labelId'), $title, $color); + return new DataResponse($label, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Delete a specific label + */ + public function delete() { + $label = $this->labelService->delete($this->request->getParam('labelId')); + return new DataResponse($label, HTTP::STATUS_OK); + } + +} \ No newline at end of file diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php new file mode 100644 index 000000000..6e4fb3867 --- /dev/null +++ b/lib/Controller/StackApiController.php @@ -0,0 +1,132 @@ + + * + * @author Steven R. Baker + * @author Ryan Fletcher + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Deck\Controller; + +use OCP\AppFramework\ApiController; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; +use OCA\Deck\Service\StackService; +use OCA\Deck\Service\BoardService; + +/** + * Class StackApiController + * + * @package OCA\Deck\Controller + */ +class StackApiController extends ApiController { + + private $boardService; + private $stackService; + + /** + * @param string $appName + * @param IRequest $request + * @param StackService $stackService + */ + public function __construct($appName, IRequest $request, StackService $stackService, BoardService $boardService) { + parent::__construct($appName, $request); + $this->stackService = $stackService; + $this->boardService = $boardService; + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Return all of the stacks in the specified board. + */ + public function index() { + $stacks = $this->stackService->findAll($this->request->getParam('boardId')); + return new DataResponse($stacks, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Return all of the stacks in the specified board. + */ + public function get() { + $stack = $this->stackService->find($this->request->getParam('stackId')); + return new DataResponse($stack, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $order + * + * Create a stack with the specified title and order. + */ + public function create($title, $order) { + $stack = $this->stackService->create($title, $this->request->getParam('boardId'), $order); + return new DataResponse($stack, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $order + * + * Update a stack by the specified stackId and boardId with the values that were put. + */ + public function update($title, $order) { + $stack = $this->stackService->update($this->request->getParam('stackId'), $title, $this->request->getParam('boardId'), $order, 0); + return new DataResponse($stack, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Delete the stack specified by $this->request->getParam('stackId'). + */ + public function delete() { + $stack = $this->stackService->delete($this->request->getParam('stackId')); + return new DataResponse($stack, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * get the stacks that have been archived. + */ + public function getArchived() { + $stacks = $this->stackService->findAllArchived($this->request->getParam('boardId')); + return new DataResponse($stacks, HTTP::STATUS_OK); + } +} diff --git a/lib/Db/AssignedUsersMapper.php b/lib/Db/AssignedUsersMapper.php index e9323811f..a7e0ea0b6 100644 --- a/lib/Db/AssignedUsersMapper.php +++ b/lib/Db/AssignedUsersMapper.php @@ -40,6 +40,12 @@ public function __construct(IDBConnection $db, CardMapper $cardMapper, IUserMana $this->userManager = $userManager; } + /** + * FIXME: rename this since it returns multiple entities otherwise the naming is confusing with Entity::find + * + * @param $cardId + * @return array|Entity + */ public function find($cardId) { $sql = 'SELECT * FROM `*PREFIX*deck_assigned_users` ' . 'WHERE `card_id` = ?'; diff --git a/lib/Db/AttachmentMapper.php b/lib/Db/AttachmentMapper.php index 4ead87510..2ccae3be8 100644 --- a/lib/Db/AttachmentMapper.php +++ b/lib/Db/AttachmentMapper.php @@ -39,6 +39,13 @@ class AttachmentMapper extends DeckMapper implements IPermissionMapper { private $userManager; private $qb; + /** + * AttachmentMapper constructor. + * + * @param IDBConnection $db + * @param CardMapper $cardMapper + * @param IUserManager $userManager + */ public function __construct(IDBConnection $db, CardMapper $cardMapper, IUserManager $userManager) { parent::__construct($db, 'deck_attachment', Attachment::class); $this->cardMapper = $cardMapper; @@ -60,7 +67,17 @@ public function find($id) { $cursor = $qb->execute(); $row = $cursor->fetch(PDO::FETCH_ASSOC); + if($row === false) { + $cursor->closeCursor(); + throw new DoesNotExistException('Did expect one result but found none when executing' . $qb); + } + + $row2 = $cursor->fetch(); $cursor->closeCursor(); + if($row2 !== false ) { + throw new MultipleObjectsReturnedException('Did not expect more than one result when executing' . $query); + } + return $this->mapRowToEntity($row); } @@ -87,6 +104,11 @@ public function findAll($cardId) { return $entities; } + /** + * @param null $cardId + * @param bool $withOffset + * @return array + */ public function findToDelete($cardId = null, $withOffset = true) { // add buffer of 5 min $timeLimit = time() - (60 * 5); diff --git a/lib/Middleware/SharingMiddleware.php b/lib/Middleware/SharingMiddleware.php index 13fed3cb9..ec6eb81f1 100644 --- a/lib/Middleware/SharingMiddleware.php +++ b/lib/Middleware/SharingMiddleware.php @@ -24,6 +24,8 @@ namespace OCA\Deck\Middleware; use OCA\Deck\StatusException; +use OCA\Deck\BadRequestException; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Middleware; use OCP\AppFramework\Http\JSONResponse; use OCP\ILogger; @@ -68,6 +70,17 @@ public function afterException($controller, $methodName, \Exception $exception) 'message' => $exception->getMessage() ], $exception->getStatus()); } + + // uncatched DoesNotExistExceptions will be thrown when the main entity is not found + // we return a 403 so we don't leak information over existing entries + // TODO: At some point those should properly be catched in the service classes + if ($exception instanceof DoesNotExistException) { + return new JSONResponse([ + 'status' => 403, + 'message' => 'Permission denied' + ], 403); + } + throw $exception; } diff --git a/lib/Service/AttachmentService.php b/lib/Service/AttachmentService.php index a2bbcbc0a..e3f8c4898 100644 --- a/lib/Service/AttachmentService.php +++ b/lib/Service/AttachmentService.php @@ -104,8 +104,14 @@ public function getService($type) { * @param $cardId * @return array * @throws \OCA\Deck\NoPermissionException + * @throws BadRequestException */ public function findAll($cardId, $withDeleted = false) { + + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); $attachments = $this->attachmentMapper->findAll($cardId); @@ -123,7 +129,17 @@ public function findAll($cardId, $withDeleted = false) { return $attachments; } + /** + * @param $cardId + * @return int|mixed + * @throws BadRequestException + */ public function count($cardId) { + + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + $count = $this->cache->get('card-' . $cardId); if (!$count) { $count = count($this->attachmentMapper->findAll($cardId)); @@ -132,7 +148,29 @@ public function count($cardId) { return $count; } + /** + * @param $cardId + * @param $type + * @param $data + * @return Attachment|\OCP\AppFramework\Db\Entity + * @throws NoPermissionException + * @throws StatusException + * @throws BadRequestException + */ public function create($cardId, $type, $data) { + + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + + if ($type === false || $type === null) { + throw new BadRequestException('type must be provided'); + } + + if ($data === false || $data === null) { + throw new BadRequestException('data must be provided'); + } + $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); $this->cache->clear('card-' . $cardId); @@ -172,11 +210,24 @@ public function create($cardId, $type, $data) { * @param $cardId * @param $attachmentId * @return Response + * @throws \OCA\Deck\NotFoundException + * @throws NoPermissionException * @throws NotFoundException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\ + * @throws BadRequestException */ public function display($cardId, $attachmentId) { - $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + + if (is_numeric($attachmentId) === false) { + throw new BadRequestException('attachment id must be a number'); + } + + $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); $attachment = $this->attachmentMapper->find($attachmentId); try { @@ -197,10 +248,23 @@ public function display($cardId, $attachmentId) { * @throws \OCA\Deck\NoPermissionException * @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException */ public function update($cardId, $attachmentId, $data) { - $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + + if (is_numeric($attachmentId) === false) { + throw new BadRequestException('attachment id must be a number'); + } + + if ($data === false || $data === null) { + throw new BadRequestException('data must be provided'); + } + + $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); $this->cache->clear('card-' . $cardId); $attachment = $this->attachmentMapper->find($attachmentId); @@ -233,10 +297,19 @@ public function update($cardId, $attachmentId, $data) { * @throws \OCA\Deck\NoPermissionException * @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException */ public function delete($cardId, $attachmentId) { - $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + + if (is_numeric($attachmentId) === false) { + throw new BadRequestException('attachment id must be a number'); + } + + $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); $this->cache->clear('card-' . $cardId); $attachment = $this->attachmentMapper->find($attachmentId); @@ -254,8 +327,16 @@ public function delete($cardId, $attachmentId) { } public function restore($cardId, $attachmentId) { - $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + + if (is_numeric($attachmentId) === false) { + throw new BadRequestException('attachment id must be a number'); + } + + $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); $this->cache->clear('card-' . $cardId); $attachment = $this->attachmentMapper->find($attachmentId); diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index ab6baf225..51c59c8b3 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -30,10 +30,13 @@ use OCA\Deck\Db\Label; use OCA\Deck\Notification\NotificationHelper; use OCP\AppFramework\Db\DoesNotExistException; +use OCP\IGroupManager; use OCP\IL10N; use OCA\Deck\Db\Board; use OCA\Deck\Db\BoardMapper; use OCA\Deck\Db\LabelMapper; +use OCP\IUserManager; +use OCA\Deck\BadRequestException; class BoardService { @@ -45,6 +48,9 @@ class BoardService { private $permissionService; private $notificationHelper; private $assignedUsersMapper; + private $userManager; + private $groupManager; + private $userId; public function __construct( BoardMapper $boardMapper, @@ -53,7 +59,10 @@ public function __construct( AclMapper $aclMapper, PermissionService $permissionService, NotificationHelper $notificationHelper, - AssignedUsersMapper $assignedUsersMapper + AssignedUsersMapper $assignedUsersMapper, + IUserManager $userManager, + IGroupManager $groupManager, + $userId ) { $this->boardMapper = $boardMapper; $this->labelMapper = $labelMapper; @@ -62,9 +71,16 @@ public function __construct( $this->permissionService = $permissionService; $this->notificationHelper = $notificationHelper; $this->assignedUsersMapper = $assignedUsersMapper; + $this->userManager = $userManager; + $this->groupManager = $groupManager; + $this->userId = $userId; } - public function findAll($userInfo) { + /** + * @return array + */ + public function findAll() { + $userInfo = $this->getBoardPrerequisites(); $userBoards = $this->boardMapper->findAllByUser($userInfo['user']); $groupBoards = $this->boardMapper->findAllByGroups($userInfo['user'], $userInfo['groups']); $complete = array_merge($userBoards, $groupBoards); @@ -90,7 +106,20 @@ public function findAll($userInfo) { return array_values($result); } + /** + * @param $boardId + * @return Board + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function find($boardId) { + + if ( is_numeric($boardId) === false ) { + throw new BadRequestException('board id must be a number'); + } + $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ); /** @var Board $board */ $board = $this->boardMapper->find($boardId, true, true); @@ -112,7 +141,34 @@ public function find($boardId) { return $board; } + /** + * @return array + */ + private function getBoardPrerequisites() { + $groups = $this->groupManager->getUserGroupIds( + $this->userManager->get($this->userId) + ); + return [ + 'user' => $this->userId, + 'groups' => $groups + ]; + } + + /** + * @param $mapper + * @param $id + * @return bool + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function isArchived($mapper, $id) { + + if (is_numeric($id) === false) { + throw new BadRequestException('id must be a number'); + } + try { $boardId = $id; if ($mapper instanceof IPermissionMapper) { @@ -128,7 +184,25 @@ public function isArchived($mapper, $id) { return $board->getArchived(); } + /** + * @param $mapper + * @param $id + * @return bool + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function isDeleted($mapper, $id) { + + if ($mapper === false || $mapper === null) { + throw new BadRequestException('mapper must be provided'); + } + + if (is_numeric($id) === false) { + throw new BadRequestException('id must be a number'); + } + try { $boardId = $id; if ($mapper instanceof IPermissionMapper) { @@ -145,13 +219,32 @@ public function isDeleted($mapper, $id) { } - + /** + * @param $title + * @param $userId + * @param $color + * @return \OCP\AppFramework\Db\Entity + * @throws BadRequestException + */ public function create($title, $userId, $color) { + + if ($title === false || $title === null) { + throw new BadRequestException('title must be provided'); + } + + if ($userId === false || $userId === null) { + throw new BadRequestException('userId must be provided'); + } + + if ($color === false || $color === null) { + throw new BadRequestException('color must be provided'); + } + $board = new Board(); $board->setTitle($title); $board->setOwner($userId); $board->setColor($color); - $new_board = $this->boardMapper->insert($board); + $new_board = $this->boardMapper->insert($board); // create new labels $default_labels = [ @@ -181,7 +274,20 @@ public function create($title, $userId, $color) { } + /** + * @param $id + * @return Board + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function delete($id) { + + if (is_numeric($id) === false) { + throw new BadRequestException('board id must be a number'); + } + $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_READ); $board = $this->find($id); $board->setDeletedAt(time()); @@ -189,20 +295,72 @@ public function delete($id) { return $board; } + /** + * @param $id + * @return \OCP\AppFramework\Db\Entity + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + */ public function deleteUndo($id) { + + if (is_numeric($id) === false) { + throw new BadRequestException('board id must be a number'); + } + $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_READ); $board = $this->find($id); $board->setDeletedAt(0); return $this->boardMapper->update($board); } - public function deleteForce($id) { + /** + * @param $id + * @return \OCP\AppFramework\Db\Entity + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ + public function deleteForce($id) { + if (is_numeric($id) === false) { + throw new BadRequestException('id must be a number'); + } + $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_READ); $board = $this->find($id); return $this->boardMapper->delete($board); } + /** + * @param $id + * @param $title + * @param $color + * @param $archived + * @return \OCP\AppFramework\Db\Entity + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function update($id, $title, $color, $archived) { + + if (is_numeric($id) === false) { + throw new BadRequestException('board id must be a number'); + } + + if ($title === false || $title === null) { + throw new BadRequestException('color must be provided'); + } + + if ($color === false || $color === null) { + throw new BadRequestException('color must be provided'); + } + + if ( is_bool($archived) === false ) { + throw new BadRequestException('archived must be a boolean'); + } + $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE); $board = $this->find($id); $board->setTitle($title); @@ -213,7 +371,43 @@ public function update($id, $title, $color, $archived) { } + /** + * @param $boardId + * @param $type + * @param $participant + * @param $edit + * @param $share + * @param $manage + * @return \OCP\AppFramework\Db\Entity + * @throws \OCA\Deck\ + * @throws BadRequestException + */ public function addAcl($boardId, $type, $participant, $edit, $share, $manage) { + + if (is_numeric($boardId) === false) { + throw new BadRequestException('board id must be a number'); + } + + if ($type === false || $type === null) { + throw new BadRequestException('type must be provided'); + } + + if ($participant === false || $participant === null) { + throw new BadRequestException('participant must be provided'); + } + + if ($edit === false || $edit === null) { + throw new BadRequestException('edit must be provided'); + } + + if ($share === false || $share === null) { + throw new BadRequestException('share must be provided'); + } + + if ($manage === false || $manage === null) { + throw new BadRequestException('manage must be provided'); + } + $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_SHARE); $acl = new Acl(); $acl->setBoardId($boardId); @@ -231,7 +425,35 @@ public function addAcl($boardId, $type, $participant, $edit, $share, $manage) { return $newAcl; } + /** + * @param $id + * @param $edit + * @param $share + * @param $manage + * @return \OCP\AppFramework\Db\Entity + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function updateAcl($id, $edit, $share, $manage) { + + if (is_numeric($id) === false) { + throw new BadRequestException('id must be a number'); + } + + if ($edit === null) { + throw new BadRequestException('edit must be provided'); + } + + if ($share === null) { + throw new BadRequestException('share must be provided'); + } + + if ($manage === null) { + throw new BadRequestException('manage must be provided'); + } + $this->permissionService->checkPermission($this->aclMapper, $id, Acl::PERMISSION_SHARE); /** @var Acl $acl */ $acl = $this->aclMapper->find($id); @@ -242,7 +464,20 @@ public function updateAcl($id, $edit, $share, $manage) { return $this->aclMapper->update($acl); } + /** + * @param $id + * @return \OCP\AppFramework\Db\Entity + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function deleteAcl($id) { + + if (is_numeric($id) === false) { + throw new BadRequestException('id must be a number'); + } + $this->permissionService->checkPermission($this->aclMapper, $id, Acl::PERMISSION_SHARE); /** @var Acl $acl */ $acl = $this->aclMapper->find($id); diff --git a/lib/Service/CardService.php b/lib/Service/CardService.php index fcf691ecc..f1b76fc0a 100644 --- a/lib/Service/CardService.php +++ b/lib/Service/CardService.php @@ -34,7 +34,7 @@ use OCA\Deck\Db\LabelMapper; use OCA\Deck\NotFoundException; use OCA\Deck\StatusException; - +use OCA\Deck\BadRequestException; class CardService { @@ -89,7 +89,20 @@ public function fetchDeleted($boardId) { return $cards; } + /** + * @param $cardId + * @return \OCA\Deck\Db\RelationalEntity + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function find($cardId) { + + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); $card = $this->cardMapper->find($cardId); $assignedUsers = $this->assignedUsersMapper->find($card->getId()); @@ -100,9 +113,40 @@ public function find($cardId) { } /** + * @param $title + * @param $stackId + * @param $type * @param integer $order + * @param $owner + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadrequestException */ public function create($title, $stackId, $type, $order, $owner) { + + if ($title === 'false' || $title === null) { + throw new BadRequestException('title must be provided'); + } + + if (is_numeric($stackId) === false) { + throw new BadRequestException('stack id must be a number'); + } + + if ($type === 'false' || $type === null) { + throw new BadRequestException('type must be provided'); + } + + if (is_numeric($order) === false) { + throw new BadRequestException('order must be a number'); + } + + if ($owner === false || $owner === null) { + throw new BadRequestException('owner must be provided'); + } + $this->permissionService->checkPermission($this->stackMapper, $stackId, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->stackMapper, $stackId)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -114,10 +158,23 @@ public function create($title, $stackId, $type, $order, $owner) { $card->setOrder($order); $card->setOwner($owner); return $this->cardMapper->insert($card); - } + /** + * @param $id + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function delete($id) { + + if (is_numeric($id) === false) { + throw new BadRequestException('card id must be a number'); + } + $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -128,7 +185,44 @@ public function delete($id) { return $card; } - public function update($id, $title, $stackId, $type, $order, $description, $owner, $duedate, $deletedAt) { + /** + * @param $id + * @param $title + * @param $stackId + * @param $type + * @param $order + * @param $description + * @param $owner + * @param $duedate + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ + public function update($id, $title, $stackId, $type, $order = 0, $description = '', $owner, $duedate = null, $deletedAt) { + + if (is_numeric($id) === false) { + throw new BadRequestException('card id must be a number'); + } + + if ($title === false || $title === null) { + throw new BadRequestException('title must be provided'); + } + + if (is_numeric($stackId) === false) { + throw new BadRequestException('stack id must be a number $$$'); + } + + if ($type === false || $type === null) { + throw new BadRequestException('type must be provided'); + } + + if ($owner === false || $owner === null) { + throw new BadRequestException('owner must be provided'); + } + $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -148,7 +242,26 @@ public function update($id, $title, $stackId, $type, $order, $description, $owne return $this->cardMapper->update($card); } + /** + * @param $id + * @param $title + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function rename($id, $title) { + + if (is_numeric($id) === false) { + throw new BadRequestException('id must be a number'); + } + + if ($title === false || $title === null) { + throw new BadRequestException('title must be provided'); + } + $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -161,7 +274,31 @@ public function rename($id, $title) { return $this->cardMapper->update($card); } + /** + * @param $id + * @param $stackId + * @param $order + * @return array + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function reorder($id, $stackId, $order) { + + if (is_numeric($id) === false) { + throw new BadRequestException('card id must be a number'); + } + + if (is_numeric($stackId) === false) { + throw new BadRequestException('stack id must be a number'); + } + + if (is_numeric($order) === false) { + throw new BadRequestException('order must be a number'); + } + $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -192,7 +329,21 @@ public function reorder($id, $stackId, $order) { return $result; } + /** + * @param $id + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\ + * @throws BadRequestException + */ public function archive($id) { + + if (is_numeric($id) === false) { + throw new BadRequestException('id must be a number'); + } + $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -202,7 +353,21 @@ public function archive($id) { return $this->cardMapper->update($card); } + /** + * @param $id + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function unarchive($id) { + + if (is_numeric($id) === false) { + throw new BadRequestException('id must be a number'); + } + $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -212,7 +377,25 @@ public function unarchive($id) { return $this->cardMapper->update($card); } + /** + * @param $cardId + * @param $labelId + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function assignLabel($cardId, $labelId) { + + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + + if (is_numeric($labelId) === false) { + throw new BadRequestException('label id must be a number'); + } + $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $cardId)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -224,7 +407,25 @@ public function assignLabel($cardId, $labelId) { $this->cardMapper->assignLabel($cardId, $labelId); } + /** + * @param $cardId + * @param $labelId + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function removeLabel($cardId, $labelId) { + + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + + if (is_numeric($labelId) === false) { + throw new BadRequestException('label id must be a number'); + } + $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $cardId)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -236,7 +437,24 @@ public function removeLabel($cardId, $labelId) { $this->cardMapper->removeLabel($cardId, $labelId); } + /** + * @param $cardId + * @param $userId + * @return bool|null|\OCP\AppFramework\Db\Entity + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function assignUser($cardId, $userId) { + + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + + if ($userId === false || $userId === null) { + throw new BadRequestException('user id must be provided'); + } + $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); $assignments = $this->assignedUsersMapper->find($cardId); foreach ($assignments as $assignment) { @@ -257,8 +475,26 @@ public function assignUser($cardId, $userId) { return $this->assignedUsersMapper->insert($assignment); } + /** + * @param $cardId + * @param $userId + * @return \OCP\AppFramework\Db\Entity + * @throws NotFoundException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function unassignUser($cardId, $userId) { $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); + + if (is_numeric($cardId) === false) { + throw new BadRequestException('card id must be a number'); + } + + if ($userId === false || $userId === null) { + throw new BadRequestException('user must be provided'); + } + $assignments = $this->assignedUsersMapper->find($cardId); foreach ($assignments as $assignment) { if ($assignment->getParticipant() === $userId) { diff --git a/lib/Service/DefaultBoardService.php b/lib/Service/DefaultBoardService.php index f79b8d24e..5e16401f8 100644 --- a/lib/Service/DefaultBoardService.php +++ b/lib/Service/DefaultBoardService.php @@ -29,6 +29,7 @@ use OCA\Deck\Service\CardService; use OCP\IConfig; use OCP\IL10N; +use OCA\Deck\BadRequestException; class DefaultBoardService { @@ -55,8 +56,14 @@ public function __construct( $this->boardMapper = $boardMapper; $this->l10n = $l10n; } - - public function checkFirstRun($userId, $appName) { + + /** + * @param $userId + * @param $appName + * @return bool + * @throws \OCP\PreConditionNotMetException + */ + public function checkFirstRun($userId, $appName) { $firstRun = $this->config->getUserValue($userId, $appName, 'firstRun', 'yes'); $userBoards = $this->boardMapper->findAllByUser($userId); @@ -68,7 +75,31 @@ public function checkFirstRun($userId, $appName) { return false; } - public function createDefaultBoard($title, $userId, $color) { + /** + * @param $title + * @param $userId + * @param $color + * @return \OCP\AppFramework\Db\Entity + * @throws \OCA\Deck\NoPermissionException + * @throws \OCA\Deck\StatusException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ + public function createDefaultBoard($title, $userId, $color) { + + if ($title === false || $title === null) { + throw new BadRequestException('title must be provided'); + } + + if ($userId === false || $userId === null) { + throw new BadRequestException('userId must be provided'); + } + + if ($color === false || $color === null) { + throw new BadRequestException('color must be provided'); + } + $defaultBoard = $this->boardService->create($title, $userId, $color); $defaultStacks = []; $defaultCards = []; diff --git a/lib/Service/FileService.php b/lib/Service/FileService.php index a122d76c5..543371bf2 100644 --- a/lib/Service/FileService.php +++ b/lib/Service/FileService.php @@ -142,6 +142,11 @@ private function getUploadedFile () { return $file; } + /** + * @param Attachment $attachment + * @throws NotPermittedException + * @throws StatusException + */ public function create(Attachment $attachment) { $file = $this->getUploadedFile(); $folder = $this->getFolder($attachment); @@ -176,6 +181,10 @@ public function update(Attachment $attachment) { $attachment->setLastModified(time()); } + /** + * @param Attachment $attachment + * @throws NotPermittedException + */ public function delete(Attachment $attachment) { try { $file = $this->getFileForAttachment($attachment); @@ -202,6 +211,11 @@ private function getFileFromRootFolder(Attachment $attachment) { return $cardFolder->get($attachment->getData()); } + /** + * @param Attachment $attachment + * @return FileDisplayResponse|\OCP\AppFramework\Http\Response|StreamResponse + * @throws \Exception + */ public function display(Attachment $attachment) { $file = $this->getFileFromRootFolder($attachment); if (method_exists($file, 'fopen')) { diff --git a/lib/Service/LabelService.php b/lib/Service/LabelService.php index 2bb910083..098c95293 100644 --- a/lib/Service/LabelService.php +++ b/lib/Service/LabelService.php @@ -27,6 +27,7 @@ use OCA\Deck\Db\Acl; use OCA\Deck\Db\LabelMapper; use OCA\Deck\StatusException; +use OCA\Deck\BadRequestException; class LabelService { @@ -44,12 +45,47 @@ public function __construct(LabelMapper $labelMapper, PermissionService $permiss $this->boardService = $boardService; } + /** + * @param $labelId + * @return \OCP\AppFramework\Db\Entity + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function find($labelId) { + if (is_numeric($labelId) === false) { + throw new BadRequestException('label id must be a number'); + } $this->permissionService->checkPermission($this->labelMapper, $labelId, Acl::PERMISSION_READ); return $this->labelMapper->find($labelId); } + /** + * @param $title + * @param $color + * @param $boardId + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function create($title, $color, $boardId) { + + if ($title === false || $title === null) { + throw new BadRequestException('title must be provided'); + } + + if ($color === false || $color === null) { + throw new BadRequestException('color must be provided'); + } + + if (is_numeric($boardId) === false) { + throw new BadRequestException('board id must be a number'); + } + $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE); if ($this->boardService->isArchived(null, $boardId)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -61,7 +97,21 @@ public function create($title, $color, $boardId) { return $this->labelMapper->insert($label); } + /** + * @param $id + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function delete($id) { + + if (is_numeric($id) === false) { + throw new BadRequestException('label id must be a number'); + } + $this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE); if ($this->boardService->isArchived($this->labelMapper, $id)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -69,7 +119,31 @@ public function delete($id) { return $this->labelMapper->delete($this->find($id)); } + /** + * @param $id + * @param $title + * @param $color + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function update($id, $title, $color) { + + if (is_numeric($id) === false) { + throw new BadRequestException('label id must be a number'); + } + + if ($title === false || $title === null) { + throw new BadRequestException('title must be provided'); + } + + if ($color === false || $color === null) { + throw new BadRequestException('color must be provided'); + } + $this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE); if ($this->boardService->isArchived($this->labelMapper, $id)) { throw new StatusException('Operation not allowed. This board is archived.'); diff --git a/lib/Service/PermissionService.php b/lib/Service/PermissionService.php index 8b7e69d12..8bd0623aa 100644 --- a/lib/Service/PermissionService.php +++ b/lib/Service/PermissionService.php @@ -31,6 +31,8 @@ use OCA\Deck\Db\User; use OCA\Deck\NoPermissionException; use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\IGroupManager; use OCP\ILogger; use OCP\IUserManager; @@ -114,42 +116,41 @@ public function matchPermissions(Board $board) { * @throws NoPermissionException */ public function checkPermission($mapper, $id, $permission) { - try { - $boardId = $id; - if ($mapper instanceof IPermissionMapper) { - $boardId = $mapper->findBoardId($id); - } - if ($boardId === null) { - // Throw NoPermission to not leak information about existing entries - throw new NoPermissionException('Permission denied'); - } - - if ($this->userIsBoardOwner($boardId)) { - return true; - } - $acls = $this->aclMapper->findAll($boardId); - $result = $this->userCan($acls, $permission); - if ($result) { - return true; - } - - } catch (DoesNotExistException $exception) { + $boardId = $id; + if ($mapper instanceof IPermissionMapper) { + $boardId = $mapper->findBoardId($id); + } + if ($boardId === null) { // Throw NoPermission to not leak information about existing entries throw new NoPermissionException('Permission denied'); } - throw new NoPermissionException('Permission denied.'); + if ($this->userIsBoardOwner($boardId)) { + return true; + } + + $acls = $this->aclMapper->findAll($boardId); + $result = $this->userCan($acls, $permission); + if ($result) { + return true; + } + // Throw NoPermission to not leak information about existing entries + throw new NoPermissionException('Permission denied'); } /** * @param $boardId * @return bool - * @throws \OCP\AppFramework\Db\DoesNotExistException */ public function userIsBoardOwner($boardId) { - $board = $this->boardMapper->find($boardId); - return $board && $this->userId === $board->getOwner(); + try { + $board = $this->boardMapper->find($boardId); + return $board && $this->userId === $board->getOwner(); + } catch (DoesNotExistException $e) { + } catch (MultipleObjectsReturnedException $e) { + return false; + } } /** @@ -192,19 +193,34 @@ public function findUsers($boardId) { $board = $this->boardMapper->find($boardId); } catch (DoesNotExistException $e) { return []; + } catch (MultipleObjectsReturnedException $e) { + return []; } + $owner = $this->userManager->get($board->getOwner()); - $users = []; - $users[$owner->getUID()] = new User($owner); + if ($owner === null) { + $this->logger->info('No owner found for board ' . $board->getId()); + } else { + $users = []; + $users[$owner->getUID()] = new User($owner); + } $acls = $this->aclMapper->findAll($boardId); /** @var Acl $acl */ foreach ($acls as $acl) { if ($acl->getType() === Acl::PERMISSION_TYPE_USER) { $user = $this->userManager->get($acl->getParticipant()); + if ($user === null) { + $this->logger->info('No user found for acl rule ' . $acl->getId()); + continue; + } $users[$user->getUID()] = new User($user); } if ($acl->getType() === Acl::PERMISSION_TYPE_GROUP) { $group = $this->groupManager->get($acl->getParticipant()); + if ($group === null) { + $this->logger->info('No group found for acl rule ' . $acl->getId()); + continue; + } foreach ($group->getUsers() as $user) { $users[$user->getUID()] = new User($user); } diff --git a/lib/Service/StackService.php b/lib/Service/StackService.php index b64766e79..f2bdbaff8 100644 --- a/lib/Service/StackService.php +++ b/lib/Service/StackService.php @@ -31,8 +31,7 @@ use OCA\Deck\Db\Stack; use OCA\Deck\Db\StackMapper; use OCA\Deck\StatusException; -use OCP\ICache; -use OCP\ICacheFactory; +use OCA\Deck\BadRequestException; class StackService { @@ -89,7 +88,40 @@ private function enrichStacksWithCards($stacks) { } } + /** + * @param $stackId + * @return \OCP\AppFramework\Db\Entity + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ + public function find($stackId) { + if (is_numeric($stackId) === false) { + throw new BadRequestException('stack id must be a number'); + } + + $stack = $this->stackMapper->find($stackId); + $cards = $this->cardMapper->findAll($stackId); + foreach ($cards as $cardIndex => $card) { + $assignedUsers = $this->assignedUsersMapper->find($card->getId()); + $card->setAssignedUsers($assignedUsers); + $card->setAttachmentCount($this->attachmentService->count($card->getId())); + } + $stack->setCards($cards); + return $stack; + } + + /** + * @param $boardId + * @return array + * @throws \OCA\Deck\NoPermissionException + * @throws BadRequestException + */ public function findAll($boardId) { + if (is_numeric($boardId) === false) { + throw new BadRequestException('boardId must be a number'); + } + $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ); $stacks = $this->stackMapper->findAll($boardId); $this->enrichStacksWithCards($stacks); @@ -103,7 +135,18 @@ public function fetchDeleted($boardId) { return $stacks; } + /** + * @param $boardId + * @return array + * @throws \OCA\Deck\NoPermissionException + * @throws BadRequestException + */ public function findAllArchived($boardId) { + + if (is_numeric($boardId) === false) { + throw new BadRequestException('board id must be a number'); + } + $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ); $stacks = $this->stackMapper->findAll($boardId); $labels = $this->labelMapper->getAssignedLabelsForBoard($boardId); @@ -120,9 +163,30 @@ public function findAllArchived($boardId) { } /** + * @param $title + * @param $boardId * @param integer $order + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException */ public function create($title, $boardId, $order) { + + if ($title === false || $title === null) { + throw new BadRequestException('title must be provided'); + } + + if (is_numeric($order) === false) { + throw new BadRequestException('order must be a number'); + } + + if (is_numeric($boardId) === false) { + throw new BadRequestException('board id must be a number'); + } + $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE); if ($this->boardService->isArchived(null, $boardId)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -135,7 +199,20 @@ public function create($title, $boardId, $order) { } + /** + * @param $id + * @return \OCP\AppFramework\Db\Entity + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function delete($id) { + + if ( is_numeric($id) === false ) { + throw new BadRequestException('stack id must be a number'); + } + $this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE); $stack = $this->stackMapper->find($id); @@ -147,8 +224,37 @@ public function delete($id) { return $stack; } - + /** + * @param $id + * @param $title + * @param $boardId + * @param $order + * @param $deletedAt + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function update($id, $title, $boardId, $order, $deletedAt) { + + if (is_numeric($id) === false) { + throw new BadRequestException('stack id must be a number'); + } + + if ($title === false || $title === null) { + throw new BadRequestException('title must be provided'); + } + + if (is_numeric($boardId) === false) { + throw new BadRequestException('board id must be a number'); + } + + if (is_numeric($order) === false) { + throw new BadRequestException('order must be a number'); + } + $this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE); if ($this->boardService->isArchived($this->stackMapper, $id)) { throw new StatusException('Operation not allowed. This board is archived.'); @@ -161,7 +267,25 @@ public function update($id, $title, $boardId, $order, $deletedAt) { return $this->stackMapper->update($stack); } + /** + * @param $id + * @param $order + * @return array + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException + */ public function reorder($id, $order) { + + if (is_numeric($id) === false) { + throw new BadRquestException('id must be a number'); + } + + if ($order === false || $order === null) { + throw new BadRequestException('order must be provided'); + } + $this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_EDIT); $stackToSort = $this->stackMapper->find($id); $stacks = $this->stackMapper->findAll($stackToSort->getBoardId()); diff --git a/tests/unit/Service/BoardServiceTest.php b/tests/unit/Service/BoardServiceTest.php index c7b89e79f..5f9d5082d 100644 --- a/tests/unit/Service/BoardServiceTest.php +++ b/tests/unit/Service/BoardServiceTest.php @@ -33,6 +33,8 @@ use OCA\Deck\Db\LabelMapper; use OCA\Deck\Notification\NotificationHelper; use OCP\IUser; +use OCP\IUserManager; +use OCP\IGroupManager; use \Test\TestCase; class BoardServiceTest extends TestCase { @@ -53,8 +55,12 @@ class BoardServiceTest extends TestCase { private $notificationHelper; /** @var AssignedUsersMapper */ private $assignedUsersMapper; + /** @var IUserManager */ + private $userManager; + /** @var IUserManager */ + private $groupManager; - private $userId = 'admin'; + private $userId = 'admin'; public function setUp() { parent::setUp(); @@ -65,6 +71,8 @@ public function setUp() { $this->permissionService = $this->createMock(PermissionService::class); $this->notificationHelper = $this->createMock(NotificationHelper::class); $this->assignedUsersMapper = $this->createMock(AssignedUsersMapper::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->groupManager = $this->createMock(IGroupManager::class); $this->service = new BoardService( $this->boardMapper, @@ -73,11 +81,14 @@ public function setUp() { $this->aclMapper, $this->permissionService, $this->notificationHelper, - $this->assignedUsersMapper + $this->assignedUsersMapper, + $this->userManager, + $this->groupManager, + $this->userId ); $user = $this->createMock(IUser::class); - $user->method('getUID')->willReturn('admin'); + $user->method('getUID')->willReturn('admin'); } public function testFindAll() { @@ -95,11 +106,14 @@ public function testFindAll() { ->method('findAllByGroups') ->with('admin', ['a', 'b', 'c']) ->willReturn([$b2, $b3]); - $userinfo = [ - 'user' => 'admin', - 'groups' => ['a', 'b', 'c'] - ]; - $result = $this->service->findAll($userinfo); + $user = $this->createMock(IUser::class); + $this->groupManager->method('getUserGroupIds') + ->willReturn(['a', 'b', 'c']); + $this->userManager->method('get') + ->with($this->userId) + ->willReturn($user); + + $result = $this->service->findAll(); sort($result); $this->assertEquals([$b1, $b2, $b3], $result); } diff --git a/tests/unit/Service/CardServiceTest.php b/tests/unit/Service/CardServiceTest.php index 74f4ee0bf..b00c5889c 100644 --- a/tests/unit/Service/CardServiceTest.php +++ b/tests/unit/Service/CardServiceTest.php @@ -151,7 +151,7 @@ public function testUpdateArchived() { $card->setArchived(true); $this->cardMapper->expects($this->once())->method('find')->willReturn($card); $this->cardMapper->expects($this->never())->method('update'); - $this->setExpectedException(StatusException::class); + $this->expectException(StatusException::class); $this->cardService->update(123, 'newtitle', 234, 'text', 999, 'foo', 'admin', '2017-01-01 00:00:00', null); } @@ -171,7 +171,7 @@ public function testRenameArchived() { $card->setArchived(true); $this->cardMapper->expects($this->once())->method('find')->willReturn($card); $this->cardMapper->expects($this->never())->method('update'); - $this->setExpectedException(StatusException::class); + $this->expectException(StatusException::class); $this->cardService->rename(123, 'newtitle'); } @@ -211,7 +211,7 @@ public function testReorderArchived() { $card->setArchived(true); $this->cardMapper->expects($this->once())->method('findAll')->willReturn([$card]); $this->cardMapper->expects($this->never())->method('update')->willReturnCallback(function($c) { return $c; }); - $this->setExpectedException(StatusException::class); + $this->expectException(StatusException::class); $actual = $this->cardService->reorder(123, 234, 1); } public function testArchive() { @@ -247,7 +247,7 @@ public function testAssignLabelArchived() { $card->setArchived(true); $this->cardMapper->expects($this->once())->method('find')->willReturn($card); $this->cardMapper->expects($this->never())->method('assignLabel'); - $this->setExpectedException(StatusException::class); + $this->expectException(StatusException::class); $this->cardService->assignLabel(123, 999); } @@ -263,8 +263,8 @@ public function testRemoveLabelArchived() { $card = new Card(); $card->setArchived(true); $this->cardMapper->expects($this->once())->method('find')->willReturn($card); - $this->cardMapper->expects($this->never())->method('removeLabel'); - $this->setExpectedException(StatusException::class); + $this->cardMapper->expects($this->never())->method('removeLabel'); + $this->expectException(StatusException::class); $this->cardService->removeLabel(123, 999); } @@ -320,7 +320,10 @@ public function testUnassignUserExisting() { } /** - * @expectedException \OCA\Deck\NotFoundException + * @expectException \OCA\Deck\NotFoundException + * + * + * */ public function testUnassignUserNotExisting() { $assignment = new AssignedUsers(); @@ -333,8 +336,8 @@ public function testUnassignUserNotExisting() { ->method('find') ->with(123) ->willReturn($assignments); - $actual = $this->cardService->unassignUser(123, 'user'); - $this->assertEquals($assignment, $actual); + $this->expectException(NotFoundException::class); + $actual = $this->cardService->unassignUser(123, 'user'); } diff --git a/tests/unit/Service/DefaultBoardServiceTest.php b/tests/unit/Service/DefaultBoardServiceTest.php index ecabdfb61..59a16f342 100644 --- a/tests/unit/Service/DefaultBoardServiceTest.php +++ b/tests/unit/Service/DefaultBoardServiceTest.php @@ -66,7 +66,8 @@ public function setUp() { $this->stackService = $this->createMock(StackService::class); $this->cardService = $this->createMock(CardService::class); $this->config = $this->createMock(IConfig::class); - $this->l10n = $this->createMock(IL10N::class); + $this->l10n = $this->createMock(IL10N::class); + $this->userId = 'admin'; $this->service = new DefaultBoardService( $this->l10n, diff --git a/tests/unit/Service/PermissionServiceTest.php b/tests/unit/Service/PermissionServiceTest.php index f4c2f41ec..432c794aa 100644 --- a/tests/unit/Service/PermissionServiceTest.php +++ b/tests/unit/Service/PermissionServiceTest.php @@ -231,7 +231,7 @@ public function testCheckPermission($boardId, $permission, $result, $owner='foo' $actual = $this->service->checkPermission($mapper, 1234, $permission); $this->assertTrue($actual); } else { - $this->setExpectedException(NoPermissionException::class); + $this->expectException(NoPermissionException::class); $this->service->checkPermission($mapper, 1234, $permission); } @@ -255,7 +255,7 @@ public function testCheckPermissionWithoutMapper($boardId, $permission, $result, $actual = $this->service->checkPermission($mapper, 1234, $permission); $this->assertTrue($actual); } else { - $this->setExpectedException(NoPermissionException::class); + $this->expectException(NoPermissionException::class); $this->service->checkPermission($mapper, 1234, $permission); } @@ -263,8 +263,8 @@ public function testCheckPermissionWithoutMapper($boardId, $permission, $result, public function testCheckPermissionNotFound() { $mapper = $this->getMockBuilder(IPermissionMapper::class)->getMock(); - $mapper->expects($this->once())->method('findBoardId')->willThrowException(new NoPermissionException(null)); - $this->setExpectedException(NoPermissionException::class); + $mapper->expects($this->once())->method('findBoardId')->willThrowException(new NoPermissionException(null)); + $this->expectException(NoPermissionException::class); $this->service->checkPermission($mapper, 1234, Acl::PERMISSION_READ); } diff --git a/tests/unit/controller/AttachmentApiControllerTest.php b/tests/unit/controller/AttachmentApiControllerTest.php new file mode 100644 index 000000000..52458f527 --- /dev/null +++ b/tests/unit/controller/AttachmentApiControllerTest.php @@ -0,0 +1,172 @@ + + * + * @author Ryan Fletcher + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\Deck\Controller; + +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; + +use OCA\Deck\Service\AttachmentService; +use OCA\Deck\Db\Attachment; + +class AttachmentApiControllerTest extends \Test\TestCase { + + private $appName = 'deck'; + private $controller; + private $request; + private $attachmentExample; + private $cardId; + private $attachmentService; + + public function setUp() { + parent::setUp(); + $this->attachmentExample = new Attachment(); + $this->attachmentExample->setId(1); + $this->cardId = 1; + $this->request = $this->createMock(IRequest::class); + $this->attachmentService = $this->createMock(AttachmentService::class); + $this->controller = new AttachmentApiController( + $this->appName, + $this->request, + $this->attachmentService + ); + } + + public function testGetAll() { + + $allAttachments = [$this->attachmentExample]; + + $this->attachmentService->expects($this->once()) + ->method('findAll') + ->willReturn($allAttachments); + + $this->request->expects($this->once()) + ->method('getParam') + ->with('cardId') + ->willReturn($allAttachments); + + $expected = new DataResponse($allAttachments, HTTP::STATUS_OK); + $actual = $this->controller->getAll(); + $this->assertEquals($expected, $actual); + } + + public function testDisplay() { + + $this->attachmentService->expects($this->once()) + ->method('display') + ->willReturn($this->attachmentExample); + + $this->request->expects($this->exactly(2)) + ->method('getParam') + ->withConsecutive( + ['cardId'], + ['attachmentId'] + )->willReturnonConsecutiveCalls( + $this->cardId, + $this->attachmentExample->getId()); + + $expected = new DataResponse($this->attachmentExample, HTTP::STATUS_OK); + $actual = $this->controller->display(); + $this->assertEquals($expected, $actual); + } + + public function testCreate() { + + $type = 'not null'; + $data = ['not null']; + + $this->attachmentService->expects($this->once()) + ->method('create') + ->willReturn($this->attachmentExample); + + $this->request->expects($this->once()) + ->method('getParam') + ->with('cardId') + ->willReturn($this->cardId); + + $expected = new DataResponse($this->attachmentExample, HTTP::STATUS_OK); + $actual = $this->controller->create($type, $data); + $this->assertEquals($expected, $actual); + } + + public function testUpdate() { + + // FIXME: what is data supposed to be in this context? + $data = ['not empty data']; + + $this->attachmentService->expects($this->once()) + ->method('update') + ->willReturn($this->attachmentExample); + + $this->request->expects($this->exactly(2)) + ->method('getParam') + ->withConsecutive( + ['cardId'], + ['attachmentId'] + )->willReturnonConsecutiveCalls( + $this->cardId, + $this->attachmentExample->getId()); + + $expected = new DataResponse($this->attachmentExample, HTTP::STATUS_OK); + $actual = $this->controller->update($data); + $this->assertEquals($expected, $actual); + } + + public function testDelete() { + $this->attachmentService->expects($this->once()) + ->method('delete') + ->willReturn($this->attachmentExample); + + $this->request->expects($this->exactly(2)) + ->method('getParam') + ->withConsecutive( + ['cardId'], + ['attachmentId'] + )->willReturnonConsecutiveCalls( + $this->cardId, + $this->attachmentExample->getId()); + + $expected = new DataResponse($this->attachmentExample, HTTP::STATUS_OK); + $actual = $this->controller->delete(); + $this->assertEquals($expected, $actual); + } + + public function testRestore() { + $this->attachmentService->expects($this->once()) + ->method('restore') + ->willReturn($this->attachmentExample); + + $this->request->expects($this->exactly(2)) + ->method('getParam') + ->withConsecutive( + ['cardId'], + ['attachmentId'] + )->willReturnonConsecutiveCalls( + $this->cardId, + $this->attachmentExample->getId()); + + $expected = new DataResponse($this->attachmentExample, HTTP::STATUS_OK); + $actual = $this->controller->restore(); + $this->assertEquals($expected, $actual); + } +} \ No newline at end of file diff --git a/tests/unit/controller/BoardApiControllerTest.php b/tests/unit/controller/BoardApiControllerTest.php new file mode 100644 index 000000000..6a2ebf2d7 --- /dev/null +++ b/tests/unit/controller/BoardApiControllerTest.php @@ -0,0 +1,169 @@ + + * + * @author Ryan Fletcher + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\Deck\Controller; + +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; + +use OCA\Deck\Service\BoardService; +use OCA\Deck\Db\Board; + +class BoardApiControllerTest extends \Test\TestCase { + + private $appName = 'deck'; + private $userId = 'admin'; + private $controller; + private $boardService; + private $exampleBoard; + private $deniedBoard; + + public function setUp() { + parent::setUp(); + $this->request = $this->createMock(IRequest::class); + $this->boardService = $this->createMock(BoardService::class); + + $this->controller = new BoardApiController( + $this->appName, + $this->request, + $this->boardService, + $this->userId + ); + + $this->exampleBoard['id'] = 1; + $this->exampleBoard['title'] = 'titled'; + $this->exampleBoard['color'] = '000000'; + + $this->deniedBoard['id'] = 2; + $this->deniedBoard['owner'] = 'someone else'; + $this->deniedBoard['title'] = 'titled'; + $this->deniedBoard['color'] = '000000'; + } + + public function testIndex() { + $board = new Board(); + $board->setId('1'); + $board->setTitle('test'); + $board->setOwner($this->userId); + $board->setColor('000000'); + $boards = [$board]; + $this->boardService->expects($this->once()) + ->method('findAll') + ->willReturn($boards); + + $expected = new DataResponse($boards, HTTP::STATUS_OK); + $actual = $this->controller->index(); + + $this->assertEquals($expected, $actual); + } + + public function testGet() { + $boardId = 25; + $board = new Board(); + $board->setId($boardId); + $this->boardService->expects($this->once()) + ->method('find') + ->willReturn($board); + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue($boardId)); + + $expected = new DataResponse($board, HTTP::STATUS_OK); + $actual = $this->controller->get(); + $this->assertEquals($expected, $actual); + } + + public function testCreate() { + $board = new Board(); + $board->setId($this->exampleBoard['id']); + $board->setTitle($this->exampleBoard['title']); + $board->setColor($this->exampleBoard['color']); + $this->boardService->expects($this->once()) + ->method('create') + ->willReturn($board); + + $expected = new DataResponse($board, HTTP::STATUS_OK); + $actual = $this->controller->create($this->exampleBoard['title'], $this->exampleBoard['color']); + $this->assertEquals($expected, $actual); + } + + public function testUpdate() { + $board = new Board(); + $board->setId($this->exampleBoard['id']); + $board->setTitle($this->exampleBoard['title']); + $board->setColor($this->exampleBoard['color']); + $this->boardService->expects($this->once()) + ->method('update') + ->willReturn($board); + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue($this->exampleBoard['id'])); + + $expected = new DataResponse($board, HTTP::STATUS_OK); + $actual = $this->controller->update($this->exampleBoard['title'], $this->exampleBoard['color']); + $this->assertEquals($expected, $actual); + } + + public function testDelete() { + $board = new Board(); + $board->setId($this->exampleBoard['id']); + $board->setTitle($this->exampleBoard['title']); + $board->setColor($this->exampleBoard['color']); + $this->boardService->expects($this->once()) + ->method('delete') + ->willReturn($board); + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue($this->exampleBoard['id'])); + + $expected = new DataResponse($board, HTTP::STATUS_OK); + $actual = $this->controller->delete(); + + $this->assertEquals($expected, $actual); + } + + public function testUndoDelete() { + $board = new board(); + $board->setId($this->exampleBoard['id']); + $board->setTitle($this->exampleBoard['title']); + $board->setColor($this->exampleBoard['color']); + $this->boardService->expects($this->once()) + ->method('deleteUndo') + ->willReturn($board); + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue($this->exampleBoard['id'])); + + $expected = new DataResponse($board, HTTP::STATUS_OK); + $actual = $this->controller->undoDelete(); + $this->assertEquals($expected, $actual); + } +} \ No newline at end of file diff --git a/tests/unit/controller/BoardControllerTest.php b/tests/unit/controller/BoardControllerTest.php index 660677125..223a54aa5 100644 --- a/tests/unit/controller/BoardControllerTest.php +++ b/tests/unit/controller/BoardControllerTest.php @@ -71,9 +71,7 @@ public function setUp() { $this->controller = new BoardController( 'deck', - $this->request, - $this->userManager, - $this->groupManager, + $this->request, $this->boardService, $this->permissionService, $this->userId diff --git a/tests/unit/controller/CardApiControllerTest.php b/tests/unit/controller/CardApiControllerTest.php new file mode 100644 index 000000000..82ad0329b --- /dev/null +++ b/tests/unit/controller/CardApiControllerTest.php @@ -0,0 +1,138 @@ + + * + * @author Ryan Fletcher + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\Deck\Controller; + +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; + +use OCA\Deck\Db\Card; +use OCA\Deck\Service\CardService; + +class CardApiControllerTest extends \Test\TestCase { + + private $controller; + private $request; + private $cardService; + private $userId = 'admin'; + private $cardExample; + private $stackExample; + + public function setUp() { + parent::setUp(); + + $this->request = $this->createMock(IRequest::class); + $this->cardService = $this->createMock(CardService::class); + + $this->cardExample['id'] = 1; + $this->stackExample['id'] = 1; + + $this->controller = new CardApiController ( + $appName = 'deck', + $this->request, + $this->cardService, + $this->userId + ); + } + + public function testGet() { + $card = new Card(); + $card->setId($this->cardExample['id']); + + $this->request->expects($this->once()) + ->method('getParam') + ->with('cardId') + ->will($this->returnValue($this->cardExample['id'])); + + $this->cardService->expects($this->once()) + ->method('find') + ->willReturn($card); + + $expected = new DataResponse($card, HTTP::STATUS_OK); + $actual = $this->controller->get(); + $this->assertEquals($expected, $actual); + } + + public function testCreate() { + + $card = new Card(); + $card->setId($this->cardExample['id']); + $card->setStackId($this->stackExample['id']); + + $this->request->expects($this->once()) + ->method('getParam') + ->with('stackId') + ->willReturn($this->stackExample['id']); + + $this->cardService->expects($this->once()) + ->method('create') + ->willReturn($card); + + $expected = new DataResponse($card, HTTP::STATUS_OK); + $actual = $this->controller->create('title'); + $this->assertEquals($expected, $actual); + } + + public function testUpdate() { + $card = new Card(); + $card->setId($this->cardExample['id']); + $card->setStackId($this->stackExample['id']); + + $this->request->expects($this->exactly(2)) + ->method('getParam') + ->withConsecutive( + ['cardId'], + ['stackId'] + )->willReturnonConsecutiveCalls( + $this->cardExample['id'], + $this->stackExample['id']); + + $this->cardService->expects($this->once()) + ->method('update') + ->willReturn($card); + + $expected = new DataResponse($card, HTTP::STATUS_OK); + $actual = $this->controller->update('title', 'plain', 0, 'description', $this->userId, null); + $this->assertEquals($expected, $actual); + } + + public function testDelete() { + + $card = new Card(); + $card->setId($this->cardExample['id']); + + $this->request->expects($this->once()) + ->method('getParam') + ->with('cardId') + ->will($this->returnValue($this->cardExample['id'])); + + $this->cardService->expects($this->once()) + ->method('delete') + ->willReturn($card); + + $expected = new DataResponse($card, HTTP::STATUS_OK); + $actual = $this->controller->delete(); + $this->assertEquals($expected, $actual); + } + +} \ No newline at end of file diff --git a/tests/unit/controller/LabelApiControllerTest.php b/tests/unit/controller/LabelApiControllerTest.php new file mode 100644 index 000000000..ff314abcb --- /dev/null +++ b/tests/unit/controller/LabelApiControllerTest.php @@ -0,0 +1,128 @@ + + * + * @author Ryan Fletcher + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\Deck\Controller; + +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; + +use OCA\Deck\Db\Label; +use OCA\Deck\Service\LabelService; + +class LabelApiControllerTest extends \Test\TestCase { + + private $controller; + private $request; + private $labelService; + private $userId = 'admin'; + private $exampleLabel; + + public function setUp() { + parent::setUp(); + $this->request = $this->createMock(IRequest::class); + $this->labelService = $this->createMock(LabelService::class); + $this->exampleLabel['id']; + $this->controller = new LabelApiController( + 'deck', + $this->request, + $this->labelService, + $this->userId + ); + } + + public function testGet() { + $label = new Label(); + $label->setId($this->exampleLabel['id']); + + $this->request->expects($this->once()) + ->method('getParam') + ->with('labelId') + ->will($this->returnValue($this->exampleLabel['id'])); + + $this->labelService->expects($this->once()) + ->method('find') + ->willReturn($label); + + $expected = new DataResponse($label, HTTP::STATUS_OK); + $actual = $this->controller->get(); + $this->assertEquals($expected, $actual); + } + + public function testCreate() { + + $label = new Label(); + $label->setId($this->exampleLabel['id']); + + $this->request->expects($this->once()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue(1)); + + $this->labelService->expects($this->once()) + ->method('create') + ->willReturn($label); + + $expected = new DataResponse($label, HTTP::STATUS_OK); + $actual = $this->controller->create('title', '000000'); + $this->assertEquals($expected, $actual); + } + + public function testUpdate() { + + $label = new Label(); + $label->setId($this->exampleLabel['id']); + + $this->request->expects($this->once()) + ->method('getParam') + ->with('labelId') + ->will($this->returnValue($this->exampleLabel['id'])); + + $this->labelService->expects($this->once()) + ->method('update') + ->will($this->returnValue($label)); + + $expected = new DataResponse($label, HTTP::STATUS_OK); + $actual = $this->controller->update('title', '000000'); + $this->assertEquals($expected, $actual); + } + + public function testDelete() { + + $label = new Label(); + $label->setId($this->exampleLabel['id']); + + $this->request->expects($this->once()) + ->method('getParam') + ->with('labelId') + ->will($this->returnValue($this->exampleLabel['id'])); + + $this->labelService->expects($this->once()) + ->method('delete') + ->willReturn($label); + + $expected = new DataResponse($label, HTTP::STATUS_OK); + $actual = $this->controller->delete(); + $this->assertEquals($expected, $actual); + } + +} \ No newline at end of file diff --git a/tests/unit/controller/StackApiControllerTest.php b/tests/unit/controller/StackApiControllerTest.php new file mode 100644 index 000000000..8ec2cc4fa --- /dev/null +++ b/tests/unit/controller/StackApiControllerTest.php @@ -0,0 +1,174 @@ + + * + * @author Ryan Fletcher + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +namespace OCA\Deck\Controller; + +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; + +use OCA\Deck\Service\BoardService; +use OCA\Deck\Service\StackService; +use OCA\Deck\Db\Board; +use OCA\Deck\Db\Stack; + +class StackApiControllerTest extends \Test\TestCase { + + private $appName = 'deck'; + private $userId = 'admin'; + private $controller; + private $boardService; + private $stackService; + private $exampleStack; + private $exampleBoard; + + public function setUp() { + parent::setUp(); + $this->request = $this->createMock(IRequest::class); + $this->boardService = $this->createMock(BoardService::class); + $this->stackService = $this->createMock(StackService::class); + + $this->exampleStack['id'] = 345; + $this->exampleStack['boardId'] = $this->exampleBoard['boardId']; + $this->exampleStack['order'] = 0; + $this->exampleStack['title'] = 'Example Stack From API'; + + $this->exampleBoard['boardId'] = '89'; + + $this->controller = new StackApiController( + $this->appName, + $this->request, + $this->stackService, + $this->boardService + ); + } + + public function testIndex() { + $stack = new Stack(); + $stack->setId($this->exampleStack['id']); + $stack->setBoardId($this->exampleStack['boardId']); + $stack->setOrder($this->exampleStack['order']); + $stacks = [$stack]; + + $this->stackService->expects($this->once()) + ->method('findAll') + ->willReturn($stacks); + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue($this->exampleBoard['boardId'])); + + $expected = new DataResponse($stacks, HTTP::STATUS_OK); + $actual = $this->controller->index(); + $this->assertEquals($expected, $actual); + } + + public function testGet() { + $stack = new Stack(); + $stack->setId($this->exampleStack['id']); + $stack->setBoardId($this->exampleStack['boardId']); + $stack->setOrder($this->exampleStack['order']); + + $this->stackService->expects($this->once()) + ->method('find') + ->willReturn($stack); + + $this->request->expects($this->once()) + ->method('getParam') + ->with('stackId') + ->willReturn($this->exampleStack['id']); + + $expected = new DataResponse($stack, HTTP::STATUS_OK); + $actual = $this->controller->get(); + $this->assertEquals($expected, $actual); + } + + public function testCreate() { + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue($this->exampleBoard['boardId'])); + + $stack = new Stack(); + $stack->setId($this->exampleStack['id']); + $stack->setBoardId($this->exampleStack['boardId']); + $stack->setOrder($this->exampleStack['order']); + $stack->setTitle($this->exampleStack['title']); + + $this->stackService->expects($this->once()) + ->method('create') + ->willReturn($stack); + + $expected = new DataResponse($stack, HTTP::STATUS_OK); + $actual = $this->controller->create($this->exampleStack['title'], $this->exampleStack['order']); + $this->assertEquals($expected, $actual); + } + + public function testUpdate() { + + $this->request->expects($this->exactly(2)) + ->method('getParam') + ->withConsecutive( + ['stackId'], + ['boardId'] + ) + ->willReturnonConsecutiveCalls($this->exampleStack['id'], $this->exampleBoard['boardId']); + + $stack = new Stack(); + $stack->setId($this->exampleStack['id']); + $stack->setBoardId($this->exampleStack['boardId']); + $stack->setOrder($this->exampleStack['order']); + $stack->setTitle($this->exampleStack['title']); + + $this->stackService->expects($this->once()) + ->method('update') + ->willReturn($stack); + + $expected = new DataResponse($stack, HTTP::STATUS_OK); + $actual = $this->controller->update($this->exampleStack['title'], $this->exampleStack['order']); + $this->assertEquals($expected, $actual); + } + + public function testDelete() { + + $stack = new Stack(); + $stack->setId($this->exampleStack['id']); + $stack->setBoardId($this->exampleStack['boardId']); + $stack->setOrder($this->exampleStack['order']); + $stack->setTitle($this->exampleStack['title']); + + $this->request->expects($this->once()) + ->method('getParam') + ->with('stackId') + ->will($this->returnValue($this->exampleStack['id'])); + + $this->stackService->expects($this->once()) + ->method('delete') + ->willReturn($stack); + + $expected = new DataResponse($stack, HTTP::STATUS_OK); + $actual = $this->controller->delete(); + $this->assertEquals($expected, $actual); + } +} \ No newline at end of file