feat: Let occ deck:import default to deck json importer
Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
@@ -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',
|
||||||
|
)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user