feat: Implement logic to import multiple boards

Signed-off-by: Julius Härtl <jus@bitgrid.net>
This commit is contained in:
Julius Härtl
2023-07-17 16:52:00 +02:00
parent 8954569aee
commit 2ae9f71483
6 changed files with 88 additions and 83 deletions

View File

@@ -30,12 +30,9 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
class BoardImport extends Command { class BoardImport extends Command {
private BoardImportCommandService $boardImportCommandService;
public function __construct( public function __construct(
BoardImportCommandService $boardImportCommandService private BoardImportCommandService $boardImportCommandService
) { ) {
$this->boardImportCommandService = $boardImportCommandService;
parent::__construct(); parent::__construct();
} }

View File

@@ -61,6 +61,10 @@ abstract class ABoardImportService {
*/ */
abstract public function bootstrap(): void; abstract public function bootstrap(): void;
public function getBoards(): array {
return [$this->getImportService()->getData()];
}
abstract public function getBoard(): ?Board; abstract public function getBoard(): ?Board;
/** /**
@@ -133,4 +137,13 @@ abstract class ABoardImportService {
public function needValidateData(): bool { public function needValidateData(): bool {
return $this->needValidateData; 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 = [];
}
} }

View File

@@ -179,6 +179,11 @@ class BoardImportCommandService extends BoardImportService {
public function import(): void { public function import(): void {
$this->getOutput()->writeln('Starting import...'); $this->getOutput()->writeln('Starting import...');
$this->bootstrap(); $this->bootstrap();
$boards = $this->getImportSystem()->getBoards();
foreach ($boards as $board) {
$this->reset();
$this->setData($board);
$this->getOutput()->writeln('Importing board...'); $this->getOutput()->writeln('Importing board...');
$this->importBoard(); $this->importBoard();
$this->getOutput()->writeln('Assign users to board...'); $this->getOutput()->writeln('Assign users to board...');
@@ -195,5 +200,7 @@ class BoardImportCommandService extends BoardImportService {
$this->importComments(); $this->importComments();
$this->getOutput()->writeln('Importing participants...'); $this->getOutput()->writeln('Importing participants...');
$this->importCardAssignments(); $this->importCardAssignments();
$this->getOutput()->writeln('<info>Finished board import of "' . $this->getBoard()->getTitle() . '"</info>');
}
} }
} }

View File

@@ -40,9 +40,9 @@ use OCA\Deck\Event\BoardImportGetAllowedEvent;
use OCA\Deck\Exceptions\ConflictException; use OCA\Deck\Exceptions\ConflictException;
use OCA\Deck\NotFoundException; use OCA\Deck\NotFoundException;
use OCA\Deck\Service\FileService; 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\TrelloApiService;
use OCA\Deck\Service\Importer\Systems\TrelloJsonService; use OCA\Deck\Service\Importer\Systems\TrelloJsonService;
use OCA\Deck\Service\Importer\Systems\DeckJsonService;
use OCP\Comments\IComment; use OCP\Comments\IComment;
use OCP\Comments\ICommentsManager; use OCP\Comments\ICommentsManager;
use OCP\Comments\NotFoundException as CommentNotFoundException; use OCP\Comments\NotFoundException as CommentNotFoundException;
@@ -51,16 +51,6 @@ use OCP\IUserManager;
use OCP\Server; use OCP\Server;
class BoardImportService { 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 string $system = '';
private ?ABoardImportService $systemInstance = null; private ?ABoardImportService $systemInstance = null;
private array $allowedSystems = []; private array $allowedSystems = [];
@@ -81,27 +71,17 @@ class BoardImportService {
private Board $board; private Board $board;
public function __construct( public function __construct(
IUserManager $userManager, private IUserManager $userManager,
BoardMapper $boardMapper, private BoardMapper $boardMapper,
AclMapper $aclMapper, private AclMapper $aclMapper,
LabelMapper $labelMapper, private LabelMapper $labelMapper,
StackMapper $stackMapper, private StackMapper $stackMapper,
AssignmentMapper $assignmentMapper, private AssignmentMapper $assignmentMapper,
AttachmentMapper $attachmentMapper, private AttachmentMapper $attachmentMapper,
CardMapper $cardMapper, private CardMapper $cardMapper,
ICommentsManager $commentsManager, private ICommentsManager $commentsManager,
IEventDispatcher $eventDispatcher 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->board = new Board();
$this->disableCommentsEvents(); $this->disableCommentsEvents();
} }
@@ -121,7 +101,11 @@ class BoardImportService {
public function import(): void { public function import(): void {
$this->bootstrap(); $this->bootstrap();
$boards = $this->getImportSystem()->getBoards();
foreach ($boards as $board) {
try { try {
$this->reset();
$this->setData($board);
$this->importBoard(); $this->importBoard();
$this->importAcl(); $this->importAcl();
$this->importLabels(); $this->importLabels();
@@ -131,15 +115,17 @@ class BoardImportService {
$this->importComments(); $this->importComments();
$this->importCardAssignments(); $this->importCardAssignments();
} catch (\Throwable $th) { } catch (\Throwable $th) {
throw $th;
throw new BadRequestException($th->getMessage()); throw new BadRequestException($th->getMessage());
} }
} }
}
public function validateSystem(): void { public function validateSystem(): void {
$allowedSystems = $this->getAllowedImportSystems(); $allowedSystems = $this->getAllowedImportSystems();
$allowedSystems = array_column($allowedSystems, 'internalName'); $allowedSystems = array_column($allowedSystems, 'internalName');
if (!in_array($this->getSystem(), $allowedSystems)) { 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; $this->systemInstance = $instance;
} }
public function reset(): void {
$this->board = new Board();
$this->getImportSystem()->reset();
}
public function importBoard(): void { public function importBoard(): void {
$board = $this->getImportSystem()->getBoard(); $board = $this->getImportSystem()->getBoard();
if ($board) { if ($board) {

View File

@@ -23,43 +23,30 @@
namespace OCA\Deck\Service\Importer\Systems; namespace OCA\Deck\Service\Importer\Systems;
use OC\Comments\Comment;
use OCA\Deck\BadRequestException; use OCA\Deck\BadRequestException;
use OCA\Deck\Db\Acl; use OCA\Deck\Db\Acl;
use OCA\Deck\Db\Assignment; use OCA\Deck\Db\Assignment;
use OCA\Deck\Db\Attachment;
use OCA\Deck\Db\Board; use OCA\Deck\Db\Board;
use OCA\Deck\Db\Card; 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\Comments\IComment;
use OCP\IL10N; use OCP\IL10N;
use OCP\IURLGenerator; use OCP\IURLGenerator;
use OCP\IUser; use OCP\IUser;
use OCP\IUserManager; use OCP\IUserManager;
class DeckJsonService extends ABoardImportService { class DeckJsonService extends ABoardImportService {
/** @var string */
public static $name = 'Deck JSON'; public static $name = 'Deck JSON';
/** @var IUserManager */
private $userManager;
/** @var IURLGenerator */
private $urlGenerator;
/** @var IL10N */
private $l10n;
/** @var IUser[] */ /** @var IUser[] */
private $members = []; private array $members = [];
private array $tmpCards = []; private array $tmpCards = [];
public function __construct( public function __construct(
IUserManager $userManager, private IUserManager $userManager,
IURLGenerator $urlGenerator, private IURLGenerator $urlGenerator,
IL10N $l10n private IL10N $l10n
) { ) {
$this->userManager = $userManager;
$this->urlGenerator = $urlGenerator;
$this->l10n = $l10n;
} }
public function bootstrap(): void { public function bootstrap(): void {
@@ -76,7 +63,7 @@ class DeckJsonService extends ABoardImportService {
} }
public function validateUsers(): void { public function validateUsers(): void {
if (empty($this->getImportService()->getConfig('uidRelation'))) { if (empty($this->getImportService()->getConfig('uidRelation')) || !isset($this->getImportService()->getData()->members)) {
return; return;
} }
foreach ($this->getImportService()->getConfig('uidRelation') as $exportUid => $nextcloudUid) { foreach ($this->getImportService()->getConfig('uidRelation') as $exportUid => $nextcloudUid) {
@@ -169,7 +156,7 @@ class DeckJsonService extends ABoardImportService {
$return[$source->id] = $stack; $return[$source->id] = $stack;
} }
if ($source->cards) { if (isset($source->cards)) {
foreach ($source->cards as $card) { foreach ($source->cards as $card) {
$card->stackId = $index; $card->stackId = $index;
$this->tmpCards[] = $card; $this->tmpCards[] = $card;
@@ -231,7 +218,9 @@ class DeckJsonService extends ABoardImportService {
} }
public function getBoards(): array { 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 { public function reset(): void {

View File

@@ -397,4 +397,12 @@ class TrelloJsonService extends ABoardImportService {
$trelloCard->desc .= "| [{$name}]({$attachment->url}) | {$attachment->date} |\n"; $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()];
}
} }