Compare commits
10 Commits
v1.1.0-bet
...
enh/cloneS
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65650691b3 | ||
|
|
caa201dc6c | ||
|
|
083cd207af | ||
|
|
24f83b875b | ||
|
|
14d90e2ff2 | ||
|
|
2a4b0a3ed3 | ||
|
|
71780b5578 | ||
|
|
c39fd43b6c | ||
|
|
e763ce1fb7 | ||
|
|
003df010dd |
@@ -17,7 +17,7 @@
|
||||
- 🚀 Get your project organized
|
||||
|
||||
</description>
|
||||
<version>1.1.0-beta2</version>
|
||||
<version>1.1.0-beta1</version>
|
||||
<licence>agpl</licence>
|
||||
<author>Julius Härtl</author>
|
||||
<namespace>Deck</namespace>
|
||||
|
||||
@@ -47,6 +47,7 @@ return [
|
||||
['name' => 'stack#delete', 'url' => '/stacks/{stackId}', 'verb' => 'DELETE'],
|
||||
['name' => 'stack#deleted', 'url' => '/{boardId}/stacks/deleted', 'verb' => 'GET'],
|
||||
['name' => 'stack#archived', 'url' => '/stacks/{boardId}/archived', 'verb' => 'GET'],
|
||||
['name' => 'stack#clone', 'url' => '/stacks/{stackId}/clone', 'verb' => 'POST'],
|
||||
|
||||
// cards
|
||||
['name' => 'card#read', 'url' => '/cards/{cardId}', 'verb' => 'GET'],
|
||||
@@ -97,6 +98,7 @@ return [
|
||||
['name' => 'stack_api#create', 'url' => '/api/v1.0/boards/{boardId}/stacks', 'verb' => 'POST'],
|
||||
['name' => 'stack_api#update', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}', 'verb' => 'PUT'],
|
||||
['name' => 'stack_api#delete', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}', 'verb' => 'DELETE'],
|
||||
['name' => 'stack_api#clone', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/clone', 'verb' => 'POST'],
|
||||
|
||||
['name' => 'card_api#get', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'GET'],
|
||||
['name' => 'card_api#create', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards', 'verb' => 'POST'],
|
||||
|
||||
87
docs/API.md
87
docs/API.md
@@ -492,6 +492,93 @@ The board list endpoint supports setting an `If-Modified-Since` header to limit
|
||||
|
||||
##### 200 Success
|
||||
|
||||
### POST /boards/{boardId}/stacks/{stackId}/clone - Clone a stack
|
||||
|
||||
#### Request parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ------- | ------------------------------------------------------- |
|
||||
| boardId | Integer | The id of the board where the stack should be cloned to |
|
||||
| stackId | Integer | The id of the stack |
|
||||
|
||||
#### Response
|
||||
It will return an object of the new stack containing the new cards as well.
|
||||
|
||||
```json
|
||||
{
|
||||
"title":"l1 (copy)",
|
||||
"boardId":6,
|
||||
"deletedAt":0,
|
||||
"lastModified":0,
|
||||
"cards":[
|
||||
{
|
||||
"title":"ME",
|
||||
"description":"123",
|
||||
"stackId":73,
|
||||
"type":"plain",
|
||||
"lastModified":1599028559,
|
||||
"lastEditor":null,
|
||||
"createdAt":1599028559,
|
||||
"labels":[
|
||||
|
||||
],
|
||||
"assignedUsers":[
|
||||
|
||||
],
|
||||
"attachments":null,
|
||||
"attachmentCount":0,
|
||||
"owner":{
|
||||
"primaryKey":"root",
|
||||
"uid":"root",
|
||||
"displayname":"root",
|
||||
"type":0
|
||||
},
|
||||
"order":0,
|
||||
"archived":false,
|
||||
"duedate":null,
|
||||
"deletedAt":0,
|
||||
"commentsUnread":0,
|
||||
"id":109,
|
||||
"overdue":0
|
||||
},
|
||||
{
|
||||
"title":"ka",
|
||||
"description":"",
|
||||
"stackId":73,
|
||||
"type":"plain",
|
||||
"lastModified":1599028559,
|
||||
"lastEditor":null,
|
||||
"createdAt":1599028559,
|
||||
"labels":[
|
||||
|
||||
],
|
||||
"assignedUsers":[
|
||||
|
||||
],
|
||||
"attachments":null,
|
||||
"attachmentCount":0,
|
||||
"owner":{
|
||||
"primaryKey":"root",
|
||||
"uid":"root",
|
||||
"displayname":"root",
|
||||
"type":0
|
||||
},
|
||||
"order":1,
|
||||
"archived":false,
|
||||
"duedate":"2020-08-26T22:00:00+00:00",
|
||||
"deletedAt":0,
|
||||
"commentsUnread":0,
|
||||
"id":110,
|
||||
"overdue":3
|
||||
}
|
||||
],
|
||||
"order":999,
|
||||
"id":73
|
||||
}
|
||||
```
|
||||
|
||||
##### 200 Success
|
||||
|
||||
## Cards
|
||||
|
||||
### GET /boards/{boardId}/stacks/{stackId}/cards/{cardId} - Get card details
|
||||
|
||||
@@ -214,7 +214,6 @@ OC.L10N.register(
|
||||
"Archived boards" : "Archivované tabule",
|
||||
"Shared with you" : "Sdíleno s vámi",
|
||||
"Use modal card view" : "Použít modální zobrazení karty",
|
||||
"Show boards in calendar/tasks" : "Zobrazit tabule v kalendáři/úkolech",
|
||||
"Limit deck usage of groups" : "Omezit využití deck na skupiny",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Omezení nastavené pro Deck brání uživatelům, kteří nejsou součástí těchto skupin, ve vytváření vlastních tabulí. Nicméně i tak ale pořád budou moci pracovat na tabulích, které jsou jim nasdíleny.",
|
||||
"New board title" : "Název nové tabule",
|
||||
|
||||
@@ -212,7 +212,6 @@
|
||||
"Archived boards" : "Archivované tabule",
|
||||
"Shared with you" : "Sdíleno s vámi",
|
||||
"Use modal card view" : "Použít modální zobrazení karty",
|
||||
"Show boards in calendar/tasks" : "Zobrazit tabule v kalendáři/úkolech",
|
||||
"Limit deck usage of groups" : "Omezit využití deck na skupiny",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Omezení nastavené pro Deck brání uživatelům, kteří nejsou součástí těchto skupin, ve vytváření vlastních tabulí. Nicméně i tak ale pořád budou moci pracovat na tabulích, které jsou jim nasdíleny.",
|
||||
"New board title" : "Název nové tabule",
|
||||
|
||||
@@ -214,7 +214,6 @@ OC.L10N.register(
|
||||
"Archived boards" : "Archivierte Boards",
|
||||
"Shared with you" : "Mit Dir geteilt",
|
||||
"Use modal card view" : "Modale Kartenansicht verwenden",
|
||||
"Show boards in calendar/tasks" : "Board im Kalender/Aufgaben anzeigen",
|
||||
"Limit deck usage of groups" : "Nutzung von Deck auf Gruppen einschränken",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Durch die Begrenzung von Deck werden Benutzer, die nicht Teil dieser Gruppen sind, daran gehindert, eigene Boards zu erstellen. Benutzer können weiterhin an Boards arbeiten, die für sie freigegeben wurden.",
|
||||
"New board title" : "Board-Titel",
|
||||
|
||||
@@ -212,7 +212,6 @@
|
||||
"Archived boards" : "Archivierte Boards",
|
||||
"Shared with you" : "Mit Dir geteilt",
|
||||
"Use modal card view" : "Modale Kartenansicht verwenden",
|
||||
"Show boards in calendar/tasks" : "Board im Kalender/Aufgaben anzeigen",
|
||||
"Limit deck usage of groups" : "Nutzung von Deck auf Gruppen einschränken",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Durch die Begrenzung von Deck werden Benutzer, die nicht Teil dieser Gruppen sind, daran gehindert, eigene Boards zu erstellen. Benutzer können weiterhin an Boards arbeiten, die für sie freigegeben wurden.",
|
||||
"New board title" : "Board-Titel",
|
||||
|
||||
@@ -214,7 +214,6 @@ OC.L10N.register(
|
||||
"Archived boards" : "Archivierte Boards",
|
||||
"Shared with you" : "Mit Ihnen geteilt",
|
||||
"Use modal card view" : "Modale Kartenansicht verwenden",
|
||||
"Show boards in calendar/tasks" : "Board im Kalender/Aufgaben anzeigen",
|
||||
"Limit deck usage of groups" : "Nutzung von Deck auf Gruppen einschränken",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Durch die Begrenzung von Deck werden Benutzer, die nicht Teil dieser Gruppen sind, daran gehindert, eigene Boards zu erstellen. Benutzer können weiterhin an Boards arbeiten, die für sie freigegeben wurden.",
|
||||
"New board title" : "Board-Titel",
|
||||
|
||||
@@ -212,7 +212,6 @@
|
||||
"Archived boards" : "Archivierte Boards",
|
||||
"Shared with you" : "Mit Ihnen geteilt",
|
||||
"Use modal card view" : "Modale Kartenansicht verwenden",
|
||||
"Show boards in calendar/tasks" : "Board im Kalender/Aufgaben anzeigen",
|
||||
"Limit deck usage of groups" : "Nutzung von Deck auf Gruppen einschränken",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Durch die Begrenzung von Deck werden Benutzer, die nicht Teil dieser Gruppen sind, daran gehindert, eigene Boards zu erstellen. Benutzer können weiterhin an Boards arbeiten, die für sie freigegeben wurden.",
|
||||
"New board title" : "Board-Titel",
|
||||
|
||||
@@ -214,7 +214,6 @@ OC.L10N.register(
|
||||
"Archived boards" : "Taboleiros arquivados",
|
||||
"Shared with you" : "Compartido con vostede",
|
||||
"Use modal card view" : "Usar a vista de tarxeta modal",
|
||||
"Show boards in calendar/tasks" : "Amosar taboleiros no calendario/tarefas",
|
||||
"Limit deck usage of groups" : "Limitar o uso da plataforma a grupos",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Limitando Deck bloqueará os usuarios que non formen parte destes grupos, para crear os seus propios taboleiros. Os usuarios aínda así poderán traballar en taboleiros compartidos con eles.",
|
||||
"New board title" : "Novo título do taboleiro",
|
||||
|
||||
@@ -212,7 +212,6 @@
|
||||
"Archived boards" : "Taboleiros arquivados",
|
||||
"Shared with you" : "Compartido con vostede",
|
||||
"Use modal card view" : "Usar a vista de tarxeta modal",
|
||||
"Show boards in calendar/tasks" : "Amosar taboleiros no calendario/tarefas",
|
||||
"Limit deck usage of groups" : "Limitar o uso da plataforma a grupos",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Limitando Deck bloqueará os usuarios que non formen parte destes grupos, para crear os seus propios taboleiros. Os usuarios aínda así poderán traballar en taboleiros compartidos con eles.",
|
||||
"New board title" : "Novo título do taboleiro",
|
||||
|
||||
@@ -214,7 +214,6 @@ OC.L10N.register(
|
||||
"Archived boards" : "Lavagne archiviate",
|
||||
"Shared with you" : "Condiviso con te",
|
||||
"Use modal card view" : "Usa la vista modale delle schede",
|
||||
"Show boards in calendar/tasks" : "Mostra le lavagne in calendario/attività",
|
||||
"Limit deck usage of groups" : "Limita utilizzo di Deck dei gruppi",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "La limitazione di Deck impedirà agli utenti che non fanno parte di tali gruppi di creare le proprie lavagne. Gli utenti saranno ancora in grado di lavorare sulle lavagne che sono state condivise con loro,",
|
||||
"New board title" : "Titolo nuova lavagna",
|
||||
|
||||
@@ -212,7 +212,6 @@
|
||||
"Archived boards" : "Lavagne archiviate",
|
||||
"Shared with you" : "Condiviso con te",
|
||||
"Use modal card view" : "Usa la vista modale delle schede",
|
||||
"Show boards in calendar/tasks" : "Mostra le lavagne in calendario/attività",
|
||||
"Limit deck usage of groups" : "Limita utilizzo di Deck dei gruppi",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "La limitazione di Deck impedirà agli utenti che non fanno parte di tali gruppi di creare le proprie lavagne. Gli utenti saranno ancora in grado di lavorare sulle lavagne che sono state condivise con loro,",
|
||||
"New board title" : "Titolo nuova lavagna",
|
||||
|
||||
@@ -214,7 +214,6 @@ OC.L10N.register(
|
||||
"Archived boards" : "Zarchiwizowane tablice",
|
||||
"Shared with you" : "Dzielone z Tobą",
|
||||
"Use modal card view" : "Użyj widoku karty modalnej",
|
||||
"Show boards in calendar/tasks" : "Pokaż tablice w kalendarzu/zadaniach",
|
||||
"Limit deck usage of groups" : "Ogranicz użycie tablic dla grup",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ograniczenie Deck zablokuje użytkownikom z tych grup możliwość tworzenia własnych tablic. Użytkownicy nadal będą mogli pracować na tablicach, które zostały im udostępnione.",
|
||||
"New board title" : "Tytuł nowej tablicy",
|
||||
|
||||
@@ -212,7 +212,6 @@
|
||||
"Archived boards" : "Zarchiwizowane tablice",
|
||||
"Shared with you" : "Dzielone z Tobą",
|
||||
"Use modal card view" : "Użyj widoku karty modalnej",
|
||||
"Show boards in calendar/tasks" : "Pokaż tablice w kalendarzu/zadaniach",
|
||||
"Limit deck usage of groups" : "Ogranicz użycie tablic dla grup",
|
||||
"Limiting Deck will block users not part of those groups from creating their own boards. Users will still be able to work on boards that have been shared with them." : "Ograniczenie Deck zablokuje użytkownikom z tych grup możliwość tworzenia własnych tablic. Użytkownicy nadal będą mogli pracować na tablicach, które zostały im udostępnione.",
|
||||
"New board title" : "Tytuł nowej tablicy",
|
||||
|
||||
@@ -107,4 +107,13 @@ class StackController extends Controller {
|
||||
public function deleted($boardId) {
|
||||
return $this->stackService->fetchDeleted($boardId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @param $boardId
|
||||
* @return \OCP\Deck\DB\Board
|
||||
*/
|
||||
public function clone($stackId, $boardId) {
|
||||
return $this->stackService->clone($stackId, $boardId, $this->userId);
|
||||
}
|
||||
}
|
||||
|
||||
38
lib/Db/AssignedLabels.php
Normal file
38
lib/Db/AssignedLabels.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2020 Jakob Röhrl <jakob.roehrl@web.de>
|
||||
*
|
||||
* @author Jakob Röhrl <jakob.roehrl@web.de>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Deck\Db;
|
||||
|
||||
use JsonSerializable;
|
||||
|
||||
class AssignedLabels extends RelationalEntity implements JsonSerializable {
|
||||
public $id;
|
||||
protected $labelId;
|
||||
protected $cardId;
|
||||
|
||||
public function __construct() {
|
||||
$this->addType('id', 'integer');
|
||||
$this->addType('cardId', 'integer');
|
||||
$this->addType('labelId', 'integer');
|
||||
}
|
||||
}
|
||||
58
lib/Db/AssignedLabelsMapper.php
Normal file
58
lib/Db/AssignedLabelsMapper.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2020 Jakob Röhrl <jakob.roehrl@web.de>
|
||||
*
|
||||
* @author Jakob Röhrl <jakob.roehrl@web.de>
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace OCA\Deck\Db;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUserManager;
|
||||
|
||||
class AssignedLabelsMapper extends DeckMapper {
|
||||
private $cardMapper;
|
||||
private $userManager;
|
||||
/**
|
||||
* @var IGroupManager
|
||||
*/
|
||||
private $groupManager;
|
||||
|
||||
public function __construct(IDBConnection $db, CardMapper $cardMapper, IUserManager $userManager, IGroupManager $groupManager) {
|
||||
parent::__construct($db, 'deck_assigned_labels', AssignedLabels::class);
|
||||
$this->cardMapper = $cardMapper;
|
||||
$this->userManager = $userManager;
|
||||
$this->groupManager = $groupManager;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param $cardId
|
||||
* @return array|Entity
|
||||
*/
|
||||
public function find($cardId) {
|
||||
$sql = 'SELECT * from `*PREFIX*deck_assigned_labels` where `card_id` = ?';
|
||||
|
||||
$labels = $this->findEntities($sql, [$cardId]);
|
||||
return $labels;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,11 @@ use OCA\Deck\Activity\ChangeSet;
|
||||
use OCA\Deck\BadRequestException;
|
||||
use OCA\Deck\Db\Acl;
|
||||
use OCA\Deck\Db\AssignedUsersMapper;
|
||||
use OCA\Deck\Db\AssignedUsers;
|
||||
use OCA\Deck\Db\AssignedLabelsMapper;
|
||||
use OCA\Deck\Db\AssignedLabels;
|
||||
use OCA\Deck\Db\BoardMapper;
|
||||
use OCA\Deck\Db\Card;
|
||||
use OCA\Deck\Db\CardMapper;
|
||||
use OCA\Deck\Db\ChangeHelper;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
@@ -38,6 +42,8 @@ use OCA\Deck\Db\StackMapper;
|
||||
use OCA\Deck\StatusException;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\EventDispatcher\GenericEvent;
|
||||
use OCP\IL10N;
|
||||
use OCA\Deck\Event\FTSEvent;
|
||||
|
||||
class StackService {
|
||||
private $stackMapper;
|
||||
@@ -48,11 +54,15 @@ class StackService {
|
||||
private $boardService;
|
||||
private $cardService;
|
||||
private $assignedUsersMapper;
|
||||
private $assignedLabelsMapper;
|
||||
private $attachmentService;
|
||||
|
||||
private $activityManager;
|
||||
/** @var EventDispatcherInterface */
|
||||
private $eventDispatcher;
|
||||
private $changeHelper;
|
||||
private $l10n;
|
||||
private $userId;
|
||||
|
||||
public function __construct(
|
||||
StackMapper $stackMapper,
|
||||
@@ -63,10 +73,13 @@ class StackService {
|
||||
BoardService $boardService,
|
||||
CardService $cardService,
|
||||
AssignedUsersMapper $assignedUsersMapper,
|
||||
AssignedLabelsMapper $assignedLabelsMapper,
|
||||
AttachmentService $attachmentService,
|
||||
ActivityManager $activityManager,
|
||||
EventDispatcherInterface $eventDispatcher,
|
||||
ChangeHelper $changeHelper
|
||||
ChangeHelper $changeHelper,
|
||||
IL10N $l10n,
|
||||
$userId
|
||||
) {
|
||||
$this->stackMapper = $stackMapper;
|
||||
$this->boardMapper = $boardMapper;
|
||||
@@ -76,10 +89,13 @@ class StackService {
|
||||
$this->boardService = $boardService;
|
||||
$this->cardService = $cardService;
|
||||
$this->assignedUsersMapper = $assignedUsersMapper;
|
||||
$this->assignedLabelsMapper = $assignedLabelsMapper;
|
||||
$this->attachmentService = $attachmentService;
|
||||
$this->activityManager = $activityManager;
|
||||
$this->eventDispatcher = $eventDispatcher;
|
||||
$this->changeHelper = $changeHelper;
|
||||
$this->l10n = $l10n;
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
private function enrichStackWithCards($stack, $since = -1) {
|
||||
@@ -365,4 +381,106 @@ class StackService {
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $id
|
||||
* @param $boardId
|
||||
* @return Stack
|
||||
* @throws StatusException
|
||||
* @throws BadRequestException
|
||||
*/
|
||||
public function clone($id, $boardId) {
|
||||
if (is_numeric($id) === false) {
|
||||
throw new BadRequestException('stack id must be a number');
|
||||
}
|
||||
if (is_numeric($boardId) === false) {
|
||||
throw new BadRequestException('board id must be a number');
|
||||
}
|
||||
|
||||
$this->permissionService->checkPermission(null, $boardId, Acl::PERMISSION_MANAGE);
|
||||
$this->permissionService->checkPermission(null, $id, Acl::PERMISSION_READ);
|
||||
|
||||
if ($this->boardService->isArchived(null, $boardId)) {
|
||||
throw new StatusException('Operation not allowed. This board is archived.');
|
||||
}
|
||||
|
||||
$stack = $this->stackMapper->find($id);
|
||||
$board = $this->boardMapper->find($boardId);
|
||||
|
||||
if ($stack->getBoardId() !== $board->getId()) {
|
||||
throw new StatusException('Operation not allowed. Stack is not part of this board');
|
||||
}
|
||||
|
||||
|
||||
$newStack = new Stack();
|
||||
|
||||
// TODO: Currently cloing is only possible on the same board.
|
||||
// If we change this and its possible to clone to other boards the 'copy' should be removed from title
|
||||
$newStack->setTitle($stack->getTitle() . ' (' . $this->l10n->t('copy') . ')');
|
||||
$newStack->setBoardId($boardId);
|
||||
$newStack->setOrder(999);
|
||||
$newStack = $this->stackMapper->insert($newStack);
|
||||
|
||||
$this->activityManager->triggerEvent(
|
||||
ActivityManager::DECK_OBJECT_BOARD, $newStack, ActivityManager::SUBJECT_STACK_CREATE
|
||||
);
|
||||
$this->changeHelper->boardChanged($boardId);
|
||||
|
||||
$this->eventDispatcher->dispatch(
|
||||
'\OCA\Deck\Stack::onCreate',
|
||||
new GenericEvent(null, ['id' => $newStack->getId(), 'stack' => $newStack])
|
||||
);
|
||||
|
||||
$cards = $this->cardMapper->findAll($id);
|
||||
foreach ($cards as $card) {
|
||||
$newCard = new Card();
|
||||
$newCard->setTitle($card->getTitle());
|
||||
$newCard->setStackId($newStack->getId());
|
||||
$newCard->setType($card->getType());
|
||||
$newCard->setOrder($card->getOrder());
|
||||
$newCard->setOwner($this->userId);
|
||||
$newCard->setDescription($card->getDescription());
|
||||
$newCard->setDuedate($card->getDuedate());
|
||||
|
||||
$newCard = $this->cardMapper->insert($newCard);
|
||||
|
||||
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $newCard, ActivityManager::SUBJECT_CARD_CREATE);
|
||||
$this->changeHelper->cardChanged($newCard->getId(), false);
|
||||
$this->eventDispatcher->dispatch('\OCA\Deck\Card::onCreate',
|
||||
new FTSEvent(
|
||||
null, ['id' => $newCard->getId(), 'card' => $newCard, 'userId' => $this->userId, 'stackId' => $stackId]
|
||||
)
|
||||
);
|
||||
|
||||
if ($boardId === $stack->getBoardId()) {
|
||||
$assignedLabels = $this->assignedLabelsMapper->find($card->getId());
|
||||
$newLabelArray = [];
|
||||
foreach ($assignedLabels as $assignedLabel) {
|
||||
$assignment = new AssignedLabels();
|
||||
$assignment->setCardId($newCard->getId());
|
||||
$assignment->setLabelId($assignedLabel->getLabelId());
|
||||
$assignment = $this->assignedLabelsMapper->insert($assignment);
|
||||
|
||||
|
||||
$newLabelArray[] = $assignment;
|
||||
}
|
||||
$newCard->setLabels($newLabelArray);
|
||||
|
||||
$assignedUsers = $this->assignedUsersMapper->find($card->getId());
|
||||
$newUserArray = [];
|
||||
foreach ($assignedUsers as $assignedUser) {
|
||||
$assignment = new AssignedUsers();
|
||||
$assignment->setCardId($newCard->getId());
|
||||
$assignment->setParticipant($assignedUser->getParticipant());
|
||||
$assignment->setType($assignedUser->getType());
|
||||
$assignment = $this->assignedUsersMapper->insert($assignment);
|
||||
$newUserArray[] = $assignment;
|
||||
}
|
||||
$newCard->setAssignedUsers($newUserArray);
|
||||
}
|
||||
}
|
||||
|
||||
$this->enrichStackWithCards($newStack);
|
||||
return $newStack;
|
||||
}
|
||||
}
|
||||
|
||||
36
package-lock.json
generated
36
package-lock.json
generated
@@ -3671,9 +3671,9 @@
|
||||
}
|
||||
},
|
||||
"@nextcloud/vue-dashboard": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue-dashboard/-/vue-dashboard-1.0.1.tgz",
|
||||
"integrity": "sha512-QKOf0qm4UYobuC3djLYwICSuj29H6xnm24IHetc0AMsrfhwPNN1/CC5IWEl1uKCCvwI0NA02HXCVFLtUErlgyg==",
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/vue-dashboard/-/vue-dashboard-0.1.8.tgz",
|
||||
"integrity": "sha512-OGr1oK/WF9+bYHK8dE8Vjwh3IDNamN+9MSti1VO7zuUSm5A9EGCzAghR7zzCG4O43rAJEDcvnQwsYIiA6g4Yrw==",
|
||||
"requires": {
|
||||
"@nextcloud/vue": "^2.3.0",
|
||||
"core-js": "^3.6.4",
|
||||
@@ -13160,9 +13160,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"markdown-it": {
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.1.tgz",
|
||||
"integrity": "sha512-aU1TzmBKcWNNYvH9pjq6u92BML+Hz3h5S/QpfTFwiQF852pLT+9qHsrhM9JYipkOXZxGn+sGH8oyJE9FD9WezQ==",
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.0.tgz",
|
||||
"integrity": "sha512-+CvOnmbSubmQFSA9dKz1BRiaSMV7rhexl3sngKqFyXSagoA3fBdJQ8oZWtRy2knXdpDXaBw44euz37DeJQ9asg==",
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"entities": "~2.0.0",
|
||||
@@ -13172,9 +13172,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"entities": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
|
||||
"integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ=="
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.2.tgz",
|
||||
"integrity": "sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -13584,9 +13584,9 @@
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.28.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.28.0.tgz",
|
||||
"integrity": "sha512-Z5KOjYmnHyd/ukynmFd/WwyXHd7L4J9vTI/nn5Ap9AVUgaAE15VvQ9MOGmJJygEUklupqIrFnor/tjTwRU+tQw=="
|
||||
"version": "2.27.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz",
|
||||
"integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ=="
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
@@ -19335,9 +19335,9 @@
|
||||
"integrity": "sha512-xhq95Mxun060bRnsOoLE2Be6BR7jYwuC89kDe18+GmCLVrRA/dU0jrGb12Xu6NjmKs+iTW0AA6saSEmEW4cR7g=="
|
||||
},
|
||||
"vue-jest": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/vue-jest/-/vue-jest-3.0.7.tgz",
|
||||
"integrity": "sha512-PIOxFM+wsBMry26ZpfBvUQ/DGH2hvp5khDQ1n51g3bN0TwFwTy4J85XVfxTRMukqHji/GnAoGUnlZ5Ao73K62w==",
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/vue-jest/-/vue-jest-3.0.6.tgz",
|
||||
"integrity": "sha512-VyuM8wR0vAlYCbPRY+PhIqRU5yUyBnUmwYTo4IFScs2+tiuis5VBItU0PGC8Wcx6qJwKB5jq5p7WFhabzMFMgQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
|
||||
@@ -20170,9 +20170,9 @@
|
||||
}
|
||||
},
|
||||
"webpack-merge": {
|
||||
"version": "5.1.4",
|
||||
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.1.4.tgz",
|
||||
"integrity": "sha512-LSmRD59mxREGkCBm9PCW3AaV4doDqxykGlx1NvioEE0FgkT2GQI54Wyvg39ptkiq2T11eRVoV39udNPsQvK+QQ==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.1.2.tgz",
|
||||
"integrity": "sha512-/slG0Kh0OKTf0zxdFJlhQHzv8bU9gUYVK5DkBjB3i/yoc1Xx4ADG0KITGO5S/6cqn2Ug43+8VR6Sz8daA/c+5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"clone-deep": "^4.0.1",
|
||||
|
||||
10
package.json
10
package.json
@@ -40,13 +40,13 @@
|
||||
"@nextcloud/moment": "^1.1.1",
|
||||
"@nextcloud/router": "^1.2.0",
|
||||
"@nextcloud/vue": "^2.6.5",
|
||||
"@nextcloud/vue-dashboard": "^1.0.1",
|
||||
"@nextcloud/vue-dashboard": "^0.1.8",
|
||||
"blueimp-md5": "^2.18.0",
|
||||
"dompurify": "^2.0.15",
|
||||
"lodash": "^4.17.20",
|
||||
"markdown-it": "^11.0.1",
|
||||
"markdown-it": "^11.0.0",
|
||||
"markdown-it-task-lists": "^2.1.1",
|
||||
"moment": "^2.28.0",
|
||||
"moment": "^2.27.0",
|
||||
"nextcloud-vue-collections": "^0.8.1",
|
||||
"p-queue": "^6.6.1",
|
||||
"url-search-params-polyfill": "^8.1.0",
|
||||
@@ -103,13 +103,13 @@
|
||||
"stylelint-scss": "^3.18.0",
|
||||
"stylelint-webpack-plugin": "^2.1.0",
|
||||
"url-loader": "^4.1.0",
|
||||
"vue-jest": "^3.0.7",
|
||||
"vue-jest": "^3.0.6",
|
||||
"vue-loader": "^15.9.3",
|
||||
"vue-template-compiler": "^2.6.12",
|
||||
"webpack": "^4.44.1",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-server": "^3.11.0",
|
||||
"webpack-merge": "^5.1.4"
|
||||
"webpack-merge": "^5.1.2"
|
||||
},
|
||||
"jest": {
|
||||
"moduleFileExtensions": [
|
||||
|
||||
@@ -42,11 +42,14 @@
|
||||
value="">
|
||||
</form>
|
||||
</transition>
|
||||
<Actions v-if="canManage && !isArchived" :force-menu="true">
|
||||
<ActionButton icon="icon-archive" @click="modalArchivAllCardsShow=true">
|
||||
<Actions v-if="!isArchived" :force-menu="true">
|
||||
<ActionButton v-if="canEdit" icon="icon-archive" @click="modalArchivAllCardsShow=true">
|
||||
{{ t('deck', 'Archive all cards') }}
|
||||
</ActionButton>
|
||||
<ActionButton icon="icon-delete" @click="deleteStack(stack)">
|
||||
<ActionButton v-if="canManage" icon="icon-clone" @click="cloneStack(stack)">
|
||||
{{ t('deck', 'Clone list') }}
|
||||
</ActionButton>
|
||||
<ActionButton v-if="canManage" icon="icon-delete" @click="deleteStack(stack)">
|
||||
{{ t('deck', 'Delete list') }}
|
||||
</ActionButton>
|
||||
</Actions>
|
||||
@@ -212,7 +215,6 @@ export default {
|
||||
this.$store.dispatch('deleteStack', stack)
|
||||
},
|
||||
archiveAllCardsFromStack(stack) {
|
||||
|
||||
this.stackTransfer.total = this.cardsByStack.length
|
||||
this.cardsByStack.forEach((card, index) => {
|
||||
this.stackTransfer.current = index
|
||||
@@ -220,6 +222,13 @@ export default {
|
||||
})
|
||||
this.modalArchivAllCardsShow = false
|
||||
},
|
||||
cloneStack(stack) {
|
||||
try {
|
||||
this.$store.dispatch('cloneStack', stack)
|
||||
} catch (e) {
|
||||
showError('Could not clone stack: ' + e.response.data.message)
|
||||
}
|
||||
},
|
||||
startEditing(stack) {
|
||||
this.copiedStack = Object.assign({}, stack)
|
||||
this.editing = true
|
||||
|
||||
@@ -140,4 +140,19 @@ export class StackApi {
|
||||
})
|
||||
}
|
||||
|
||||
cloneStack(stack) {
|
||||
return axios.post(this.url(`/stacks/${stack.id}/clone`), stack)
|
||||
.then(
|
||||
(response) => {
|
||||
return Promise.resolve(response.data)
|
||||
},
|
||||
(err) => {
|
||||
return Promise.reject(err)
|
||||
}
|
||||
)
|
||||
.catch((err) => {
|
||||
return Promise.reject(err)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -97,6 +97,15 @@ export default {
|
||||
commit('addStack', createdStack)
|
||||
})
|
||||
},
|
||||
cloneStack({ commit }, stack) {
|
||||
apiClient.cloneStack(stack)
|
||||
.then((stack) => {
|
||||
for (const j in stack.cards) {
|
||||
commit('addCard', stack.cards[j])
|
||||
}
|
||||
commit('addStack', stack)
|
||||
})
|
||||
},
|
||||
deleteStack({ commit }, stack) {
|
||||
apiClient.deleteStack(stack.id)
|
||||
.then((stack) => {
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
|
||||
<template>
|
||||
<DashboardWidget :items="cards"
|
||||
empty-content-icon="icon-deck"
|
||||
:empty-content-message="t('deck', 'No upcoming cards')"
|
||||
:show-more-text="t('deck', 'upcoming cards')"
|
||||
:show-more-url="showMoreUrl"
|
||||
:loading="loading"
|
||||
@@ -46,11 +44,21 @@
|
||||
</ul>
|
||||
</a>
|
||||
</template>
|
||||
<template v-slot:empty-content>
|
||||
<EmptyContent
|
||||
id="deck-widget-empty-content"
|
||||
icon="icon-deck">
|
||||
<template #desc>
|
||||
{{ t('deck', 'No upcoming cards') }}
|
||||
</template>
|
||||
</EmptyContent>
|
||||
</template>
|
||||
</DashboardWidget>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { DashboardWidget } from '@nextcloud/vue-dashboard'
|
||||
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
|
||||
import { mapGetters } from 'vuex'
|
||||
import labelStyle from './../mixins/labelStyle'
|
||||
import DueDate from '../components/cards/badges/DueDate'
|
||||
@@ -60,6 +68,7 @@ export default {
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
DueDate,
|
||||
EmptyContent,
|
||||
DashboardWidget,
|
||||
},
|
||||
mixins: [ labelStyle ],
|
||||
|
||||
@@ -33,8 +33,10 @@ use OCA\Deck\Db\Label;
|
||||
use OCA\Deck\Db\LabelMapper;
|
||||
use OCA\Deck\Db\Stack;
|
||||
use OCA\Deck\Db\StackMapper;
|
||||
use OCA\Deck\Db\AssignedLabelsMapper;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use \Test\TestCase;
|
||||
use OCP\IL10N;
|
||||
|
||||
/**
|
||||
* Class StackServiceTest
|
||||
@@ -70,6 +72,9 @@ class StackServiceTest extends TestCase {
|
||||
private $changeHelper;
|
||||
/** @var EventDispatcherInterface */
|
||||
private $eventDispatcher;
|
||||
private $l10n;
|
||||
private $userId;
|
||||
private $assignedLabelsMapper;
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
@@ -85,6 +90,10 @@ class StackServiceTest extends TestCase {
|
||||
$this->activityManager = $this->createMock(ActivityManager::class);
|
||||
$this->changeHelper = $this->createMock(ChangeHelper::class);
|
||||
$this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$this->l10n = $this->createMock(IL10N::class);
|
||||
$this->userId = "admin";
|
||||
$this->assignedLabelsMapper = $this->createMock(AssignedLabelsMapper::class);
|
||||
|
||||
|
||||
$this->stackService = new StackService(
|
||||
$this->stackMapper,
|
||||
@@ -98,7 +107,10 @@ class StackServiceTest extends TestCase {
|
||||
$this->attachmentService,
|
||||
$this->activityManager,
|
||||
$this->eventDispatcher,
|
||||
$this->changeHelper
|
||||
$this->changeHelper,
|
||||
$this->l10n,
|
||||
$this->userId,
|
||||
$this->assassignedLabelsMapper
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user