-
Notifications
You must be signed in to change notification settings - Fork 279
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clone cards together with the board #3430
base: main
Are you sure you want to change the base?
Changes from all commits
4fd05b0
2bf80d8
19b4c5c
f6cbf31
5e31d44
8c88e5f
3b0af35
8d11c5a
44c02e3
81b08ef
0473133
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
use OCA\Deck\Db\AssignmentMapper; | ||
use OCA\Deck\Db\Board; | ||
use OCA\Deck\Db\BoardMapper; | ||
use OCA\Deck\Db\Card; | ||
use OCA\Deck\Db\CardMapper; | ||
use OCA\Deck\Db\ChangeHelper; | ||
use OCA\Deck\Db\IPermissionMapper; | ||
|
@@ -28,6 +29,7 @@ | |
use OCA\Deck\Event\AclDeletedEvent; | ||
use OCA\Deck\Event\AclUpdatedEvent; | ||
use OCA\Deck\Event\BoardUpdatedEvent; | ||
use OCA\Deck\Event\CardCreatedEvent; | ||
use OCA\Deck\NoPermissionException; | ||
use OCA\Deck\Notification\NotificationHelper; | ||
use OCA\Deck\Validators\BoardServiceValidator; | ||
|
@@ -37,80 +39,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, | ||
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->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; | ||
} | ||
|
||
/** | ||
|
@@ -520,13 +479,19 @@ public function deleteAcl(int $id): ?Acl { | |
/** | ||
* @param $id | ||
* @param $userId | ||
* @param $withCards | ||
* @param $withAssignments | ||
* @param $withLabels | ||
* @param $withDueDate | ||
* @param $moveCardsToLeftStack | ||
* @param $restoreArchivedCards | ||
* @return Board | ||
* @throws DoesNotExistException | ||
* @throws \OCA\Deck\NoPermissionException | ||
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException | ||
* @throws BadRequestException | ||
*/ | ||
public function clone($id, $userId) { | ||
public function clone($id, $userId, $withCards = false, $withAssignments = false, $withLabels = false, $withDueDate = false, $moveCardsToLeftStack = false, $restoreArchivedCards = false) { | ||
grnd-alt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
$this->boardServiceValidator->check(compact('id', 'userId')); | ||
|
||
if (!$this->permissionService->canCreate()) { | ||
|
@@ -549,6 +514,16 @@ public function clone($id, $userId) { | |
]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can separate the board cloning logics in a different class - The BoardMapper or the Service. |
||
$this->boardMapper->insert($newBoard); | ||
|
||
foreach ($this->aclMapper->findAll($board->getId()) as $acl) { | ||
$this->addAcl($newBoard->getId(), | ||
$acl->getType(), | ||
$acl->getParticipant(), | ||
$acl->getPermissionEdit(), | ||
$acl->getPermissionShare(), | ||
$acl->getPermissionManage()); | ||
} | ||
|
||
|
||
$labels = $this->labelMapper->findAll($id); | ||
foreach ($labels as $label) { | ||
$newLabel = new Label(); | ||
|
@@ -566,6 +541,10 @@ public function clone($id, $userId) { | |
$this->stackMapper->insert($newStack); | ||
} | ||
|
||
if ($withCards) { | ||
$this->cloneCards($board, $newBoard, $withAssignments, $withLabels, $withDueDate, $moveCardsToLeftStack, $restoreArchivedCards); | ||
} | ||
|
||
return $this->find($newBoard->getId()); | ||
} | ||
|
||
|
@@ -669,6 +648,88 @@ private function enrichBoards(array $boards, bool $fullDetails = true): array { | |
return $boards; | ||
} | ||
|
||
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: Move to specific column | ||
Comment on lines
+652
to
+655
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still valid? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's remove those from the code and track as enhancement follow up issues. |
||
|
||
$stacks = $this->stackMapper->findAll($board->getId()); | ||
usort($stacks, function (Stack $a, Stack $b) { | ||
return $a->getOrder() - $b->getOrder(); | ||
}); | ||
|
||
$newStacks = $this->stackMapper->findAll($newBoard->getId()); | ||
usort($newStacks, function (Stack $a, Stack $b) { | ||
return $a->getOrder() - $b->getOrder(); | ||
}); | ||
|
||
$i = 0; | ||
foreach ($stacks as $stack) { | ||
$cards = $this->cardMapper->findAll($stack->getId()); | ||
$archivedCards = $this->cardMapper->findAllArchived($stack->getId()); | ||
|
||
/** @var Card[] $cards */ | ||
$cards = array_merge($cards, $archivedCards); | ||
|
||
foreach ($cards as $card) { | ||
$targetStackId = $moveCardsToLeftStack ? $newStacks[0]->getId() : $newStacks[$i]->getId(); | ||
|
||
// Create a cloned card. | ||
// Done with setters as only fields set via setters get written to db | ||
$newCard = new Card(); | ||
juliusknorr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
$newCard->setTitle($card->getTitle()); | ||
$newCard->setDescription($card->getDescription()); | ||
$newCard->setStackId($targetStackId); | ||
$newCard->setType($card->getType()); | ||
$newCard->setOwner($card->getOwner()); | ||
$newCard->setOrder($card->getOrder()); | ||
$newCard->setDuedate($withDueDate ? $card->getDuedate() : null); | ||
$newCard->setArchived($restoreArchivedCards ? false : $card->getArchived()); | ||
$newCard->setStackId($targetStackId); | ||
|
||
// Persist the cloned card. | ||
$newCard = $this->cardMapper->insert($newCard); | ||
|
||
|
||
// 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) { | ||
$newLabelId = $newLabelTitles[$label->getTitle()]?->getId() ?? null; | ||
if ($newLabelId) { | ||
$this->cardMapper->assignLabel($newCard->getId(), $newLabelId); | ||
} | ||
} | ||
} | ||
|
||
|
||
// Copy assignments. | ||
if ($withAssignments) { | ||
$assignments = $this->assignedUsersMapper->findAll($card->getId()); | ||
|
||
foreach ($assignments as $assignment) { | ||
$this->assignmentService->assignUser($newCard->getId(), $assignment->getParticipant(), $assignment->getType()); | ||
} | ||
} | ||
|
||
|
||
// Copied from CardService because CardService cannot be injected due to cyclic dependencies. | ||
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $card, ActivityManager::SUBJECT_CARD_CREATE); | ||
$this->changeHelper->cardChanged($card->getId(), false); | ||
$this->eventDispatcher->dispatchTyped(new CardCreatedEvent($card)); | ||
Comment on lines
+724
to
+726
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
$i++; | ||
} | ||
} | ||
|
||
private function enrichWithStacks($board, $since = -1) { | ||
$stacks = $this->stackMapper->findAll($board->getId(), null, null, $since); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to have this available through the API the required routes would also need to be handled for the BoardApiController similar to https://github.com/nextcloud/deck/pull/3430/files#diff-f126d1440653a8583122ad9fa4e49497074f2eabe1c511d76288a547ab8f1575