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
Родитель cccc4f2f67
Коммит e7d5fbff63
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4C614C6ED2CDE6DF
7 изменённых файлов: 146 добавлений и 17 удалений

Просмотреть файл

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

Просмотреть файл

@ -138,7 +138,7 @@ class RelationalEntity extends Entity implements \JsonSerializable {
$attr = lcfirst(substr($methodName, 3));
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'];
}
parent::setter($attr, $args);

Просмотреть файл

@ -25,6 +25,7 @@ namespace OCA\Deck\Service\Importer;
use OCA\Deck\Exceptions\ConflictException;
use OCA\Deck\NotFoundException;
use OCA\Deck\Service\Importer\Systems\DeckJsonService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@ -76,6 +77,10 @@ class BoardImportCommandService extends BoardImportService {
}
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 {
$config = $this->getInput()->getOption('config');
if (is_string($config)) {
@ -145,6 +150,18 @@ class BoardImportCommandService extends BoardImportService {
if (!$this->getImportSystem()->needValidateData()) {
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');
if (is_string($data)) {
$data = json_decode(file_get_contents($data));

Просмотреть файл

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

Просмотреть файл

@ -31,8 +31,6 @@ use OCA\Deck\Db\Card;
use OCA\Deck\Db\Label;
use OCA\Deck\Db\Stack;
use OCA\Deck\Service\Importer\ABoardImportService;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
@ -44,8 +42,6 @@ class DeckJsonService extends ABoardImportService {
public function __construct(
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 {
$assignments = [];
foreach ($this->tmpCards as $sourceCard) {
@ -176,6 +186,7 @@ class DeckJsonService extends ABoardImportService {
$card = new Card();
$card->setTitle($cardSource->title);
$card->setLastModified($cardSource->lastModified);
$card->setCreatedAt($cardSource->createdAt);
$card->setArchived($cardSource->archived);
$card->setDescription($cardSource->description);
$card->setStackId($this->stacks[$cardSource->stackId]->getId());

Просмотреть файл

@ -26,6 +26,7 @@ namespace OCA\Deck\Db;
use OCA\Deck\Command\BoardImport;
use OCA\Deck\Service\Importer\BoardImportService;
use OCA\Deck\Service\Importer\Systems\DeckJsonService;
use OCP\AppFramework\Db\Entity;
use OCP\IDBConnection;
use OCP\IGroupManager;
use OCP\IUserManager;
@ -117,10 +118,98 @@ class ImportExportTest extends \Test\TestCase {
public function assertDatabase() {
$boardMapper = \OCP\Server::get(BoardMapper::class);
$stackMapper = \OCP\Server::get(StackMapper::class);
$cardMapper = \OCP\Server::get(CardMapper::class);
$boards = $boardMapper->findAllByOwner('admin');
self::assertEquals('My test board', $boards[0]->getTitle());
self::assertEquals('Shared board', $boards[1]->getTitle());
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 {

Просмотреть файл

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