Merge pull request #6452 from nextcloud/feat/1813-clonecopy-a-card
feat(cards): add card cloning ability
This commit is contained in:
@@ -137,6 +137,8 @@ return [
|
||||
['name' => 'comments_api#update', 'url' => '/api/v{apiVersion}/cards/{cardId}/comments/{commentId}', 'verb' => 'PUT'],
|
||||
['name' => 'comments_api#delete', 'url' => '/api/v{apiVersion}/cards/{cardId}/comments/{commentId}', 'verb' => 'DELETE'],
|
||||
|
||||
['name' => 'card#clone', 'url' => '/api/v{apiVersion}/cards/{cardId}/clone', 'verb' => 'POST'],
|
||||
|
||||
['name' => 'overview_api#upcomingCards', 'url' => '/api/v{apiVersion}/overview/upcoming', 'verb' => 'GET'],
|
||||
|
||||
['name' => 'search#search', 'url' => '/api/v{apiVersion}/search', 'verb' => 'GET'],
|
||||
|
||||
@@ -71,6 +71,10 @@ describe('Card', function() {
|
||||
|
||||
cy.get('.button-vue[aria-label*="Add card"]')
|
||||
.first().click()
|
||||
|
||||
// Somehow this avoids the electron crash
|
||||
cy.wait(2000)
|
||||
|
||||
cy.get('.modal-mask.card-selector .card-title').should('be.visible').click().type(newCardTitle)
|
||||
cy.get('.modal-mask.card-selector .multiselect-board').should('be.visible').click()
|
||||
cy.get('.vs__dropdown-menu [data-cy="board-select-title"]:contains("' + boardData.title + '")').should('be.visible').click()
|
||||
@@ -124,7 +128,7 @@ describe('Card', function() {
|
||||
cy.get('.attachment-list .basename').contains('welcome.txt')
|
||||
})
|
||||
|
||||
it.only('Shows the modal with the editor', () => {
|
||||
it('Shows the modal with the editor', () => {
|
||||
cy.get('.card:contains("Hello world")').should('be.visible').click()
|
||||
cy.intercept({ method: 'PUT', url: '**/apps/deck/cards/*' }).as('save')
|
||||
cy.get('.modal__card').should('be.visible')
|
||||
@@ -161,9 +165,9 @@ describe('Card', function() {
|
||||
cy.get('.reference-picker-modal--content .reference-picker .multiselect-list').should('be.visible').contains(boardData.stacks[0].title)
|
||||
cy.get('.reference-picker-modal--content .reference-picker button.button-vue--vue-primary').should('be.visible').click()
|
||||
cy.wait('@save', { timeout: 7000 })
|
||||
cy.get('.modal__card .ProseMirror').contains('/index.php/apps/deck/card/').should('be.visible')
|
||||
cy.get('.modal__card .ProseMirror').contains('/index.php/apps/deck/card/').should('have.length', 1)
|
||||
|
||||
cy.visit(`/apps/deck/#/board/${boardId}`)
|
||||
cy.visit(`/apps/deck/board/${boardId}`)
|
||||
cy.reload()
|
||||
cy.get('.board .stack').eq(0).within(() => {
|
||||
cy.get(`.card:contains("${newCardTitle}")`).should('be.visible')
|
||||
@@ -298,5 +302,18 @@ describe('Card', function() {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('clone card', () => {
|
||||
cy.intercept({ method: 'POST', url: '**/apps/deck/**/cards/*/clone' }).as('clone')
|
||||
cy.get('.card:contains("Hello world")').should('be.visible').click()
|
||||
cy.get('#app-sidebar-vue')
|
||||
.find('.ProseMirror h1').contains('Hello world').should('be.visible')
|
||||
|
||||
cy.get('.app-sidebar-header .action-item__menutoggle').click()
|
||||
cy.get('.v-popper__popper button:contains("Move/copy card")').click()
|
||||
cy.get('.modal-container button:contains("Copy card")').click()
|
||||
cy.wait('@clone', { timeout: 7000 })
|
||||
cy.get('.card:contains("Hello world")').should('have.length', 2)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -90,6 +90,15 @@ class CardController extends Controller {
|
||||
public function update($id, $title, $stackId, $type, $order, $description, $duedate, $deletedAt) {
|
||||
return $this->cardService->update($id, $title, $stackId, $type, $this->userId, $description, $order, $duedate, $deletedAt);
|
||||
}
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @param $cardId
|
||||
* @param $targetStackId
|
||||
* @return \OCP\AppFramework\Db\Entity
|
||||
*/
|
||||
public function clone(int $cardId, ?int $targetStackId = null) {
|
||||
return $this->cardService->cloneCard($cardId, $targetStackId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
|
||||
@@ -37,69 +37,33 @@ use OCP\IUserManager;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class CardService {
|
||||
private CardMapper $cardMapper;
|
||||
private StackMapper $stackMapper;
|
||||
private BoardMapper $boardMapper;
|
||||
private LabelMapper $labelMapper;
|
||||
private LabelService $labelService;
|
||||
private PermissionService $permissionService;
|
||||
private BoardService $boardService;
|
||||
private NotificationHelper $notificationHelper;
|
||||
private AssignmentMapper $assignedUsersMapper;
|
||||
private AttachmentService $attachmentService;
|
||||
private ?string $currentUser;
|
||||
private ActivityManager $activityManager;
|
||||
private ICommentsManager $commentsManager;
|
||||
private ChangeHelper $changeHelper;
|
||||
private IEventDispatcher $eventDispatcher;
|
||||
private IUserManager $userManager;
|
||||
private IURLGenerator $urlGenerator;
|
||||
private LoggerInterface $logger;
|
||||
private IRequest $request;
|
||||
private CardServiceValidator $cardServiceValidator;
|
||||
|
||||
private string $currentUser;
|
||||
|
||||
public function __construct(
|
||||
CardMapper $cardMapper,
|
||||
StackMapper $stackMapper,
|
||||
BoardMapper $boardMapper,
|
||||
LabelMapper $labelMapper,
|
||||
LabelService $labelService,
|
||||
PermissionService $permissionService,
|
||||
BoardService $boardService,
|
||||
NotificationHelper $notificationHelper,
|
||||
AssignmentMapper $assignedUsersMapper,
|
||||
AttachmentService $attachmentService,
|
||||
ActivityManager $activityManager,
|
||||
ICommentsManager $commentsManager,
|
||||
IUserManager $userManager,
|
||||
ChangeHelper $changeHelper,
|
||||
IEventDispatcher $eventDispatcher,
|
||||
IURLGenerator $urlGenerator,
|
||||
LoggerInterface $logger,
|
||||
IRequest $request,
|
||||
CardServiceValidator $cardServiceValidator,
|
||||
private CardMapper $cardMapper,
|
||||
private StackMapper $stackMapper,
|
||||
private BoardMapper $boardMapper,
|
||||
private LabelMapper $labelMapper,
|
||||
private LabelService $labelService,
|
||||
private PermissionService $permissionService,
|
||||
private BoardService $boardService,
|
||||
private NotificationHelper $notificationHelper,
|
||||
private AssignmentMapper $assignedUsersMapper,
|
||||
private AttachmentService $attachmentService,
|
||||
private ActivityManager $activityManager,
|
||||
private ICommentsManager $commentsManager,
|
||||
private IUserManager $userManager,
|
||||
private ChangeHelper $changeHelper,
|
||||
private IEventDispatcher $eventDispatcher,
|
||||
private IURLGenerator $urlGenerator,
|
||||
private LoggerInterface $logger,
|
||||
private IRequest $request,
|
||||
private CardServiceValidator $cardServiceValidator,
|
||||
private AssignmentService $assignmentService,
|
||||
?string $userId,
|
||||
) {
|
||||
$this->cardMapper = $cardMapper;
|
||||
$this->stackMapper = $stackMapper;
|
||||
$this->boardMapper = $boardMapper;
|
||||
$this->labelMapper = $labelMapper;
|
||||
$this->labelService = $labelService;
|
||||
$this->permissionService = $permissionService;
|
||||
$this->boardService = $boardService;
|
||||
$this->notificationHelper = $notificationHelper;
|
||||
$this->assignedUsersMapper = $assignedUsersMapper;
|
||||
$this->attachmentService = $attachmentService;
|
||||
$this->activityManager = $activityManager;
|
||||
$this->commentsManager = $commentsManager;
|
||||
$this->userManager = $userManager;
|
||||
$this->changeHelper = $changeHelper;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->currentUser = $userId;
|
||||
$this->urlGenerator = $urlGenerator;
|
||||
$this->logger = $logger;
|
||||
$this->request = $request;
|
||||
$this->cardServiceValidator = $cardServiceValidator;
|
||||
}
|
||||
|
||||
public function enrichCards($cards) {
|
||||
@@ -391,6 +355,38 @@ class CardService {
|
||||
return $card;
|
||||
}
|
||||
|
||||
public function cloneCard(int $id, ?int $targetStackId = null):Card {
|
||||
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_READ);
|
||||
$originCard = $this->cardMapper->find($id);
|
||||
if ($targetStackId === null) {
|
||||
$targetStackId = $originCard->getStackId();
|
||||
}
|
||||
$this->permissionService->checkPermission($this->stackMapper, $targetStackId, Acl::PERMISSION_EDIT);
|
||||
$newCard = $this->create($originCard->getTitle(), $targetStackId, $originCard->getType(), $originCard->getOrder(), $originCard->getOwner());
|
||||
$boardId = $this->stackMapper->findBoardId($targetStackId);
|
||||
foreach ($this->labelMapper->findAssignedLabelsForCard($id) as $label) {
|
||||
if ($boardId != $this->stackMapper->findBoardId($originCard->getStackId())) {
|
||||
try {
|
||||
$label = $this->labelService->cloneLabelIfNotExists($label->getId(), $boardId);
|
||||
} catch (NoPermissionException $e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assignLabel($newCard->getId(), $label->getId());
|
||||
}
|
||||
foreach ($this->assignedUsersMapper->findAll($id) as $assignement) {
|
||||
try {
|
||||
$this->permissionService->checkPermission($this->cardMapper, $newCard->getId(), Acl::PERMISSION_READ, $assignement->getParticipant());
|
||||
} catch (NoPermissionException $e) {
|
||||
continue;
|
||||
}
|
||||
$this->assignmentService->assignUser($newCard->getId(), $assignement->getParticipant());
|
||||
}
|
||||
$newCard->setDescription($originCard->getDescription());
|
||||
$card = $this->enrichCards([$this->cardMapper->update($newCard)]);
|
||||
return $card[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param $title
|
||||
|
||||
@@ -93,6 +93,18 @@ class LabelService {
|
||||
return $this->labelMapper->insert($label);
|
||||
}
|
||||
|
||||
public function cloneLabelIfNotExists(int $labelId, int $targetBoardId): Label {
|
||||
$this->permissionService->checkPermission(null, $targetBoardId, Acl::PERMISSION_MANAGE);
|
||||
$boardLabels = $this->boardService->find($targetBoardId)->getLabels();
|
||||
$originLabel = $this->find($labelId);
|
||||
$filteredValues = array_values(array_filter($boardLabels, fn ($item) => $item->getTitle() === $originLabel->getTitle()));
|
||||
if (empty($filteredValues)) {
|
||||
$label = $this->create($originLabel->getTitle(), $originLabel->getColor(), $targetBoardId);
|
||||
return $label;
|
||||
}
|
||||
return $originLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @return \OCP\AppFramework\Db\Entity
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
<template>
|
||||
<NcModal v-if="modalShow" :title="t('deck', 'Move card to another board')" @close="modalShow=false">
|
||||
<NcDialog :open.sync="modalShow" :name="t('deck', 'Move/copy card')">
|
||||
<div class="modal__content">
|
||||
<h3>{{ t('deck', 'Move card to another board') }}</h3>
|
||||
<NcSelect v-model="selectedBoard"
|
||||
:input-label="t('deck', 'Select a board')"
|
||||
:placeholder="t('deck', 'Select a board')"
|
||||
@@ -20,26 +19,28 @@
|
||||
:options="stacksFromBoard"
|
||||
:max-height="100"
|
||||
label="title" />
|
||||
|
||||
<button :disabled="!isBoardAndStackChoosen" class="primary" @click="moveCard">
|
||||
{{ t('deck', 'Move card') }}
|
||||
</button>
|
||||
<button @click="modalShow=false">
|
||||
{{ t('deck', 'Cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</NcModal>
|
||||
<template #actions>
|
||||
<NcButton :disabled="!isBoardAndStackChoosen" type="secondary" @click="moveCard">
|
||||
{{ t('deck', 'Move card') }}
|
||||
</NcButton>
|
||||
<NcButton :disabled="!isBoardAndStackChoosen" type="primary" @click="cloneCard">
|
||||
{{ t('deck', 'Copy card') }}
|
||||
</NcButton>
|
||||
</template>
|
||||
</NcDialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { NcModal, NcSelect } from '@nextcloud/vue'
|
||||
import { NcDialog, NcSelect, NcButton } from '@nextcloud/vue'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import axios from '@nextcloud/axios'
|
||||
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'CardMoveDialog',
|
||||
components: { NcModal, NcSelect },
|
||||
components: { NcDialog, NcSelect, NcButton },
|
||||
data() {
|
||||
return {
|
||||
card: null,
|
||||
@@ -50,6 +51,7 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['stackById', 'boardById']),
|
||||
activeBoards() {
|
||||
return this.$store.getters.boards.filter((item) => item.deletedAt === 0 && item.archived === false)
|
||||
},
|
||||
@@ -66,6 +68,9 @@ export default {
|
||||
methods: {
|
||||
openModal(card) {
|
||||
this.card = card
|
||||
this.selectedStack = this.stackById(this.card.stackId)
|
||||
this.selectedBoard = this.boardById(this.selectedStack.boardId)
|
||||
this.loadStacksFromBoard(this.selectedBoard)
|
||||
this.modalShow = true
|
||||
},
|
||||
async loadStacksFromBoard(board) {
|
||||
@@ -81,33 +86,23 @@ export default {
|
||||
this.copiedCard = Object.assign({}, this.card)
|
||||
this.copiedCard.stackId = this.selectedStack.id
|
||||
this.$store.dispatch('moveCard', this.copiedCard)
|
||||
if (parseInt(this.boardId) === parseInt(this.selectedStack.boardId)) {
|
||||
if (parseInt(this.selectedBoard.id) === parseInt(this.selectedStack.boardId)) {
|
||||
await this.$store.commit('addNewCard', { ...this.copiedCard })
|
||||
}
|
||||
this.modalShow = false
|
||||
},
|
||||
async cloneCard() {
|
||||
this.$store.dispatch('cloneCard', { cardId: this.card.id, targetStackId: this.selectedStack.id })
|
||||
this.modalShow = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.modal__content {
|
||||
min-width: 250px;
|
||||
min-height: 120px;
|
||||
margin: 20px 20px 100px 20px;
|
||||
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.select {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.modal__content button {
|
||||
float: right;
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
icon="icon-external"
|
||||
:close-after-click="true"
|
||||
@click="openCardMoveDialog">
|
||||
{{ t('deck', 'Move card') }}
|
||||
{{ t('deck', 'Move/copy card') }}
|
||||
</NcActionButton>
|
||||
<NcActionButton v-for="action in cardActions"
|
||||
:key="action.label"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import axios from '@nextcloud/axios'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import { generateOcsUrl, generateUrl } from '@nextcloud/router'
|
||||
|
||||
export class CardApi {
|
||||
|
||||
@@ -28,6 +28,23 @@ export class CardApi {
|
||||
})
|
||||
}
|
||||
|
||||
cloneCard(cardId, targetStackId) {
|
||||
return axios.post(generateOcsUrl(`apps/deck/api/v1.0/cards/${cardId}/clone`), {
|
||||
targetStackId,
|
||||
})
|
||||
.then(
|
||||
(response) => {
|
||||
return Promise.resolve(response.data)
|
||||
},
|
||||
(err) => {
|
||||
return Promise.reject(err)
|
||||
},
|
||||
)
|
||||
.catch((err) => {
|
||||
return Promise.reject(err)
|
||||
})
|
||||
}
|
||||
|
||||
deleteCard(cardId) {
|
||||
return axios.delete(this.url(`/cards/${cardId}`))
|
||||
.then(
|
||||
|
||||
@@ -272,6 +272,11 @@ export default {
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async cloneCard({ commit }, { cardId, targetStackId }) {
|
||||
const createdCard = await apiClient.cloneCard(cardId, targetStackId)
|
||||
commit('addCard', createdCard)
|
||||
return createdCard
|
||||
},
|
||||
async addCard({ commit }, card) {
|
||||
const createdCard = await apiClient.addCard(card)
|
||||
commit('addCard', createdCard)
|
||||
|
||||
@@ -32,6 +32,7 @@ use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Db\Card;
|
||||
use OCA\Deck\Db\CardMapper;
|
||||
use OCA\Deck\Db\ChangeHelper;
|
||||
use OCA\Deck\Db\Label;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
use OCA\Deck\Db\Stack;
|
||||
use OCA\Deck\Db\StackMapper;
|
||||
@@ -93,6 +94,9 @@ class CardServiceTest extends TestCase {
|
||||
/** @var CardServiceValidator|MockObject */
|
||||
private $cardServiceValidator;
|
||||
|
||||
/** @var AssignmentService|MockObject */
|
||||
private $assignmentService;
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->cardMapper = $this->createMock(CardMapper::class);
|
||||
@@ -114,6 +118,7 @@ class CardServiceTest extends TestCase {
|
||||
$this->logger = $this->createMock(LoggerInterface::class);
|
||||
$this->request = $this->createMock(IRequest::class);
|
||||
$this->cardServiceValidator = $this->createMock(CardServiceValidator::class);
|
||||
$this->assignmentService = $this->createMock(AssignmentService::class);
|
||||
|
||||
$this->logger->expects($this->any())->method('error');
|
||||
|
||||
@@ -137,6 +142,7 @@ class CardServiceTest extends TestCase {
|
||||
$this->logger,
|
||||
$this->request,
|
||||
$this->cardServiceValidator,
|
||||
$this->assignmentService,
|
||||
'user1'
|
||||
);
|
||||
}
|
||||
@@ -219,6 +225,61 @@ class CardServiceTest extends TestCase {
|
||||
$this->assertEquals($b->getStackId(), 123);
|
||||
}
|
||||
|
||||
public function testClone() {
|
||||
$card = new Card();
|
||||
$card->setId(1);
|
||||
$card->setTitle('Card title');
|
||||
$card->setOwner('admin');
|
||||
$card->setStackId(12345);
|
||||
$clonedCard = clone $card;
|
||||
$clonedCard->setId(2);
|
||||
$clonedCard->setStackId(1234);
|
||||
$this->cardMapper->expects($this->exactly(2))
|
||||
->method('insert')
|
||||
->willReturn($card, $clonedCard);
|
||||
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('update')->willReturn($clonedCard);
|
||||
$this->cardMapper->expects($this->exactly(2))
|
||||
->method('find')
|
||||
->willReturn($card, $clonedCard);
|
||||
|
||||
// check if users are assigned
|
||||
$this->assignmentService->expects($this->once())
|
||||
->method('assignUser')
|
||||
->with(2, 'admin');
|
||||
$a1 = new Assignment();
|
||||
$a1->setCardId(2);
|
||||
$a1->setType(0);
|
||||
$a1->setParticipant('admin');
|
||||
$this->assignedUsersMapper->expects($this->once())
|
||||
->method('findAll')
|
||||
->with(1)
|
||||
->willReturn([$a1]);
|
||||
|
||||
// check if labels get cloned
|
||||
$label = new Label();
|
||||
$label->setId(1);
|
||||
$this->labelMapper->expects($this->once())
|
||||
->method('findAssignedLabelsForCard')
|
||||
->willReturn([$label]);
|
||||
$this->cardMapper->expects($this->once())
|
||||
->method('assignLabel')
|
||||
->with($clonedCard->getId(), $label->getId())
|
||||
->willReturn($label);
|
||||
|
||||
$stackMock = new Stack();
|
||||
$stackMock->setBoardId(1234);
|
||||
$this->stackMapper->expects($this->once())
|
||||
->method('find')
|
||||
->willReturn($stackMock);
|
||||
$b = $this->cardService->create('Card title', 123, 'text', 999, 'admin');
|
||||
$c = $this->cardService->cloneCard($b->getId(), 1234);
|
||||
$this->assertEquals($b->getTitle(), $c->getTitle());
|
||||
$this->assertEquals($b->getOwner(), $c->getOwner());
|
||||
$this->assertNotEquals($b->getStackId(), $c->getStackId());
|
||||
}
|
||||
|
||||
public function testDelete() {
|
||||
$cardToBeDeleted = new Card();
|
||||
$this->cardMapper->expects($this->once())
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
namespace OCA\Deck\Service;
|
||||
|
||||
use OCA\Deck\Db\Board;
|
||||
use OCA\Deck\Db\ChangeHelper;
|
||||
use OCA\Deck\Db\Label;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
@@ -105,6 +106,53 @@ class LabelServiceTest extends TestCase {
|
||||
$this->assertEquals($b->getColor(), 'ffffff');
|
||||
}
|
||||
|
||||
public function testCloneLabelIfNotExists() {
|
||||
$label = new Label();
|
||||
$label->setId(1);
|
||||
$label->setTitle('title');
|
||||
$label->setColor('00ff00');
|
||||
$this->labelMapper->expects($this->once())
|
||||
->method('find')
|
||||
->willReturn($label);
|
||||
|
||||
$expectedLabel = new Label();
|
||||
$expectedLabel->setTitle('title');
|
||||
$expectedLabel->setColor('00ff00');
|
||||
$expectedLabel->setBoardId(1);
|
||||
$this->labelMapper->expects($this->once())
|
||||
->method('insert')
|
||||
->with($expectedLabel)
|
||||
->willReturn($label);
|
||||
$board = new Board();
|
||||
$board->setLabels([]);
|
||||
$this->boardService->expects($this->once())
|
||||
->method('find')
|
||||
->willReturn($board);
|
||||
|
||||
$this->labelService->cloneLabelIfNotExists(1, 1);
|
||||
}
|
||||
|
||||
public function testCloneLabelIfExists() {
|
||||
$label = new Label();
|
||||
$label->setId(1);
|
||||
$label->setTitle('title');
|
||||
$label->setColor('00ff00');
|
||||
$this->labelMapper->expects($this->once())
|
||||
->method('find')
|
||||
->willReturn($label);
|
||||
$this->labelMapper->expects($this->never())
|
||||
->method('insert')
|
||||
->with($label);
|
||||
$board = new Board();
|
||||
$board->setLabels([$label]);
|
||||
$this->boardService->expects($this->once())
|
||||
->method('find')
|
||||
->willReturn($board);
|
||||
|
||||
$this->labelService->cloneLabelIfNotExists(1, 1);
|
||||
|
||||
}
|
||||
|
||||
public function testDelete() {
|
||||
$label = new Label();
|
||||
$label->setId(1);
|
||||
|
||||
Reference in New Issue
Block a user