From 4e96dec47477dfde5ed574a413084c85e10b44a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Fri, 25 May 2018 11:45:38 +0200 Subject: [PATCH 1/2] Implement user data export via occ command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- appinfo/info.xml | 3 + lib/Command/UserExport.php | 119 +++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 lib/Command/UserExport.php diff --git a/appinfo/info.xml b/appinfo/info.xml index d02adc6a4..8956e84d7 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -37,4 +37,7 @@ OCA\Deck\Migration\UnknownUsers + + OCA\Deck\Command\UserExport + diff --git a/lib/Command/UserExport.php b/lib/Command/UserExport.php new file mode 100644 index 000000000..dbec8b34e --- /dev/null +++ b/lib/Command/UserExport.php @@ -0,0 +1,119 @@ + + * + * @author Julius Härtl + * + * @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\Command; + +use OCA\Deck\Db\AssignedUsersMapper; +use OCA\Deck\Db\BoardMapper; +use OCA\Deck\Db\CardMapper; +use OCA\Deck\Db\StackMapper; +use OCA\Deck\Service\BoardService; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Db\MultipleObjectsReturnedException; +use OCP\IGroupManager; +use OCP\IUserManager; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class UserExport extends Command { + + protected $boardService; + protected $cardMapper; + private $userManager; + private $groupManager; + private $assignedUsersMapper; + + public function __construct(BoardMapper $boardMapper, + BoardService $boardService, + StackMapper $stackMapper, + CardMapper $cardMapper, + AssignedUsersMapper $assignedUsersMapper, + IUserManager $userManager, + IGroupManager $groupManager) { + parent::__construct(); + + $this->cardMapper = $cardMapper; + $this->boardService = $boardService; + $this->stackMapper = $stackMapper; + $this->assignedUsersMapper = $assignedUsersMapper; + $this->boardMapper = $boardMapper; + + $this->userManager = $userManager; + $this->groupManager = $groupManager; + } + + protected function configure() { + $this + ->setName('deck:export') + ->setDescription('Export a JSON dump of user data') + ->addArgument( + 'user-id', + InputArgument::REQUIRED, + 'User ID of the user' + ) + ; + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return void + * @throws DoesNotExistException + * @throws MultipleObjectsReturnedException + * @throws \ReflectionException + */ + protected function execute(InputInterface $input, OutputInterface $output) { + + $userId = $input->getArgument('user-id'); + + $groups = $this->groupManager->getUserGroupIds( + $this->userManager->get($userId) + ); + $boards = $this->boardService->findAll([ + 'user' => $userId, + 'groups' => $groups + ]); + + $data = []; + foreach ($boards as $board) { + $fullBoard = $this->boardMapper->find($board->getId(), true, true); + $data[$board->getId()] = (array)$fullBoard->jsonSerialize(); + $stacks = $this->stackMapper->findAll($board->getId()); + foreach ($stacks as $stack) { + $data[$board->getId()]['stacks'][] = (array)$stack->jsonSerialize(); + $cards = $this->cardMapper->findAllByStack($stack->getId()); + foreach ($cards as $card) { + $fullCard = $this->cardMapper->find($card->getId()); + $assignedUsers = $this->assignedUsersMapper->find($card->getId()); + $fullCard->setAssignedUsers($assignedUsers); + $data[$board->getId()]['stacks'][$stack->getId()]['cards'] = (array)$fullCard->jsonSerialize(); + } + } + } + $output->writeln(json_encode($data, JSON_PRETTY_PRINT)); + } +} + + From 8d60a4379dceaab7c3bec9f83ca7b3f244ca4c11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 2 Jul 2018 11:51:53 +0200 Subject: [PATCH 2/2] Add rough test and fix card array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Command/UserExport.php | 2 +- tests/unit/Command/UserExportTest.php | 141 ++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 tests/unit/Command/UserExportTest.php diff --git a/lib/Command/UserExport.php b/lib/Command/UserExport.php index dbec8b34e..6c6d05dbc 100644 --- a/lib/Command/UserExport.php +++ b/lib/Command/UserExport.php @@ -108,7 +108,7 @@ class UserExport extends Command { $fullCard = $this->cardMapper->find($card->getId()); $assignedUsers = $this->assignedUsersMapper->find($card->getId()); $fullCard->setAssignedUsers($assignedUsers); - $data[$board->getId()]['stacks'][$stack->getId()]['cards'] = (array)$fullCard->jsonSerialize(); + $data[$board->getId()]['stacks'][$stack->getId()]['cards'][] = (array)$fullCard->jsonSerialize(); } } } diff --git a/tests/unit/Command/UserExportTest.php b/tests/unit/Command/UserExportTest.php new file mode 100644 index 000000000..efba542ac --- /dev/null +++ b/tests/unit/Command/UserExportTest.php @@ -0,0 +1,141 @@ + + * + * @author Julius Härtl + * + * @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\Command; + +use OCA\Deck\Db\AssignedUsersMapper; +use OCA\Deck\Db\Attachment; +use OCA\Deck\Db\AttachmentMapper; +use OCA\Deck\Db\Board; +use OCA\Deck\Db\BoardMapper; +use OCA\Deck\Db\Card; +use OCA\Deck\Db\CardMapper; +use OCA\Deck\Db\Stack; +use OCA\Deck\Db\StackMapper; +use OCA\Deck\InvalidAttachmentType; +use OCA\Deck\Service\AttachmentService; +use OCA\Deck\Service\BoardService; +use OCA\Deck\Service\IAttachmentService; +use OCP\IGroupManager; +use OCP\IUser; +use OCP\IUserManager; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +class UserExportTest extends \Test\TestCase { + + protected $boardMapper; + protected $boardService; + protected $stackMapper; + protected $cardMapper; + protected $assignedUserMapper; + protected $userManager; + protected $groupManager; + + private $userExport; + + public function setUp() { + parent::setUp(); + $this->boardMapper = $this->createMock(BoardMapper::class); + $this->boardService= $this->createMock(BoardService::class); + $this->stackMapper= $this->createMock(StackMapper::class); + $this->cardMapper= $this->createMock(CardMapper::class); + $this->assignedUserMapper= $this->createMock(AssignedUsersMapper::class); + $this->userManager = $this->createMock(IUserManager::class); + $this->groupManager = $this->createMock(IGroupManager::class); + $this->userExport = new UserExport($this->boardMapper, $this->boardService, $this->stackMapper, $this->cardMapper, $this->assignedUserMapper, $this->userManager, $this->groupManager); + } + + public function getBoard($id) { + $board = new Board(); + $board->setId($id); + $board->setTitle('Board ' . $id); + return $board; + } + public function getStack($id) { + $stack = new Stack(); + $stack->setId($id); + $stack->setTitle('Stack ' . $id); + return $stack; + } + public function getCard($id) { + $card = new Card(); + $card->setId($id); + $card->setTitle('Card ' . $id); + return $card; + } + public function testExecute() { + $input = $this->createMock(InputInterface::class); + $input->expects($this->once())->method('getArgument')->with('user-id')->willReturn('admin'); + $output = $this->createMock(OutputInterface::class); + + $user = $this->createMock(IUser::class); + $this->userManager->expects($this->once()) + ->method('get') + ->with('admin') + ->willReturn($user); + + $groups = []; + $this->groupManager->expects($this->once()) + ->method('getUserGroupIds') + ->with($user) + ->willReturn($groups); + + $boards = [ + $this->getBoard(1), + $this->getBoard(2), + ]; + $this->boardService->expects($this->once()) + ->method('findAll') + ->with([ + 'user' => 'admin', + 'groups' => $groups + ]) + ->willReturn($boards); + $this->boardMapper->expects($this->exactly(count($boards))) + ->method('find') + ->willReturn($boards[0]); + $stacks = [ + $this->getStack(1), + $this->getStack(2) + ]; + $this->stackMapper->expects($this->exactly(count($boards))) + ->method('findAll') + ->willReturn($stacks); + $cards = [ + $this->getCard(1), + $this->getCard(2), + $this->getCard(3), + ]; + $this->cardMapper->expects($this->exactly(count($boards)*count($stacks))) + ->method('findAllByStack') + ->willReturn($cards); + $this->cardMapper->expects($this->exactly(count($boards)*count($stacks)*count($cards))) + ->method('find') + ->willReturn($cards[0]); + $this->assignedUserMapper->expects($this->exactly(count($boards)*count($stacks)*count($cards))) + ->method('find') + ->willReturn([]); + $result = $this->invokePrivate($this->userExport, 'execute', [$input, $output]); + } +} \ No newline at end of file