diff --git a/lib/Service/Importer/Systems/DeckJsonService.php b/lib/Service/Importer/Systems/DeckJsonService.php index 37c99ec11..b9d202b3a 100644 --- a/lib/Service/Importer/Systems/DeckJsonService.php +++ b/lib/Service/Importer/Systems/DeckJsonService.php @@ -132,9 +132,13 @@ class DeckJsonService extends ABoardImportService { if (empty($this->getImportService()->getData()->title)) { throw new BadRequestException('Invalid name of board'); } - $board->setTitle($this->getImportService()->getData()->title); - $board->setOwner($this->getImportService()->getData()->owner->uid); - $board->setColor($this->getImportService()->getData()->color); + $importBoard = $this->getImportService()->getData(); + $board->setTitle($importBoard->title); + $board->setOwner($importBoard->owner->uid); + $board->setColor($importBoard->color); + $board->setArchived($importBoard->archived); + $board->setDeletedAt($importBoard->deletedAt); + $board->setLastModified($importBoard->lastModified); return $board; } @@ -147,6 +151,7 @@ class DeckJsonService extends ABoardImportService { $newLabel->setTitle($label->title); $newLabel->setColor($label->color); $newLabel->setBoardId($this->getImportService()->getBoard()->getId()); + $newLabel->setLastModified($label->lastModified); $this->labels[$label->id] = $newLabel; } return $this->labels; @@ -203,21 +208,17 @@ class DeckJsonService extends ABoardImportService { * @return Acl[] */ public function getAclList(): array { - // FIXME: To implement + $board = $this->getImportService()->getData(); $return = []; - foreach ($this->members as $member) { - if ($member->getUID() === $this->getImportService()->getConfig('owner')->getUID()) { - continue; - } + foreach ($board->acl as $aclData) { + // FIXME: Figure out mapping $acl = new Acl(); $acl->setBoardId($this->getImportService()->getBoard()->getId()); - $acl->setType(Acl::PERMISSION_TYPE_USER); - $acl->setParticipant($member->getUID()); - $acl->setPermissionEdit(false); - $acl->setPermissionShare(false); - $acl->setPermissionManage(false); - // FIXME: Figure out a way to collect and aggregate warnings about users - // FIXME: Maybe have a dry run? + $acl->setType($aclData->type); + $acl->setParticipant($aclData->participant?->primaryKey ?? $aclData->participant); + $acl->setPermissionEdit($aclData->permissionEdit); + $acl->setPermissionShare($aclData->permissionShare); + $acl->setPermissionManage($aclData->permissionManage); $return[] = $acl; } return $return; diff --git a/tests/integration/import/ImportExportTest.php b/tests/integration/import/ImportExportTest.php index 4ee73c5ad..ce79fe1fe 100644 --- a/tests/integration/import/ImportExportTest.php +++ b/tests/integration/import/ImportExportTest.php @@ -24,15 +24,21 @@ namespace OCA\Deck\Db; use OCA\Deck\Command\BoardImport; +use OCA\Deck\Command\UserExport; +use OCA\Deck\Service\BoardService; use OCA\Deck\Service\Importer\BoardImportService; use OCA\Deck\Service\Importer\Systems\DeckJsonService; +use OCA\Deck\Service\PermissionService; +use OCA\Deck\Service\StackService; use OCP\AppFramework\Db\Entity; use OCP\IDBConnection; use OCP\IGroupManager; use OCP\IUserManager; use OCP\Server; +use PHPUnit\Framework\ExpectationFailedException; use Symfony\Component\Console\Application; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; /** @@ -102,6 +108,73 @@ class ImportExportTest extends \Test\TestCase { $this->assertDatabase(); } + /** + * This test runs an import, export and another import to assert that multiple attempts result in the same data structure + */ + public function testReimportOcc() { + // initial import from test fixture json + $input = $this->createMock(InputInterface::class); + $input->expects($this->any()) + ->method('getOption') + ->willReturnCallback(function ($arg) { + return match ($arg) { + 'system' => 'DeckJson', + 'data' => __DIR__ . '/../../data/deck.json', + 'config' => __DIR__ . '/../../data/config-trelloJson.json', + }; + }); + $output = $this->createMock(OutputInterface::class); + $importer = \OCP\Server::get(BoardImport::class); + $application = new Application(); + $importer->setApplication($application); + $importer->run($input, $output); + + $this->assertDatabase(); + + self::overwriteService(BoardService::class, self::getFreshService(BoardService::class)); + // export to a temporary file + $input = $this->createMock(InputInterface::class); + $input->expects($this->any()) + ->method('getArgument') + ->with('user-id') + ->willReturn('admin'); + $output = new BufferedOutput(); + $exporter = \OCP\Server::get(UserExport::class); + $exporter->setApplication($application); + $exporter->run($input, $output); + $jsonOutput = $output->fetch(); + json_decode($jsonOutput); + self::assertTrue(json_last_error() === JSON_ERROR_NONE); + $tmpExportFile = tempnam('/tmp', 'export'); + file_put_contents($tmpExportFile, $jsonOutput); + + // self::assertEquals(file_get_contents(__DIR__ . '/../../data/deck.json'), $jsonOutput); + + // cleanup test database + $this->connection->rollBack(); + $this->connection->beginTransaction(); + + self::overwriteService(BoardService::class, self::getFreshService(BoardService::class)); + // Re-import from temporary file + $input = $this->createMock(InputInterface::class); + $input->expects($this->any()) + ->method('getOption') + ->willReturnCallback(function ($arg) use ($tmpExportFile) { + return match ($arg) { + 'system' => 'DeckJson', + 'data' => $tmpExportFile, + 'config' => __DIR__ . '/../../data/config-trelloJson.json', + }; + }); + $output = $this->createMock(OutputInterface::class); + $importer = \OCP\Server::get(BoardImport::class); + $application = new Application(); + $importer->setApplication($application); + $importer->run($input, $output); + + $this->assertDatabase(); + } + public function testImport() { $importer = \OCP\Server::get(BoardImportService::class); $deckJsonService = \OCP\Server::get(DeckJsonService::class); @@ -116,12 +189,24 @@ class ImportExportTest extends \Test\TestCase { $this->assertDatabase(); } + /** + * @template T + * @param class-string|string $className + * @return T + */ + private function getFreshService(string $className): mixed { + return \OC::$server->getRegisteredAppContainer('deck')->resolve($className); + } + public function assertDatabase() { + $permissionService = \OCP\Server::get(PermissionService::class); + $permissionService->setUserId('admin'); $boardMapper = \OCP\Server::get(BoardMapper::class); $stackMapper = \OCP\Server::get(StackMapper::class); $cardMapper = \OCP\Server::get(CardMapper::class); $boards = $boardMapper->findAllByOwner('admin'); + $boardNames = array_map(fn ($board) => $board->getTitle(), $boards); self::assertEquals(2, count($boards)); $board = $boards[0]; @@ -129,7 +214,15 @@ class ImportExportTest extends \Test\TestCase { 'title' => 'My test board', 'color' => 'e0ed31', 'owner' => 'admin', + 'lastModified' => 1689667796, ]), $board); + $boardService = $this->getFreshService(BoardService::class); + $fullBoard = $boardService->find($board->getId(), true); + self::assertEntityInArray(Label::fromParams([ + 'title' => 'L2', + 'color' => '31CC7C', + ]), $fullBoard->getLabels(), true); + $stacks = $stackMapper->findAll($board->getId()); self::assertCount(3, $stacks); @@ -183,13 +276,41 @@ class ImportExportTest extends \Test\TestCase { 'title' => 'Shared board', 'color' => '30b6d8', 'owner' => 'admin', - ]), $sharedBoard); + ]), $sharedBoard, true); + + $stackService = \OCP\Server::get(StackService::class); + $stacks = $stackService->findAll($board->getId()); + self::assertEntityInArray(Label::fromParams([ + 'title' => 'L2', + 'color' => '31CC7C', + ]), $stacks[0]->getCards()[0]->getLabels(), true); + self::assertEntity(Label::fromParams([ + 'title' => 'L2', + 'color' => '31CC7C', + ]), $stacks[0]->getCards()[0]->getLabels()[0], true); $stacks = $stackMapper->findAll($sharedBoard->getId()); self::assertCount(3, $stacks); } - public static function assertEntity(Entity $expected, Entity $actual, bool $checkProperties = false) { + public static function assertEntityInArray(Entity $expected, array $array, bool $checkProperties): void { + $exists = null; + foreach ($array as $entity) { + try { + self::assertEntity($expected, $entity, $checkProperties); + $exists = $entity; + } catch (ExpectationFailedException $e) { + } + } + if ($exists) { + self::assertEntity($expected, $exists, $checkProperties); + } else { + // THis is hard to debug if it fails as the actual diff is not returned but hidden in the above exception + self::assertEquals($expected, $exists); + } + } + + public static function assertEntity(Entity $expected, Entity $actual, bool $checkProperties = false): void { if ($checkProperties === true) { $e = clone $expected; $a = clone $actual;