diff --git a/lib/Controller/BoardController.php b/lib/Controller/BoardController.php index e4c294a17..6a4eb9336 100644 --- a/lib/Controller/BoardController.php +++ b/lib/Controller/BoardController.php @@ -151,21 +151,11 @@ public function deleteAcl($aclId) { /** * @NoAdminRequired - * @param $boardId - * @param bool $withCards - * @param bool $withAssignments - * @param bool $withLabels - * @param bool $withDueDate - * @param bool $moveCardsToLeftStack - * @param bool $restoreArchivedCards - * @return \OCA\Deck\Db\Board - * @throws \OCA\Deck\BadRequestException - * @throws \OCA\Deck\NoPermissionException - * @throws \OCP\AppFramework\Db\DoesNotExistException - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException */ - public function clone($boardId, $withCards = false, $withAssignments = false, $withLabels = false, $withDueDate = false, $moveCardsToLeftStack = false, $restoreArchivedCards = false) { - return $this->boardService->clone($boardId, $this->userId, $withCards, $withAssignments, $withLabels, $withDueDate, $moveCardsToLeftStack, $restoreArchivedCards); + public function clone(int $boardId, bool $withCards = false, bool $withAssignments = false, bool $withLabels = false, bool $withDueDate = false, bool $moveCardsToLeftStack = false, bool $restoreArchivedCards = false): DataResponse { + return new DataResponse( + $this->boardService->clone($boardId, $this->userId, $withCards, $withAssignments, $withLabels, $withDueDate, $moveCardsToLeftStack, $restoreArchivedCards) + ); } /** diff --git a/lib/Db/Label.php b/lib/Db/Label.php index b6e6b414f..f01e0bf13 100644 --- a/lib/Db/Label.php +++ b/lib/Db/Label.php @@ -23,6 +23,9 @@ namespace OCA\Deck\Db; +/** + * @method getTitle(): string + */ class Label extends RelationalEntity { protected $title; protected $color; diff --git a/lib/Db/LabelMapper.php b/lib/Db/LabelMapper.php index af8453c6c..66fcfa0dd 100644 --- a/lib/Db/LabelMapper.php +++ b/lib/Db/LabelMapper.php @@ -114,11 +114,6 @@ public function findAssignedLabelsForBoard($boardId, $limit = null, $offset = nu return $this->findEntities($qb); } - public function findLabelByTitle($boardId, $title, $limit = null, $offset = null) { - $sql = 'SELECT * FROM `*PREFIX*deck_labels` WHERE `board_id` = ? AND title = ? ORDER BY `id`'; - return $this->findEntity($sql, [$boardId, $title], $limit, $offset); - } - public function insert(Entity $entity): Entity { if (!in_array('lastModified', $entity->getUpdatedFields())) { $entity->setLastModified(time()); diff --git a/lib/Service/AssignmentService.php b/lib/Service/AssignmentService.php index 3e69948fe..3af2e5bb2 100644 --- a/lib/Service/AssignmentService.php +++ b/lib/Service/AssignmentService.php @@ -104,8 +104,6 @@ public function __construct( $this->changeHelper = $changeHelper; $this->activityManager = $activityManager; $this->eventDispatcher = $eventDispatcher; - - $this->assignmentServiceValidator->check(compact('userId')); $this->currentUser = $userId; } diff --git a/lib/Service/BoardService.php b/lib/Service/BoardService.php index 68746101e..9dd8f487f 100644 --- a/lib/Service/BoardService.php +++ b/lib/Service/BoardService.php @@ -34,7 +34,6 @@ use OCA\Deck\Db\AssignmentMapper; use OCA\Deck\Db\Board; use OCA\Deck\Db\BoardMapper; -use OCA\Deck\Db\AttachmentMapper; use OCA\Deck\Db\Card; use OCA\Deck\Db\CardMapper; use OCA\Deck\Db\ChangeHelper; @@ -59,82 +58,37 @@ use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use OCP\IDBConnection; -use OCP\IGroupManager; use OCP\IL10N; use OCP\IURLGenerator; -use OCP\IUserManager; use OCP\Server; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; class BoardService { - private BoardMapper $boardMapper; - private StackMapper $stackMapper; - private LabelMapper $labelMapper; - private AclMapper $aclMapper; - private IConfig $config; - private IL10N $l10n; - private PermissionService $permissionService; - private NotificationHelper $notificationHelper; - private AssignmentMapper $assignedUsersMapper; - private IUserManager $userManager; - private IGroupManager $groupManager; - private ?string $userId; - private ActivityManager $activityManager; - private IEventDispatcher $eventDispatcher; - private ChangeHelper $changeHelper; - private CardMapper $cardMapper; private ?array $boardsCacheFull = null; private ?array $boardsCachePartial = null; - private IURLGenerator $urlGenerator; - private IDBConnection $connection; - private BoardServiceValidator $boardServiceValidator; - private SessionMapper $sessionMapper; public function __construct( - BoardMapper $boardMapper, - StackMapper $stackMapper, - CardMapper $cardMapper, - IConfig $config, - IL10N $l10n, - LabelMapper $labelMapper, - AclMapper $aclMapper, - PermissionService $permissionService, - AssignmentService $assignmentService, - NotificationHelper $notificationHelper, - AssignmentMapper $assignedUsersMapper, - IUserManager $userManager, - IGroupManager $groupManager, - ActivityManager $activityManager, - IEventDispatcher $eventDispatcher, - ChangeHelper $changeHelper, - IURLGenerator $urlGenerator, - IDBConnection $connection, - BoardServiceValidator $boardServiceValidator, - SessionMapper $sessionMapper, - ?string $userId + private BoardMapper $boardMapper, + private StackMapper $stackMapper, + private CardMapper $cardMapper, + private IConfig $config, + private IL10N $l10n, + private LabelMapper $labelMapper, + private AclMapper $aclMapper, + private PermissionService $permissionService, + private AssignmentService $assignmentService, + private NotificationHelper $notificationHelper, + private AssignmentMapper $assignedUsersMapper, + private ActivityManager $activityManager, + private IEventDispatcher $eventDispatcher, + private ChangeHelper $changeHelper, + private IURLGenerator $urlGenerator, + private IDBConnection $connection, + private BoardServiceValidator $boardServiceValidator, + private SessionMapper $sessionMapper, + private ?string $userId ) { - $this->boardMapper = $boardMapper; - $this->stackMapper = $stackMapper; - $this->cardMapper = $cardMapper; - $this->labelMapper = $labelMapper; - $this->config = $config; - $this->aclMapper = $aclMapper; - $this->l10n = $l10n; - $this->permissionService = $permissionService; - $this->assignmentService = $assignmentService; - $this->notificationHelper = $notificationHelper; - $this->assignedUsersMapper = $assignedUsersMapper; - $this->userManager = $userManager; - $this->groupManager = $groupManager; - $this->activityManager = $activityManager; - $this->eventDispatcher = $eventDispatcher; - $this->changeHelper = $changeHelper; - $this->userId = $userId; - $this->urlGenerator = $urlGenerator; - $this->connection = $connection; - $this->boardServiceValidator = $boardServiceValidator; - $this->sessionMapper = $sessionMapper; } /** @@ -541,22 +495,12 @@ public function deleteAcl(int $id): ?Acl { return $deletedAcl; } - /** - * @param $id - * @param $userId - * @return Board - * @throws DoesNotExistException - * @throws \OCA\Deck\NoPermissionException - * @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException - * @throws BadRequestException - */ - public function clone($id, $userId, $withCards = false, $withAssignments = false, $withLabels = false, $withDueDate = false, $moveCardsToLeftStack = false, $restoreArchivedCards = false) { - $this->boardServiceValidator->check(compact('id', 'userId')); + public function clone(int $boardId, string $userId, bool $withCards = false, bool $withAssignments = false, bool $withLabels = false, bool $withDueDate = false, bool $moveCardsToLeftStack = false, bool $restoreArchivedCards = false) { + $this->boardServiceValidator->check(compact('boardId', 'userId')); - $this->permissionService->checkPermission($this->boardMapper, $id, Acl::PERMISSION_READ); + $this->permissionService->checkPermission($this->boardMapper, $boardId, Acl::PERMISSION_READ); - /** @var Board $board */ - $board = $this->boardMapper->find($id); + $board = $this->boardMapper->find($boardId); $newBoard = new Board(); $newBoard->setTitle($board->getTitle() . ' (' . $this->l10n->t('copy') . ')'); $newBoard->setOwner($userId); @@ -580,7 +524,7 @@ public function clone($id, $userId, $withCards = false, $withAssignments = false } - $labels = $this->labelMapper->findAll($id); + $labels = $this->labelMapper->findAll($boardId); foreach ($labels as $label) { $newLabel = new Label(); $newLabel->setTitle($label->getTitle()); @@ -589,7 +533,7 @@ public function clone($id, $userId, $withCards = false, $withAssignments = false $this->labelMapper->insert($newLabel); } - $stacks = $this->stackMapper->findAll($id); + $stacks = $this->stackMapper->findAll($boardId); foreach ($stacks as $stack) { $newStack = new Stack(); $newStack->setTitle($stack->getTitle()); @@ -601,8 +545,6 @@ public function clone($id, $userId, $withCards = false, $withAssignments = false $this->cloneCards($board, $newBoard, $withAssignments, $withLabels, $withDueDate, $moveCardsToLeftStack, $restoreArchivedCards); } - return $newBoard; - return $this->find($newBoard->getId()); } @@ -706,20 +648,17 @@ private function enrichBoards(array $boards, bool $fullDetails = true): array { return $boards; } - private function cloneCards(Board $board, Board $newBoard, $withAssignments = false, $withLabels = false, $withDueDate = false, $moveCardsToLeftStack = false, $restoreArchivedCards = false) { + private function cloneCards(Board $board, Board $newBoard, bool $withAssignments = false, bool $withLabels = false, bool $withDueDate = false, bool $moveCardsToLeftStack = false, bool $restoreArchivedCards = false): void { // TODO: Undelete cards // TODO: Copy attachments (or not?) // TODO: Copy comments (or not?) - // TODO: Create Test // TODO: Move to specific column - /** @var Stack[] $stacks */ $stacks = $this->stackMapper->findAll($board->getId()); usort($stacks, function (Stack $a, Stack $b) { return $a->getOrder() - $b->getOrder(); }); - /** @var Stack[] $newStacks */ $newStacks = $this->stackMapper->findAll($newBoard->getId()); usort($stacks, function (Stack $a, Stack $b) { return $a->getOrder() - $b->getOrder(); @@ -746,9 +685,7 @@ private function cloneCards(Board $board, Board $newBoard, $withAssignments = fa $newCard->setOrder($card->getOrder()); $newCard->setDuedate($withDueDate ? $card->getDuedate() : null); $newCard->setArchived($restoreArchivedCards ? false : $card->getArchived()); - - $newCard->setRelatedStack($targetStackId); - $newCard->setRelatedBoard($newBoard->getId()); + $newCard->setStackId($targetStackId); // Persist the cloned card. $newCard = $this->cardMapper->insert($newCard); @@ -757,10 +694,17 @@ private function cloneCards(Board $board, Board $newBoard, $withAssignments = fa // Copy labels. if ($withLabels) { $labels = $this->labelMapper->findAssignedLabelsForCard($card->getId()); + $newLabels = $this->labelMapper->findAll($newBoard->getId()); + $newLabelTitles = []; + foreach ($newLabels as $label) { + $newLabelTitles[$label->getTitle()] = $label; + } foreach ($labels as $label) { - $newLabel = $this->labelMapper->findLabelByTitle($newBoard->getId(), $label->getTitle()); - $this->cardMapper->assignLabel($newCard->getId(), $newLabel->getId()); + $newLabelId = $newLabelTitles[$label->getTitle()]?->getId() ?? null; + if ($newLabelId) { + $this->cardMapper->assignLabel($newCard->getId(), $newLabelId); + } } } diff --git a/src/components/navigation/AppNavigationBoard.vue b/src/components/navigation/AppNavigationBoard.vue index 86a8ebe03..e7a08ca60 100644 --- a/src/components/navigation/AppNavigationBoard.vue +++ b/src/components/navigation/AppNavigationBoard.vue @@ -27,7 +27,10 @@ :undo="deleted" :menu-placement="'auto'" @undo="unDelete"> - + - -
- -
- -
- - - -
-
@@ -162,7 +150,7 @@ import { NcAppNavigationIconBullet, NcAppNavigationCounter, NcAppNavigationItem, import ClickOutside from 'vue-click-outside' import ArchiveIcon from 'vue-material-design-icons/Archive.vue' import CloneIcon from 'vue-material-design-icons/ContentDuplicate.vue' -import BoardCloneModal from './BoardCloneModal' +import BoardCloneModal from './BoardCloneModal.vue' export default { name: 'AppNavigationBoard', @@ -265,6 +253,26 @@ export default { this.editColor = '#' + this.board.color this.editing = true }, + showCloneModal() { + this.cloneModalOpen = true + }, + async onCloseCloneModal(data) { + this.cloneModalOpen = false + if (data) { + this.loading = true + try { + const newBoard = await this.$store.dispatch('cloneBoard', { + boardData: this.board, + settings: data, + }) + this.loading = false + await this.$router.push({ name: 'board', params: { id: newBoard.id } }) + } catch (e) { + OC.Notification.showTemporary(t('deck', 'An error occurred')) + console.error(e) + } + } + }, actionArchive() { this.loading = true this.$store.dispatch('archiveBoard', this.board) @@ -329,26 +337,6 @@ export default { actionExport() { this.boardApi.exportBoard(this.board) }, - showCloneModal() { - this.cloneModalOpen = true - }, - async onCloseCloneModal(data) { - this.cloneModalOpen = false - if (data) { - this.loading = true - try { - const newBoard = await this.$store.dispatch('cloneBoard', { - boardData: this.board, - settings: data, - }) - this.loading = false - this.$router.push({ name: 'board', params: { id: newBoard.id } }) - } catch (e) { - OC.Notification.showTemporary(t('deck', 'An error occurred')) - console.error(e) - } - } - }, }, } diff --git a/src/components/navigation/BoardCloneModal.vue b/src/components/navigation/BoardCloneModal.vue index 3b1607fa1..084498fe2 100644 --- a/src/components/navigation/BoardCloneModal.vue +++ b/src/components/navigation/BoardCloneModal.vue @@ -20,23 +20,23 @@ - -->