From 56e16b2d3fdf467dd5f1336897376bc1337f44ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Mon, 17 Jul 2023 16:52:00 +0200 Subject: [PATCH] feat: Implement logic to import multiple boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Command/BoardImport.php | 5 +- lib/Service/Importer/ABoardImportService.php | 13 ++++ .../Importer/BoardImportCommandService.php | 39 ++++++---- lib/Service/Importer/BoardImportService.php | 77 ++++++++----------- .../Importer/Systems/DeckJsonService.php | 29 +++---- .../Importer/Systems/TrelloJsonService.php | 8 ++ 6 files changed, 88 insertions(+), 83 deletions(-) diff --git a/lib/Command/BoardImport.php b/lib/Command/BoardImport.php index ae0388f91..4c70c61ae 100644 --- a/lib/Command/BoardImport.php +++ b/lib/Command/BoardImport.php @@ -30,12 +30,9 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class BoardImport extends Command { - private BoardImportCommandService $boardImportCommandService; - public function __construct( - BoardImportCommandService $boardImportCommandService + private BoardImportCommandService $boardImportCommandService ) { - $this->boardImportCommandService = $boardImportCommandService; parent::__construct(); } diff --git a/lib/Service/Importer/ABoardImportService.php b/lib/Service/Importer/ABoardImportService.php index 2e6acb605..43ec745f5 100644 --- a/lib/Service/Importer/ABoardImportService.php +++ b/lib/Service/Importer/ABoardImportService.php @@ -61,6 +61,10 @@ abstract class ABoardImportService { */ abstract public function bootstrap(): void; + public function getBoards(): array { + return [$this->getImportService()->getData()]; + } + abstract public function getBoard(): ?Board; /** @@ -133,4 +137,13 @@ abstract class ABoardImportService { public function needValidateData(): bool { return $this->needValidateData; } + + public function reset(): void { + // FIXME: Would be cleaner if we could just get a new instance per board + // but currently https://github.com/nextcloud/deck/blob/7d820aa3f9fc69ada8188549b9a2fbb9093ffb95/lib/Service/Importer/BoardImportService.php#L194 returns a singleton + $this->labels = []; + $this->stacks = []; + $this->acls = []; + $this->cards = []; + } } diff --git a/lib/Service/Importer/BoardImportCommandService.php b/lib/Service/Importer/BoardImportCommandService.php index ced94fd47..0aea5ca97 100644 --- a/lib/Service/Importer/BoardImportCommandService.php +++ b/lib/Service/Importer/BoardImportCommandService.php @@ -179,21 +179,28 @@ class BoardImportCommandService extends BoardImportService { public function import(): void { $this->getOutput()->writeln('Starting import...'); $this->bootstrap(); - $this->getOutput()->writeln('Importing board...'); - $this->importBoard(); - $this->getOutput()->writeln('Assign users to board...'); - $this->importAcl(); - $this->getOutput()->writeln('Importing labels...'); - $this->importLabels(); - $this->getOutput()->writeln('Importing stacks...'); - $this->importStacks(); - $this->getOutput()->writeln('Importing cards...'); - $this->importCards(); - $this->getOutput()->writeln('Assign cards to labels...'); - $this->assignCardsToLabels(); - $this->getOutput()->writeln('Importing comments...'); - $this->importComments(); - $this->getOutput()->writeln('Importing participants...'); - $this->importCardAssignments(); + $boards = $this->getImportSystem()->getBoards(); + + foreach ($boards as $board) { + $this->reset(); + $this->setData($board); + $this->getOutput()->writeln('Importing board...'); + $this->importBoard(); + $this->getOutput()->writeln('Assign users to board...'); + $this->importAcl(); + $this->getOutput()->writeln('Importing labels...'); + $this->importLabels(); + $this->getOutput()->writeln('Importing stacks...'); + $this->importStacks(); + $this->getOutput()->writeln('Importing cards...'); + $this->importCards(); + $this->getOutput()->writeln('Assign cards to labels...'); + $this->assignCardsToLabels(); + $this->getOutput()->writeln('Importing comments...'); + $this->importComments(); + $this->getOutput()->writeln('Importing participants...'); + $this->importCardAssignments(); + $this->getOutput()->writeln('Finished board import of "' . $this->getBoard()->getTitle() . '"'); + } } } diff --git a/lib/Service/Importer/BoardImportService.php b/lib/Service/Importer/BoardImportService.php index 20fd959f6..364fd1bce 100644 --- a/lib/Service/Importer/BoardImportService.php +++ b/lib/Service/Importer/BoardImportService.php @@ -40,9 +40,9 @@ use OCA\Deck\Event\BoardImportGetAllowedEvent; use OCA\Deck\Exceptions\ConflictException; use OCA\Deck\NotFoundException; use OCA\Deck\Service\FileService; +use OCA\Deck\Service\Importer\Systems\DeckJsonService; use OCA\Deck\Service\Importer\Systems\TrelloApiService; use OCA\Deck\Service\Importer\Systems\TrelloJsonService; -use OCA\Deck\Service\Importer\Systems\DeckJsonService; use OCP\Comments\IComment; use OCP\Comments\ICommentsManager; use OCP\Comments\NotFoundException as CommentNotFoundException; @@ -51,16 +51,6 @@ use OCP\IUserManager; use OCP\Server; class BoardImportService { - private IUserManager $userManager; - private BoardMapper $boardMapper; - private AclMapper $aclMapper; - private LabelMapper $labelMapper; - private StackMapper $stackMapper; - private CardMapper $cardMapper; - private AssignmentMapper $assignmentMapper; - private AttachmentMapper $attachmentMapper; - private ICommentsManager $commentsManager; - private IEventDispatcher $eventDispatcher; private string $system = ''; private ?ABoardImportService $systemInstance = null; private array $allowedSystems = []; @@ -81,27 +71,17 @@ class BoardImportService { private Board $board; public function __construct( - IUserManager $userManager, - BoardMapper $boardMapper, - AclMapper $aclMapper, - LabelMapper $labelMapper, - StackMapper $stackMapper, - AssignmentMapper $assignmentMapper, - AttachmentMapper $attachmentMapper, - CardMapper $cardMapper, - ICommentsManager $commentsManager, - IEventDispatcher $eventDispatcher + private IUserManager $userManager, + private BoardMapper $boardMapper, + private AclMapper $aclMapper, + private LabelMapper $labelMapper, + private StackMapper $stackMapper, + private AssignmentMapper $assignmentMapper, + private AttachmentMapper $attachmentMapper, + private CardMapper $cardMapper, + private ICommentsManager $commentsManager, + private IEventDispatcher $eventDispatcher ) { - $this->userManager = $userManager; - $this->boardMapper = $boardMapper; - $this->aclMapper = $aclMapper; - $this->labelMapper = $labelMapper; - $this->stackMapper = $stackMapper; - $this->cardMapper = $cardMapper; - $this->assignmentMapper = $assignmentMapper; - $this->attachmentMapper = $attachmentMapper; - $this->commentsManager = $commentsManager; - $this->eventDispatcher = $eventDispatcher; $this->board = new Board(); $this->disableCommentsEvents(); } @@ -121,17 +101,23 @@ class BoardImportService { public function import(): void { $this->bootstrap(); - try { - $this->importBoard(); - $this->importAcl(); - $this->importLabels(); - $this->importStacks(); - $this->importCards(); - $this->assignCardsToLabels(); - $this->importComments(); - $this->importCardAssignments(); - } catch (\Throwable $th) { - throw new BadRequestException($th->getMessage()); + $boards = $this->getImportSystem()->getBoards(); + foreach ($boards as $board) { + try { + $this->reset(); + $this->setData($board); + $this->importBoard(); + $this->importAcl(); + $this->importLabels(); + $this->importStacks(); + $this->importCards(); + $this->assignCardsToLabels(); + $this->importComments(); + $this->importCardAssignments(); + } catch (\Throwable $th) { + throw $th; + throw new BadRequestException($th->getMessage()); + } } } @@ -139,7 +125,7 @@ class BoardImportService { $allowedSystems = $this->getAllowedImportSystems(); $allowedSystems = array_column($allowedSystems, 'internalName'); if (!in_array($this->getSystem(), $allowedSystems)) { - throw new NotFoundException('Invalid system'); + throw new NotFoundException('Invalid system: ' . $this->getSystem()); } } @@ -201,6 +187,11 @@ class BoardImportService { $this->systemInstance = $instance; } + public function reset(): void { + $this->board = new Board(); + $this->getImportSystem()->reset(); + } + public function importBoard(): void { $board = $this->getImportSystem()->getBoard(); if ($board) { diff --git a/lib/Service/Importer/Systems/DeckJsonService.php b/lib/Service/Importer/Systems/DeckJsonService.php index 70b1f23a2..03d3c2e6e 100644 --- a/lib/Service/Importer/Systems/DeckJsonService.php +++ b/lib/Service/Importer/Systems/DeckJsonService.php @@ -23,43 +23,30 @@ namespace OCA\Deck\Service\Importer\Systems; -use OC\Comments\Comment; use OCA\Deck\BadRequestException; use OCA\Deck\Db\Acl; use OCA\Deck\Db\Assignment; -use OCA\Deck\Db\Attachment; use OCA\Deck\Db\Board; use OCA\Deck\Db\Card; use OCA\Deck\Db\Label; use OCA\Deck\Db\Stack; use OCA\Deck\Service\Importer\ABoardImportService; -use OCP\Comments\IComment; use OCP\IL10N; use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserManager; class DeckJsonService extends ABoardImportService { - /** @var string */ public static $name = 'Deck JSON'; - /** @var IUserManager */ - private $userManager; - /** @var IURLGenerator */ - private $urlGenerator; - /** @var IL10N */ - private $l10n; /** @var IUser[] */ - private $members = []; + private array $members = []; private array $tmpCards = []; public function __construct( - IUserManager $userManager, - IURLGenerator $urlGenerator, - IL10N $l10n + private IUserManager $userManager, + private IURLGenerator $urlGenerator, + private IL10N $l10n ) { - $this->userManager = $userManager; - $this->urlGenerator = $urlGenerator; - $this->l10n = $l10n; } public function bootstrap(): void { @@ -76,7 +63,7 @@ class DeckJsonService extends ABoardImportService { } public function validateUsers(): void { - if (empty($this->getImportService()->getConfig('uidRelation'))) { + if (empty($this->getImportService()->getConfig('uidRelation')) || !isset($this->getImportService()->getData()->members)) { return; } foreach ($this->getImportService()->getConfig('uidRelation') as $exportUid => $nextcloudUid) { @@ -169,7 +156,7 @@ class DeckJsonService extends ABoardImportService { $return[$source->id] = $stack; } - if ($source->cards) { + if (isset($source->cards)) { foreach ($source->cards as $card) { $card->stackId = $index; $this->tmpCards[] = $card; @@ -231,7 +218,9 @@ class DeckJsonService extends ABoardImportService { } public function getBoards(): array { - return get_object_vars($this->getImportService()->getData()); + // Old format has just the raw board data, new one a key boards + $data = $this->getImportService()->getData(); + return array_values((array)($data->boards ?? $data)); } public function reset(): void { diff --git a/lib/Service/Importer/Systems/TrelloJsonService.php b/lib/Service/Importer/Systems/TrelloJsonService.php index 88c4ae23a..a4a3673c1 100644 --- a/lib/Service/Importer/Systems/TrelloJsonService.php +++ b/lib/Service/Importer/Systems/TrelloJsonService.php @@ -397,4 +397,12 @@ class TrelloJsonService extends ABoardImportService { $trelloCard->desc .= "| [{$name}]({$attachment->url}) | {$attachment->date} |\n"; } } + + public function getBoards(): array { + if ($this->getImportService()->getData()->boards) { + return $this->getImportService()->getData()->boards; + } + + return [$this->getImportService()->getData()]; + } }