From 0c266d4a1f3c8efa32b041e4467b052549af700c Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Sat, 29 Jul 2017 01:41:39 +0200 Subject: [PATCH 01/78] List boards, and fetch a specific board. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- appinfo/routes.php | 6 ++ lib/Controller/BoardApiController.php | 88 +++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 lib/Controller/BoardApiController.php diff --git a/appinfo/routes.php b/appinfo/routes.php index 90dffb520..20d177939 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -76,5 +76,11 @@ ['name' => 'label#update', 'url' => '/labels/{labelId}', 'verb' => 'PUT'], ['name' => 'label#delete', 'url' => '/labels/{labelId}', 'verb' => 'DELETE'], + // api + ['name' => 'board_api#index', 'url' => '/api/v0.1/boards', 'verb' => 'GET'], + ['name' => 'board_api#get', 'url' => '/api/v0.1/board/{id}', 'verb' => 'GET'], + + ['name' => 'board_api#preflighted_cors', 'url' => '/api/0.1/{path}', + 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ] ]; diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php new file mode 100644 index 000000000..6c4b48118 --- /dev/null +++ b/lib/Controller/BoardApiController.php @@ -0,0 +1,88 @@ + + * + * @author Steven R. Baker + * + * @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\DataResponse; +use OCP\IRequest; +use OCP\IUserManager; +use OCP\IGroupManager; + +use OCA\Deck\Service\BoardService; + +/** + * Class BoardApiController + * + * @package OCA\Deck\Controller + */ +class BoardApiController extends ApiController { + + private $service; + private $userInfo; + + /** + * @param string $appName + * @param IRequest $request + * @param BoardService $service + */ + public function __construct($appName, IRequest $request, IUserManager $userManager, IGroupManager $groupManager, BoardService $service, $userId) { + parent::__construct($appName, $request); + $this->service = $service; + $this->userId = $userId; + $this->userManager = $userManager; + $this->groupManager = $groupManager; + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + */ + public function index() { + $boards = $this->service->findAll($this->getUserInfo()); + + return (new DataResponse($boards)); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + */ + public function get($id) { + $board = $this->service->find($id); + + return (new DataResponse($board)); + } + + // this is taken from BoardController, but it's not ideal + private function getUserInfo() { + $groups = $this->groupManager->getUserGroupIds( + $this->userManager->get($this->userId) + ); + return ['user' => $this->userId, + 'groups' => $groups]; + } + +} From 7dcd49c485fe66d0d321c7ed25f85a43f4a47a9a Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Sat, 29 Jul 2017 02:06:26 +0200 Subject: [PATCH 02/78] Delete boards via the API. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- appinfo/routes.php | 1 + lib/Controller/BoardApiController.php | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/appinfo/routes.php b/appinfo/routes.php index 20d177939..e094e9f00 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -79,6 +79,7 @@ // api ['name' => 'board_api#index', 'url' => '/api/v0.1/boards', 'verb' => 'GET'], ['name' => 'board_api#get', 'url' => '/api/v0.1/board/{id}', 'verb' => 'GET'], + ['name' => 'board_api#delete', 'url' => '/api/v0.1/board/{id}', 'verb' => 'DELETE'], ['name' => 'board_api#preflighted_cors', 'url' => '/api/0.1/{path}', 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 6c4b48118..d73863ca9 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -73,6 +73,19 @@ public function index() { public function get($id) { $board = $this->service->find($id); + // FIXME: this should probably 404 if the board has been deleted + + return (new DataResponse($board)); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + */ + public function delete($id) { + $board = $this->service->delete($id); + return (new DataResponse($board)); } From b4224dadfbb9cbd3db2f53394d79598070eb2521 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Sat, 29 Jul 2017 02:10:02 +0200 Subject: [PATCH 03/78] Undo deletion of boards via API. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- appinfo/routes.php | 1 + lib/Controller/BoardApiController.php | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/appinfo/routes.php b/appinfo/routes.php index e094e9f00..fa8156c6c 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -80,6 +80,7 @@ ['name' => 'board_api#index', 'url' => '/api/v0.1/boards', 'verb' => 'GET'], ['name' => 'board_api#get', 'url' => '/api/v0.1/board/{id}', 'verb' => 'GET'], ['name' => 'board_api#delete', 'url' => '/api/v0.1/board/{id}', 'verb' => 'DELETE'], + ['name' => 'board_api#undo_delete', 'url' => '/api/v0.1/board/{id}/undo_delete', 'verb' => 'POST'], ['name' => 'board_api#preflighted_cors', 'url' => '/api/0.1/{path}', 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index d73863ca9..2bd0cd397 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -89,6 +89,18 @@ public function delete($id) { return (new DataResponse($board)); } + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + */ + public function undoDelete($id) { + $board = $this->service->find($id); + $this->service->deleteUndo($id); + + return (new DataResponse($board)); + } + // this is taken from BoardController, but it's not ideal private function getUserInfo() { $groups = $this->groupManager->getUserGroupIds( From 975b6f35728225f19eb885cb3bbc24c037830788 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Sat, 29 Jul 2017 16:54:30 +0200 Subject: [PATCH 04/78] Update the documentation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Controller/BoardApiController.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 2bd0cd397..68ffea9f3 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -44,7 +44,10 @@ class BoardApiController extends ApiController { /** * @param string $appName * @param IRequest $request + * @param IUserManager $userManager + * @param IGroupManager $groupManager * @param BoardService $service + * @param $userId */ public function __construct($appName, IRequest $request, IUserManager $userManager, IGroupManager $groupManager, BoardService $service, $userId) { parent::__construct($appName, $request); @@ -58,6 +61,8 @@ public function __construct($appName, IRequest $request, IUserManager $userManag * @NoAdminRequired * @CORS * @NoCSRFRequired + * + * Return all of the boards that the current user has access to. */ public function index() { $boards = $this->service->findAll($this->getUserInfo()); @@ -69,6 +74,10 @@ public function index() { * @NoAdminRequired * @CORS * @NoCSRFRequired + * + * @params $id + * + * Return the board specified by $id. */ public function get($id) { $board = $this->service->find($id); @@ -82,6 +91,10 @@ public function get($id) { * @NoAdminRequired * @CORS * @NoCSRFRequired + * + * @params $id + * + * Delete the board specified by $id. Return the board that was deleted. */ public function delete($id) { $board = $this->service->delete($id); @@ -93,6 +106,10 @@ public function delete($id) { * @NoAdminRequired * @CORS * @NoCSRFRequired + * + * @params $id + * + * Undo the deletion of the board specified by $id. */ public function undoDelete($id) { $board = $this->service->find($id); From 84a8db7b753100a8c07697b537cf0c184d634565 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Sat, 29 Jul 2017 16:55:31 +0200 Subject: [PATCH 05/78] Change the API version to 1.0, and fix the preflighted_cors version. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- appinfo/routes.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index fa8156c6c..eefd46dd6 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -77,12 +77,12 @@ ['name' => 'label#delete', 'url' => '/labels/{labelId}', 'verb' => 'DELETE'], // api - ['name' => 'board_api#index', 'url' => '/api/v0.1/boards', 'verb' => 'GET'], - ['name' => 'board_api#get', 'url' => '/api/v0.1/board/{id}', 'verb' => 'GET'], - ['name' => 'board_api#delete', 'url' => '/api/v0.1/board/{id}', 'verb' => 'DELETE'], - ['name' => 'board_api#undo_delete', 'url' => '/api/v0.1/board/{id}/undo_delete', 'verb' => 'POST'], + ['name' => 'board_api#index', 'url' => '/api/v1.0/boards', 'verb' => 'GET'], + ['name' => 'board_api#get', 'url' => '/api/v1.0/board/{id}', 'verb' => 'GET'], + ['name' => 'board_api#delete', 'url' => '/api/v1.0/board/{id}', 'verb' => 'DELETE'], + ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/board/{id}/undo_delete', 'verb' => 'POST'], - ['name' => 'board_api#preflighted_cors', 'url' => '/api/0.1/{path}', + ['name' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}', 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ] ]; From 86dde2d6b811e1b62eaa36035399483b25ae2837 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Sat, 29 Jul 2017 16:50:18 +0200 Subject: [PATCH 06/78] These parens are not needed. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Controller/BoardApiController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 68ffea9f3..feb814f45 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -67,7 +67,7 @@ public function __construct($appName, IRequest $request, IUserManager $userManag public function index() { $boards = $this->service->findAll($this->getUserInfo()); - return (new DataResponse($boards)); + return new DataResponse($boards); } /** @@ -84,7 +84,7 @@ public function get($id) { // FIXME: this should probably 404 if the board has been deleted - return (new DataResponse($board)); + return new DataResponse($board); } /** @@ -99,7 +99,7 @@ public function get($id) { public function delete($id) { $board = $this->service->delete($id); - return (new DataResponse($board)); + return new DataResponse($board); } /** @@ -115,7 +115,7 @@ public function undoDelete($id) { $board = $this->service->find($id); $this->service->deleteUndo($id); - return (new DataResponse($board)); + return new DataResponse($board); } // this is taken from BoardController, but it's not ideal From 8316a0b25fe47e4655b0c87e0839038f28f167cb Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Sat, 29 Jul 2017 23:02:05 +0200 Subject: [PATCH 07/78] Board creation via API. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- appinfo/routes.php | 1 + lib/Controller/BoardApiController.php | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/appinfo/routes.php b/appinfo/routes.php index eefd46dd6..d2a5b33fa 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -79,6 +79,7 @@ // api ['name' => 'board_api#index', 'url' => '/api/v1.0/boards', 'verb' => 'GET'], ['name' => 'board_api#get', 'url' => '/api/v1.0/board/{id}', 'verb' => 'GET'], + ['name' => 'board_api#create', 'url' => '/api/v1.0/board', 'verb' => 'POST'], ['name' => 'board_api#delete', 'url' => '/api/v1.0/board/{id}', 'verb' => 'DELETE'], ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/board/{id}/undo_delete', 'verb' => 'POST'], diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index feb814f45..814c942d3 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -87,6 +87,22 @@ public function get($id) { return new DataResponse($board); } + /** + * @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); + } + /** * @NoAdminRequired * @CORS From a4b348488bcb864c50abeef908b66b9122f06fcd Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Sat, 29 Jul 2017 23:14:01 +0200 Subject: [PATCH 08/78] Add Stack support to API. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- appinfo/routes.php | 4 + lib/Controller/StackApiController.php | 101 ++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 lib/Controller/StackApiController.php diff --git a/appinfo/routes.php b/appinfo/routes.php index d2a5b33fa..c075405bd 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -83,6 +83,10 @@ ['name' => 'board_api#delete', 'url' => '/api/v1.0/board/{id}', 'verb' => 'DELETE'], ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/board/{id}/undo_delete', 'verb' => 'POST'], + ['name' => 'stack_api#index', 'url' => '/api/v1.0/boards/{boardId}/stacks', 'verb' => 'GET'], + ['name' => 'stack_api#create', 'url' => '/api/v1.0/board/{boardId}/stack', 'verb' => 'POST'], + ['name' => 'stack_api#delete', 'url' => '/api/v1.0/board/{boardId}/stack/{id}', 'verb' => 'DELETE'], + ['name' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}', 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ] diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php new file mode 100644 index 000000000..6186694a4 --- /dev/null +++ b/lib/Controller/StackApiController.php @@ -0,0 +1,101 @@ + + * + * @author Steven R. Baker + * + * @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\DataResponse; +use OCP\IRequest; +use OCP\IUserManager; +use OCP\IGroupManager; + +use OCA\Deck\Service\StackService; + +/** + * Class StackApiController + * + * @package OCA\Deck\Controller + */ +class StackApiController extends ApiController { + + private $service; + private $userInfo; + + /** + * @param string $appName + * @param IRequest $request + * @param StackService $service + * @param $boardId + */ + public function __construct($appName, IRequest $request, StackService $service, $boardId) { + parent::__construct($appName, $request); + $this->service = $service; + $this->boardId = $boardId; + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Return all of the stacks in the specified board. + */ + public function index() { + $stacks = $this->service->findAll($this->boardId); + + return new DataResponse($stacks); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $order + * + * Create a stack with the specified title and order. + */ + public function create($title, $order) { + // this throws a StatusException that needs to be caught and handled + $stack = $this->service->create($title, $this->boardId, $order); + + return new DataResponse($stack); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $id + * + * Delete the stack specified by $id. Return the board that was deleted. + */ + public function delete($id) { + $stack = $this->service->delete($id); + + return new DataResponse($stack); + } + +} From 40f34eb3bc9ba968cba94ebec9e39fc906fc3ac3 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Sun, 30 Jul 2017 00:13:12 +0200 Subject: [PATCH 09/78] Fix the routing and the stacks API endpoint. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- appinfo/routes.php | 2 +- lib/Controller/StackApiController.php | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index c075405bd..209227f6e 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -83,7 +83,7 @@ ['name' => 'board_api#delete', 'url' => '/api/v1.0/board/{id}', 'verb' => 'DELETE'], ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/board/{id}/undo_delete', 'verb' => 'POST'], - ['name' => 'stack_api#index', 'url' => '/api/v1.0/boards/{boardId}/stacks', 'verb' => 'GET'], + ['name' => 'stack_api#index', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'GET'], ['name' => 'stack_api#create', 'url' => '/api/v1.0/board/{boardId}/stack', 'verb' => 'POST'], ['name' => 'stack_api#delete', 'url' => '/api/v1.0/board/{boardId}/stack/{id}', 'verb' => 'DELETE'], diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 6186694a4..159d571e2 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -26,8 +26,6 @@ use OCP\AppFramework\ApiController; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; -use OCP\IUserManager; -use OCP\IGroupManager; use OCA\Deck\Service\StackService; @@ -45,12 +43,10 @@ class StackApiController extends ApiController { * @param string $appName * @param IRequest $request * @param StackService $service - * @param $boardId */ - public function __construct($appName, IRequest $request, StackService $service, $boardId) { + public function __construct($appName, IRequest $request, StackService $service) { parent::__construct($appName, $request); $this->service = $service; - $this->boardId = $boardId; } /** @@ -60,8 +56,8 @@ public function __construct($appName, IRequest $request, StackService $service, * * Return all of the stacks in the specified board. */ - public function index() { - $stacks = $this->service->findAll($this->boardId); + public function index($boardId) { + $stacks = $this->service->findAll($boardId); return new DataResponse($stacks); } @@ -76,9 +72,9 @@ public function index() { * * Create a stack with the specified title and order. */ - public function create($title, $order) { + public function create($boardId, $title, $order) { // this throws a StatusException that needs to be caught and handled - $stack = $this->service->create($title, $this->boardId, $order); + $stack = $this->service->create($title, $boardId, $order); return new DataResponse($stack); } @@ -92,7 +88,7 @@ public function create($title, $order) { * * Delete the stack specified by $id. Return the board that was deleted. */ - public function delete($id) { + public function delete($boardId, $id) { $stack = $this->service->delete($id); return new DataResponse($stack); From 8ec97032b19abd946c29894a16ab43992a0d8295 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Mon, 12 Feb 2018 11:55:02 +0100 Subject: [PATCH 10/78] Re-format code according to the coding style. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- appinfo/routes.php | 22 +-- lib/Controller/BoardApiController.php | 204 +++++++++++++------------- lib/Controller/StackApiController.php | 100 ++++++------- 3 files changed, 163 insertions(+), 163 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index 209227f6e..f54a04eda 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -76,18 +76,18 @@ ['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/board/{id}', 'verb' => 'GET'], - ['name' => 'board_api#create', 'url' => '/api/v1.0/board', 'verb' => 'POST'], - ['name' => 'board_api#delete', 'url' => '/api/v1.0/board/{id}', 'verb' => 'DELETE'], - ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/board/{id}/undo_delete', 'verb' => 'POST'], + // api + ['name' => 'board_api#index', 'url' => '/api/v1.0/boards', 'verb' => 'GET'], + ['name' => 'board_api#get', 'url' => '/api/v1.0/board/{id}', 'verb' => 'GET'], + ['name' => 'board_api#create', 'url' => '/api/v1.0/board', 'verb' => 'POST'], + ['name' => 'board_api#delete', 'url' => '/api/v1.0/board/{id}', 'verb' => 'DELETE'], + ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/board/{id}/undo_delete', 'verb' => 'POST'], - ['name' => 'stack_api#index', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'GET'], - ['name' => 'stack_api#create', 'url' => '/api/v1.0/board/{boardId}/stack', 'verb' => 'POST'], - ['name' => 'stack_api#delete', 'url' => '/api/v1.0/board/{boardId}/stack/{id}', 'verb' => 'DELETE'], + ['name' => 'stack_api#index', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'GET'], + ['name' => 'stack_api#create', 'url' => '/api/v1.0/board/{boardId}/stack', 'verb' => 'POST'], + ['name' => 'stack_api#delete', 'url' => '/api/v1.0/board/{boardId}/stack/{id}', 'verb' => 'DELETE'], - ['name' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}', - 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], + ['name' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}', + 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ] ]; diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 814c942d3..22b7821ee 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -38,109 +38,109 @@ */ class BoardApiController extends ApiController { - private $service; - private $userInfo; - - /** - * @param string $appName - * @param IRequest $request - * @param IUserManager $userManager - * @param IGroupManager $groupManager - * @param BoardService $service - * @param $userId - */ - public function __construct($appName, IRequest $request, IUserManager $userManager, IGroupManager $groupManager, BoardService $service, $userId) { - parent::__construct($appName, $request); - $this->service = $service; - $this->userId = $userId; - $this->userManager = $userManager; - $this->groupManager = $groupManager; - } - - /** - * @NoAdminRequired - * @CORS - * @NoCSRFRequired - * - * Return all of the boards that the current user has access to. - */ - public function index() { - $boards = $this->service->findAll($this->getUserInfo()); - - return new DataResponse($boards); - } - - /** - * @NoAdminRequired - * @CORS - * @NoCSRFRequired - * - * @params $id - * - * Return the board specified by $id. - */ - public function get($id) { - $board = $this->service->find($id); - - // FIXME: this should probably 404 if the board has been deleted - - return new DataResponse($board); - } - - /** - * @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); - } - - /** - * @NoAdminRequired - * @CORS - * @NoCSRFRequired - * - * @params $id - * - * Delete the board specified by $id. Return the board that was deleted. - */ - public function delete($id) { - $board = $this->service->delete($id); - - return new DataResponse($board); - } - - /** - * @NoAdminRequired - * @CORS - * @NoCSRFRequired - * - * @params $id - * - * Undo the deletion of the board specified by $id. - */ - public function undoDelete($id) { - $board = $this->service->find($id); - $this->service->deleteUndo($id); - - return new DataResponse($board); - } - - // this is taken from BoardController, but it's not ideal - private function getUserInfo() { - $groups = $this->groupManager->getUserGroupIds( + private $service; + private $userInfo; + + /** + * @param string $appName + * @param IRequest $request + * @param IUserManager $userManager + * @param IGroupManager $groupManager + * @param BoardService $service + * @param $userId + */ + public function __construct($appName, IRequest $request, IUserManager $userManager, IGroupManager $groupManager, BoardService $service, $userId) { + parent::__construct($appName, $request); + $this->service = $service; + $this->userId = $userId; + $this->userManager = $userManager; + $this->groupManager = $groupManager; + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Return all of the boards that the current user has access to. + */ + public function index() { + $boards = $this->service->findAll($this->getUserInfo()); + + return new DataResponse($boards); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $id + * + * Return the board specified by $id. + */ + public function get($id) { + $board = $this->service->find($id); + + // FIXME: this should probably 404 if the board has been deleted + + return new DataResponse($board); + } + + /** + * @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); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $id + * + * Delete the board specified by $id. Return the board that was deleted. + */ + public function delete($id) { + $board = $this->service->delete($id); + + return new DataResponse($board); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $id + * + * Undo the deletion of the board specified by $id. + */ + public function undoDelete($id) { + $board = $this->service->find($id); + $this->service->deleteUndo($id); + + return new DataResponse($board); + } + + // this is taken from BoardController, but it's not ideal + private function getUserInfo() { + $groups = $this->groupManager->getUserGroupIds( $this->userManager->get($this->userId) ); - return ['user' => $this->userId, - 'groups' => $groups]; - } + return ['user' => $this->userId, + 'groups' => $groups]; + } } diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 159d571e2..9cae1a8af 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -36,62 +36,62 @@ */ class StackApiController extends ApiController { - private $service; - private $userInfo; + private $service; + private $userInfo; - /** - * @param string $appName - * @param IRequest $request - * @param StackService $service - */ - public function __construct($appName, IRequest $request, StackService $service) { - parent::__construct($appName, $request); - $this->service = $service; - } + /** + * @param string $appName + * @param IRequest $request + * @param StackService $service + */ + public function __construct($appName, IRequest $request, StackService $service) { + parent::__construct($appName, $request); + $this->service = $service; + } - /** - * @NoAdminRequired - * @CORS - * @NoCSRFRequired - * - * Return all of the stacks in the specified board. - */ - public function index($boardId) { - $stacks = $this->service->findAll($boardId); + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Return all of the stacks in the specified board. + */ + public function index($boardId) { + $stacks = $this->service->findAll($boardId); - return new DataResponse($stacks); - } + return new DataResponse($stacks); + } - /** - * @NoAdminRequired - * @CORS - * @NoCSRFRequired - * - * @params $title - * @params $order - * - * Create a stack with the specified title and order. - */ - public function create($boardId, $title, $order) { - // this throws a StatusException that needs to be caught and handled - $stack = $this->service->create($title, $boardId, $order); + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $order + * + * Create a stack with the specified title and order. + */ + public function create($boardId, $title, $order) { + // this throws a StatusException that needs to be caught and handled + $stack = $this->service->create($title, $boardId, $order); - return new DataResponse($stack); - } + return new DataResponse($stack); + } - /** - * @NoAdminRequired - * @CORS - * @NoCSRFRequired - * - * @params $id - * - * Delete the stack specified by $id. Return the board that was deleted. - */ - public function delete($boardId, $id) { - $stack = $this->service->delete($id); + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $id + * + * Delete the stack specified by $id. Return the board that was deleted. + */ + public function delete($boardId, $id) { + $stack = $this->service->delete($id); - return new DataResponse($stack); - } + return new DataResponse($stack); + } } From 41cf623bb883c483acdb5bf06018e1d381cef612 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Mon, 12 Feb 2018 11:56:40 +0100 Subject: [PATCH 11/78] This should be 200 on deletion, so we can tell whether a deletion succeeds or not. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Controller/BoardApiController.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 22b7821ee..088a62d73 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -82,8 +82,6 @@ public function index() { public function get($id) { $board = $this->service->find($id); - // FIXME: this should probably 404 if the board has been deleted - return new DataResponse($board); } From 1ffa3211bae5ea6af576a354d3a8cb1cc68c0820 Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Mon, 12 Feb 2018 12:11:39 +0100 Subject: [PATCH 12/78] Extract getBoardPererequisites() so it can be re-used. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Controller/BoardApiController.php | 12 ++---------- lib/Controller/BoardController.php | 16 +--------------- lib/Service/BoardService.php | 10 ++++++++++ 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 088a62d73..5222068d7 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -55,6 +55,7 @@ public function __construct($appName, IRequest $request, IUserManager $userManag $this->userId = $userId; $this->userManager = $userManager; $this->groupManager = $groupManager; + $this->userInfo = $this->service->getBoardPrerequisites(); } /** @@ -65,7 +66,7 @@ public function __construct($appName, IRequest $request, IUserManager $userManag * Return all of the boards that the current user has access to. */ public function index() { - $boards = $this->service->findAll($this->getUserInfo()); + $boards = $this->service->findAll($this->userInfo); return new DataResponse($boards); } @@ -132,13 +133,4 @@ public function undoDelete($id) { return new DataResponse($board); } - // this is taken from BoardController, but it's not ideal - private function getUserInfo() { - $groups = $this->groupManager->getUserGroupIds( - $this->userManager->get($this->userId) - ); - return ['user' => $this->userId, - 'groups' => $groups]; - } - } diff --git a/lib/Controller/BoardController.php b/lib/Controller/BoardController.php index 0ecd044b1..d447f849e 100644 --- a/lib/Controller/BoardController.php +++ b/lib/Controller/BoardController.php @@ -47,21 +47,7 @@ public function __construct($appName, IRequest $request, IUserManager $userManag $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 - ]; + $this->userInfo = $this->boardSerivce->getBoardPrerequisites(); } /** diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index ab6baf225..e9140d09a 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -112,6 +112,16 @@ public function find($boardId) { return $board; } + public function getBoardPrerequisites() { + $groups = $this->groupManager->getUserGroupIds( + $this->userManager->get($this->userId) + ); + return [ + 'user' => $this->userId, + 'groups' => $groups + ]; + } + public function isArchived($mapper, $id) { try { $boardId = $id; From e32adb17f2ddfd6f9baa3134eaf12680bdf3ed3b Mon Sep 17 00:00:00 2001 From: "Steven R. Baker" Date: Mon, 12 Feb 2018 16:28:37 +0100 Subject: [PATCH 13/78] Don't need to pass around the userInfo with it encapsulated in BoardService. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Controller/BoardApiController.php | 10 ++-------- lib/Controller/BoardController.php | 4 +--- lib/Service/BoardService.php | 5 +++-- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 5222068d7..312590541 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -39,23 +39,17 @@ class BoardApiController extends ApiController { private $service; - private $userInfo; /** * @param string $appName * @param IRequest $request - * @param IUserManager $userManager - * @param IGroupManager $groupManager * @param BoardService $service * @param $userId */ - public function __construct($appName, IRequest $request, IUserManager $userManager, IGroupManager $groupManager, BoardService $service, $userId) { + public function __construct($appName, IRequest $request, BoardService $service, $userId) { parent::__construct($appName, $request); $this->service = $service; $this->userId = $userId; - $this->userManager = $userManager; - $this->groupManager = $groupManager; - $this->userInfo = $this->service->getBoardPrerequisites(); } /** @@ -66,7 +60,7 @@ public function __construct($appName, IRequest $request, IUserManager $userManag * Return all of the boards that the current user has access to. */ public function index() { - $boards = $this->service->findAll($this->userInfo); + $boards = $this->service->findAll(); return new DataResponse($boards); } diff --git a/lib/Controller/BoardController.php b/lib/Controller/BoardController.php index d447f849e..1d9eb28f7 100644 --- a/lib/Controller/BoardController.php +++ b/lib/Controller/BoardController.php @@ -38,7 +38,6 @@ class BoardController extends ApiController { private $userManager; private $groupManager; private $permissionService; - private $userInfo; public function __construct($appName, IRequest $request, IUserManager $userManager, IGroupManager $groupManager, BoardService $boardService, PermissionService $permissionService, $userId) { parent::__construct($appName, $request); @@ -47,14 +46,13 @@ public function __construct($appName, IRequest $request, IUserManager $userManag $this->groupManager = $groupManager; $this->boardService = $boardService; $this->permissionService = $permissionService; - $this->userInfo = $this->boardSerivce->getBoardPrerequisites(); } /** * @NoAdminRequired */ public function index() { - return $this->boardService->findAll($this->userInfo); + return $this->boardService->findAll(); } /** diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index e9140d09a..5b3c07030 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -64,7 +64,8 @@ public function __construct( $this->assignedUsersMapper = $assignedUsersMapper; } - public function findAll($userInfo) { + 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); @@ -112,7 +113,7 @@ public function find($boardId) { return $board; } - public function getBoardPrerequisites() { + private function getBoardPrerequisites() { $groups = $this->groupManager->getUserGroupIds( $this->userManager->get($this->userId) ); From 9fc01eb51f3587fdbd99f2a1d51d319532c4b224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Thu, 12 Jul 2018 15:24:53 +0200 Subject: [PATCH 14/78] Move DI of IUserManager, IGroupManager, userId to the BoardService MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Controller/BoardController.php | 6 +----- lib/Service/BoardService.php | 13 ++++++++++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/Controller/BoardController.php b/lib/Controller/BoardController.php index 1d9eb28f7..6cb65ff01 100644 --- a/lib/Controller/BoardController.php +++ b/lib/Controller/BoardController.php @@ -35,15 +35,11 @@ class BoardController extends ApiController { private $userId; private $boardService; - private $userManager; - private $groupManager; private $permissionService; - 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; } diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 5b3c07030..1ce4f546b 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -30,10 +30,12 @@ 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; class BoardService { @@ -45,6 +47,9 @@ class BoardService { private $permissionService; private $notificationHelper; private $assignedUsersMapper; + private $userManager; + private $groupManager; + private $userId; public function __construct( BoardMapper $boardMapper, @@ -53,7 +58,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,6 +70,9 @@ public function __construct( $this->permissionService = $permissionService; $this->notificationHelper = $notificationHelper; $this->assignedUsersMapper = $assignedUsersMapper; + $this->userManager = $userManager; + $this->groupManager = $groupManager; + $this->userId = $userId; } public function findAll() { From 656e8efa4307b4fb214566adca4c4c33d79e56d4 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 10:43:46 -0400 Subject: [PATCH 15/78] quick test in StackApiController Signed-off-by: Ryan Fletcher --- lib/Controller/StackApiController.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 9cae1a8af..2cf02e499 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -24,6 +24,7 @@ namespace OCA\Deck\Controller; use OCP\AppFramework\ApiController; +use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; @@ -73,10 +74,18 @@ public function index($boardId) { * Create a stack with the specified title and order. */ public function create($boardId, $title, $order) { - // this throws a StatusException that needs to be caught and handled - $stack = $this->service->create($title, $boardId, $order); - - return new DataResponse($stack); + $errorMessage['params']['boardId'] = $boardId; + $errorMessage['params']['title'] = $title; + $errorMessage['params']['order'] = $order; + + // try { + // // this throws a StatusException that needs to be caught and handled + // $stack = $this->service->create($title, $boardId, $order); + // } catch (StatusException $e) { + // return new DataResponse(null, Http::STATUS_OK); + // } + + return new DataResponse($errorMessage, HTTP::STATUS_NOT_IMPLEMENTED); } /** From 8771e35f11e1ccc6a44c9f260f8f25596dd0655e Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 15:31:52 -0400 Subject: [PATCH 16/78] Added exception handling to StackApiController->create() Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 4 ++-- lib/Controller/StackApiController.php | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index f54a04eda..4b632a268 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -84,8 +84,8 @@ ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/board/{id}/undo_delete', 'verb' => 'POST'], ['name' => 'stack_api#index', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'GET'], - ['name' => 'stack_api#create', 'url' => '/api/v1.0/board/{boardId}/stack', 'verb' => 'POST'], - ['name' => 'stack_api#delete', 'url' => '/api/v1.0/board/{boardId}/stack/{id}', 'verb' => 'DELETE'], + ['name' => 'stack_api#create', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'POST'], + ['name' => 'stack_api#delete', 'url' => '/api/v1.0/board/{boardId}/stacks/{id}', 'verb' => 'DELETE'], ['name' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}', 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 2cf02e499..ad4dae9be 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -28,6 +28,7 @@ use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; +use OCA\Deck\StatusException; use OCA\Deck\Service\StackService; /** @@ -59,7 +60,6 @@ public function __construct($appName, IRequest $request, StackService $service) */ public function index($boardId) { $stacks = $this->service->findAll($boardId); - return new DataResponse($stacks); } @@ -73,19 +73,17 @@ public function index($boardId) { * * Create a stack with the specified title and order. */ - public function create($boardId, $title, $order) { - $errorMessage['params']['boardId'] = $boardId; - $errorMessage['params']['title'] = $title; - $errorMessage['params']['order'] = $order; - - // try { - // // this throws a StatusException that needs to be caught and handled - // $stack = $this->service->create($title, $boardId, $order); - // } catch (StatusException $e) { - // return new DataResponse(null, Http::STATUS_OK); - // } + public function create($boardId, $title, $order) { + + try { + // this throws a StatusException that needs to be caught and handled + $stack = $this->service->create($title, $boardId, $order); + } catch (StatusException $e) { + $errorMessage['error'] = $e->getMessage(); + return new DataResponse($errorMessage, Http::STATUS_INTERNAL_SERVER_ERROR); + } - return new DataResponse($errorMessage, HTTP::STATUS_NOT_IMPLEMENTED); + return new DataResponse($stack, HTTP::STATUS_OK); } /** From 9bc9569a0d832a7878e7a63bfbf0692d12ec837e Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 16:11:30 -0400 Subject: [PATCH 17/78] Added checks to see if the entity is not found in BoardApiController -> get($id) Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 8 ++++---- lib/Controller/BoardApiController.php | 9 +++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index 4b632a268..f7a6f0576 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -78,10 +78,10 @@ // api ['name' => 'board_api#index', 'url' => '/api/v1.0/boards', 'verb' => 'GET'], - ['name' => 'board_api#get', 'url' => '/api/v1.0/board/{id}', 'verb' => 'GET'], - ['name' => 'board_api#create', 'url' => '/api/v1.0/board', 'verb' => 'POST'], - ['name' => 'board_api#delete', 'url' => '/api/v1.0/board/{id}', 'verb' => 'DELETE'], - ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/board/{id}/undo_delete', 'verb' => 'POST'], + ['name' => 'board_api#get', 'url' => '/api/v1.0/boards/{id}', 'verb' => 'GET'], + ['name' => 'board_api#create', 'url' => '/api/v1.0/boards', 'verb' => 'POST'], + ['name' => 'board_api#delete', 'url' => '/api/v1.0/boards/{id}', 'verb' => 'DELETE'], + ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/boards/{id}/undo_delete', 'verb' => 'POST'], ['name' => 'stack_api#index', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'GET'], ['name' => 'stack_api#create', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'POST'], diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 312590541..c2d2813f7 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -24,6 +24,7 @@ namespace OCA\Deck\Controller; use OCP\AppFramework\ApiController; +use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; use OCP\IUserManager; @@ -74,10 +75,14 @@ public function index() { * * Return the board specified by $id. */ - public function get($id) { + public function get($id) { $board = $this->service->find($id); + + if ($board === false || $board === null) { + return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); + } - return new DataResponse($board); + return new DataResponse($board, HTTP::STATUS_OK); } /** From 3b49c7f262e7cce2f0e698047b5ff43585350e72 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 17:14:35 -0400 Subject: [PATCH 18/78] Added exception handling to BoardApiController -> Delete Signed-off-by: Ryan Fletcher --- lib/Controller/BoardApiController.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index c2d2813f7..448428bbb 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -113,7 +113,11 @@ public function create($title, $color) { public function delete($id) { $board = $this->service->delete($id); - return new DataResponse($board); + if ($board === false || $board === null) { + return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); + } + + return new DataResponse($board, HTTP::STATUS_OK); } /** From d82746be97b7a990b4c2c48273a0ee861f7273f7 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 17:31:59 -0400 Subject: [PATCH 19/78] Error handling for undoDelete and created an update method in BoardApiController Signed-off-by: Ryan Fletcher --- lib/Controller/BoardApiController.php | 32 +++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 448428bbb..c90d1240d 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -3,6 +3,7 @@ * @copyright Copyright (c) 2017 Steven R. Baker * * @author Steven R. Baker + * @author Ryan Fletcher * * @license GNU AGPL version 3 or any later version * @@ -101,6 +102,28 @@ public function create($title, $color) { return new DataResponse($board); } + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $boardId + * @params $title + * @params $color + * @params $archived + * + * Create a board with the specified title and color. + */ + public function update($boardId, $title, $color, $archived) { + $board = $this->service->update($boardId, $title, $color, $archived); + + if ($board === false || $board === null) { + return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); + } + + return new DataResponse($board, HTTP::STATUS_OK); + } + /** * @NoAdminRequired * @CORS @@ -131,9 +154,14 @@ public function delete($id) { */ public function undoDelete($id) { $board = $this->service->find($id); - $this->service->deleteUndo($id); - return new DataResponse($board); + if ($board === false || $board === null) { + return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); + } else { + $board = $this->service->deleteUndo($id); + } + + return new DataResponse($board, HTTP::STATUS_OK); } } From 6822d7d099827414429eba95d85ed6825750e3db Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 18:08:53 -0400 Subject: [PATCH 20/78] Error handling in undelete function and created the update function in BoardApiController Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 1 + lib/Controller/BoardApiController.php | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index f7a6f0576..e6524ae51 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -81,6 +81,7 @@ ['name' => 'board_api#get', 'url' => '/api/v1.0/boards/{id}', 'verb' => 'GET'], ['name' => 'board_api#create', 'url' => '/api/v1.0/boards', 'verb' => 'POST'], ['name' => 'board_api#delete', 'url' => '/api/v1.0/boards/{id}', 'verb' => 'DELETE'], + ['name' => 'board_api#update', 'url' => '/api/v1.0/boards/{id}', 'verb' => 'PUT'], ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/boards/{id}/undo_delete', 'verb' => 'POST'], ['name' => 'stack_api#index', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'GET'], diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index c90d1240d..1f0ede20e 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -114,7 +114,8 @@ public function create($title, $color) { * * Create a board with the specified title and color. */ - public function update($boardId, $title, $color, $archived) { + public function update($boardId, $title, $color, $archived) { + $board = $this->service->update($boardId, $title, $color, $archived); if ($board === false || $board === null) { From 0da84a3e8cf9ec9bdce3935f558cade94043502a Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 20:33:12 -0400 Subject: [PATCH 21/78] Corrected comment in BoardApiController from copy / paste. Signed-off-by: Ryan Fletcher --- lib/Controller/BoardApiController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 1f0ede20e..f854e0278 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -112,7 +112,7 @@ public function create($title, $color) { * @params $color * @params $archived * - * Create a board with the specified title and color. + * Update a board with the specified boardId, title and color, and archived state. */ public function update($boardId, $title, $color, $archived) { From cec06493c0db56f5cef00fddec7c8d0d69bef52f Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 20:54:54 -0400 Subject: [PATCH 22/78] Error handling for StackApiController->Index() Signed-off-by: Ryan Fletcher --- lib/Controller/StackApiController.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index ad4dae9be..bde0296c7 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -60,7 +60,12 @@ public function __construct($appName, IRequest $request, StackService $service) */ public function index($boardId) { $stacks = $this->service->findAll($boardId); - return new DataResponse($stacks); + + if ($stacks === false || $stacks === null) { + return new DataResponse("No Stacks Found", HTTP::STATUS_NOT_FOUND); + } + + return new DataResponse($stacks, HTTP::STATUS_OK); } /** From be91ff641c601fe13e2301c7944d1700bd7cf790 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 21:11:40 -0400 Subject: [PATCH 23/78] StackApiController added the update put route. Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 1 + lib/Controller/StackApiController.php | 29 ++++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index e6524ae51..b07f465d9 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -86,6 +86,7 @@ ['name' => 'stack_api#index', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'GET'], ['name' => 'stack_api#create', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'POST'], + ['name' => 'stack_api#update', 'url' => '/api/v1.0/board/{boardId}/stacks/{id}', 'verb' => 'PUT'], ['name' => 'stack_api#delete', 'url' => '/api/v1.0/board/{boardId}/stacks/{id}', 'verb' => 'DELETE'], ['name' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}', diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index bde0296c7..77c08c683 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -80,12 +80,35 @@ public function index($boardId) { */ public function create($boardId, $title, $order) { - try { - // this throws a StatusException that needs to be caught and handled + try { $stack = $this->service->create($title, $boardId, $order); } catch (StatusException $e) { $errorMessage['error'] = $e->getMessage(); - return new DataResponse($errorMessage, Http::STATUS_INTERNAL_SERVER_ERROR); + return new DataResponse($errorMessage, HTTP::STATUS_INTERNAL_SERVER_ERROR); + } + + return new DataResponse($stack, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $stackId + * @params $title + * @params $boardId + * @params $order + * + * Create a stack with the specified title and order. + */ + public function update($stackId, $title, $boardId, $order) { + + try { + $stack = $this->service->update($stackId, $title, $boardId, $order); + } catch (StatusException $e) { + $errorMessage['error'] = $e->getMessage(); + return new DataResponse($errorMessage, HTTP::STATUS_INTERNAL_SERVER_ERROR); } return new DataResponse($stack, HTTP::STATUS_OK); From 03e0559afe4a8e01cd1d4833c48197a23f4258bb Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 21:17:04 -0400 Subject: [PATCH 24/78] StackApiController->delete($boardId, $id) added in error handling Signed-off-by: Ryan Fletcher --- lib/Controller/StackApiController.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 77c08c683..f73a768e7 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -123,10 +123,14 @@ public function update($stackId, $title, $boardId, $order) { * * Delete the stack specified by $id. Return the board that was deleted. */ - public function delete($boardId, $id) { - $stack = $this->service->delete($id); + public function delete($boardId, $stackId) { + $stack = $this->service->delete($stackId); - return new DataResponse($stack); + if ($stack == false || $stack == null) { + return new DataResponse("Stack Not Found", HTTP::STATUS_NOT_FOUND); + } + + return new DataResponse($stack, HTTP::STATUS_OK); } } From 3cb496daa2b5a607cceba632013039e4e155f89e Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 21:45:43 -0400 Subject: [PATCH 25/78] Cleaned up StackApiController to use proper route parameters, removed route parameters from request payloads as per rest standards. Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 8 +++--- lib/Controller/StackApiController.php | 40 +++++++++++++-------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index b07f465d9..f9f0fb992 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -84,10 +84,10 @@ ['name' => 'board_api#update', 'url' => '/api/v1.0/boards/{id}', 'verb' => 'PUT'], ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/boards/{id}/undo_delete', 'verb' => 'POST'], - ['name' => 'stack_api#index', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'GET'], - ['name' => 'stack_api#create', 'url' => '/api/v1.0/board/{boardId}/stacks', 'verb' => 'POST'], - ['name' => 'stack_api#update', 'url' => '/api/v1.0/board/{boardId}/stacks/{id}', 'verb' => 'PUT'], - ['name' => 'stack_api#delete', 'url' => '/api/v1.0/board/{boardId}/stacks/{id}', 'verb' => 'DELETE'], + ['name' => 'stack_api#index', 'url' => '/api/v1.0/boards/{boardId}/stacks', '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' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}', 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index f73a768e7..84717c100 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -3,6 +3,7 @@ * @copyright Copyright (c) 2017 Steven R. Baker * * @author Steven R. Baker + * @author Ryan Fletcher * * @license GNU AGPL version 3 or any later version * @@ -58,8 +59,8 @@ public function __construct($appName, IRequest $request, StackService $service) * * Return all of the stacks in the specified board. */ - public function index($boardId) { - $stacks = $this->service->findAll($boardId); + public function index() { + $stacks = $this->service->findAll($this->request->params['boardId']); if ($stacks === false || $stacks === null) { return new DataResponse("No Stacks Found", HTTP::STATUS_NOT_FOUND); @@ -78,10 +79,10 @@ public function index($boardId) { * * Create a stack with the specified title and order. */ - public function create($boardId, $title, $order) { + public function create($title, $order) { - try { - $stack = $this->service->create($title, $boardId, $order); + try { + $stack = $this->service->create($title, $this->request->params['boardId'], $order); } catch (StatusException $e) { $errorMessage['error'] = $e->getMessage(); return new DataResponse($errorMessage, HTTP::STATUS_INTERNAL_SERVER_ERROR); @@ -94,18 +95,19 @@ public function create($boardId, $title, $order) { * @NoAdminRequired * @CORS * @NoCSRFRequired - * - * @params $stackId - * @params $title - * @params $boardId + * + * @params $title * @params $order * - * Create a stack with the specified title and order. + * Update a stack by the specified stackId and boardId with the values that were put. */ - public function update($stackId, $title, $boardId, $order) { - + public function update($title, $order) { try { - $stack = $this->service->update($stackId, $title, $boardId, $order); + $stack = $this->service->update( + $this->request->params['stackId'], + $title, + $this->request->params['boardId'], + $order); } catch (StatusException $e) { $errorMessage['error'] = $e->getMessage(); return new DataResponse($errorMessage, HTTP::STATUS_INTERNAL_SERVER_ERROR); @@ -117,15 +119,13 @@ public function update($stackId, $title, $boardId, $order) { /** * @NoAdminRequired * @CORS - * @NoCSRFRequired - * - * @params $id + * @NoCSRFRequired * - * Delete the stack specified by $id. Return the board that was deleted. + * Delete the stack specified by $this->request->params['id']. Return the board that was deleted. */ - public function delete($boardId, $stackId) { - $stack = $this->service->delete($stackId); - + public function delete() { + $stack = $this->service->delete($this->request->params['stackId']); + if ($stack == false || $stack == null) { return new DataResponse("Stack Not Found", HTTP::STATUS_NOT_FOUND); } From 5415ec21dc2b813815082c8f6adc2ae9c3a69884 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 22:10:43 -0400 Subject: [PATCH 26/78] Validation Checking against StackApiController Signed-off-by: Ryan Fletcher --- lib/Controller/StackApiController.php | 35 ++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 84717c100..e86c7931b 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -60,6 +60,12 @@ public function __construct($appName, IRequest $request, StackService $service) * Return all of the stacks in the specified board. */ public function index() { + + // validation check against the id. + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + $stacks = $this->service->findAll($this->request->params['boardId']); if ($stacks === false || $stacks === null) { @@ -81,6 +87,15 @@ public function index() { */ public function create($title, $order) { + // validation check against the id. + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($order) === false) { + return new DataResponse("order must be a number", HTTP::STATUS_BAD_REQUEST); + } + try { $stack = $this->service->create($title, $this->request->params['boardId'], $order); } catch (StatusException $e) { @@ -102,6 +117,19 @@ public function create($title, $order) { * Update a stack by the specified stackId and boardId with the values that were put. */ public function update($title, $order) { + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($this->request->params['stackId']) === false) { + return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($order) === false) { + return new DataResponse("order must be a number", HTTP::STATUS_BAD_REQUEST); + } + try { $stack = $this->service->update( $this->request->params['stackId'], @@ -121,9 +149,14 @@ public function update($title, $order) { * @CORS * @NoCSRFRequired * - * Delete the stack specified by $this->request->params['id']. Return the board that was deleted. + * Delete the stack specified by $this->request->params['stackId']. Return the board that was deleted. */ public function delete() { + + if (is_numeric($this->request->params['stackId']) === false) { + return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + } + $stack = $this->service->delete($this->request->params['stackId']); if ($stack == false || $stack == null) { From ced87edfa5b25f3295998b331929f16b22369c45 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 23:01:38 -0400 Subject: [PATCH 27/78] Put in validation responses in BoardApiController Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 11 ++-- lib/Controller/BoardApiController.php | 82 ++++++++++++++++++++------- 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index f9f0fb992..9329a04ee 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -78,18 +78,17 @@ // api ['name' => 'board_api#index', 'url' => '/api/v1.0/boards', 'verb' => 'GET'], - ['name' => 'board_api#get', 'url' => '/api/v1.0/boards/{id}', '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/{id}', 'verb' => 'DELETE'], - ['name' => 'board_api#update', 'url' => '/api/v1.0/boards/{id}', 'verb' => 'PUT'], - ['name' => 'board_api#undo_delete', 'url' => '/api/v1.0/boards/{id}/undo_delete', '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#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' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}', - 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], + ['name' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}','verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ] ]; diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index f854e0278..7ad777060 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -64,7 +64,7 @@ public function __construct($appName, IRequest $request, BoardService $service, public function index() { $boards = $this->service->findAll(); - return new DataResponse($boards); + return new DataResponse($boards, HTTP::STATUS_OK); } /** @@ -72,13 +72,17 @@ public function index() { * @CORS * @NoCSRFRequired * - * @params $id * - * Return the board specified by $id. + * Return the board specified by $this->request->params['boardId']. */ - public function get($id) { - $board = $this->service->find($id); - + public function get() { + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + $board = $this->service->find($this->request->params['boardId']); + if ($board === false || $board === null) { return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); } @@ -97,26 +101,54 @@ public function get($id) { * Create a board with the specified title and color. */ public function create($title, $color) { + + if ($title === false) { + return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + } + + if ($color === false) { + return new DataResponse("color must be provided", HTTP::STATUS_BAD_REQUEST); + } + $board = $this->service->create($title, $this->userId, $color); - return new DataResponse($board); + if ($board === false || $board === null) { + return new DataResponse('Internal Server Error', HTTP::STATUS_INTERNAL_SERVER_ERROR); + } + + return new DataResponse($board, HTTP::STATUS_OK); } /** * @NoAdminRequired * @CORS * @NoCSRFRequired - * - * @params $boardId + * * @params $title * @params $color * @params $archived * * Update a board with the specified boardId, title and color, and archived state. */ - public function update($boardId, $title, $color, $archived) { + public function update($title, $color, $archived = false) { + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_bool($archived) === false) { + return new DataResponse("archived must be a boolean", HTTP::STATUS_BAD_REQUEST); + } + + if ($title === false) { + return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + } + + if ($color === false) { + return new DataResponse("color must be provided", HTTP::STATUS_BAD_REQUEST); + } - $board = $this->service->update($boardId, $title, $color, $archived); + $board = $this->service->update($this->request->params['boardId'], $title, $color, $archived); if ($board === false || $board === null) { return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); @@ -129,13 +161,17 @@ public function update($boardId, $title, $color, $archived) { * @NoAdminRequired * @CORS * @NoCSRFRequired + * * - * @params $id - * - * Delete the board specified by $id. Return the board that was deleted. + * Delete the board specified by $boardId. Return the board that was deleted. */ - public function delete($id) { - $board = $this->service->delete($id); + public function delete() { + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + $board = $this->service->delete($this->request->params['boardId']); if ($board === false || $board === null) { return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); @@ -148,13 +184,17 @@ public function delete($id) { * @NoAdminRequired * @CORS * @NoCSRFRequired + * * - * @params $id - * - * Undo the deletion of the board specified by $id. + * Undo the deletion of the board specified by $boardId. */ - public function undoDelete($id) { - $board = $this->service->find($id); + public function undoDelete() { + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + $board = $this->service->find($this->request->params['boardId']); if ($board === false || $board === null) { return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); From 0c0910ee8146a1a04afce5136c6a5b114e5b210b Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Thu, 12 Jul 2018 23:11:52 -0400 Subject: [PATCH 28/78] Co authored for my changes. Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 1 + 1 file changed, 1 insertion(+) diff --git a/appinfo/routes.php b/appinfo/routes.php index 9329a04ee..881b25390 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 * From a68e888654553d35091430b1688a908c1ed44f83 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 01:44:46 -0400 Subject: [PATCH 29/78] Started CardApiController Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 4 + lib/Controller/CardApiController.php | 125 +++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 lib/Controller/CardApiController.php diff --git a/appinfo/routes.php b/appinfo/routes.php index 881b25390..bedac90ed 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -85,11 +85,15 @@ ['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'], + // TODO: Add in a get for the stack_api ['name' => 'stack_api#index', 'url' => '/api/v1.0/boards/{boardId}/stacks', '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' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}','verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ] ]; diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php new file mode 100644 index 000000000..5f2d5d7d9 --- /dev/null +++ b/lib/Controller/CardApiController.php @@ -0,0 +1,125 @@ + + * + * @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 BoardService $service + * @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() { + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($this->request->params['stackId']) === false) { + return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($this->request->params['cardId']) === false) { + return new DataResponse("card id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + $card = $this->cardService->find($this->request->params['cardId']); + + if ($card === false || $card === null) { + return new DataResponse('Card not found', HTTP::STATUS_NOT_FOUND); + } + + 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) { + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($this->request->params['stackId']) === false) { + return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if ($title === false) { + return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + } + + if ($type === false) { + return new DataResponse("type must be provided", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($order) === false) { + return new DataResponse("order must be a number", HTTP::STATUS_BAD_REQUEST); + } + + try { + $card = $this->cardService->create($title, $this->request->params['stackId'], $type, $order, $this->userId); + } catch (StatusException $e) { + return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); + } + + return new DataResponse($card, HTTP::STATUS_OK); + } +} \ No newline at end of file From e5f7f89ed9549a9fcf1713dd47f0e01d9c1a3b52 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 08:37:51 -0400 Subject: [PATCH 30/78] Wrote update method for CardApiController Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 1 + lib/Controller/CardApiController.php | 56 +++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index bedac90ed..b8a372d80 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -93,6 +93,7 @@ ['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' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}','verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ] diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index 5f2d5d7d9..64e68ac11 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -102,24 +102,68 @@ public function create($title, $type = 'plain', $order = 999) { return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); } - if ($title === false) { + if ($title === false || $title === null) { return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); } - if ($type === false) { - return new DataResponse("type must be provided", HTTP::STATUS_BAD_REQUEST); - } - if (is_numeric($order) === false) { return new DataResponse("order must be a number", HTTP::STATUS_BAD_REQUEST); } try { $card = $this->cardService->create($title, $this->request->params['stackId'], $type, $order, $this->userId); - } catch (StatusException $e) { + } catch (Exception $e) { return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); } return new DataResponse($card, HTTP::STATUS_OK); } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $type + * @params $order + * @params $description + * @params $duedate + * + * Get a specific card. + */ + public function update($title, $type, $order, $description = null, $duedate = null) { + + if (is_numeric($this->request->params['cardId']) === false) { + return new DataResponse("card id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($this->request->params['stackId']) === false) { + return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if ($title === false || $title === null) { + return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($order) === false) { + return new DataResponse("order must be a number", HTTP::STATUS_BAD_REQUEST); + } + + try { + $card = $this->cardService->update( + $this->request->params['cardId'], + $title, + $this->request->params['stackId'], + $type, + $order, + $description, + $this->userId, + $duedate); + } catch(Exception $e) { + return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); + } + + return new DataResponse($card, HTTP::STATUS_OK); + } } \ No newline at end of file From b82591a0bc2720fa6ce4ef595f9bd96720ee2852 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 10:04:22 -0400 Subject: [PATCH 31/78] Added delete operation to CardApiController Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 1 + lib/Controller/CardApiController.php | 34 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/appinfo/routes.php b/appinfo/routes.php index b8a372d80..6c7a6e5c7 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -94,6 +94,7 @@ ['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#delete', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'DELETE'], ['name' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}','verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ] diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index 64e68ac11..e375a9660 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -142,6 +142,10 @@ public function update($title, $type, $order, $description = null, $duedate = nu return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); } + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + if ($title === false || $title === null) { return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); } @@ -164,6 +168,36 @@ public function update($title, $type, $order, $description = null, $duedate = nu return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); } + return new DataResponse($card, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Delete a specific card. + */ + public function delete() { + + if (is_numeric($this->request->params['cardId']) === false) { + return new DataResponse("card id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($this->request->params['stackId']) === false) { + return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + try { + $card = $this->cardService->delete($this->request->params['cardId']); + } catch (Exception $e) { + return new DataResponse($e.getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); + } + return new DataResponse($card, HTTP::STATUS_OK); } } \ No newline at end of file From 7e4d24236a86f56a5a361e2ff45d374bfb0da3f0 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 10:52:14 -0400 Subject: [PATCH 32/78] Updated the CardApiController->update method to allow updating of archive state and assigned user,. Signed-off-by: Ryan Fletcher --- lib/Controller/CardApiController.php | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index e375a9660..1b3cfe779 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -129,10 +129,12 @@ public function create($title, $type = 'plain', $order = 999) { * @params $order * @params $description * @params $duedate + * @params $archive + * @params $assignedUserId * * Get a specific card. */ - public function update($title, $type, $order, $description = null, $duedate = null) { + public function update($title, $type, $order, $description = null, $duedate = null, $archive = false, $assignedUserId = 0) { if (is_numeric($this->request->params['cardId']) === false) { return new DataResponse("card id must be a number", HTTP::STATUS_BAD_REQUEST); @@ -154,6 +156,14 @@ public function update($title, $type, $order, $description = null, $duedate = nu return new DataResponse("order must be a number", HTTP::STATUS_BAD_REQUEST); } + if (is_bool($order) === false) { + return new DataResponse("archive must be a boolean", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($assignedUserId) === false) { + return new DataResponse("user id must be a number", HTTP::STATUS_BAD_REQUEST); + } + try { $card = $this->cardService->update( $this->request->params['cardId'], @@ -164,12 +174,25 @@ public function update($title, $type, $order, $description = null, $duedate = nu $description, $this->userId, $duedate); + + if ($archive) { + $card = $this->cardService->archive($this->request->params['cardId']); + } else { + $card = $this->cardService->unarchive($this->request->params['cardId']); + } + + if ($assignedUserId > 0) { + $card = $this->cardService->assignUser($this->request->params['cardId'], $assignedUserId); + } else { + $card = $this->cardService->assignUser($this->request->params['cardId'], $assignedUserId); + } + } catch(Exception $e) { return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); } return new DataResponse($card, HTTP::STATUS_OK); - } + } /** * @NoAdminRequired From 6002067b6478df6607baa39d02c0e8bc2f888a90 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 11:43:44 -0400 Subject: [PATCH 33/78] Created LabelApiController and it's get / update methods. Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 3 + lib/Controller/CardApiController.php | 4 +- lib/Controller/LabelApiController.php | 117 ++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 lib/Controller/LabelApiController.php diff --git a/appinfo/routes.php b/appinfo/routes.php index 6c7a6e5c7..5b90c0759 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -96,6 +96,9 @@ ['name' => 'card_api#update', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}', '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#update', 'url' => '/api/v1.0/boards/{boardId}/labels/{labelId}', 'verb' => 'PUT'], + ['name' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}','verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ] ]; diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index 1b3cfe779..679a34f13 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -42,7 +42,7 @@ class CardApiController extends ApiController { /** * @param string $appName * @param IRequest $request - * @param BoardService $service + * @param CardService $service * @param $userId */ public function __construct($appName, IRequest $request, CardService $cardService, $userId) { @@ -70,7 +70,7 @@ public function get() { if (is_numeric($this->request->params['cardId']) === false) { return new DataResponse("card id must be a number", HTTP::STATUS_BAD_REQUEST); - } + } $card = $this->cardService->find($this->request->params['cardId']); diff --git a/lib/Controller/LabelApiController.php b/lib/Controller/LabelApiController.php new file mode 100644 index 000000000..11aa32974 --- /dev/null +++ b/lib/Controller/LabelApiController.php @@ -0,0 +1,117 @@ + + * + * @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; + + /** + * Class BoardApiController + * + * @package OCA\Deck\Controller + */ +class LabelApiController extends ApiController { + + private $labelService; + private $userId; + + /** + * @param string $appName + * @param IRequest $request + * @param LabelService $service + * @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() { + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($this->request->params['labelId']) === false) { + return new DataResponse("label id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + $label = $this->labelService->find($this->request->params['labelId']); + + if ($label === false || $label === null) { + return new DataResponse('Label not found', HTTP::STATUS_NOT_FOUND); + } + + return new DataResponse($label, HTTP::STATUS_OK); + } + + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $color + * Update a specific label + */ + public function update($title, $color) { + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($this->request->params['labelId']) === false) { + return new DataResponse("label id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if ($title === false || $title === null) { + return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + } + + if ($color === false || $color === null) { + return new DataResponse("color must be provided", HTTP::STATUS_BAD_REQUEST); + } + + try { + $label = $this->labelService->update($this->request->params['labelId'], $title, $color); + } catch (Exception $e) { + return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); + } + + return new DataResponse($label, HTTP::STATUS_OK); + } + +} \ No newline at end of file From f97c7c3f7b29a8a18232fe138ba471bd7c7f75f4 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 12:29:23 -0400 Subject: [PATCH 34/78] Added in Create + Delete functions to the LabelApiController Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 2 + lib/Controller/LabelApiController.php | 58 +++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/appinfo/routes.php b/appinfo/routes.php index 5b90c0759..3c9eaf484 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -97,7 +97,9 @@ ['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' => 'board_api#preflighted_cors', 'url' => '/api/v1.0/{path}','verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], ] diff --git a/lib/Controller/LabelApiController.php b/lib/Controller/LabelApiController.php index 11aa32974..86410730a 100644 --- a/lib/Controller/LabelApiController.php +++ b/lib/Controller/LabelApiController.php @@ -78,6 +78,38 @@ public function get() { return new DataResponse($label, HTTP::STATUS_OK); } + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * @params $title + * @params $color + * Create a new label + */ + public function create($title, $color) { + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if ($title === false || $title === null) { + return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + } + + if ($color === false || $color === null) { + return new DataResponse("color must be provided", HTTP::STATUS_BAD_REQUEST); + } + + try { + $label = $this->labelService->create($title, $color, $this->request->params['boardId']); + } catch (Exception $e) { + return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); + } + + return new DataResponse($label, HTTP::STATUS_OK); + } + /** * @NoAdminRequired * @CORS @@ -114,4 +146,30 @@ public function update($title, $color) { return new DataResponse($label, HTTP::STATUS_OK); } + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Delete a specific label + */ + public function delete() { + + if (is_numeric($this->request->params['boardId']) === false) { + return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + if (is_numeric($this->request->params['labelId']) === false) { + return new DataResponse("label id must be a number", HTTP::STATUS_BAD_REQUEST); + } + + try { + $label = $this->labelService->delete($this->request->params['labelId']); + } catch (Exception $e) { + return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); + } + + return new DataResponse($label, HTTP::STATUS_OK); + } + } \ No newline at end of file From 7d9fc83dc97723eafafade45eaa936dfa7d5d388 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 12:39:19 -0400 Subject: [PATCH 35/78] Code style fixings. Signed-off-by: Ryan Fletcher --- lib/Controller/BoardApiController.php | 18 +++++++------- lib/Controller/CardApiController.php | 34 +++++++++++++-------------- lib/Controller/LabelApiController.php | 22 ++++++++--------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 7ad777060..0822822a7 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -78,7 +78,7 @@ public function index() { public function get() { if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } $board = $this->service->find($this->request->params['boardId']); @@ -103,11 +103,11 @@ public function get() { public function create($title, $color) { if ($title === false) { - return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); } if ($color === false) { - return new DataResponse("color must be provided", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); } $board = $this->service->create($title, $this->userId, $color); @@ -133,19 +133,19 @@ public function create($title, $color) { public function update($title, $color, $archived = false) { if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_bool($archived) === false) { - return new DataResponse("archived must be a boolean", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('archived must be a boolean', HTTP::STATUS_BAD_REQUEST); } if ($title === false) { - return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); } if ($color === false) { - return new DataResponse("color must be provided", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); } $board = $this->service->update($this->request->params['boardId'], $title, $color, $archived); @@ -168,7 +168,7 @@ public function update($title, $color, $archived = false) { public function delete() { if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } $board = $this->service->delete($this->request->params['boardId']); @@ -191,7 +191,7 @@ public function delete() { public function undoDelete() { if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } $board = $this->service->find($this->request->params['boardId']); diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index 679a34f13..c754dd84c 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -61,15 +61,15 @@ public function __construct($appName, IRequest $request, CardService $cardServic public function get() { if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($this->request->params['stackId']) === false) { - return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($this->request->params['cardId']) === false) { - return new DataResponse("card id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('card id must be a number', HTTP::STATUS_BAD_REQUEST); } $card = $this->cardService->find($this->request->params['cardId']); @@ -95,19 +95,19 @@ public function get() { public function create($title, $type = 'plain', $order = 999) { if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($this->request->params['stackId']) === false) { - return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); } if ($title === false || $title === null) { - return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($order) === false) { - return new DataResponse("order must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('order must be a number', HTTP::STATUS_BAD_REQUEST); } try { @@ -137,31 +137,31 @@ public function create($title, $type = 'plain', $order = 999) { public function update($title, $type, $order, $description = null, $duedate = null, $archive = false, $assignedUserId = 0) { if (is_numeric($this->request->params['cardId']) === false) { - return new DataResponse("card id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('card id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($this->request->params['stackId']) === false) { - return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } if ($title === false || $title === null) { - return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($order) === false) { - return new DataResponse("order must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('order must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_bool($order) === false) { - return new DataResponse("archive must be a boolean", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('archive must be a boolean', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($assignedUserId) === false) { - return new DataResponse("user id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('user id must be a number', HTTP::STATUS_BAD_REQUEST); } try { @@ -204,15 +204,15 @@ public function update($title, $type, $order, $description = null, $duedate = nu public function delete() { if (is_numeric($this->request->params['cardId']) === false) { - return new DataResponse("card id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('card id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($this->request->params['stackId']) === false) { - return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } try { diff --git a/lib/Controller/LabelApiController.php b/lib/Controller/LabelApiController.php index 86410730a..c74cd1408 100644 --- a/lib/Controller/LabelApiController.php +++ b/lib/Controller/LabelApiController.php @@ -62,11 +62,11 @@ public function __construct($appName, IRequest $request, LabelService $labelServ public function get() { if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($this->request->params['labelId']) === false) { - return new DataResponse("label id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('label id must be a number', HTTP::STATUS_BAD_REQUEST); } $label = $this->labelService->find($this->request->params['labelId']); @@ -90,15 +90,15 @@ public function get() { public function create($title, $color) { if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } if ($title === false || $title === null) { - return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); } if ($color === false || $color === null) { - return new DataResponse("color must be provided", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); } try { @@ -122,19 +122,19 @@ public function create($title, $color) { public function update($title, $color) { if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($this->request->params['labelId']) === false) { - return new DataResponse("label id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('label id must be a number', HTTP::STATUS_BAD_REQUEST); } if ($title === false || $title === null) { - return new DataResponse("title must be provided", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); } if ($color === false || $color === null) { - return new DataResponse("color must be provided", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); } try { @@ -156,11 +156,11 @@ public function update($title, $color) { public function delete() { if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($this->request->params['labelId']) === false) { - return new DataResponse("label id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('label id must be a number', HTTP::STATUS_BAD_REQUEST); } try { From a14ca3d1f5cb914c63de4e2b335a0707097b26a7 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 13:26:47 -0400 Subject: [PATCH 36/78] Better error handling in StackApiController Signed-off-by: Ryan Fletcher --- lib/Controller/StackApiController.php | 88 ++++++++++++++++++--------- 1 file changed, 58 insertions(+), 30 deletions(-) diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index e86c7931b..b22cd7a94 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -39,6 +39,7 @@ */ class StackApiController extends ApiController { + private $boardService; private $service; private $userInfo; @@ -47,9 +48,10 @@ class StackApiController extends ApiController { * @param IRequest $request * @param StackService $service */ - public function __construct($appName, IRequest $request, StackService $service) { + public function __construct($appName, IRequest $request, StackService $service, BoardService $boardService) { parent::__construct($appName, $request); $this->service = $service; + $this->boardService = $boardService; } /** @@ -59,17 +61,17 @@ public function __construct($appName, IRequest $request, StackService $service) * * Return all of the stacks in the specified board. */ - public function index() { + public function index() { + $boardError = boardHasError($this->request->params['boardId']); - // validation check against the id. - if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); } - - $stacks = $this->service->findAll($this->request->params['boardId']); + $stacks = $this->service->findAll($this->request->params['boardId']); + if ($stacks === false || $stacks === null) { - return new DataResponse("No Stacks Found", HTTP::STATUS_NOT_FOUND); + return new DataResponse('No Stacks Found', HTTP::STATUS_NOT_FOUND); } return new DataResponse($stacks, HTTP::STATUS_OK); @@ -87,13 +89,14 @@ public function index() { */ public function create($title, $order) { - // validation check against the id. - if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + $boardError = boardHasError($this->request->params['boardId']); + + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); } if (is_numeric($order) === false) { - return new DataResponse("order must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('order must be a number', HTTP::STATUS_BAD_REQUEST); } try { @@ -118,52 +121,77 @@ public function create($title, $order) { */ public function update($title, $order) { - if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse("board id must be a number", HTTP::STATUS_BAD_REQUEST); + $boardError = boardHasError($this->request->params['boardId']); + + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); } if (is_numeric($this->request->params['stackId']) === false) { - return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($order) === false) { - return new DataResponse("order must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('order must be a number', HTTP::STATUS_BAD_REQUEST); } try { - $stack = $this->service->update( - $this->request->params['stackId'], - $title, - $this->request->params['boardId'], - $order); - } catch (StatusException $e) { - $errorMessage['error'] = $e->getMessage(); - return new DataResponse($errorMessage, HTTP::STATUS_INTERNAL_SERVER_ERROR); + $stack = $this->service->update($this->request->params['stackId'], $title, $this->request->params['boardId'], $order); + + if ($stack === false || $stack === null) { + return new DataResponse('Stack not found', HTTP::STATUS_NOT_FOUND); + } + + return new DataResponse($stack, HTTP::STATUS_OK); + } catch (StatusException $e) { + return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); } - - return new DataResponse($stack, HTTP::STATUS_OK); } /** * @NoAdminRequired * @CORS - * @NoCSRFRequired + * @NoCSRFRequired * - * Delete the stack specified by $this->request->params['stackId']. Return the board that was deleted. + * Delete the stack specified by $this->request->params['stackId']. */ public function delete() { + $boardError = boardHasError($this->request->params['boardId']); + + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); + } + if (is_numeric($this->request->params['stackId']) === false) { - return new DataResponse("stack id must be a number", HTTP::STATUS_BAD_REQUEST); + return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); } $stack = $this->service->delete($this->request->params['stackId']); if ($stack == false || $stack == null) { - return new DataResponse("Stack Not Found", HTTP::STATUS_NOT_FOUND); + return new DataResponse('Stack Not Found', HTTP::STATUS_NOT_FOUND); } return new DataResponse($stack, HTTP::STATUS_OK); } + + private function boardHasError($boardId) { + if (is_numeric($boardId) === false) { + $error['message'] = 'Board id must be a number'; + $error['status'] = HTTP::STATUS_BAD_REQUEST; + return $error; + } + + $board = $this->boardService->find($boardId); + + if ($board === false || $board === null) { + $error['message'] = 'Board does not exist'; + $error['status'] = HTTP::STATUS_NOT_FOUND; + return $error; + } + + return false; + } } From d9f3d492dc32f3dcbe3d399af58816c806970840 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 13:56:24 -0400 Subject: [PATCH 37/78] Better variable name for stackService in StackApiController Signed-off-by: Ryan Fletcher --- lib/Controller/StackApiController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index b22cd7a94..54c07900f 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -40,17 +40,17 @@ class StackApiController extends ApiController { private $boardService; - private $service; + private $stackService; private $userInfo; /** * @param string $appName * @param IRequest $request - * @param StackService $service + * @param StackService $stackService */ - public function __construct($appName, IRequest $request, StackService $service, BoardService $boardService) { + public function __construct($appName, IRequest $request, StackService $stackService, BoardService $boardService) { parent::__construct($appName, $request); - $this->service = $service; + $this->service = $stackService; $this->boardService = $boardService; } From a388d199dcd343acd30816634acc0fa814428dcc Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 14:55:46 -0400 Subject: [PATCH 38/78] Refactored error handling in StackApiController and moved it into ApiHelper.php, this will allow me to use the same checks in all controllers. Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 3 +- lib/Controller/Helper/ApiHelper.php | 49 +++++++++++++++++++++++++++ lib/Controller/StackApiController.php | 33 ++++++------------ 3 files changed, 60 insertions(+), 25 deletions(-) create mode 100644 lib/Controller/Helper/ApiHelper.php diff --git a/appinfo/routes.php b/appinfo/routes.php index 3c9eaf484..2b2e967c0 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -84,8 +84,7 @@ ['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'], - - // TODO: Add in a get for the stack_api + ['name' => 'stack_api#index', 'url' => '/api/v1.0/boards/{boardId}/stacks', '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'], diff --git a/lib/Controller/Helper/ApiHelper.php b/lib/Controller/Helper/ApiHelper.php new file mode 100644 index 000000000..f8f16828b --- /dev/null +++ b/lib/Controller/Helper/ApiHelper.php @@ -0,0 +1,49 @@ + + * + * @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\Helper; + +use OCP\AppFramework\Http; + +class ApiHelper { + + public static function entityHasError($entityId, $entityName, $service) { + if (is_numeric($entityId) === false) { + $error['message'] = $entityName . ' id must be a number'; + $error['status'] = HTTP::STATUS_BAD_REQUEST; + return $error; + } + + $entity = $service->find($entityId); + + if ($entity === false || $entity === null) { + $error['message'] = 'Board does not exist'; + $error['status'] = HTTP::STATUS_NOT_FOUND; + return $error; + } + + return false; + } + +} \ No newline at end of file diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 54c07900f..cba2383ed 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -31,6 +31,8 @@ use OCA\Deck\StatusException; use OCA\Deck\Service\StackService; +use OCA\Deck\Service\BoardService; +use OCA\Deck\Controller\Helper\ApiHelper; /** * Class StackApiController @@ -42,6 +44,7 @@ class StackApiController extends ApiController { private $boardService; private $stackService; private $userInfo; + private $apiHelper; /** * @param string $appName @@ -52,6 +55,7 @@ public function __construct($appName, IRequest $request, StackService $stackServ parent::__construct($appName, $request); $this->service = $stackService; $this->boardService = $boardService; + $this->apiHelper = new ApiHelper(); } /** @@ -62,7 +66,7 @@ public function __construct($appName, IRequest $request, StackService $stackServ * Return all of the stacks in the specified board. */ public function index() { - $boardError = boardHasError($this->request->params['boardId']); + $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -77,6 +81,8 @@ public function index() { return new DataResponse($stacks, HTTP::STATUS_OK); } + + /** * @NoAdminRequired * @CORS @@ -89,7 +95,7 @@ public function index() { */ public function create($title, $order) { - $boardError = boardHasError($this->request->params['boardId']); + $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -121,7 +127,7 @@ public function create($title, $order) { */ public function update($title, $order) { - $boardError = boardHasError($this->request->params['boardId']); + $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -157,7 +163,7 @@ public function update($title, $order) { */ public function delete() { - $boardError = boardHasError($this->request->params['boardId']); + $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -175,23 +181,4 @@ public function delete() { return new DataResponse($stack, HTTP::STATUS_OK); } - - private function boardHasError($boardId) { - if (is_numeric($boardId) === false) { - $error['message'] = 'Board id must be a number'; - $error['status'] = HTTP::STATUS_BAD_REQUEST; - return $error; - } - - $board = $this->boardService->find($boardId); - - if ($board === false || $board === null) { - $error['message'] = 'Board does not exist'; - $error['status'] = HTTP::STATUS_NOT_FOUND; - return $error; - } - - return false; - } - } From 2668f6b80c35311f92782e8dd9b066e75b3991dc Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 15:44:48 -0400 Subject: [PATCH 39/78] committing WIP (improving error validation across the api's) Signed-off-by: Ryan Fletcher --- lib/Controller/CardApiController.php | 66 +++++++++++++++++---------- lib/Controller/Helper/ApiHelper.php | 30 +++++++++--- lib/Controller/StackApiController.php | 8 ++-- lib/Service/StackService.php | 4 ++ 4 files changed, 73 insertions(+), 35 deletions(-) diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index c754dd84c..f91f97250 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -28,6 +28,9 @@ use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; + use OCA\Deck\Controller\Helper\ApiHelper; + use OCA\Deck\Service\BoardService; + use OCA\Deck\Service\StackService; use OCA\Deck\Service\CardService; /** @@ -37,7 +40,10 @@ */ class CardApiController extends ApiController { private $cardService; + private $boardService; + private $stackService; private $userId; + private $apiHelper; /** * @param string $appName @@ -45,10 +51,13 @@ class CardApiController extends ApiController { * @param CardService $service * @param $userId */ - public function __construct($appName, IRequest $request, CardService $cardService, $userId) { + public function __construct($appName, IRequest $request, CardService $cardService, BoardService $boardService, StackService $stackService, $userId) { parent::__construct($appName, $request); + $this->boardService = $boardService; $this->cardService = $cardService; + $this->stackService = $stackService; $this->userId = $userId; + $this->apiHelper = new ApiHelper(); } /** @@ -58,14 +67,15 @@ public function __construct($appName, IRequest $request, CardService $cardServic * * Get a specific card. */ - public function get() { - - if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); + public function get() { + $boardError = $this->apiHelper->boardHasError($this->request->params['boardId'], $this->boardService); + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); } - if (is_numeric($this->request->params['stackId']) === false) { - return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); + $stackError = $this->apiHelper->entityHasError($this->request->params['stackId'], 'stack', $this->stackService); + if ($stackError) { + return new DataResponse($stackError['message'], $stackError['status']); } if (is_numeric($this->request->params['cardId']) === false) { @@ -94,12 +104,14 @@ public function get() { */ public function create($title, $type = 'plain', $order = 999) { - if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); + $boardError = $this->apiHelper->boardHasError($this->request->params['boardId'], 'board', $this->boardService); + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); } - if (is_numeric($this->request->params['stackId']) === false) { - return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); + $stackError = $this->apiHelper->entityHasError($this->request->params['stackId'], 'stack', $this->stackService); + if ($stackError) { + return new DataResponse($stackError['message'], $stackError['status']); } if ($title === false || $title === null) { @@ -136,17 +148,19 @@ public function create($title, $type = 'plain', $order = 999) { */ public function update($title, $type, $order, $description = null, $duedate = null, $archive = false, $assignedUserId = 0) { - if (is_numeric($this->request->params['cardId']) === false) { - return new DataResponse('card id must be a number', HTTP::STATUS_BAD_REQUEST); + $boardError = $this->apiHelper->boardHasError($this->request->params['boardId'], 'board', $this->boardService); + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); } - if (is_numeric($this->request->params['stackId']) === false) { - return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); + $stackError = $this->apiHelper->entityHasError($this->request->params['stackId'], 'stack', $this->stackService); + if ($stackError) { + return new DataResponse($stackError['message'], $stackError['status']); } - if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - } + if (is_numeric($this->request->params['cardId']) === false) { + return new DataResponse('card id must be a number', HTTP::STATUS_BAD_REQUEST); + } if ($title === false || $title === null) { return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); @@ -203,17 +217,19 @@ public function update($title, $type, $order, $description = null, $duedate = nu */ public function delete() { - if (is_numeric($this->request->params['cardId']) === false) { - return new DataResponse('card id must be a number', HTTP::STATUS_BAD_REQUEST); + $boardError = $this->apiHelper->boardHasError($this->request->params['boardId'], 'board', $this->boardService); + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); } - if (is_numeric($this->request->params['stackId']) === false) { - return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); + $stackError = $this->apiHelper->entityHasError($this->request->params['stackId'], 'stack', $this->stackService); + if ($stackError) { + return new DataResponse($stackError['message'], $stackError['status']); } - if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - } + if (is_numeric($this->request->params['cardId']) === false) { + return new DataResponse('card id must be a number', HTTP::STATUS_BAD_REQUEST); + } try { $card = $this->cardService->delete($this->request->params['cardId']); diff --git a/lib/Controller/Helper/ApiHelper.php b/lib/Controller/Helper/ApiHelper.php index f8f16828b..8785dcbe0 100644 --- a/lib/Controller/Helper/ApiHelper.php +++ b/lib/Controller/Helper/ApiHelper.php @@ -28,17 +28,35 @@ class ApiHelper { - public static function entityHasError($entityId, $entityName, $service) { - if (is_numeric($entityId) === false) { - $error['message'] = $entityName . ' id must be a number'; + public static function boardHasError($boardId, $boardService) { + if (is_numeric($boardId) === false) { + $error['message'] = 'board id must be a number'; $error['status'] = HTTP::STATUS_BAD_REQUEST; return $error; } - $entity = $service->find($entityId); + $board = $boardService->find($boardId); - if ($entity === false || $entity === null) { - $error['message'] = 'Board does not exist'; + if ($board === false || $board === null) { + $error['message'] = 'board does not exist'; + $error['status'] = HTTP::STATUS_NOT_FOUND; + return $error; + } + + return false; + } + + public static function stackHasError($stackId, $stackService) { + if (is_numeric($stackId) === false) { + $error['message'] = 'board id must be a number'; + $error['status'] = HTTP::STATUS_BAD_REQUEST; + return $error; + } + + $stack = $stackService->find($stackId); + + if ($stack === false || $stack === null) { + $error['message'] = 'stack does not exist'; $error['status'] = HTTP::STATUS_NOT_FOUND; return $error; } diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index cba2383ed..e00fbfa85 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -66,7 +66,7 @@ public function __construct($appName, IRequest $request, StackService $stackServ * Return all of the stacks in the specified board. */ public function index() { - $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); + $boardError = $this->apiHelper->boardHasError( $this->request->params['boardId'], $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -95,7 +95,7 @@ public function index() { */ public function create($title, $order) { - $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); + $boardError = $this->apiHelper->boardHasError( $this->request->params['boardId'], $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -127,7 +127,7 @@ public function create($title, $order) { */ public function update($title, $order) { - $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); + $boardError = $this->apiHelper->boardHasError( $this->request->params['boardId'], $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -163,7 +163,7 @@ public function update($title, $order) { */ public function delete() { - $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); + $boardError = $this->apiHelper->boardHasError( $this->request->params['boardId'], $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); diff --git a/lib/Service/StackService.php b/lib/Service/StackService.php index b64766e79..72211f730 100644 --- a/lib/Service/StackService.php +++ b/lib/Service/StackService.php @@ -89,6 +89,10 @@ private function enrichStacksWithCards($stacks) { } } + public function find($stackId) { + throw new \Exception('Not yet implemented'); + } + public function findAll($boardId) { $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ); $stacks = $this->stackMapper->findAll($boardId); From dd1d4246fe3ad0851e7f5635d4842e1d30d1a30e Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 19:07:08 -0400 Subject: [PATCH 40/78] Finished Error handling across the API Signed-off-by: Ryan Fletcher --- lib/Controller/CardApiController.php | 8 +++---- lib/Controller/Helper/ApiHelper.php | 32 ++++++--------------------- lib/Controller/LabelApiController.php | 29 +++++++++++++++--------- lib/Controller/StackApiController.php | 8 +++---- lib/Service/StackService.php | 1 + 5 files changed, 34 insertions(+), 44 deletions(-) diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index f91f97250..d4b1dce08 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -68,7 +68,7 @@ public function __construct($appName, IRequest $request, CardService $cardServic * Get a specific card. */ public function get() { - $boardError = $this->apiHelper->boardHasError($this->request->params['boardId'], $this->boardService); + $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); } @@ -104,7 +104,7 @@ public function get() { */ public function create($title, $type = 'plain', $order = 999) { - $boardError = $this->apiHelper->boardHasError($this->request->params['boardId'], 'board', $this->boardService); + $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); } @@ -148,7 +148,7 @@ public function create($title, $type = 'plain', $order = 999) { */ public function update($title, $type, $order, $description = null, $duedate = null, $archive = false, $assignedUserId = 0) { - $boardError = $this->apiHelper->boardHasError($this->request->params['boardId'], 'board', $this->boardService); + $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); } @@ -217,7 +217,7 @@ public function update($title, $type, $order, $description = null, $duedate = nu */ public function delete() { - $boardError = $this->apiHelper->boardHasError($this->request->params['boardId'], 'board', $this->boardService); + $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); } diff --git a/lib/Controller/Helper/ApiHelper.php b/lib/Controller/Helper/ApiHelper.php index 8785dcbe0..81aa003a5 100644 --- a/lib/Controller/Helper/ApiHelper.php +++ b/lib/Controller/Helper/ApiHelper.php @@ -28,40 +28,22 @@ class ApiHelper { - public static function boardHasError($boardId, $boardService) { - if (is_numeric($boardId) === false) { - $error['message'] = 'board id must be a number'; + public static function entityHasError($entityId, $entityName, $service) { + if (is_numeric($entityId) === false) { + $error['message'] = $entityName . ' id must be a number'; $error['status'] = HTTP::STATUS_BAD_REQUEST; return $error; } - $board = $boardService->find($boardId); + $entity = $service->find($entityId); - if ($board === false || $board === null) { - $error['message'] = 'board does not exist'; + if ($entity === false || $entity === null) { + $error['message'] = $entityName . ' does not exist'; $error['status'] = HTTP::STATUS_NOT_FOUND; return $error; } return false; - } - - public static function stackHasError($stackId, $stackService) { - if (is_numeric($stackId) === false) { - $error['message'] = 'board id must be a number'; - $error['status'] = HTTP::STATUS_BAD_REQUEST; - return $error; - } - - $stack = $stackService->find($stackId); - - if ($stack === false || $stack === null) { - $error['message'] = 'stack does not exist'; - $error['status'] = HTTP::STATUS_NOT_FOUND; - return $error; - } - - return false; - } + } } \ No newline at end of file diff --git a/lib/Controller/LabelApiController.php b/lib/Controller/LabelApiController.php index c74cd1408..b2617d2f6 100644 --- a/lib/Controller/LabelApiController.php +++ b/lib/Controller/LabelApiController.php @@ -27,8 +27,9 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; - use OCA\Deck\Service\LabelService; +use OCA\Deck\Service\BoardService; +use OCA\Deck\Controller\Helper\ApiHelper; /** * Class BoardApiController @@ -46,10 +47,12 @@ class LabelApiController extends ApiController { * @param LabelService $service * @param $userId */ - public function __construct($appName, IRequest $request, LabelService $labelService, $userId) { + public function __construct($appName, IRequest $request, LabelService $labelService, BoardService $boardService, $userId) { parent::__construct($appName, $request); $this->labelService = $labelService; + $this->boardService = $boardService; $this->userId = $userId; + $this->apiHelper = new ApiHelper(); } /** @@ -61,9 +64,10 @@ public function __construct($appName, IRequest $request, LabelService $labelServ */ public function get() { - if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - } + $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); + } if (is_numeric($this->request->params['labelId']) === false) { return new DataResponse('label id must be a number', HTTP::STATUS_BAD_REQUEST); @@ -89,8 +93,9 @@ public function get() { */ public function create($title, $color) { - if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); + $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); } if ($title === false || $title === null) { @@ -121,8 +126,9 @@ public function create($title, $color) { */ public function update($title, $color) { - if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); + $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); } if (is_numeric($this->request->params['labelId']) === false) { @@ -155,8 +161,9 @@ public function update($title, $color) { */ public function delete() { - if (is_numeric($this->request->params['boardId']) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); + $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); } if (is_numeric($this->request->params['labelId']) === false) { diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index e00fbfa85..cba2383ed 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -66,7 +66,7 @@ public function __construct($appName, IRequest $request, StackService $stackServ * Return all of the stacks in the specified board. */ public function index() { - $boardError = $this->apiHelper->boardHasError( $this->request->params['boardId'], $this->boardService ); + $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -95,7 +95,7 @@ public function index() { */ public function create($title, $order) { - $boardError = $this->apiHelper->boardHasError( $this->request->params['boardId'], $this->boardService ); + $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -127,7 +127,7 @@ public function create($title, $order) { */ public function update($title, $order) { - $boardError = $this->apiHelper->boardHasError( $this->request->params['boardId'], $this->boardService ); + $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -163,7 +163,7 @@ public function update($title, $order) { */ public function delete() { - $boardError = $this->apiHelper->boardHasError( $this->request->params['boardId'], $this->boardService ); + $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); diff --git a/lib/Service/StackService.php b/lib/Service/StackService.php index 72211f730..4d4b086b5 100644 --- a/lib/Service/StackService.php +++ b/lib/Service/StackService.php @@ -89,6 +89,7 @@ private function enrichStacksWithCards($stacks) { } } + //TODO: Write this function so we can look up one stack id. public function find($stackId) { throw new \Exception('Not yet implemented'); } From cfd9ab98c69add5a4ee0fda36079fed65813ec48 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 13 Jul 2018 19:29:39 -0400 Subject: [PATCH 41/78] Implemented StackApiController Get Function. Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 1 + lib/Controller/StackApiController.php | 25 +++++++++++++++++++++++-- lib/Service/StackService.php | 14 ++++++++++++-- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index 2b2e967c0..69c7ca590 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -86,6 +86,7 @@ ['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#index', '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'], diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index cba2383ed..0cc57f9f5 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -66,7 +66,7 @@ public function __construct($appName, IRequest $request, StackService $stackServ * Return all of the stacks in the specified board. */ public function index() { - $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); + $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -81,8 +81,29 @@ public function index() { return new DataResponse($stacks, HTTP::STATUS_OK); } - + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + * Return all of the stacks in the specified board. + */ + public function get() { + $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); + } + + $stack = $this->service->find($this->request->params['stackId']); + + if ($stack == false || $stack == null) { + return new DataResponse("Stack not found", HTTP::STATUS_NOT_FOUND); + } + + return new DataResponse($stack, HTTP::STATUS_OK); + } + /** * @NoAdminRequired * @CORS diff --git a/lib/Service/StackService.php b/lib/Service/StackService.php index 4d4b086b5..c5bdb7a8d 100644 --- a/lib/Service/StackService.php +++ b/lib/Service/StackService.php @@ -89,9 +89,19 @@ private function enrichStacksWithCards($stacks) { } } - //TODO: Write this function so we can look up one stack id. public function find($stackId) { - throw new \Exception('Not yet implemented'); + $stack = $this->stackMapper->find($stackId); + $cards = $this->cardMapper->findAll($stackId); + foreach ($cards as $cardIndex => $card) { + $assignedUsers = $this->assignedUsersMapper->find($card->getId()); + $card->setAssignedUsers($assignedUsers); + if (array_key_exists($card->id, $labels)) { + $cards[$cardIndex]->setLabels($labels[$card->id]); + } + $card->setAttachmentCount($this->attachmentService->count($card->getId())); + } + $stack->setCards($cards); + return $stack; } public function findAll($boardId) { From 881b05aeb152657ed625ffbc0320aee93d265922 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sat, 14 Jul 2018 14:56:25 -0400 Subject: [PATCH 42/78] fixed BoardControllerTest from errors Signed-off-by: Ryan Fletcher --- tests/unit/controller/BoardControllerTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 From e0049cf07baf7ca577498236b11e2f757bfb8f03 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sat, 14 Jul 2018 15:11:21 -0400 Subject: [PATCH 43/78] Resolved unit tests errors, down from 36 to 9. Signed-off-by: Ryan Fletcher --- tests/unit/Service/CardServiceTest.php | 17 ++++++++++------- tests/unit/Service/PermissionServiceTest.php | 8 ++++---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/unit/Service/CardServiceTest.php b/tests/unit/Service/CardServiceTest.php index 74f4ee0bf..65fc67257 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(); 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); } From e8c53d71aa74256bdfae987d06873e36c6aff2f7 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sat, 14 Jul 2018 16:08:47 -0400 Subject: [PATCH 44/78] fixed more unit tests. Signed-off-by: Ryan Fletcher --- tests/unit/Service/BoardServiceTest.php | 21 ++++++++++++++++----- tests/unit/Service/CardServiceTest.php | 4 ++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/tests/unit/Service/BoardServiceTest.php b/tests/unit/Service/BoardServiceTest.php index c7b89e79f..d2b42f43d 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() { @@ -94,12 +105,12 @@ public function testFindAll() { $this->boardMapper->expects($this->once()) ->method('findAllByGroups') ->with('admin', ['a', 'b', 'c']) - ->willReturn([$b2, $b3]); + ->willReturn([$b2, $b3]); $userinfo = [ 'user' => 'admin', 'groups' => ['a', 'b', 'c'] ]; - $result = $this->service->findAll($userinfo); + $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 65fc67257..b00c5889c 100644 --- a/tests/unit/Service/CardServiceTest.php +++ b/tests/unit/Service/CardServiceTest.php @@ -336,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'); } From fad579c4d37dc10b689a226998d0a780e88c758e Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sat, 14 Jul 2018 19:53:04 -0400 Subject: [PATCH 45/78] Wrote first unit test for BoardApiController Signed-off-by: Ryan Fletcher --- .../controller/BoardApiControllerTest.php | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 tests/unit/controller/BoardApiControllerTest.php diff --git a/tests/unit/controller/BoardApiControllerTest.php b/tests/unit/controller/BoardApiControllerTest.php new file mode 100644 index 000000000..34231739f --- /dev/null +++ b/tests/unit/controller/BoardApiControllerTest.php @@ -0,0 +1,104 @@ + + * + * @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; + + 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 + ); + + } + + // Test to pass + 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); + } + + // test for the bad request path + public function testIndexBadRequest() { + $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->index(); + + $this->assertEquals($expected, $actual); + } + + // TODO: Write testGet() + public function testGet() { + $this->assertEquals(false, true); + } + + // TODO: Write testCreate() + public function testCreate() { + $this->assertEquals(false, true); + } + + // TODO: Write testUpdate() + public function testUpdate() { + $this->assertEquals(false, true); + } + + // TODO: Write testDelete() + public function testDelete() { + $this->assertEquals(false, true); + } + + // TODO: Write testUndoDelete() + public function testUndoDelete() { + $this->assertEquals(false, true); + } +} \ No newline at end of file From bd254fd2618aa82ef9a92957dc2a7efe45376467 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sat, 14 Jul 2018 21:57:16 -0400 Subject: [PATCH 46/78] BoardApiControllerTest wrote get() tests. Signed-off-by: Ryan Fletcher --- lib/Controller/BoardApiController.php | 8 ++-- .../controller/BoardApiControllerTest.php | 43 ++++++++++++++++--- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 0822822a7..5b5a82e6f 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -75,16 +75,16 @@ public function index() { * * Return the board specified by $this->request->params['boardId']. */ - public function get() { + public function get() { - if (is_numeric($this->request->params['boardId']) === false) { + if (is_numeric($this->request->getParam('boardId')) === false) { return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } - $board = $this->service->find($this->request->params['boardId']); + $board = $this->service->find($this->request->getParam('boardId')); if ($board === false || $board === null) { - return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); + return new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); } return new DataResponse($board, HTTP::STATUS_OK); diff --git a/tests/unit/controller/BoardApiControllerTest.php b/tests/unit/controller/BoardApiControllerTest.php index 34231739f..323f3d10b 100644 --- a/tests/unit/controller/BoardApiControllerTest.php +++ b/tests/unit/controller/BoardApiControllerTest.php @@ -51,7 +51,6 @@ public function setUp() { } - // Test to pass public function testIndex() { $board = new Board(); $board->setId('1'); @@ -68,18 +67,48 @@ public function testIndex() { $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 testGetBadRequest() { + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue('hello')); - // test for the bad request path - public function testIndexBadRequest() { $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->index(); + $actual = $this->controller->get(); $this->assertEquals($expected, $actual); } - // TODO: Write testGet() - public function testGet() { - $this->assertEquals(false, true); + public function testGetNotFound() { + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue('999')); + + $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); + $actual = $this->controller->get(); + + $this->assertEquals($expected, $actual); } // TODO: Write testCreate() From 1fe70568cb1c1cd344ced8e0dc147ff3e1cc96aa Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sat, 14 Jul 2018 22:30:41 -0400 Subject: [PATCH 47/78] Wrote unit tests for the BoardApiController -> create tests Signed-off-by: Ryan Fletcher --- lib/Controller/BoardApiController.php | 4 +-- .../controller/BoardApiControllerTest.php | 32 ++++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 5b5a82e6f..059432430 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -102,11 +102,11 @@ public function get() { */ public function create($title, $color) { - if ($title === false) { + if ($title === false || $title === null) { return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); } - if ($color === false) { + if ($color === false || $color === null) { return new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); } diff --git a/tests/unit/controller/BoardApiControllerTest.php b/tests/unit/controller/BoardApiControllerTest.php index 323f3d10b..3dd4af748 100644 --- a/tests/unit/controller/BoardApiControllerTest.php +++ b/tests/unit/controller/BoardApiControllerTest.php @@ -20,7 +20,6 @@ * along with this program. If not, see . * */ - namespace OCA\Deck\Controller; use OCP\AppFramework\Http; @@ -36,6 +35,7 @@ class BoardApiControllerTest extends \Test\TestCase { private $userId = 'admin'; private $controller; private $boardService; + private $exampleBoard; public function setUp() { parent::setUp(); @@ -49,6 +49,9 @@ public function setUp() { $this->userId ); + $this->exampleBoard['id'] = 1; + $this->exampleBoard['title'] = 'titled'; + $this->exampleBoard['color'] = '000000'; } public function testIndex() { @@ -110,10 +113,31 @@ public function testGetNotFound() { $this->assertEquals($expected, $actual); } - - // TODO: Write testCreate() + public function testCreate() { - $this->assertEquals(false, true); + $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 testCreateBadTitle() { + $expected = new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->create(null, $this->exampleBoard['color']); + $this->assertEquals($expected, $actual); + } + + public function testCreateBadColor() { + $expected = new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->create($this->exampleBoard['title'], null); + $this->assertEquals($expected, $actual); } // TODO: Write testUpdate() From 8dd732631af0155a6f2d801db0624f19176570b9 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sat, 14 Jul 2018 23:21:53 -0400 Subject: [PATCH 48/78] BoardApiController wrote update tests Signed-off-by: Ryan Fletcher --- lib/Controller/BoardApiController.php | 8 +-- .../controller/BoardApiControllerTest.php | 70 ++++++++++++++++++- 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 059432430..c76b04057 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -132,7 +132,7 @@ public function create($title, $color) { */ public function update($title, $color, $archived = false) { - if (is_numeric($this->request->params['boardId']) === false) { + if (is_numeric($this->request->getParam('boardId')) === false) { return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); } @@ -140,15 +140,15 @@ public function update($title, $color, $archived = false) { return new DataResponse('archived must be a boolean', HTTP::STATUS_BAD_REQUEST); } - if ($title === false) { + if ($title === false || $title === null) { return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); } - if ($color === false) { + if ($color === false || $color === null) { return new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); } - $board = $this->service->update($this->request->params['boardId'], $title, $color, $archived); + $board = $this->service->update($this->request->getParam('boardId'), $title, $color, $archived); if ($board === false || $board === null) { return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); diff --git a/tests/unit/controller/BoardApiControllerTest.php b/tests/unit/controller/BoardApiControllerTest.php index 3dd4af748..440c332d0 100644 --- a/tests/unit/controller/BoardApiControllerTest.php +++ b/tests/unit/controller/BoardApiControllerTest.php @@ -139,10 +139,74 @@ public function testCreateBadColor() { $actual = $this->controller->create($this->exampleBoard['title'], null); $this->assertEquals($expected, $actual); } - - // TODO: Write testUpdate() + public function testUpdate() { - $this->assertEquals(false, true); + $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 testUpdateBadId() { + $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->update($this->exampleBoard['title'], $this->exampleBoard['color']); + $this->assertEquals($expected, $actual); + } + + public function testUpdateBadArchived() { + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue($this->exampleBoard['id'])); + + $expected = new DataResponse('archived must be a boolean', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->update($this->exampleBoard['title'], $this->exampleBoard['color'], 'Not a boolean value'); + $this->assertEquals($expected, $actual); + } + + public function testUpdateBadTitle() { + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue($this->exampleBoard['id'])); + + $expected = new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->update(null, $this->exampleBoard['color']); + $this->assertEquals($expected, $actual); + } + + public function testUpdateBadColor() { + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue($this->exampleBoard['id'])); + + $expected = new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->update($this->exampleBoard['title'], null); + $this->assertEquals($expected, $actual); + } + + public function testUpdateBoardNotFound() { + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue($this->exampleBoard['id'])); + + $expected = new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); + $actual = $this->controller->update($this->exampleBoard['title'], $this->exampleBoard['color']); + $this->assertEquals($expected, $actual); } // TODO: Write testDelete() From 6d57b1081a1305a0bdf996f61054f9d5dfd293d9 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sun, 15 Jul 2018 07:48:57 -0400 Subject: [PATCH 49/78] BoardApiControllerTest wrote delete tests Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 2 +- lib/Controller/BoardApiController.php | 22 ++--- .../controller/BoardApiControllerTest.php | 91 ++++++++++++++++++- 3 files changed, 97 insertions(+), 18 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index 69c7ca590..26a2a4460 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -86,7 +86,7 @@ ['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#index', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}', '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'], diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index c76b04057..7859ea9cd 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -73,7 +73,7 @@ public function index() { * @NoCSRFRequired * * - * Return the board specified by $this->request->params['boardId']. + * Return the board specified by $this->request->getParam('boardId'). */ public function get() { @@ -151,7 +151,7 @@ public function update($title, $color, $archived = false) { $board = $this->service->update($this->request->getParam('boardId'), $title, $color, $archived); if ($board === false || $board === null) { - return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); + return new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); } return new DataResponse($board, HTTP::STATUS_OK); @@ -167,14 +167,14 @@ public function update($title, $color, $archived = false) { */ public function delete() { - if (is_numeric($this->request->params['boardId']) === false) { + if (is_numeric($this->request->getParam('boardId')) === false) { return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - } + } - $board = $this->service->delete($this->request->params['boardId']); + $board = $this->service->delete($this->request->getParam('boardId')); if ($board === false || $board === null) { - return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); + return new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); } return new DataResponse($board, HTTP::STATUS_OK); @@ -190,16 +190,14 @@ public function delete() { */ public function undoDelete() { - if (is_numeric($this->request->params['boardId']) === false) { + if (is_numeric($this->request->getParam('boardId')) === false) { return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - } + } - $board = $this->service->find($this->request->params['boardId']); + $board = $this->service->deleteUndo($this->request->getParam('boardId')); if ($board === false || $board === null) { - return new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); - } else { - $board = $this->service->deleteUndo($id); + return new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); } return new DataResponse($board, HTTP::STATUS_OK); diff --git a/tests/unit/controller/BoardApiControllerTest.php b/tests/unit/controller/BoardApiControllerTest.php index 440c332d0..0ed9915b7 100644 --- a/tests/unit/controller/BoardApiControllerTest.php +++ b/tests/unit/controller/BoardApiControllerTest.php @@ -204,18 +204,99 @@ public function testUpdateBoardNotFound() { ->with('boardId') ->will($this->returnValue($this->exampleBoard['id'])); - $expected = new DataResponse('Board not found', HTTP::STATUS_NOT_FOUND); + $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); $actual = $this->controller->update($this->exampleBoard['title'], $this->exampleBoard['color']); $this->assertEquals($expected, $actual); } // TODO: Write testDelete() - public function testDelete() { - $this->assertEquals(false, true); + 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); } - // TODO: Write testUndoDelete() + public function testDeleteBadId() { + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue('bad id')); + + $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->delete(); + + $this->assertEquals($expected, $actual); + } + + public function testDeleteNotFound() { + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue('85')); + + $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); + $actual = $this->controller->delete(); + + $this->assertEquals($expected, $actual); + } + public function testUndoDelete() { - $this->assertEquals(false, true); + $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); + } + + public function testUndoDeleteBadId() { + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue('bad id')); + + $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->undoDelete(); + $this->assertEquals($expected, $actual); + } + + public function testUndoDeleteNotFound() { + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue(189)); + + $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); + $actual = $this->controller->undoDelete(); + $this->assertEquals($expected, $actual); } } \ No newline at end of file From 2482dc963a6ba159bfca125a660ea3b22164b025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Sun, 15 Jul 2018 14:55:50 +0200 Subject: [PATCH 50/78] Fix BoardServiceTest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- tests/unit/Service/BoardServiceTest.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/unit/Service/BoardServiceTest.php b/tests/unit/Service/BoardServiceTest.php index d2b42f43d..5f9d5082d 100644 --- a/tests/unit/Service/BoardServiceTest.php +++ b/tests/unit/Service/BoardServiceTest.php @@ -105,11 +105,14 @@ public function testFindAll() { $this->boardMapper->expects($this->once()) ->method('findAllByGroups') ->with('admin', ['a', 'b', 'c']) - ->willReturn([$b2, $b3]); - $userinfo = [ - 'user' => 'admin', - 'groups' => ['a', 'b', 'c'] - ]; + ->willReturn([$b2, $b3]); + $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); From dcfb9f3903586b71d5fa5715a7852a6753123083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Sun, 15 Jul 2018 15:01:01 +0200 Subject: [PATCH 51/78] Properly annotate exceptions thrown by services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Db/AssignedUsersMapper.php | 6 ++ lib/Db/AttachmentMapper.php | 22 ++++++ lib/Service/AttachmentService.php | 16 +++++ lib/Service/BoardService.php | 94 ++++++++++++++++++++++++- lib/Service/CardService.php | 105 ++++++++++++++++++++++++++++ lib/Service/DefaultBoardService.php | 22 +++++- lib/Service/FileService.php | 14 ++++ lib/Service/LabelService.php | 35 ++++++++++ lib/Service/PermissionService.php | 66 ++++++++++------- lib/Service/StackService.php | 54 ++++++++++++-- 10 files changed, 401 insertions(+), 33 deletions(-) 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/Service/AttachmentService.php b/lib/Service/AttachmentService.php index a2bbcbc0a..53f89f518 100644 --- a/lib/Service/AttachmentService.php +++ b/lib/Service/AttachmentService.php @@ -123,6 +123,10 @@ public function findAll($cardId, $withDeleted = false) { return $attachments; } + /** + * @param $cardId + * @return int|mixed + */ public function count($cardId) { $count = $this->cache->get('card-' . $cardId); if (!$count) { @@ -132,6 +136,14 @@ public function count($cardId) { return $count; } + /** + * @param $cardId + * @param $type + * @param $data + * @return Attachment|\OCP\AppFramework\Db\Entity + * @throws NoPermissionException + * @throws StatusException + */ public function create($cardId, $type, $data) { $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); @@ -172,7 +184,11 @@ 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\MultipleObjectsReturnedException */ public function display($cardId, $attachmentId) { $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 1ce4f546b..6b250fb4a 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -75,6 +75,9 @@ public function __construct( $this->userId = $userId; } + /** + * @return array + */ public function findAll() { $userInfo = $this->getBoardPrerequisites(); $userBoards = $this->boardMapper->findAllByUser($userInfo['user']); @@ -102,6 +105,13 @@ public function findAll() { return array_values($result); } + /** + * @param $boardId + * @return Board + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + */ public function find($boardId) { $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ); /** @var Board $board */ @@ -124,6 +134,9 @@ public function find($boardId) { return $board; } + /** + * @return array + */ private function getBoardPrerequisites() { $groups = $this->groupManager->getUserGroupIds( $this->userManager->get($this->userId) @@ -134,6 +147,14 @@ private function getBoardPrerequisites() { ]; } + /** + * @param $mapper + * @param $id + * @return bool + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + */ public function isArchived($mapper, $id) { try { $boardId = $id; @@ -150,6 +171,14 @@ 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 + */ public function isDeleted($mapper, $id) { try { $boardId = $id; @@ -167,7 +196,12 @@ public function isDeleted($mapper, $id) { } - + /** + * @param $title + * @param $userId + * @param $color + * @return \OCP\AppFramework\Db\Entity + */ public function create($title, $userId, $color) { $board = new Board(); $board->setTitle($title); @@ -203,6 +237,13 @@ public function create($title, $userId, $color) { } + /** + * @param $id + * @return Board + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + */ public function delete($id) { $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_READ); $board = $this->find($id); @@ -211,6 +252,13 @@ 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) { $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_READ); $board = $this->find($id); @@ -218,12 +266,29 @@ public function deleteUndo($id) { return $this->boardMapper->update($board); } + /** + * @param $id + * @return \OCP\AppFramework\Db\Entity + * @throws DoesNotExistException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + */ public function deleteForce($id) { $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 + */ public function update($id, $title, $color, $archived) { $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_MANAGE); $board = $this->find($id); @@ -235,6 +300,16 @@ 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\NoPermissionException + */ public function addAcl($boardId, $type, $participant, $edit, $share, $manage) { $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_SHARE); $acl = new Acl(); @@ -253,6 +328,16 @@ 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 + */ public function updateAcl($id, $edit, $share, $manage) { $this->permissionService->checkPermission($this->aclMapper, $id, Acl::PERMISSION_SHARE); /** @var Acl $acl */ @@ -264,6 +349,13 @@ 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 + */ public function deleteAcl($id) { $this->permissionService->checkPermission($this->aclMapper, $id, Acl::PERMISSION_SHARE); /** @var Acl $acl */ diff --git a/lib/Service/CardService.php b/lib/Service/CardService.php index fcf691ecc..ad54f819d 100644 --- a/lib/Service/CardService.php +++ b/lib/Service/CardService.php @@ -89,6 +89,13 @@ 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 + */ public function find($cardId) { $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_READ); $card = $this->cardMapper->find($cardId); @@ -100,7 +107,16 @@ 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 */ public function create($title, $stackId, $type, $order, $owner) { $this->permissionService->checkPermission($this->stackMapper, $stackId, Acl::PERMISSION_EDIT); @@ -117,6 +133,14 @@ public function create($title, $stackId, $type, $order, $owner) { } + /** + * @param $id + * @return \OCP\AppFramework\Db\Entity + * @throws StatusException + * @throws \OCA\Deck\NoPermissionException + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + */ public function delete($id) { $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { @@ -128,6 +152,21 @@ public function delete($id) { return $card; } + /** + * @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 + */ public function update($id, $title, $stackId, $type, $order, $description, $owner, $duedate, $deletedAt) { $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { @@ -148,6 +187,15 @@ 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 + */ public function rename($id, $title) { $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { @@ -161,6 +209,16 @@ 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 + */ public function reorder($id, $stackId, $order) { $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { @@ -192,6 +250,14 @@ 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\MultipleObjectsReturnedException + */ public function archive($id) { $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { @@ -202,6 +268,14 @@ 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 + */ public function unarchive($id) { $this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $id)) { @@ -212,6 +286,14 @@ 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 + */ public function assignLabel($cardId, $labelId) { $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $cardId)) { @@ -224,6 +306,14 @@ 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 + */ public function removeLabel($cardId, $labelId) { $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); if ($this->boardService->isArchived($this->cardMapper, $cardId)) { @@ -236,6 +326,13 @@ 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 + */ public function assignUser($cardId, $userId) { $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); $assignments = $this->assignedUsersMapper->find($cardId); @@ -257,6 +354,14 @@ 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 + */ public function unassignUser($cardId, $userId) { $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); $assignments = $this->assignedUsersMapper->find($cardId); diff --git a/lib/Service/DefaultBoardService.php b/lib/Service/DefaultBoardService.php index f79b8d24e..82fc02fa5 100644 --- a/lib/Service/DefaultBoardService.php +++ b/lib/Service/DefaultBoardService.php @@ -55,8 +55,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 +74,17 @@ 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 + */ + public function createDefaultBoard($title, $userId, $color) { $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..2b0a640be 100644 --- a/lib/Service/LabelService.php +++ b/lib/Service/LabelService.php @@ -44,11 +44,28 @@ 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 + */ public function find($labelId) { $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 + */ public function create($title, $color, $boardId) { $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE); if ($this->boardService->isArchived(null, $boardId)) { @@ -61,6 +78,14 @@ 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 + */ public function delete($id) { $this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE); if ($this->boardService->isArchived($this->labelMapper, $id)) { @@ -69,6 +94,16 @@ 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 + */ public function update($id, $title, $color) { $this->permissionService->checkPermission($this->labelMapper, $id, Acl::PERMISSION_MANAGE); if ($this->boardService->isArchived($this->labelMapper, $id)) { diff --git a/lib/Service/PermissionService.php b/lib/Service/PermissionService.php index 8b7e69d12..5dff31be8 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,41 +116,40 @@ 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); + try { + $board = $this->boardMapper->find($boardId); + } catch (DoesNotExistException $e) { + } catch (MultipleObjectsReturnedException $e) { + return false; + } return $board && $this->userId === $board->getOwner(); } @@ -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 c5bdb7a8d..ae0850dae 100644 --- a/lib/Service/StackService.php +++ b/lib/Service/StackService.php @@ -89,21 +89,29 @@ private function enrichStacksWithCards($stacks) { } } + /** + * @param $stackId + * @return \OCP\AppFramework\Db\Entity + * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + */ public function find($stackId) { $stack = $this->stackMapper->find($stackId); $cards = $this->cardMapper->findAll($stackId); foreach ($cards as $cardIndex => $card) { $assignedUsers = $this->assignedUsersMapper->find($card->getId()); $card->setAssignedUsers($assignedUsers); - if (array_key_exists($card->id, $labels)) { - $cards[$cardIndex]->setLabels($labels[$card->id]); - } $card->setAttachmentCount($this->attachmentService->count($card->getId())); } $stack->setCards($cards); return $stack; } + /** + * @param $boardId + * @return array + * @throws \OCA\Deck\NoPermissionException + */ public function findAll($boardId) { $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ); $stacks = $this->stackMapper->findAll($boardId); @@ -118,6 +126,11 @@ public function fetchDeleted($boardId) { return $stacks; } + /** + * @param $boardId + * @return array + * @throws \OCA\Deck\NoPermissionException + */ public function findAllArchived($boardId) { $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_READ); $stacks = $this->stackMapper->findAll($boardId); @@ -135,7 +148,14 @@ 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 */ public function create($title, $boardId, $order) { $this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE); @@ -150,6 +170,13 @@ 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 + */ public function delete($id) { $this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE); @@ -162,7 +189,18 @@ 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 + */ public function update($id, $title, $boardId, $order, $deletedAt) { $this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_MANAGE); if ($this->boardService->isArchived($this->stackMapper, $id)) { @@ -176,6 +214,14 @@ 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 + */ public function reorder($id, $order) { $this->permissionService->checkPermission($this->stackMapper, $id, Acl::PERMISSION_EDIT); $stackToSort = $this->stackMapper->find($id); From 54f110f7c687cbab98f227f8e6037c5d0d0ba06f Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sun, 15 Jul 2018 12:17:55 -0400 Subject: [PATCH 52/78] first attempt at BoardApiControllerTest->testGetNoPermission() Signed-off-by: Ryan Fletcher --- lib/Controller/BoardApiController.php | 2 +- .../controller/BoardApiControllerTest.php | 34 ++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 7859ea9cd..30296e150 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -75,7 +75,7 @@ public function index() { * * Return the board specified by $this->request->getParam('boardId'). */ - public function get() { + public function get() { if (is_numeric($this->request->getParam('boardId')) === false) { return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); diff --git a/tests/unit/controller/BoardApiControllerTest.php b/tests/unit/controller/BoardApiControllerTest.php index 0ed9915b7..1cd0f84ba 100644 --- a/tests/unit/controller/BoardApiControllerTest.php +++ b/tests/unit/controller/BoardApiControllerTest.php @@ -36,6 +36,7 @@ class BoardApiControllerTest extends \Test\TestCase { private $controller; private $boardService; private $exampleBoard; + private $deniedBoard; public function setUp() { parent::setUp(); @@ -51,7 +52,12 @@ public function setUp() { $this->exampleBoard['id'] = 1; $this->exampleBoard['title'] = 'titled'; - $this->exampleBoard['color'] = '000000'; + $this->exampleBoard['color'] = '000000'; + + $this->deniedBoard['id'] = 2; + $this->deniedBoard['owner'] = 'someone else'; + $this->deniedBoard['title'] = 'titled'; + $this->deniedBoard['color'] = '000000'; } public function testIndex() { @@ -113,6 +119,32 @@ public function testGetNotFound() { $this->assertEquals($expected, $actual); } + + public function testGetNoPermission() { + + $board = new Board(); + $board->setId($this->deniedBoard['id']); + $board->setOwner($this->deniedBoard['owner']); + $this->boardService->expects($this->once()) + ->method('find') + ->willReturn($board); + + // permission service check. + // ------ there be dragons here ----- + // $this->permissionsService->expect($this->once()) + // ->method('matchPermissions') + // ->with($board) + // ->will($this->) + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue('999')); + + $expected = new DataResponse("Access Denied: User has no access rights to board", HTTP::STATUS_FORBIDDEN); + $actual = $this->controller->get(); + $this->assertEquals($expected, $actual); + } public function testCreate() { $board = new Board(); From 891fa7b7d5896c7e3fbf5ef09d0da4c226351ad3 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sun, 15 Jul 2018 15:35:48 -0400 Subject: [PATCH 53/78] Created index tests for StackApiTestController Signed-off-by: Ryan Fletcher --- lib/Controller/Helper/ApiHelper.php | 2 +- lib/Controller/StackApiController.php | 22 ++-- lib/Service/PermissionService.php | 4 +- .../controller/BoardApiControllerTest.php | 26 ---- .../controller/StackApiControllerTest.php | 113 ++++++++++++++++++ 5 files changed, 125 insertions(+), 42 deletions(-) create mode 100644 tests/unit/controller/StackApiControllerTest.php diff --git a/lib/Controller/Helper/ApiHelper.php b/lib/Controller/Helper/ApiHelper.php index 81aa003a5..c19baaaf8 100644 --- a/lib/Controller/Helper/ApiHelper.php +++ b/lib/Controller/Helper/ApiHelper.php @@ -38,7 +38,7 @@ public static function entityHasError($entityId, $entityName, $service) { $entity = $service->find($entityId); if ($entity === false || $entity === null) { - $error['message'] = $entityName . ' does not exist'; + $error['message'] = $entityName . ' not found'; $error['status'] = HTTP::STATUS_NOT_FOUND; return $error; } diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 0cc57f9f5..137de1e6d 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -66,17 +66,13 @@ public function __construct($appName, IRequest $request, StackService $stackServ * Return all of the stacks in the specified board. */ public function index() { - $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); + $boardError = $this->apiHelper->entityHasError($this->request->getParam('boardId'), 'board', $this->boardService); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); } - - $stacks = $this->service->findAll($this->request->params['boardId']); - if ($stacks === false || $stacks === null) { - return new DataResponse('No Stacks Found', HTTP::STATUS_NOT_FOUND); - } + $stacks = $this->service->findAll($this->request->getParam('boardId')); return new DataResponse($stacks, HTTP::STATUS_OK); } @@ -88,8 +84,8 @@ public function index() { * * Return all of the stacks in the specified board. */ - public function get() { - $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); + public function get() { + $boardError = $this->apiHelper->entityHasError($this->request->getParam('boardId'), 'board', $this->boardService); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -116,7 +112,7 @@ public function get() { */ public function create($title, $order) { - $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); + $boardError = $this->apiHelper->entityHasError( $this->request->getParam('boardId'), 'board', $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -127,7 +123,7 @@ public function create($title, $order) { } try { - $stack = $this->service->create($title, $this->request->params['boardId'], $order); + $stack = $this->service->create($title, $this->request->getParam('boardId'), $order); } catch (StatusException $e) { $errorMessage['error'] = $e->getMessage(); return new DataResponse($errorMessage, HTTP::STATUS_INTERNAL_SERVER_ERROR); @@ -148,7 +144,7 @@ public function create($title, $order) { */ public function update($title, $order) { - $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); + $boardError = $this->apiHelper->entityHasError( $this->request->getParam('boardId'), 'board', $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); @@ -163,7 +159,7 @@ public function update($title, $order) { } try { - $stack = $this->service->update($this->request->params['stackId'], $title, $this->request->params['boardId'], $order); + $stack = $this->service->update($this->request->params['stackId'], $title, $this->request->getParam('boardId'), $order); if ($stack === false || $stack === null) { return new DataResponse('Stack not found', HTTP::STATUS_NOT_FOUND); @@ -184,7 +180,7 @@ public function update($title, $order) { */ public function delete() { - $boardError = $this->apiHelper->entityHasError( $this->request->params['boardId'], 'board', $this->boardService ); + $boardError = $this->apiHelper->entityHasError( $this->request->getParam('boardId'), 'board', $this->boardService ); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); diff --git a/lib/Service/PermissionService.php b/lib/Service/PermissionService.php index 5dff31be8..8bd0623aa 100644 --- a/lib/Service/PermissionService.php +++ b/lib/Service/PermissionService.php @@ -146,11 +146,11 @@ public function checkPermission($mapper, $id, $permission) { public function userIsBoardOwner($boardId) { try { $board = $this->boardMapper->find($boardId); + return $board && $this->userId === $board->getOwner(); } catch (DoesNotExistException $e) { } catch (MultipleObjectsReturnedException $e) { return false; - } - return $board && $this->userId === $board->getOwner(); + } } /** diff --git a/tests/unit/controller/BoardApiControllerTest.php b/tests/unit/controller/BoardApiControllerTest.php index 1cd0f84ba..df3783f1a 100644 --- a/tests/unit/controller/BoardApiControllerTest.php +++ b/tests/unit/controller/BoardApiControllerTest.php @@ -119,32 +119,6 @@ public function testGetNotFound() { $this->assertEquals($expected, $actual); } - - public function testGetNoPermission() { - - $board = new Board(); - $board->setId($this->deniedBoard['id']); - $board->setOwner($this->deniedBoard['owner']); - $this->boardService->expects($this->once()) - ->method('find') - ->willReturn($board); - - // permission service check. - // ------ there be dragons here ----- - // $this->permissionsService->expect($this->once()) - // ->method('matchPermissions') - // ->with($board) - // ->will($this->) - - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue('999')); - - $expected = new DataResponse("Access Denied: User has no access rights to board", HTTP::STATUS_FORBIDDEN); - $actual = $this->controller->get(); - $this->assertEquals($expected, $actual); - } public function testCreate() { $board = new Board(); diff --git a/tests/unit/controller/StackApiControllerTest.php b/tests/unit/controller/StackApiControllerTest.php new file mode 100644 index 000000000..4a8bb93d1 --- /dev/null +++ b/tests/unit/controller/StackApiControllerTest.php @@ -0,0 +1,113 @@ + + * + * @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'] = 245; + $this->exampleStack['order'] = 0; + + $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]; + + $board = new Board(); + $board->setId($this->exampleBoard['boardId']); + $this->boardService->expects($this->once()) + ->method('find') + ->willReturn($board); + + $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 testIndexBadBoardId() { + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue('bad board id')); + + $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->index(); + $this->assertEquals($expected, $actual); + } + + public function testIndexBoardNotFound() { + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue(689)); + + $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); + $actual = $this->controller->index(); + $this->assertEquals($expected, $actual); + } + +} \ No newline at end of file From 5719e9f134f3079e640bdbcd7f6c47b2d2730eac Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sun, 15 Jul 2018 20:01:55 -0400 Subject: [PATCH 54/78] Wrote unit tests against StackApiController -> get() Signed-off-by: Ryan Fletcher --- lib/Controller/StackApiController.php | 24 ++-- .../controller/StackApiControllerTest.php | 109 +++++++++++++++++- 2 files changed, 121 insertions(+), 12 deletions(-) diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 137de1e6d..d605d6499 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -90,11 +90,15 @@ public function get() { if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); } - - $stack = $this->service->find($this->request->params['stackId']); - if ($stack == false || $stack == null) { - return new DataResponse("Stack not found", HTTP::STATUS_NOT_FOUND); + if (is_numeric($this->request->getParam('stackId')) === false) { + return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); + } + + $stack = $this->service->find($this->request->getParam('stackId')); + + if ($stack === false || $stack === null) { + return new DataResponse('stack not found', HTTP::STATUS_NOT_FOUND); } return new DataResponse($stack, HTTP::STATUS_OK); @@ -150,7 +154,7 @@ public function update($title, $order) { return new DataResponse($boardError['message'], $boardError['status']); } - if (is_numeric($this->request->params['stackId']) === false) { + if (is_numeric($this->request->getParam('stackId')) === false) { return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); } @@ -159,10 +163,10 @@ public function update($title, $order) { } try { - $stack = $this->service->update($this->request->params['stackId'], $title, $this->request->getParam('boardId'), $order); + $stack = $this->service->update($this->request->getParam('stackId'), $title, $this->request->getParam('boardId'), $order); if ($stack === false || $stack === null) { - return new DataResponse('Stack not found', HTTP::STATUS_NOT_FOUND); + return new DataResponse('stack not found', HTTP::STATUS_NOT_FOUND); } return new DataResponse($stack, HTTP::STATUS_OK); @@ -176,7 +180,7 @@ public function update($title, $order) { * @CORS * @NoCSRFRequired * - * Delete the stack specified by $this->request->params['stackId']. + * Delete the stack specified by $this->request->getParam('stackId'). */ public function delete() { @@ -186,11 +190,11 @@ public function delete() { return new DataResponse($boardError['message'], $boardError['status']); } - if (is_numeric($this->request->params['stackId']) === false) { + if (is_numeric($this->request->getParam('stackId')) === false) { return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); } - $stack = $this->service->delete($this->request->params['stackId']); + $stack = $this->service->delete($this->request->getParam('stackId')); if ($stack == false || $stack == null) { return new DataResponse('Stack Not Found', HTTP::STATUS_NOT_FOUND); diff --git a/tests/unit/controller/StackApiControllerTest.php b/tests/unit/controller/StackApiControllerTest.php index 4a8bb93d1..4b02701cc 100644 --- a/tests/unit/controller/StackApiControllerTest.php +++ b/tests/unit/controller/StackApiControllerTest.php @@ -48,7 +48,7 @@ public function setUp() { $this->stackService = $this->createMock(StackService::class); $this->exampleStack['id'] = 345; - $this->exampleStack['boardId'] = 245; + $this->exampleStack['boardId'] = $this->exampleBoard['boardId']; $this->exampleStack['order'] = 0; $this->exampleBoard['boardId'] = '89'; @@ -65,7 +65,7 @@ public function testIndex() { $stack = new Stack(); $stack->setId($this->exampleStack['id']); $stack->setBoardId($this->exampleStack['boardId']); - $stack->setOrder($this->exampleStack['order']); + $stack->setOrder($this->exampleStack['order']); $stacks = [$stack]; $board = new Board(); @@ -110,4 +110,109 @@ public function testIndexBoardNotFound() { $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']); + + $board = new Board(); + $board->setId($this->exampleBoard['boardId']); + $this->boardService->expects($this->once()) + ->method('find') + ->willReturn($board); + + $this->stackService->expects($this->once()) + ->method('find') + ->willReturn($stack); + + $this->request->expects($this->exactly(3)) + ->method('getParam') + ->withConsecutive( + ['boardId'], + ['stackId'], + ['stackId'] + ) + ->willReturnOnConsecutiveCalls( + $this->returnValue($this->exampleBoard['boardId']), + $this->returnValue($this->exampleStack['id']), + $this->returnValue($this->exampleStack['id'])); + + $expected = new DataResponse($stack, HTTP::STATUS_OK); + $actual = $this->controller->get(); + $this->assertEquals($expected, $actual); + } + + public function testGetBadBoardId() { + + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue('NOT A BOARD ID')); + + $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->get(); + $this->assertEquals($expected, $actual); + } + + public function testGetBoardNotFound() { + $this->request->expects($this->any()) + ->method('getParam') + ->with('boardId') + ->will($this->returnValue(9251)); + + $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); + $actual = $this->controller->get(); + $this->assertEquals($expected, $actual); + } + + public function testGetStackBadStackId() { + + $board = new Board(); + $board->setId($this->exampleBoard['boardId']); + $this->boardService->expects($this->once()) + ->method('find') + ->willReturn($board); + + $this->request->expects($this->exactly(2)) + ->method('getParam') + ->withConsecutive( + ['boardId'], + ['stackId'] + ) + ->willReturnOnConsecutiveCalls( + $this->returnValue($this->exampleBoard['boardId']), + $this->returnValue('not a stack id'), + $this->returnValue('not a stack id')); + + $expected = new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->get(); + $this->assertEquals($expected, $actual); + } + + public function testGetStackNotFound() { + + $board = new Board(); + $board->setId($this->exampleBoard['boardId']); + $this->boardService->expects($this->once()) + ->method('find') + ->willReturn($board); + + $this->request->expects($this->exactly(3)) + ->method('getParam') + ->withConsecutive( + ['boardId'], + ['stackId'], + ['stackId'] + ) + ->willReturnOnConsecutiveCalls( + $this->returnValue($this->exampleBoard['boardId']), + $this->returnValue(5), + $this->returnValue(5)); + + $expected = new DataResponse('stack not found', HTTP::STATUS_NOT_FOUND); + $actual = $this->controller->get(); + $this->assertEquals($expected, $actual); + } + } \ No newline at end of file From 570ac81848f646f34aa1bf2748e77cd8f0daf8f4 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sun, 15 Jul 2018 21:11:49 -0400 Subject: [PATCH 55/78] added the create tests in StackApiControllerTest Signed-off-by: Ryan Fletcher --- lib/Controller/StackApiController.php | 29 +++-- .../controller/StackApiControllerTest.php | 114 +++++++++++++----- 2 files changed, 96 insertions(+), 47 deletions(-) diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index d605d6499..f38be59cf 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -85,15 +85,15 @@ public function index() { * Return all of the stacks in the specified board. */ public function get() { + if (is_numeric($this->request->getParam('stackId')) === false) { + return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); + } + $boardError = $this->apiHelper->entityHasError($this->request->getParam('boardId'), 'board', $this->boardService); if ($boardError) { return new DataResponse($boardError['message'], $boardError['status']); - } - - if (is_numeric($this->request->getParam('stackId')) === false) { - return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); - } + } $stack = $this->service->find($this->request->getParam('stackId')); @@ -116,22 +116,21 @@ public function get() { */ public function create($title, $order) { - $boardError = $this->apiHelper->entityHasError( $this->request->getParam('boardId'), 'board', $this->boardService ); - - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); + if ($title === false || $title === null) { + return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); } if (is_numeric($order) === false) { return new DataResponse('order must be a number', HTTP::STATUS_BAD_REQUEST); } - try { - $stack = $this->service->create($title, $this->request->getParam('boardId'), $order); - } catch (StatusException $e) { - $errorMessage['error'] = $e->getMessage(); - return new DataResponse($errorMessage, HTTP::STATUS_INTERNAL_SERVER_ERROR); - } + $boardError = $this->apiHelper->entityHasError( $this->request->getParam('boardId'), 'board', $this->boardService ); + + if ($boardError) { + return new DataResponse($boardError['message'], $boardError['status']); + } + + $stack = $this->service->create($title, $this->request->getParam('boardId'), $order); return new DataResponse($stack, HTTP::STATUS_OK); } diff --git a/tests/unit/controller/StackApiControllerTest.php b/tests/unit/controller/StackApiControllerTest.php index 4b02701cc..047ed88f7 100644 --- a/tests/unit/controller/StackApiControllerTest.php +++ b/tests/unit/controller/StackApiControllerTest.php @@ -49,7 +49,8 @@ public function setUp() { $this->exampleStack['id'] = 345; $this->exampleStack['boardId'] = $this->exampleBoard['boardId']; - $this->exampleStack['order'] = 0; + $this->exampleStack['order'] = 0; + $this->exampleStack['title'] = 'Example Stack From API'; $this->exampleBoard['boardId'] = '89'; @@ -128,14 +129,14 @@ public function testGet() { $this->request->expects($this->exactly(3)) ->method('getParam') - ->withConsecutive( - ['boardId'], + ->withConsecutive( ['stackId'], + ['boardId'], ['stackId'] ) - ->willReturnOnConsecutiveCalls( - $this->returnValue($this->exampleBoard['boardId']), + ->willReturnOnConsecutiveCalls( $this->returnValue($this->exampleStack['id']), + $this->returnValue($this->exampleBoard['boardId']), $this->returnValue($this->exampleStack['id'])); $expected = new DataResponse($stack, HTTP::STATUS_OK); @@ -145,45 +146,44 @@ public function testGet() { public function testGetBadBoardId() { - $this->request->expects($this->any()) + $this->request->expects($this->exactly(2)) ->method('getParam') - ->with('boardId') - ->will($this->returnValue('NOT A BOARD ID')); + ->withConsecutive( + ['stackId'], + ['boardId'] + ) + ->willReturnOnConsecutiveCalls( + $this->returnValue(5), + $this->returnValue('not a board id')); $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); $actual = $this->controller->get(); $this->assertEquals($expected, $actual); } - public function testGetBoardNotFound() { - $this->request->expects($this->any()) + public function testGetBoardNotFound() { + $this->request->expects($this->exactly(2)) ->method('getParam') - ->with('boardId') - ->will($this->returnValue(9251)); + ->withConsecutive( + ['stackId'], + ['boardId'] + ) + ->willReturnOnConsecutiveCalls( + $this->returnValue(5), + $this->returnValue($this->exampleBoard['boardId'])); + $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); $actual = $this->controller->get(); $this->assertEquals($expected, $actual); } - public function testGetStackBadStackId() { + public function testGetStackBadStackId() { - $board = new Board(); - $board->setId($this->exampleBoard['boardId']); - $this->boardService->expects($this->once()) - ->method('find') - ->willReturn($board); - - $this->request->expects($this->exactly(2)) + $this->request->expects($this->any()) ->method('getParam') - ->withConsecutive( - ['boardId'], - ['stackId'] - ) - ->willReturnOnConsecutiveCalls( - $this->returnValue($this->exampleBoard['boardId']), - $this->returnValue('not a stack id'), - $this->returnValue('not a stack id')); + ->with('stackId') + ->will($this->returnValue('not a stack id')); $expected = new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); $actual = $this->controller->get(); @@ -196,18 +196,18 @@ public function testGetStackNotFound() { $board->setId($this->exampleBoard['boardId']); $this->boardService->expects($this->once()) ->method('find') - ->willReturn($board); + ->willReturn($board); $this->request->expects($this->exactly(3)) ->method('getParam') ->withConsecutive( - ['boardId'], ['stackId'], + ['boardId'], ['stackId'] ) - ->willReturnOnConsecutiveCalls( - $this->returnValue($this->exampleBoard['boardId']), + ->willReturnOnConsecutiveCalls( $this->returnValue(5), + $this->returnValue($this->exampleBoard['boardId']), $this->returnValue(5)); $expected = new DataResponse('stack not found', HTTP::STATUS_NOT_FOUND); @@ -215,4 +215,54 @@ public function testGetStackNotFound() { $this->assertEquals($expected, $actual); } + public function testCreate() { + + $board = new Board(); + $board->setId($this->exampleBoard['boardId']); + $this->boardService->expects($this->once()) + ->method('find') + ->willReturn($board); + $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 testCreateBadOrder() { + $expected = new DataResponse('order must be a number', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->create($this->exampleStack['title'], 'not an order number'); + $this->assertEquals($expected, $actual); + } + + public function testCreateBadTitle() { + $expected = new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); + $actual = $this->controller->create(null, 999); + $this->assertEquals($expected, $actual); + } + + public function testCreateBoardNotFound() { + + $this->request->expects($this->once()) + ->method('getParam') + ->will($this->returnValue(453)); + + $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); + $actual = $this->controller->create($this->exampleStack['title'], $this->exampleStack['order']); + $this->assertEquals($expected, $actual); + } + } \ No newline at end of file From 8cac183af6dd0e1065dfdf5eb01be5fb9f773f0a Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sun, 15 Jul 2018 23:20:16 -0400 Subject: [PATCH 56/78] simple code style changes according to codacy standards. Signed-off-by: Ryan Fletcher --- lib/Controller/StackApiController.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index f38be59cf..c8ced0795 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -42,8 +42,7 @@ class StackApiController extends ApiController { private $boardService; - private $stackService; - private $userInfo; + private $stackService; private $apiHelper; /** @@ -53,7 +52,7 @@ class StackApiController extends ApiController { */ public function __construct($appName, IRequest $request, StackService $stackService, BoardService $boardService) { parent::__construct($appName, $request); - $this->service = $stackService; + $this->stackService = $stackService; $this->boardService = $boardService; $this->apiHelper = new ApiHelper(); } @@ -72,7 +71,7 @@ public function index() { return new DataResponse($boardError['message'], $boardError['status']); } - $stacks = $this->service->findAll($this->request->getParam('boardId')); + $stacks = $this->stackService->findAll($this->request->getParam('boardId')); return new DataResponse($stacks, HTTP::STATUS_OK); } @@ -95,7 +94,7 @@ public function get() { return new DataResponse($boardError['message'], $boardError['status']); } - $stack = $this->service->find($this->request->getParam('stackId')); + $stack = $this->stackService->find($this->request->getParam('stackId')); if ($stack === false || $stack === null) { return new DataResponse('stack not found', HTTP::STATUS_NOT_FOUND); @@ -130,7 +129,7 @@ public function create($title, $order) { return new DataResponse($boardError['message'], $boardError['status']); } - $stack = $this->service->create($title, $this->request->getParam('boardId'), $order); + $stack = $this->stackService->create($title, $this->request->getParam('boardId'), $order); return new DataResponse($stack, HTTP::STATUS_OK); } @@ -162,7 +161,7 @@ public function update($title, $order) { } try { - $stack = $this->service->update($this->request->getParam('stackId'), $title, $this->request->getParam('boardId'), $order); + $stack = $this->stackService->update($this->request->getParam('stackId'), $title, $this->request->getParam('boardId'), $order); if ($stack === false || $stack === null) { return new DataResponse('stack not found', HTTP::STATUS_NOT_FOUND); @@ -193,7 +192,7 @@ public function delete() { return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); } - $stack = $this->service->delete($this->request->getParam('stackId')); + $stack = $this->stackService->delete($this->request->getParam('stackId')); if ($stack == false || $stack == null) { return new DataResponse('Stack Not Found', HTTP::STATUS_NOT_FOUND); From d33dd3e0fcdfc447aa0b70d2843998cbcf381811 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Mon, 16 Jul 2018 09:53:54 -0400 Subject: [PATCH 57/78] Moved BadRequestException checks to middleware, removed uneeded unit tests in BoardApiController Signed-off-by: Ryan Fletcher --- lib/BadRequestException.php | 36 +++++ lib/Controller/BoardApiController.php | 79 +--------- lib/Middleware/SharingMiddleware.php | 3 +- lib/Service/BoardService.php | 52 +++++- .../controller/BoardApiControllerTest.php | 149 +----------------- 5 files changed, 100 insertions(+), 219 deletions(-) create mode 100644 lib/BadRequestException.php diff --git a/lib/BadRequestException.php b/lib/BadRequestException.php new file mode 100644 index 000000000..894721a35 --- /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 \Exception { + + 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/BoardApiController.php b/lib/Controller/BoardApiController.php index 30296e150..0d4770d7a 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -63,7 +63,6 @@ public function __construct($appName, IRequest $request, BoardService $service, */ public function index() { $boards = $this->service->findAll(); - return new DataResponse($boards, HTTP::STATUS_OK); } @@ -75,18 +74,8 @@ public function index() { * * Return the board specified by $this->request->getParam('boardId'). */ - public function get() { - - if (is_numeric($this->request->getParam('boardId')) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - } - + public function get() { $board = $this->service->find($this->request->getParam('boardId')); - - if ($board === false || $board === null) { - return new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); - } - return new DataResponse($board, HTTP::STATUS_OK); } @@ -100,22 +89,8 @@ public function get() { * * Create a board with the specified title and color. */ - public function create($title, $color) { - - if ($title === false || $title === null) { - return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); - } - - if ($color === false || $color === null) { - return new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); - } - - $board = $this->service->create($title, $this->userId, $color); - - if ($board === false || $board === null) { - return new DataResponse('Internal Server Error', HTTP::STATUS_INTERNAL_SERVER_ERROR); - } - + public function create($title, $color) { + $board = $this->service->create($title, $this->userId, $color); return new DataResponse($board, HTTP::STATUS_OK); } @@ -131,29 +106,7 @@ public function create($title, $color) { * Update a board with the specified boardId, title and color, and archived state. */ public function update($title, $color, $archived = false) { - - if (is_numeric($this->request->getParam('boardId')) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - if (is_bool($archived) === false) { - return new DataResponse('archived must be a boolean', HTTP::STATUS_BAD_REQUEST); - } - - if ($title === false || $title === null) { - return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); - } - - if ($color === false || $color === null) { - return new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); - } - $board = $this->service->update($this->request->getParam('boardId'), $title, $color, $archived); - - if ($board === false || $board === null) { - return new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); - } - return new DataResponse($board, HTTP::STATUS_OK); } @@ -166,17 +119,7 @@ public function update($title, $color, $archived = false) { * Delete the board specified by $boardId. Return the board that was deleted. */ public function delete() { - - if (is_numeric($this->request->getParam('boardId')) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - $board = $this->service->delete($this->request->getParam('boardId')); - - if ($board === false || $board === null) { - return new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); - } - + $board = $this->service->delete($this->request->getParam('boardId')); return new DataResponse($board, HTTP::STATUS_OK); } @@ -188,18 +131,8 @@ public function delete() { * * Undo the deletion of the board specified by $boardId. */ - public function undoDelete() { - - if (is_numeric($this->request->getParam('boardId')) === false) { - return new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - $board = $this->service->deleteUndo($this->request->getParam('boardId')); - - if ($board === false || $board === null) { - return new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); - } - + public function undoDelete() { + $board = $this->service->deleteUndo($this->request->getParam('boardId')); return new DataResponse($board, HTTP::STATUS_OK); } diff --git a/lib/Middleware/SharingMiddleware.php b/lib/Middleware/SharingMiddleware.php index 13fed3cb9..5e53a69df 100644 --- a/lib/Middleware/SharingMiddleware.php +++ b/lib/Middleware/SharingMiddleware.php @@ -24,6 +24,7 @@ namespace OCA\Deck\Middleware; use OCA\Deck\StatusException; +use OCA\Deck\BadRequestException; use OCP\AppFramework\Middleware; use OCP\AppFramework\Http\JSONResponse; use OCP\ILogger; @@ -59,7 +60,7 @@ public function __construct(ILogger $logger, IConfig $config) { * @throws \Exception */ public function afterException($controller, $methodName, \Exception $exception) { - if ($exception instanceof StatusException) { + if ($exception instanceof StatusException || $exception instanceof BadRequestException) { if ($this->config->getSystemValue('loglevel', Util::WARN) === Util::DEBUG) { $this->logger->logException($exception); } diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 6b250fb4a..b6d3da122 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -36,6 +36,7 @@ use OCA\Deck\Db\BoardMapper; use OCA\Deck\Db\LabelMapper; use OCP\IUserManager; +use OCA\Deck\BadRequestException; class BoardService { @@ -111,8 +112,14 @@ public function findAll() { * @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); @@ -201,13 +208,27 @@ public function isDeleted($mapper, $id) { * @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 = [ @@ -243,8 +264,14 @@ public function create($title, $userId, $color) { * @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()); @@ -260,6 +287,11 @@ public function delete($id) { * @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); @@ -288,8 +320,26 @@ public function deleteForce($id) { * @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); diff --git a/tests/unit/controller/BoardApiControllerTest.php b/tests/unit/controller/BoardApiControllerTest.php index df3783f1a..6a2ebf2d7 100644 --- a/tests/unit/controller/BoardApiControllerTest.php +++ b/tests/unit/controller/BoardApiControllerTest.php @@ -92,31 +92,6 @@ public function testGet() { $expected = new DataResponse($board, HTTP::STATUS_OK); $actual = $this->controller->get(); - $this->assertEquals($expected, $actual); - } - - public function testGetBadRequest() { - - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue('hello')); - - $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->get(); - - $this->assertEquals($expected, $actual); - } - - public function testGetNotFound() { - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue('999')); - - $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); - $actual = $this->controller->get(); - $this->assertEquals($expected, $actual); } @@ -132,20 +107,8 @@ public function testCreate() { $expected = new DataResponse($board, HTTP::STATUS_OK); $actual = $this->controller->create($this->exampleBoard['title'], $this->exampleBoard['color']); $this->assertEquals($expected, $actual); - } + } - public function testCreateBadTitle() { - $expected = new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->create(null, $this->exampleBoard['color']); - $this->assertEquals($expected, $actual); - } - - public function testCreateBadColor() { - $expected = new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->create($this->exampleBoard['title'], null); - $this->assertEquals($expected, $actual); - } - public function testUpdate() { $board = new Board(); $board->setId($this->exampleBoard['id']); @@ -163,61 +126,9 @@ public function testUpdate() { $expected = new DataResponse($board, HTTP::STATUS_OK); $actual = $this->controller->update($this->exampleBoard['title'], $this->exampleBoard['color']); $this->assertEquals($expected, $actual); - } - - public function testUpdateBadId() { - $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->update($this->exampleBoard['title'], $this->exampleBoard['color']); - $this->assertEquals($expected, $actual); - } - - public function testUpdateBadArchived() { - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue($this->exampleBoard['id'])); - - $expected = new DataResponse('archived must be a boolean', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->update($this->exampleBoard['title'], $this->exampleBoard['color'], 'Not a boolean value'); - $this->assertEquals($expected, $actual); - } - - public function testUpdateBadTitle() { - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue($this->exampleBoard['id'])); - - $expected = new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->update(null, $this->exampleBoard['color']); - $this->assertEquals($expected, $actual); - } - - public function testUpdateBadColor() { - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue($this->exampleBoard['id'])); - - $expected = new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->update($this->exampleBoard['title'], null); - $this->assertEquals($expected, $actual); - } - - public function testUpdateBoardNotFound() { - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue($this->exampleBoard['id'])); - - $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); - $actual = $this->controller->update($this->exampleBoard['title'], $this->exampleBoard['color']); - $this->assertEquals($expected, $actual); - } - - // TODO: Write testDelete() - public function testDelete() { - + } + + public function testDelete() { $board = new Board(); $board->setId($this->exampleBoard['id']); $board->setTitle($this->exampleBoard['title']); @@ -235,33 +146,7 @@ public function testDelete() { $actual = $this->controller->delete(); $this->assertEquals($expected, $actual); - } - - public function testDeleteBadId() { - - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue('bad id')); - - $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->delete(); - - $this->assertEquals($expected, $actual); - } - - public function testDeleteNotFound() { - - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue('85')); - - $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); - $actual = $this->controller->delete(); - - $this->assertEquals($expected, $actual); - } + } public function testUndoDelete() { $board = new board(); @@ -281,28 +166,4 @@ public function testUndoDelete() { $actual = $this->controller->undoDelete(); $this->assertEquals($expected, $actual); } - - public function testUndoDeleteBadId() { - - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue('bad id')); - - $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->undoDelete(); - $this->assertEquals($expected, $actual); - } - - public function testUndoDeleteNotFound() { - - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue(189)); - - $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); - $actual = $this->controller->undoDelete(); - $this->assertEquals($expected, $actual); - } } \ No newline at end of file From f2268c7f58bd4d908e96374c6657cca85bc9cf0e Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Mon, 16 Jul 2018 10:25:07 -0400 Subject: [PATCH 58/78] Moved Data Response checks into stack serivice, cleaned up related unit tests. Signed-off-by: Ryan Fletcher --- lib/Controller/StackApiController.php | 96 +---------- lib/Service/StackService.php | 49 ++++++ .../controller/StackApiControllerTest.php | 155 +----------------- 3 files changed, 65 insertions(+), 235 deletions(-) diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index c8ced0795..4cc6a2f6e 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -64,15 +64,8 @@ public function __construct($appName, IRequest $request, StackService $stackServ * * Return all of the stacks in the specified board. */ - public function index() { - $boardError = $this->apiHelper->entityHasError($this->request->getParam('boardId'), 'board', $this->boardService); - - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - + public function index() { $stacks = $this->stackService->findAll($this->request->getParam('boardId')); - return new DataResponse($stacks, HTTP::STATUS_OK); } @@ -83,23 +76,8 @@ public function index() { * * Return all of the stacks in the specified board. */ - public function get() { - if (is_numeric($this->request->getParam('stackId')) === false) { - return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - $boardError = $this->apiHelper->entityHasError($this->request->getParam('boardId'), 'board', $this->boardService); - - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - + public function get() { $stack = $this->stackService->find($this->request->getParam('stackId')); - - if ($stack === false || $stack === null) { - return new DataResponse('stack not found', HTTP::STATUS_NOT_FOUND); - } - return new DataResponse($stack, HTTP::STATUS_OK); } @@ -113,24 +91,8 @@ public function get() { * * Create a stack with the specified title and order. */ - public function create($title, $order) { - - if ($title === false || $title === null) { - return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); - } - - if (is_numeric($order) === false) { - return new DataResponse('order must be a number', HTTP::STATUS_BAD_REQUEST); - } - - $boardError = $this->apiHelper->entityHasError( $this->request->getParam('boardId'), 'board', $this->boardService ); - - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - - $stack = $this->stackService->create($title, $this->request->getParam('boardId'), $order); - + public function create($title, $order) { + $stack = $this->stackService->create($title, $this->request->getParam('boardId'), $order); return new DataResponse($stack, HTTP::STATUS_OK); } @@ -144,33 +106,9 @@ public function create($title, $order) { * * Update a stack by the specified stackId and boardId with the values that were put. */ - public function update($title, $order) { - - $boardError = $this->apiHelper->entityHasError( $this->request->getParam('boardId'), 'board', $this->boardService ); - - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - - if (is_numeric($this->request->getParam('stackId')) === false) { - return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - if (is_numeric($order) === false) { - return new DataResponse('order must be a number', HTTP::STATUS_BAD_REQUEST); - } - - try { - $stack = $this->stackService->update($this->request->getParam('stackId'), $title, $this->request->getParam('boardId'), $order); - - if ($stack === false || $stack === null) { - return new DataResponse('stack not found', HTTP::STATUS_NOT_FOUND); - } - - return new DataResponse($stack, HTTP::STATUS_OK); - } catch (StatusException $e) { - return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); - } + public function update($title, $order) { + $stack = $this->stackService->update($this->request->getParam('stackId'), $title, $this->request->getParam('boardId'), $order); + return new DataResponse($stack, HTTP::STATUS_OK); } /** @@ -180,24 +118,8 @@ public function update($title, $order) { * * Delete the stack specified by $this->request->getParam('stackId'). */ - public function delete() { - - $boardError = $this->apiHelper->entityHasError( $this->request->getParam('boardId'), 'board', $this->boardService ); - - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - - if (is_numeric($this->request->getParam('stackId')) === false) { - return new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - $stack = $this->stackService->delete($this->request->getParam('stackId')); - - if ($stack == false || $stack == null) { - return new DataResponse('Stack Not Found', HTTP::STATUS_NOT_FOUND); - } - + public function delete() { + $stack = $this->stackService->delete($this->request->getParam('stackId')); return new DataResponse($stack, HTTP::STATUS_OK); } } diff --git a/lib/Service/StackService.php b/lib/Service/StackService.php index ae0850dae..152c28258 100644 --- a/lib/Service/StackService.php +++ b/lib/Service/StackService.php @@ -31,6 +31,7 @@ use OCA\Deck\Db\Stack; use OCA\Deck\Db\StackMapper; use OCA\Deck\StatusException; +use OCA\Deck\BadRequestException; use OCP\ICache; use OCP\ICacheFactory; @@ -94,8 +95,13 @@ private function enrichStacksWithCards($stacks) { * @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) { @@ -111,8 +117,13 @@ public function find($stackId) { * @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); @@ -156,8 +167,22 @@ public function findAllArchived($boardId) { * @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.'); @@ -176,8 +201,14 @@ public function create($title, $boardId, $order) { * @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); @@ -200,8 +231,26 @@ public function delete($id) { * @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.'); diff --git a/tests/unit/controller/StackApiControllerTest.php b/tests/unit/controller/StackApiControllerTest.php index 047ed88f7..5f844845d 100644 --- a/tests/unit/controller/StackApiControllerTest.php +++ b/tests/unit/controller/StackApiControllerTest.php @@ -67,13 +67,7 @@ public function testIndex() { $stack->setId($this->exampleStack['id']); $stack->setBoardId($this->exampleStack['boardId']); $stack->setOrder($this->exampleStack['order']); - $stacks = [$stack]; - - $board = new Board(); - $board->setId($this->exampleBoard['boardId']); - $this->boardService->expects($this->once()) - ->method('find') - ->willReturn($board); + $stacks = [$stack]; $this->stackService->expects($this->once()) ->method('findAll') @@ -89,139 +83,28 @@ public function testIndex() { $this->assertEquals($expected, $actual); } - public function testIndexBadBoardId() { - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue('bad board id')); - - $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->index(); - $this->assertEquals($expected, $actual); - } - - public function testIndexBoardNotFound() { - $this->request->expects($this->any()) - ->method('getParam') - ->with('boardId') - ->will($this->returnValue(689)); - - $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); - $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']); - - $board = new Board(); - $board->setId($this->exampleBoard['boardId']); - $this->boardService->expects($this->once()) - ->method('find') - ->willReturn($board); + $stack->setOrder($this->exampleStack['order']); $this->stackService->expects($this->once()) ->method('find') ->willReturn($stack); - $this->request->expects($this->exactly(3)) - ->method('getParam') - ->withConsecutive( - ['stackId'], - ['boardId'], - ['stackId'] - ) - ->willReturnOnConsecutiveCalls( - $this->returnValue($this->exampleStack['id']), - $this->returnValue($this->exampleBoard['boardId']), - $this->returnValue($this->exampleStack['id'])); - - $expected = new DataResponse($stack, HTTP::STATUS_OK); - $actual = $this->controller->get(); - $this->assertEquals($expected, $actual); - } - - public function testGetBadBoardId() { - - $this->request->expects($this->exactly(2)) - ->method('getParam') - ->withConsecutive( - ['stackId'], - ['boardId'] - ) - ->willReturnOnConsecutiveCalls( - $this->returnValue(5), - $this->returnValue('not a board id')); - - $expected = new DataResponse('board id must be a number', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->get(); - $this->assertEquals($expected, $actual); - } - - public function testGetBoardNotFound() { - $this->request->expects($this->exactly(2)) - ->method('getParam') - ->withConsecutive( - ['stackId'], - ['boardId'] - ) - ->willReturnOnConsecutiveCalls( - $this->returnValue(5), - $this->returnValue($this->exampleBoard['boardId'])); - - - $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); - $actual = $this->controller->get(); - $this->assertEquals($expected, $actual); - } - - public function testGetStackBadStackId() { - - $this->request->expects($this->any()) + $this->request->expects($this->once()) ->method('getParam') ->with('stackId') - ->will($this->returnValue('not a stack id')); - - $expected = new DataResponse('stack id must be a number', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->get(); - $this->assertEquals($expected, $actual); - } - - public function testGetStackNotFound() { - - $board = new Board(); - $board->setId($this->exampleBoard['boardId']); - $this->boardService->expects($this->once()) - ->method('find') - ->willReturn($board); - - $this->request->expects($this->exactly(3)) - ->method('getParam') - ->withConsecutive( - ['stackId'], - ['boardId'], - ['stackId'] - ) - ->willReturnOnConsecutiveCalls( - $this->returnValue(5), - $this->returnValue($this->exampleBoard['boardId']), - $this->returnValue(5)); + ->willReturn($this->exampleStack['id']); - $expected = new DataResponse('stack not found', HTTP::STATUS_NOT_FOUND); + $expected = new DataResponse($stack, HTTP::STATUS_OK); $actual = $this->controller->get(); $this->assertEquals($expected, $actual); - } + } public function testCreate() { - $board = new Board(); - $board->setId($this->exampleBoard['boardId']); - $this->boardService->expects($this->once()) - ->method('find') - ->willReturn($board); $this->request->expects($this->any()) ->method('getParam') ->with('boardId') @@ -240,29 +123,5 @@ public function testCreate() { $expected = new DataResponse($stack, HTTP::STATUS_OK); $actual = $this->controller->create($this->exampleStack['title'], $this->exampleStack['order']); $this->assertEquals($expected, $actual); - } - - public function testCreateBadOrder() { - $expected = new DataResponse('order must be a number', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->create($this->exampleStack['title'], 'not an order number'); - $this->assertEquals($expected, $actual); - } - - public function testCreateBadTitle() { - $expected = new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); - $actual = $this->controller->create(null, 999); - $this->assertEquals($expected, $actual); - } - - public function testCreateBoardNotFound() { - - $this->request->expects($this->once()) - ->method('getParam') - ->will($this->returnValue(453)); - - $expected = new DataResponse('board not found', HTTP::STATUS_NOT_FOUND); - $actual = $this->controller->create($this->exampleStack['title'], $this->exampleStack['order']); - $this->assertEquals($expected, $actual); - } - + } } \ No newline at end of file From f1169b9c7eecea82a2bbc9e2b0ad4b7f22182a6e Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Mon, 16 Jul 2018 10:53:31 -0400 Subject: [PATCH 59/78] finished writing StackApiControllerTest.php Signed-off-by: Ryan Fletcher --- .../controller/StackApiControllerTest.php | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/tests/unit/controller/StackApiControllerTest.php b/tests/unit/controller/StackApiControllerTest.php index 5f844845d..8ec2cc4fa 100644 --- a/tests/unit/controller/StackApiControllerTest.php +++ b/tests/unit/controller/StackApiControllerTest.php @@ -123,5 +123,52 @@ public function testCreate() { $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 From 5bc8a363b9fec5491e88a4fee293102ea19e2723 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Mon, 16 Jul 2018 13:25:24 -0400 Subject: [PATCH 60/78] Split Card Update in CardApiController as it was gigantic and broke codacy complexity rules by a lot. Also moved validation checks into respective services. Signed-off-by: Ryan Fletcher --- lib/Controller/CardApiController.php | 152 +++------------------------ lib/Service/CardService.php | 55 +++++++++- 2 files changed, 69 insertions(+), 138 deletions(-) diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index d4b1dce08..82363d62f 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -67,27 +67,8 @@ public function __construct($appName, IRequest $request, CardService $cardServic * * Get a specific card. */ - public function get() { - $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - - $stackError = $this->apiHelper->entityHasError($this->request->params['stackId'], 'stack', $this->stackService); - if ($stackError) { - return new DataResponse($stackError['message'], $stackError['status']); - } - - if (is_numeric($this->request->params['cardId']) === false) { - return new DataResponse('card id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - $card = $this->cardService->find($this->request->params['cardId']); - - if ($card === false || $card === null) { - return new DataResponse('Card not found', HTTP::STATUS_NOT_FOUND); - } - + public function get() { + $card = $this->cardService->find($this->request->params['cardId']); return new DataResponse($card, HTTP::STATUS_OK); } @@ -102,32 +83,8 @@ public function get() { * * Get a specific card. */ - public function create($title, $type = 'plain', $order = 999) { - - $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - - $stackError = $this->apiHelper->entityHasError($this->request->params['stackId'], 'stack', $this->stackService); - if ($stackError) { - return new DataResponse($stackError['message'], $stackError['status']); - } - - if ($title === false || $title === null) { - return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); - } - - if (is_numeric($order) === false) { - return new DataResponse('order must be a number', HTTP::STATUS_BAD_REQUEST); - } - - try { - $card = $this->cardService->create($title, $this->request->params['stackId'], $type, $order, $this->userId); - } catch (Exception $e) { - return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); - } - + public function create($title, $type = 'plain', $order = 999) { + $card = $this->cardService->create($title, $this->request->params['stackId'], $type, $order, $this->userId); return new DataResponse($card, HTTP::STATUS_OK); } @@ -135,77 +92,22 @@ public function create($title, $type = 'plain', $order = 999) { * @NoAdminRequired * @CORS * @NoCSRFRequired - * - * @params $title - * @params $type - * @params $order - * @params $description - * @params $duedate - * @params $archive - * @params $assignedUserId + * * - * Get a specific card. + * Update a card */ - public function update($title, $type, $order, $description = null, $duedate = null, $archive = false, $assignedUserId = 0) { - - $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - - $stackError = $this->apiHelper->entityHasError($this->request->params['stackId'], 'stack', $this->stackService); - if ($stackError) { - return new DataResponse($stackError['message'], $stackError['status']); - } - - if (is_numeric($this->request->params['cardId']) === false) { - return new DataResponse('card id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - if ($title === false || $title === null) { - return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); - } - - if (is_numeric($order) === false) { - return new DataResponse('order must be a number', HTTP::STATUS_BAD_REQUEST); - } - - if (is_bool($order) === false) { - return new DataResponse('archive must be a boolean', HTTP::STATUS_BAD_REQUEST); - } - - if (is_numeric($assignedUserId) === false) { - return new DataResponse('user id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - try { - $card = $this->cardService->update( - $this->request->params['cardId'], - $title, - $this->request->params['stackId'], - $type, - $order, - $description, - $this->userId, - $duedate); - - if ($archive) { - $card = $this->cardService->archive($this->request->params['cardId']); - } else { - $card = $this->cardService->unarchive($this->request->params['cardId']); - } - - if ($assignedUserId > 0) { - $card = $this->cardService->assignUser($this->request->params['cardId'], $assignedUserId); - } else { - $card = $this->cardService->assignUser($this->request->params['cardId'], $assignedUserId); - } + public function update($cardId, $title, $stackId, $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); + return new DataResponse($card, HTTP::STATUS_OK); + } - } catch(Exception $e) { - return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); - } + + public function assignUser() { + throw new Exception('Not Implemented'); + } - return new DataResponse($card, HTTP::STATUS_OK); + public function unassignUser() { + throw new Exception('Not Implemented'); } /** @@ -216,27 +118,7 @@ public function update($title, $type, $order, $description = null, $duedate = nu * Delete a specific card. */ public function delete() { - - $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - - $stackError = $this->apiHelper->entityHasError($this->request->params['stackId'], 'stack', $this->stackService); - if ($stackError) { - return new DataResponse($stackError['message'], $stackError['status']); - } - - if (is_numeric($this->request->params['cardId']) === false) { - return new DataResponse('card id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - try { - $card = $this->cardService->delete($this->request->params['cardId']); - } catch (Exception $e) { - return new DataResponse($e.getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); - } - + $card = $this->cardService->delete($this->request->params['cardId']); return new DataResponse($card, HTTP::STATUS_OK); } } \ No newline at end of file diff --git a/lib/Service/CardService.php b/lib/Service/CardService.php index ad54f819d..5e9d9af61 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 { @@ -117,8 +117,30 @@ public function find($cardId) { * @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.'); @@ -130,7 +152,6 @@ public function create($title, $stackId, $type, $order, $owner) { $card->setOrder($order); $card->setOwner($owner); return $this->cardMapper->insert($card); - } /** @@ -140,8 +161,14 @@ public function create($title, $stackId, $type, $order, $owner) { * @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.'); @@ -166,8 +193,30 @@ public function delete($id) { * @throws \OCA\Deck\NoPermissionException * @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException */ - public function update($id, $title, $stackId, $type, $order, $description, $owner, $duedate, $deletedAt) { + 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.'); From 9c81584b026426caad7c94e092ef55769539068a Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Mon, 16 Jul 2018 19:25:01 -0400 Subject: [PATCH 61/78] Wrote tests for CardApiControllerTest.php Signed-off-by: Ryan Fletcher --- lib/Controller/CardApiController.php | 37 ++--- lib/Controller/StackApiController.php | 7 +- .../unit/controller/CardApiControllerTest.php | 138 ++++++++++++++++++ 3 files changed, 152 insertions(+), 30 deletions(-) create mode 100644 tests/unit/controller/CardApiControllerTest.php diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index 82363d62f..64d48ec71 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -42,8 +42,7 @@ class CardApiController extends ApiController { private $cardService; private $boardService; private $stackService; - private $userId; - private $apiHelper; + private $userId; /** * @param string $appName @@ -51,13 +50,10 @@ class CardApiController extends ApiController { * @param CardService $service * @param $userId */ - public function __construct($appName, IRequest $request, CardService $cardService, BoardService $boardService, StackService $stackService, $userId) { - parent::__construct($appName, $request); - $this->boardService = $boardService; - $this->cardService = $cardService; - $this->stackService = $stackService; - $this->userId = $userId; - $this->apiHelper = new ApiHelper(); + public function __construct($appName, IRequest $request, CardService $cardService, $userId) { + parent::__construct($appName, $request); + $this->cardService = $cardService; + $this->userId = $userId; } /** @@ -67,8 +63,8 @@ public function __construct($appName, IRequest $request, CardService $cardServic * * Get a specific card. */ - public function get() { - $card = $this->cardService->find($this->request->params['cardId']); + public function get() { + $card = $this->cardService->find($this->request->getParam('cardId')); return new DataResponse($card, HTTP::STATUS_OK); } @@ -83,8 +79,8 @@ public function get() { * * Get a specific card. */ - public function create($title, $type = 'plain', $order = 999) { - $card = $this->cardService->create($title, $this->request->params['stackId'], $type, $order, $this->userId); + 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); } @@ -96,19 +92,10 @@ public function create($title, $type = 'plain', $order = 999) { * * Update a card */ - public function update($cardId, $title, $stackId, $type, $order = 0, $description = '', $owner, $duedate = null) { + 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); return new DataResponse($card, HTTP::STATUS_OK); - } - - - public function assignUser() { - throw new Exception('Not Implemented'); - } - - public function unassignUser() { - throw new Exception('Not Implemented'); - } + } /** * @NoAdminRequired @@ -118,7 +105,7 @@ public function unassignUser() { * Delete a specific card. */ public function delete() { - $card = $this->cardService->delete($this->request->params['cardId']); + $card = $this->cardService->delete($this->request->getParam('cardId')); return new DataResponse($card, HTTP::STATUS_OK); } } \ No newline at end of file diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 4cc6a2f6e..f5565633a 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -32,7 +32,6 @@ use OCA\Deck\StatusException; use OCA\Deck\Service\StackService; use OCA\Deck\Service\BoardService; -use OCA\Deck\Controller\Helper\ApiHelper; /** * Class StackApiController @@ -42,8 +41,7 @@ class StackApiController extends ApiController { private $boardService; - private $stackService; - private $apiHelper; + private $stackService; /** * @param string $appName @@ -53,8 +51,7 @@ class StackApiController extends ApiController { public function __construct($appName, IRequest $request, StackService $stackService, BoardService $boardService) { parent::__construct($appName, $request); $this->stackService = $stackService; - $this->boardService = $boardService; - $this->apiHelper = new ApiHelper(); + $this->boardService = $boardService; } /** 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 From 184cd00a8b6bc98db8dfd7e033fdd0cbce8c8d38 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Mon, 16 Jul 2018 22:29:51 -0400 Subject: [PATCH 62/78] Wrote initial unit tests for LabelApiControllerTest.php Signed-off-by: Ryan Fletcher --- lib/Controller/LabelApiController.php | 90 ++---------- .../controller/LabelApiControllerTest.php | 128 ++++++++++++++++++ 2 files changed, 136 insertions(+), 82 deletions(-) create mode 100644 tests/unit/controller/LabelApiControllerTest.php diff --git a/lib/Controller/LabelApiController.php b/lib/Controller/LabelApiController.php index b2617d2f6..09694d17f 100644 --- a/lib/Controller/LabelApiController.php +++ b/lib/Controller/LabelApiController.php @@ -47,12 +47,10 @@ class LabelApiController extends ApiController { * @param LabelService $service * @param $userId */ - public function __construct($appName, IRequest $request, LabelService $labelService, BoardService $boardService, $userId) { + public function __construct($appName, IRequest $request, LabelService $labelService, $userId) { parent::__construct($appName, $request); - $this->labelService = $labelService; - $this->boardService = $boardService; - $this->userId = $userId; - $this->apiHelper = new ApiHelper(); + $this->labelService = $labelService; + $this->userId = $userId; } /** @@ -63,22 +61,7 @@ public function __construct($appName, IRequest $request, LabelService $labelServ * Get a specific label. */ public function get() { - - $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - - if (is_numeric($this->request->params['labelId']) === false) { - return new DataResponse('label id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - $label = $this->labelService->find($this->request->params['labelId']); - - if ($label === false || $label === null) { - return new DataResponse('Label not found', HTTP::STATUS_NOT_FOUND); - } - + $label = $this->labelService->find($this->request->getParam('labelId')); return new DataResponse($label, HTTP::STATUS_OK); } @@ -92,26 +75,7 @@ public function get() { * Create a new label */ public function create($title, $color) { - - $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - - if ($title === false || $title === null) { - return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); - } - - if ($color === false || $color === null) { - return new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); - } - - try { - $label = $this->labelService->create($title, $color, $this->request->params['boardId']); - } catch (Exception $e) { - return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); - } - + $label = $this->labelService->create($title, $color, $this->request->getParam('boardId')); return new DataResponse($label, HTTP::STATUS_OK); } @@ -124,31 +88,8 @@ public function create($title, $color) { * @params $color * Update a specific label */ - public function update($title, $color) { - - $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - - if (is_numeric($this->request->params['labelId']) === false) { - return new DataResponse('label id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - if ($title === false || $title === null) { - return new DataResponse('title must be provided', HTTP::STATUS_BAD_REQUEST); - } - - if ($color === false || $color === null) { - return new DataResponse('color must be provided', HTTP::STATUS_BAD_REQUEST); - } - - try { - $label = $this->labelService->update($this->request->params['labelId'], $title, $color); - } catch (Exception $e) { - return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); - } - + public function update($title, $color) { + $label = $this->labelService->update($this->request->getParam('labelId'), $title, $color); return new DataResponse($label, HTTP::STATUS_OK); } @@ -160,22 +101,7 @@ public function update($title, $color) { * Delete a specific label */ public function delete() { - - $boardError = $this->apiHelper->entityHasError($this->request->params['boardId'], 'board', $this->boardService); - if ($boardError) { - return new DataResponse($boardError['message'], $boardError['status']); - } - - if (is_numeric($this->request->params['labelId']) === false) { - return new DataResponse('label id must be a number', HTTP::STATUS_BAD_REQUEST); - } - - try { - $label = $this->labelService->delete($this->request->params['labelId']); - } catch (Exception $e) { - return new DataResponse($e->getMessage(), HTTP::STATUS_INTERNAL_SERVER_ERROR); - } - + $label = $this->labelService->delete($this->request->getParam('labelId')); return new DataResponse($label, HTTP::STATUS_OK); } 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 From 507a7fd24351b391a9b73ac2f104d9a084a02079 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Mon, 16 Jul 2018 22:41:41 -0400 Subject: [PATCH 63/78] Code cleanup, removing unused code from older iteration. Signed-off-by: Ryan Fletcher --- lib/Controller/CardApiController.php | 9 ++--- lib/Controller/Helper/ApiHelper.php | 49 --------------------------- lib/Controller/LabelApiController.php | 2 +- 3 files changed, 4 insertions(+), 56 deletions(-) delete mode 100644 lib/Controller/Helper/ApiHelper.php diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index 64d48ec71..b82030582 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -27,8 +27,7 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; - - use OCA\Deck\Controller\Helper\ApiHelper; + use OCA\Deck\Service\BoardService; use OCA\Deck\Service\StackService; use OCA\Deck\Service\CardService; @@ -39,15 +38,13 @@ * @package OCA\Deck\Controller */ class CardApiController extends ApiController { - private $cardService; - private $boardService; - private $stackService; + private $cardService; private $userId; /** * @param string $appName * @param IRequest $request - * @param CardService $service + * @param CardService $cardService * @param $userId */ public function __construct($appName, IRequest $request, CardService $cardService, $userId) { diff --git a/lib/Controller/Helper/ApiHelper.php b/lib/Controller/Helper/ApiHelper.php deleted file mode 100644 index c19baaaf8..000000000 --- a/lib/Controller/Helper/ApiHelper.php +++ /dev/null @@ -1,49 +0,0 @@ - - * - * @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\Helper; - -use OCP\AppFramework\Http; - -class ApiHelper { - - public static function entityHasError($entityId, $entityName, $service) { - if (is_numeric($entityId) === false) { - $error['message'] = $entityName . ' id must be a number'; - $error['status'] = HTTP::STATUS_BAD_REQUEST; - return $error; - } - - $entity = $service->find($entityId); - - if ($entity === false || $entity === null) { - $error['message'] = $entityName . ' not found'; - $error['status'] = HTTP::STATUS_NOT_FOUND; - return $error; - } - - return false; - } - -} \ No newline at end of file diff --git a/lib/Controller/LabelApiController.php b/lib/Controller/LabelApiController.php index 09694d17f..72643c963 100644 --- a/lib/Controller/LabelApiController.php +++ b/lib/Controller/LabelApiController.php @@ -44,7 +44,7 @@ class LabelApiController extends ApiController { /** * @param string $appName * @param IRequest $request - * @param LabelService $service + * @param LabelService $labelService * @param $userId */ public function __construct($appName, IRequest $request, LabelService $labelService, $userId) { From 72aeb723a5cf59e8348acb2417359e73320a5f7c Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 20 Jul 2018 09:26:36 -0400 Subject: [PATCH 64/78] fixed up missing checks from labelService, BadRequestException is now extending StatusException Signed-off-by: Ryan Fletcher --- lib/BadRequestException.php | 2 +- lib/Middleware/SharingMiddleware.php | 2 +- lib/Service/LabelService.php | 36 ++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/lib/BadRequestException.php b/lib/BadRequestException.php index 894721a35..b3ffb98c1 100644 --- a/lib/BadRequestException.php +++ b/lib/BadRequestException.php @@ -24,7 +24,7 @@ namespace OCA\Deck; use OCP\AppFramework\Http; -class BadRequestException extends \Exception { +class BadRequestException extends StatusException { public function __construct($message) { parent::__construct($message); diff --git a/lib/Middleware/SharingMiddleware.php b/lib/Middleware/SharingMiddleware.php index 5e53a69df..0bbdb7058 100644 --- a/lib/Middleware/SharingMiddleware.php +++ b/lib/Middleware/SharingMiddleware.php @@ -60,7 +60,7 @@ public function __construct(ILogger $logger, IConfig $config) { * @throws \Exception */ public function afterException($controller, $methodName, \Exception $exception) { - if ($exception instanceof StatusException || $exception instanceof BadRequestException) { + if ($exception instanceof StatusException) { if ($this->config->getSystemValue('loglevel', Util::WARN) === Util::DEBUG) { $this->logger->logException($exception); } diff --git a/lib/Service/LabelService.php b/lib/Service/LabelService.php index 2b0a640be..48ccb89e1 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 { @@ -50,8 +51,12 @@ public function __construct(LabelMapper $labelMapper, PermissionService $permiss * @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); } @@ -67,6 +72,19 @@ public function find($labelId) { * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException */ 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.'); @@ -87,6 +105,11 @@ public function create($title, $color, $boardId) { * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException */ 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.'); @@ -105,6 +128,19 @@ public function delete($id) { * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException */ 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.'); From 3e965d0cfb83f58bdd673fa2abc9b688aa63825b Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Fri, 20 Jul 2018 11:17:18 -0400 Subject: [PATCH 65/78] Implemented additional CardApiController endpoints Signed-off-by: Ryan Fletcher --- lib/Controller/CardApiController.php | 53 ++++++++++++++++++++++++++++ lib/Service/CardService.php | 52 +++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index b82030582..6d40d3d91 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -105,4 +105,57 @@ 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/Service/CardService.php b/lib/Service/CardService.php index 5e9d9af61..4f4da3c3e 100644 --- a/lib/Service/CardService.php +++ b/lib/Service/CardService.php @@ -267,8 +267,22 @@ public function rename($id, $title) { * @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.'); @@ -344,6 +358,15 @@ public function unarchive($id) { * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException */ 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.'); @@ -364,6 +387,15 @@ public function assignLabel($cardId, $labelId) { * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException */ 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.'); @@ -381,8 +413,18 @@ public function removeLabel($cardId, $labelId) { * @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 (is_numeric($userId) === false) { + throw new BadRequestException('user id must be a number'); + } + $this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT); $assignments = $this->assignedUsersMapper->find($cardId); foreach ($assignments as $assignment) { @@ -410,9 +452,19 @@ public function assignUser($cardId, $userId) { * @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 (is_numeric($userId) === false) { + throw new BadRequestException('user id must be a number'); + } + $assignments = $this->assignedUsersMapper->find($cardId); foreach ($assignments as $assignment) { if ($assignment->getParticipant() === $userId) { From 172a80fa5d943f53b8c5f99a4ad69b67e2cc9b01 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Sat, 21 Jul 2018 12:17:28 -0400 Subject: [PATCH 66/78] Added additional endpoints for cards / stacks Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 6 ++++++ lib/Controller/StackApiController.php | 12 ++++++++++++ lib/Service/StackService.php | 6 ++++++ 3 files changed, 24 insertions(+) diff --git a/appinfo/routes.php b/appinfo/routes.php index 26a2a4460..ba9ef9cdf 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -86,6 +86,7 @@ ['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'], @@ -94,6 +95,11 @@ ['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'], diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index f5565633a..025843f18 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -119,4 +119,16 @@ 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/Service/StackService.php b/lib/Service/StackService.php index 152c28258..e8bcacaf3 100644 --- a/lib/Service/StackService.php +++ b/lib/Service/StackService.php @@ -141,8 +141,14 @@ public function fetchDeleted($boardId) { * @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); From e88c9a760d780e07a14215f6657a07fc7994ad13 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Mon, 23 Jul 2018 10:29:03 -0400 Subject: [PATCH 67/78] Wrote unit tests for AttachmentApiController and stubbed out AttachmentApicontroller. Trying out test driven development. Signed-off-by: Ryan Fletcher --- lib/Controller/AttachmentApiController.php | 46 +++++ .../AttachmentApiControllerTest.php | 165 ++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 lib/Controller/AttachmentApiController.php create mode 100644 tests/unit/controller/AttachmentApiControllerTest.php diff --git a/lib/Controller/AttachmentApiController.php b/lib/Controller/AttachmentApiController.php new file mode 100644 index 000000000..ee34c4d0d --- /dev/null +++ b/lib/Controller/AttachmentApiController.php @@ -0,0 +1,46 @@ + + * + * @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; + +class AttachmentApiController extends ApiController { + public function __construct($appName, IRequest $request) { + parent::__construct($appName, $request); + } + + public function getAll() {} + + public function display() {} + + public function create() {} + + public function update() {} + + public function delete() {} + + public function restore() {} +} \ No newline at end of file diff --git a/tests/unit/controller/AttachmentApiControllerTest.php b/tests/unit/controller/AttachmentApiControllerTest.php new file mode 100644 index 000000000..cedce2563 --- /dev/null +++ b/tests/unit/controller/AttachmentApiControllerTest.php @@ -0,0 +1,165 @@ + + * + * @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 + ); + } + + 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($this->attachmentExample, 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() { + + $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(); + $this->assertEquals($expected, $actual); + } + + public function testUpdate() { + + $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(); + $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 From 37a2858d5f1cd61c7a92eb47ad7578cdd8753cb4 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Tue, 24 Jul 2018 11:21:33 -0400 Subject: [PATCH 68/78] wrote attachment api controller, fixed bug caught by unit test in CardService Signed-off-by: Ryan Fletcher --- appinfo/routes.php | 7 ++ lib/Controller/AttachmentApiController.php | 74 +++++++++++++++++-- lib/Service/CardService.php | 9 ++- .../AttachmentApiControllerTest.php | 15 +++- 4 files changed, 90 insertions(+), 15 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index ba9ef9cdf..dd55fb408 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -107,6 +107,13 @@ ['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/Controller/AttachmentApiController.php b/lib/Controller/AttachmentApiController.php index ee34c4d0d..d290b1906 100644 --- a/lib/Controller/AttachmentApiController.php +++ b/lib/Controller/AttachmentApiController.php @@ -27,20 +27,80 @@ use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; +use OCA\Deck\Service\AttachmentService; + class AttachmentApiController extends ApiController { - public function __construct($appName, IRequest $request) { + + private $attachmentService; + + public function __construct($appName, IRequest $request, AttachmentService $attachmentService) { parent::__construct($appName, $request); + $this->attachmentService = $attachmentService; } - public function getAll() {} + /** + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * + */ + public function getAll() { + $attachment = $this->attachmentService->findAll($this->request->getParam('cardId')); + return new DataResponse($attachment, HTTP::STATUS_OK); + } - public function display() {} + /** + * @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); + } - public function create() {} + /** + * @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); + } - public function update() {} + /** + * @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); + } - public function delete() {} + /** + * @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); + } - public function restore() {} + /** + * @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/Service/CardService.php b/lib/Service/CardService.php index 4f4da3c3e..37a63902f 100644 --- a/lib/Service/CardService.php +++ b/lib/Service/CardService.php @@ -356,6 +356,7 @@ public function unarchive($id) { * @throws \OCA\Deck\NoPermissionException * @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException */ public function assignLabel($cardId, $labelId) { @@ -421,8 +422,8 @@ public function assignUser($cardId, $userId) { throw new BadRequestException('card id must be a number'); } - if (is_numeric($userId) === false) { - throw new BadRequestException('user 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); @@ -461,8 +462,8 @@ public function unassignUser($cardId, $userId) { throw new BadRequestException('card id must be a number'); } - if (is_numeric($userId) === false) { - throw new BadRequestException('user id must be a number'); + if ($userId === false || $userId === null) { + throw new BadRequestException('user must be provided'); } $assignments = $this->assignedUsersMapper->find($cardId); diff --git a/tests/unit/controller/AttachmentApiControllerTest.php b/tests/unit/controller/AttachmentApiControllerTest.php index cedce2563..52458f527 100644 --- a/tests/unit/controller/AttachmentApiControllerTest.php +++ b/tests/unit/controller/AttachmentApiControllerTest.php @@ -47,7 +47,8 @@ public function setUp() { $this->attachmentService = $this->createMock(AttachmentService::class); $this->controller = new AttachmentApiController( $this->appName, - $this->request + $this->request, + $this->attachmentService ); } @@ -64,7 +65,7 @@ public function testGetAll() { ->with('cardId') ->willReturn($allAttachments); - $expected = new DataResponse($this->attachmentExample, HTTP::STATUS_OK); + $expected = new DataResponse($allAttachments, HTTP::STATUS_OK); $actual = $this->controller->getAll(); $this->assertEquals($expected, $actual); } @@ -91,6 +92,9 @@ public function testDisplay() { public function testCreate() { + $type = 'not null'; + $data = ['not null']; + $this->attachmentService->expects($this->once()) ->method('create') ->willReturn($this->attachmentExample); @@ -101,12 +105,15 @@ public function testCreate() { ->willReturn($this->cardId); $expected = new DataResponse($this->attachmentExample, HTTP::STATUS_OK); - $actual = $this->controller->create(); + $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); @@ -121,7 +128,7 @@ public function testUpdate() { $this->attachmentExample->getId()); $expected = new DataResponse($this->attachmentExample, HTTP::STATUS_OK); - $actual = $this->controller->update(); + $actual = $this->controller->update($data); $this->assertEquals($expected, $actual); } From 7930fec5d72fde2de62eba58cc54bf4cd3907acd Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Tue, 7 Aug 2018 08:18:20 -0400 Subject: [PATCH 69/78] Added in BadRequestException tests into AttachmentService.php Signed-off-by: Ryan Fletcher --- lib/Service/AttachmentService.php | 75 ++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/lib/Service/AttachmentService.php b/lib/Service/AttachmentService.php index 53f89f518..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); @@ -126,8 +132,14 @@ public function findAll($cardId, $withDeleted = false) { /** * @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)); @@ -143,8 +155,22 @@ public function count($cardId) { * @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); @@ -188,11 +214,20 @@ public function create($cardId, $type, $data) { * @throws NoPermissionException * @throws NotFoundException * @throws \OCP\AppFramework\Db\DoesNotExistException - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @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 { @@ -213,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); @@ -249,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); @@ -270,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); From e8571454d98714cf82bd58b19c15af9dfb2373d7 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Tue, 7 Aug 2018 08:30:48 -0400 Subject: [PATCH 70/78] Added BadRequestException checks into BoardService.php Signed-off-by: Ryan Fletcher --- lib/Service/BoardService.php | 79 +++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index b6d3da122..764ddb44c 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -161,8 +161,18 @@ private function getBoardPrerequisites() { * @throws DoesNotExistException * @throws \OCA\Deck\NoPermissionException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException */ public function isArchived($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) { @@ -185,8 +195,18 @@ public function isArchived($mapper, $id) { * @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) { @@ -304,8 +324,13 @@ public function deleteUndo($id) { * @throws DoesNotExistException * @throws \OCA\Deck\NoPermissionException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException */ - public function deleteForce($id) { + 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); @@ -358,9 +383,35 @@ public function update($id, $title, $color, $archived) { * @param $share * @param $manage * @return \OCP\AppFramework\Db\Entity - * @throws \OCA\Deck\NoPermissionException + * @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); @@ -387,8 +438,26 @@ public function addAcl($boardId, $type, $participant, $edit, $share, $manage) { * @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 === 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->aclMapper, $id, Acl::PERMISSION_SHARE); /** @var Acl $acl */ $acl = $this->aclMapper->find($id); @@ -405,8 +474,14 @@ public function updateAcl($id, $edit, $share, $manage) { * @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); From 6f5c0a2816236d390c58d6744934936f7787e20e Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Tue, 7 Aug 2018 08:37:10 -0400 Subject: [PATCH 71/78] Added in BadRequestException checks in CardService.php Signed-off-by: Ryan Fletcher --- lib/Service/CardService.php | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/Service/CardService.php b/lib/Service/CardService.php index 37a63902f..f1b76fc0a 100644 --- a/lib/Service/CardService.php +++ b/lib/Service/CardService.php @@ -95,8 +95,14 @@ public function fetchDeleted($boardId) { * @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()); @@ -244,8 +250,18 @@ public function update($id, $title, $stackId, $type, $order = 0, $description = * @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.'); @@ -319,9 +335,15 @@ public function reorder($id, $stackId, $order) { * @throws StatusException * @throws \OCA\Deck\NoPermissionException * @throws \OCP\AppFramework\Db\DoesNotExistException - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @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.'); @@ -338,8 +360,14 @@ public function archive($id) { * @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.'); @@ -386,6 +414,7 @@ public function assignLabel($cardId, $labelId) { * @throws \OCA\Deck\NoPermissionException * @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException */ public function removeLabel($cardId, $labelId) { From aba7d02cfeb5e76fff260d0f4690d88b34e05c85 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Tue, 7 Aug 2018 08:50:00 -0400 Subject: [PATCH 72/78] Added BadRequestException checks in DefaultBoardService. Fixed bug in DefaultBoardService BadRequestException checks. Signed-off-by: Ryan Fletcher --- lib/Service/BoardService.php | 6 +++--- lib/Service/DefaultBoardService.php | 15 +++++++++++++++ tests/unit/Service/DefaultBoardServiceTest.php | 3 ++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 764ddb44c..befce6f30 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -446,15 +446,15 @@ public function updateAcl($id, $edit, $share, $manage) { throw new BadRequestException('id must be a number'); } - if ($edit === false || $edit === null) { + if ($edit === null) { throw new BadRequestException('edit must be provided'); } - if ($share === false || $share === null) { + if ($share === null) { throw new BadRequestException('share must be provided'); } - if ($manage === false || $manage === null) { + if ($manage === null) { throw new BadRequestException('manage must be provided'); } diff --git a/lib/Service/DefaultBoardService.php b/lib/Service/DefaultBoardService.php index 82fc02fa5..4c961f2e3 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 { @@ -83,8 +84,22 @@ public function checkFirstRun($userId, $appName) { * @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/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, From 4391bf4eb8d2b4a76f46710714284e3883418a21 Mon Sep 17 00:00:00 2001 From: Ryan Fletcher Date: Tue, 7 Aug 2018 08:56:58 -0400 Subject: [PATCH 73/78] added missing BadRequestException checks to StackService.php Signed-off-by: Ryan Fletcher --- lib/Service/LabelService.php | 3 +++ lib/Service/StackService.php | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/Service/LabelService.php b/lib/Service/LabelService.php index 48ccb89e1..098c95293 100644 --- a/lib/Service/LabelService.php +++ b/lib/Service/LabelService.php @@ -70,6 +70,7 @@ public function find($labelId) { * @throws \OCA\Deck\NoPermissionException * @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException */ public function create($title, $color, $boardId) { @@ -103,6 +104,7 @@ public function create($title, $color, $boardId) { * @throws \OCA\Deck\NoPermissionException * @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException */ public function delete($id) { @@ -126,6 +128,7 @@ public function delete($id) { * @throws \OCA\Deck\NoPermissionException * @throws \OCP\AppFramework\Db\DoesNotExistException * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException + * @throws BadRequestException */ public function update($id, $title, $color) { diff --git a/lib/Service/StackService.php b/lib/Service/StackService.php index e8bcacaf3..b30c94296 100644 --- a/lib/Service/StackService.php +++ b/lib/Service/StackService.php @@ -276,8 +276,18 @@ public function update($id, $title, $boardId, $order, $deletedAt) { * @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()); From 47a7e76a4deb5d6904aa91b3515711cf5d0c0280 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Tue, 14 Aug 2018 21:23:15 +0200 Subject: [PATCH 74/78] Catch DoesNotExistException to return proper API repsonses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Middleware/SharingMiddleware.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/Middleware/SharingMiddleware.php b/lib/Middleware/SharingMiddleware.php index 0bbdb7058..ec6eb81f1 100644 --- a/lib/Middleware/SharingMiddleware.php +++ b/lib/Middleware/SharingMiddleware.php @@ -25,6 +25,7 @@ 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; @@ -69,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; } From 81d333243d327794588c97668585e0f3e49d7ed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 15 Aug 2018 20:18:02 +0200 Subject: [PATCH 75/78] Fix comparison MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Service/DefaultBoardService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Service/DefaultBoardService.php b/lib/Service/DefaultBoardService.php index 4c961f2e3..5e16401f8 100644 --- a/lib/Service/DefaultBoardService.php +++ b/lib/Service/DefaultBoardService.php @@ -92,7 +92,7 @@ public function createDefaultBoard($title, $userId, $color) { throw new BadRequestException('title must be provided'); } - if ($userId === false || $userId == null) { + if ($userId === false || $userId === null) { throw new BadRequestException('userId must be provided'); } From 0c9b1f5338cfa05ba4e264b4a726856a1ca7e029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 15 Aug 2018 20:21:49 +0200 Subject: [PATCH 76/78] Mapper can be null if provided id is a board id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Service/BoardService.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index befce6f30..51c59c8b3 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -165,10 +165,6 @@ private function getBoardPrerequisites() { */ public function isArchived($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'); } From babfcbddd858dc5bce39e904b808b0d7722d2d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 15 Aug 2018 21:03:06 +0200 Subject: [PATCH 77/78] Fix imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Controller/AttachmentApiController.php | 1 - lib/Controller/BoardApiController.php | 2 -- lib/Controller/CardApiController.php | 3 --- lib/Controller/LabelApiController.php | 1 - lib/Controller/StackApiController.php | 2 -- lib/Service/StackService.php | 2 -- 6 files changed, 11 deletions(-) diff --git a/lib/Controller/AttachmentApiController.php b/lib/Controller/AttachmentApiController.php index d290b1906..8e82739a0 100644 --- a/lib/Controller/AttachmentApiController.php +++ b/lib/Controller/AttachmentApiController.php @@ -26,7 +26,6 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; - use OCA\Deck\Service\AttachmentService; class AttachmentApiController extends ApiController { diff --git a/lib/Controller/BoardApiController.php b/lib/Controller/BoardApiController.php index 0d4770d7a..d45644eef 100644 --- a/lib/Controller/BoardApiController.php +++ b/lib/Controller/BoardApiController.php @@ -28,8 +28,6 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; -use OCP\IUserManager; -use OCP\IGroupManager; use OCA\Deck\Service\BoardService; diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index 6d40d3d91..a26817c9a 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -27,9 +27,6 @@ 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\Service\CardService; /** diff --git a/lib/Controller/LabelApiController.php b/lib/Controller/LabelApiController.php index 72643c963..87f729d8b 100644 --- a/lib/Controller/LabelApiController.php +++ b/lib/Controller/LabelApiController.php @@ -28,7 +28,6 @@ use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; use OCA\Deck\Service\LabelService; -use OCA\Deck\Service\BoardService; use OCA\Deck\Controller\Helper\ApiHelper; /** diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 025843f18..936311bac 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -28,8 +28,6 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; - -use OCA\Deck\StatusException; use OCA\Deck\Service\StackService; use OCA\Deck\Service\BoardService; diff --git a/lib/Service/StackService.php b/lib/Service/StackService.php index b30c94296..f2bdbaff8 100644 --- a/lib/Service/StackService.php +++ b/lib/Service/StackService.php @@ -32,8 +32,6 @@ use OCA\Deck\Db\StackMapper; use OCA\Deck\StatusException; use OCA\Deck\BadRequestException; -use OCP\ICache; -use OCP\ICacheFactory; class StackService { From 5639bd12741537c686a28aba5003ea06d38ffcc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Wed, 15 Aug 2018 21:09:39 +0200 Subject: [PATCH 78/78] Fix controller deleted at parameter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Controller/CardApiController.php | 2 +- lib/Controller/StackApiController.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Controller/CardApiController.php b/lib/Controller/CardApiController.php index a26817c9a..5aa45d0f6 100644 --- a/lib/Controller/CardApiController.php +++ b/lib/Controller/CardApiController.php @@ -87,7 +87,7 @@ public function create($title, $type = 'plain', $order = 999) { * 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); + $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); } diff --git a/lib/Controller/StackApiController.php b/lib/Controller/StackApiController.php index 936311bac..6e4fb3867 100644 --- a/lib/Controller/StackApiController.php +++ b/lib/Controller/StackApiController.php @@ -102,7 +102,7 @@ public function create($title, $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); + $stack = $this->stackService->update($this->request->getParam('stackId'), $title, $this->request->getParam('boardId'), $order, 0); return new DataResponse($stack, HTTP::STATUS_OK); }