feat: Let occ deck:import default to deck json importer

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl
2023-07-19 09:52:44 +02:00
parent cccc4f2f67
commit e7d5fbff63
7 changed files with 146 additions and 17 deletions

View File

@@ -25,6 +25,7 @@ namespace OCA\Deck\Command;
use OCA\Deck\Service\Importer\BoardImportCommandService; use OCA\Deck\Service\Importer\BoardImportCommandService;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
@@ -41,7 +42,9 @@ class BoardImport extends Command {
*/ */
protected function configure() { protected function configure() {
$allowedSystems = $this->boardImportCommandService->getAllowedImportSystems(); $allowedSystems = $this->boardImportCommandService->getAllowedImportSystems();
$names = array_column($allowedSystems, 'name'); $names = array_map(function ($name) {
return '"' . $name . '"';
}, array_column($allowedSystems, 'internalName'));
$this $this
->setName('deck:import') ->setName('deck:import')
->setDescription('Import data') ->setDescription('Import data')
@@ -50,7 +53,7 @@ class BoardImport extends Command {
null, null,
InputOption::VALUE_REQUIRED, InputOption::VALUE_REQUIRED,
'Source system for import. Available options: ' . implode(', ', $names) . '.', 'Source system for import. Available options: ' . implode(', ', $names) . '.',
null 'DeckJson',
) )
->addOption( ->addOption(
'config', 'config',
@@ -66,6 +69,11 @@ class BoardImport extends Command {
'Data file to import.', 'Data file to import.',
'data.json' 'data.json'
) )
->addArgument(
'file',
InputArgument::OPTIONAL,
'File to import',
)
; ;
} }

View File

@@ -138,7 +138,7 @@ class RelationalEntity extends Entity implements \JsonSerializable {
$attr = lcfirst(substr($methodName, 3)); $attr = lcfirst(substr($methodName, 3));
if (array_key_exists($attr, $this->_resolvedProperties) && str_starts_with($methodName, 'set')) { if (array_key_exists($attr, $this->_resolvedProperties) && str_starts_with($methodName, 'set')) {
if (!is_scalar($args[0])) { if ($args[0] !== null && !is_scalar($args[0])) {
$args[0] = $args[0]['primaryKey']; $args[0] = $args[0]['primaryKey'];
} }
parent::setter($attr, $args); parent::setter($attr, $args);

View File

@@ -25,6 +25,7 @@ namespace OCA\Deck\Service\Importer;
use OCA\Deck\Exceptions\ConflictException; use OCA\Deck\Exceptions\ConflictException;
use OCA\Deck\NotFoundException; use OCA\Deck\NotFoundException;
use OCA\Deck\Service\Importer\Systems\DeckJsonService;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
@@ -76,6 +77,10 @@ class BoardImportCommandService extends BoardImportService {
} }
protected function validateConfig(): void { protected function validateConfig(): void {
// FIXME: Make config optional for deck plain importer (but use a call on the importer insterad)
if ($this->getImportSystem() instanceof DeckJsonService) {
return;
}
try { try {
$config = $this->getInput()->getOption('config'); $config = $this->getInput()->getOption('config');
if (is_string($config)) { if (is_string($config)) {
@@ -145,6 +150,18 @@ class BoardImportCommandService extends BoardImportService {
if (!$this->getImportSystem()->needValidateData()) { if (!$this->getImportSystem()->needValidateData()) {
return; return;
} }
$data = $this->getInput()->getArgument('file');
if (is_string($data)) {
if (!file_exists($data)) {
throw new \OCP\Files\NotFoundException('Could not find file ' . $data);
}
$data = json_decode(file_get_contents($data));
if ($data instanceof \stdClass) {
$this->setData($data);
return;
}
}
$data = $this->getInput()->getOption('data'); $data = $this->getInput()->getOption('data');
if (is_string($data)) { if (is_string($data)) {
$data = json_decode(file_get_contents($data)); $data = json_decode(file_get_contents($data));

View File

@@ -84,6 +84,8 @@ class BoardImportService {
) { ) {
$this->board = new Board(); $this->board = new Board();
$this->disableCommentsEvents(); $this->disableCommentsEvents();
$this->config = new \stdClass();
} }
private function disableCommentsEvents(): void { private function disableCommentsEvents(): void {
@@ -151,6 +153,11 @@ class BoardImportService {
public function getAllowedImportSystems(): array { public function getAllowedImportSystems(): array {
if (!$this->allowedSystems) { if (!$this->allowedSystems) {
$this->addAllowedImportSystem([
'name' => DeckJsonService::$name,
'class' => DeckJsonService::class,
'internalName' => 'DeckJson'
]);
$this->addAllowedImportSystem([ $this->addAllowedImportSystem([
'name' => TrelloApiService::$name, 'name' => TrelloApiService::$name,
'class' => TrelloApiService::class, 'class' => TrelloApiService::class,
@@ -161,11 +168,6 @@ class BoardImportService {
'class' => TrelloJsonService::class, 'class' => TrelloJsonService::class,
'internalName' => 'TrelloJson' 'internalName' => 'TrelloJson'
]); ]);
$this->addAllowedImportSystem([
'name' => DeckJsonService::$name,
'class' => DeckJsonService::class,
'internalName' => 'DeckJson'
]);
} }
$this->eventDispatcher->dispatchTyped(new BoardImportGetAllowedEvent($this)); $this->eventDispatcher->dispatchTyped(new BoardImportGetAllowedEvent($this));
return $this->allowedSystems; return $this->allowedSystems;

View File

@@ -31,8 +31,6 @@ use OCA\Deck\Db\Card;
use OCA\Deck\Db\Label; use OCA\Deck\Db\Label;
use OCA\Deck\Db\Stack; use OCA\Deck\Db\Stack;
use OCA\Deck\Service\Importer\ABoardImportService; use OCA\Deck\Service\Importer\ABoardImportService;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser; use OCP\IUser;
use OCP\IUserManager; use OCP\IUserManager;
@@ -44,8 +42,6 @@ class DeckJsonService extends ABoardImportService {
public function __construct( public function __construct(
private IUserManager $userManager, private IUserManager $userManager,
private IURLGenerator $urlGenerator,
private IL10N $l10n
) { ) {
} }
@@ -86,6 +82,20 @@ class DeckJsonService extends ABoardImportService {
} }
} }
public function mapMember($uid): ?string {
$uidCandidate = $this->members[$uid]?->getUID() ?? null;
if ($uidCandidate) {
return $uidCandidate;
}
if ($this->userManager->userExists($uid)) {
return $uid;
}
return null;
}
public function getCardAssignments(): array { public function getCardAssignments(): array {
$assignments = []; $assignments = [];
foreach ($this->tmpCards as $sourceCard) { foreach ($this->tmpCards as $sourceCard) {
@@ -176,6 +186,7 @@ class DeckJsonService extends ABoardImportService {
$card = new Card(); $card = new Card();
$card->setTitle($cardSource->title); $card->setTitle($cardSource->title);
$card->setLastModified($cardSource->lastModified); $card->setLastModified($cardSource->lastModified);
$card->setCreatedAt($cardSource->createdAt);
$card->setArchived($cardSource->archived); $card->setArchived($cardSource->archived);
$card->setDescription($cardSource->description); $card->setDescription($cardSource->description);
$card->setStackId($this->stacks[$cardSource->stackId]->getId()); $card->setStackId($this->stacks[$cardSource->stackId]->getId());

View File

@@ -26,6 +26,7 @@ namespace OCA\Deck\Db;
use OCA\Deck\Command\BoardImport; use OCA\Deck\Command\BoardImport;
use OCA\Deck\Service\Importer\BoardImportService; use OCA\Deck\Service\Importer\BoardImportService;
use OCA\Deck\Service\Importer\Systems\DeckJsonService; use OCA\Deck\Service\Importer\Systems\DeckJsonService;
use OCP\AppFramework\Db\Entity;
use OCP\IDBConnection; use OCP\IDBConnection;
use OCP\IGroupManager; use OCP\IGroupManager;
use OCP\IUserManager; use OCP\IUserManager;
@@ -117,10 +118,98 @@ class ImportExportTest extends \Test\TestCase {
public function assertDatabase() { public function assertDatabase() {
$boardMapper = \OCP\Server::get(BoardMapper::class); $boardMapper = \OCP\Server::get(BoardMapper::class);
$stackMapper = \OCP\Server::get(StackMapper::class);
$cardMapper = \OCP\Server::get(CardMapper::class);
$boards = $boardMapper->findAllByOwner('admin'); $boards = $boardMapper->findAllByOwner('admin');
self::assertEquals('My test board', $boards[0]->getTitle());
self::assertEquals('Shared board', $boards[1]->getTitle());
self::assertEquals(2, count($boards)); self::assertEquals(2, count($boards));
$board = $boards[0];
self::assertEntity(Board::fromRow([
'title' => 'My test board',
'color' => 'e0ed31',
'owner' => 'admin',
]), $board);
$stacks = $stackMapper->findAll($board->getId());
self::assertCount(3, $stacks);
self::assertEntity(Stack::fromRow([
'title' => 'A',
'order' => 999,
'boardId' => $boards[0]->getId(),
]), $stacks[0]);
self::assertEntity(Stack::fromRow([
'title' => 'B',
'order' => 999,
'boardId' => $boards[0]->getId(),
]), $stacks[1]);
self::assertEntity(Stack::fromRow([
'title' => 'C',
'order' => 999,
'boardId' => $boards[0]->getId(),
]), $stacks[2]);
$cards = $cardMapper->findAll($stacks[0]->getId());
self::assertEntity(Card::fromRow([
'title' => '1',
'description' => '',
'type' => 'plain',
'lastModified' => 1689667779,
'createdAt' => 1689667569,
'owner' => 'admin',
'duedate' => new \DateTime('2050-07-24T22:00:00.000000+0000'),
'order' => 999,
'stackId' => $stacks[0]->getId(),
]), $cards[0]);
self::assertEntity(Card::fromRow([
'title' => '2',
'duedate' => new \DateTime('2050-07-24T22:00:00.000000+0000'),
]), $cards[1], true);
self::assertEntity(Card::fromParams([
'title' => '3',
'duedate' => null,
]), $cards[2], true);
$cards = $cardMapper->findAll($stacks[1]->getId());
self::assertEntity(Card::fromParams([
'title' => '6',
'duedate' => null,
'description' => "# Test description\n\nHello world",
]), $cards[2], true);
// Shared board
$sharedBoard = $boards[1];
self::assertEntity(Board::fromRow([
'title' => 'Shared board',
'color' => '30b6d8',
'owner' => 'admin',
]), $sharedBoard);
$stacks = $stackMapper->findAll($sharedBoard->getId());
self::assertCount(3, $stacks);
}
public static function assertEntity(Entity $expected, Entity $actual, bool $checkProperties = false) {
if ($checkProperties === true) {
$e = clone $expected;
$a = clone $actual;
foreach ($e->getUpdatedFields() as $property => $updated) {
$expectedValue = call_user_func([$e, 'get' . ucfirst($property)]);
$actualValue = call_user_func([$a, 'get' . ucfirst($property)]);
self::assertEquals(
$expectedValue,
$actualValue
);
}
} else {
$e = clone $expected;
$e->setId(null);
$a = clone $actual;
$a->setId(null);
$e->resetUpdatedFields();
$a->resetUpdatedFields();
self::assertEquals($e, $a);
}
} }
public function tearDown(): void { public function tearDown(): void {

View File

@@ -118,6 +118,9 @@ class BoardImportServiceTest extends \Test\TestCase {
$this->trelloJsonService $this->trelloJsonService
->method('getJsonSchemaPath') ->method('getJsonSchemaPath')
->willReturn($configFile); ->willReturn($configFile);
$this->trelloJsonService
->method('getBoards')
->willReturn([$data]);
$this->boardImportService->setImportSystem($this->trelloJsonService); $this->boardImportService->setImportSystem($this->trelloJsonService);
$owner = $this->createMock(IUser::class); $owner = $this->createMock(IUser::class);
@@ -192,8 +195,7 @@ class BoardImportServiceTest extends \Test\TestCase {
->expects($this->once()) ->expects($this->once())
->method('insert'); ->method('insert');
$actual = $this->boardImportService->import(); $this->boardImportService->import();
self::assertTrue(true);
$this->assertNull($actual);
} }
} }