From 3c5f68e0c33aaf3a47d20b0c01254518ec29cb6b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakob=20R=C3=B6hrl?=
Date: Wed, 20 May 2020 11:18:23 +0200
Subject: [PATCH 01/13] card dashboard
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Jakob Röhrl
---
appinfo/routes.php | 7 +
lib/Controller/CardController.php | 20 ++-
lib/Db/CardMapper.php | 17 ++
lib/Service/CardService.php | 24 +++
lib/Service/DashboardService.php | 163 ++++++++++++++++++++
src/App.vue | 1 +
src/components/Controls.vue | 9 ++
src/components/dashboards/Dashboards.vue | 156 +++++++++++++++++++
src/components/navigation/AppNavigation.vue | 20 +++
src/router.js | 15 ++
src/services/CardApi.js | 20 +++
src/store/dashboard.js | 63 ++++++++
src/store/main.js | 2 +
13 files changed, 516 insertions(+), 1 deletion(-)
create mode 100644 lib/Service/DashboardService.php
create mode 100644 src/components/dashboards/Dashboards.vue
create mode 100644 src/store/dashboard.js
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 4ab64f84a..96774f444 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -65,7 +65,12 @@ return [
['name' => 'card#removeLabel', 'url' => '/cards/{cardId}/label/{labelId}', 'verb' => 'DELETE'],
['name' => 'card#assignUser', 'url' => '/cards/{cardId}/assign', 'verb' => 'POST'],
['name' => 'card#unassignUser', 'url' => '/cards/{cardId}/unassign', 'verb' => 'PUT'],
+
+ // dashboard
+ ['name' => 'card#findAllWithDue', 'url' => '/dashboard/due', 'verb' => 'GET'],
+ ['name' => 'card#findMyAssignedCards', 'url' => '/dashboard/assigned', 'verb' => 'GET'],
+ // attachments
['name' => 'attachment#getAll', 'url' => '/cards/{cardId}/attachments', 'verb' => 'GET'],
['name' => 'attachment#create', 'url' => '/cards/{cardId}/attachment', 'verb' => 'POST'],
['name' => 'attachment#display', 'url' => '/cards/{cardId}/attachment/{attachmentId}', 'verb' => 'GET'],
@@ -110,6 +115,8 @@ return [
['name' => 'card_api#reorder', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}/reorder', 'verb' => 'PUT'],
['name' => 'card_api#delete', 'url' => '/api/v1.0/boards/{boardId}/stacks/{stackId}/cards/{cardId}', 'verb' => 'DELETE'],
+ ['name' => 'card_api#findAllWithDue', 'url' => '/api/v1.0/dashboard/due', 'verb' => 'GET'],
+
['name' => 'label_api#get', 'url' => '/api/v1.0/boards/{boardId}/labels/{labelId}', 'verb' => 'GET'],
['name' => 'label_api#create', 'url' => '/api/v1.0/boards/{boardId}/labels', 'verb' => 'POST'],
['name' => 'label_api#update', 'url' => '/api/v1.0/boards/{boardId}/labels/{labelId}', 'verb' => 'PUT'],
diff --git a/lib/Controller/CardController.php b/lib/Controller/CardController.php
index dcb3e6046..db6bc08bd 100644
--- a/lib/Controller/CardController.php
+++ b/lib/Controller/CardController.php
@@ -25,6 +25,7 @@ namespace OCA\Deck\Controller;
use OCA\Deck\Service\AssignmentService;
use OCA\Deck\Service\CardService;
+use OCA\Deck\Service\DashboardService;
use OCP\IRequest;
use OCP\AppFramework\Controller;
@@ -33,10 +34,11 @@ class CardController extends Controller {
private $cardService;
private $assignmentService;
- public function __construct($appName, IRequest $request, CardService $cardService, AssignmentService $assignmentService, $userId) {
+ public function __construct($appName, IRequest $request, CardService $cardService, DashboardService $dashboardService, AssignmentService $assignmentService, $userId) {
parent::__construct($appName, $request);
$this->userId = $userId;
$this->cardService = $cardService;
+ $this->dashboardService = $dashboardService;
$this->assignmentService = $assignmentService;
}
@@ -165,4 +167,20 @@ class CardController extends Controller {
public function unassignUser($cardId, $userId, $type = 0) {
return $this->assignmentService->unassignUser($cardId, $userId, $type);
}
+
+ /**
+ * @NoAdminRequired
+ * @return array
+ */
+ public function findAllWithDue($userId) {
+ return $this->dashboardService->findAllWithDue($userId);
+ }
+
+ /**
+ * @NoAdminRequired
+ * @return array
+ */
+ public function findMyAssignedCards($userId) {
+ return $this->dashboardService->findMyAssignedCards($userId);
+ }
}
diff --git a/lib/Db/CardMapper.php b/lib/Db/CardMapper.php
index ad2c97724..1a77dac0d 100644
--- a/lib/Db/CardMapper.php
+++ b/lib/Db/CardMapper.php
@@ -141,6 +141,23 @@ class CardMapper extends DeckMapper implements IPermissionMapper {
return $this->findEntities($sql, [$stackId], $limit, $offset);
}
+ public function findAllWithDue($boardId) {
+ $sql = 'SELECT c.* FROM `*PREFIX*deck_cards` c
+ INNER JOIN `*PREFIX*deck_stacks` s ON s.id = c.stack_id
+ INNER JOIN `*PREFIX*deck_boards` b ON b.id = s.board_id
+ WHERE `s`.`board_id` = ? AND duedate IS NOT NULL AND NOT c.archived AND c.deleted_at = 0 AND s.deleted_at = 0 AND NOT b.archived AND b.deleted_at = 0';
+ return $this->findEntities($sql, [$boardId]);
+ }
+
+ public function findMyAssignedCards($boardId, $username) {
+ $sql = 'SELECT c.* FROM `*PREFIX*deck_cards` c
+ INNER JOIN `*PREFIX*deck_stacks` s ON s.id = c.stack_id
+ INNER JOIN `*PREFIX*deck_boards` b ON b.id = s.board_id
+ INNER JOIN `*PREFIX*deck_assigned_users` u ON c.id = card_id
+ WHERE `s`.`board_id` = ? AND participant = ? AND NOT c.archived AND c.deleted_at = 0 AND s.deleted_at = 0 AND NOT b.archived AND b.deleted_at = 0';
+ return $this->findEntities($sql, [$boardId, $username]);
+ }
+
public function findOverdue() {
$sql = 'SELECT id,title,duedate,notified from `*PREFIX*deck_cards` WHERE duedate < NOW() AND NOT archived AND deleted_at = 0';
return $this->findEntities($sql);
diff --git a/lib/Service/CardService.php b/lib/Service/CardService.php
index 50ea6fa49..4b969709a 100644
--- a/lib/Service/CardService.php
+++ b/lib/Service/CardService.php
@@ -564,4 +564,28 @@ class CardService {
'\OCA\Deck\Card::onUpdate', new FTSEvent(null, ['id' => $cardId, 'card' => $card])
);
}
+
+ /**
+ *
+ * @return array
+ * @throws \OCA\Deck\NoPermissionException
+ * @throws BadRequestException
+ */
+ public function findAllWithDue($userId) {
+ $cards = $this->cardMapper->findAllWithDue($userId);
+
+ return $cards;
+ }
+
+ /**
+ *
+ * @return array
+ * @throws \OCA\Deck\NoPermissionException
+ * @throws BadRequestException
+ */
+ public function findMyAssignedCards($userId) {
+ $cards = $this->cardMapper->findMyAssignedCards($userId);
+
+ return $cards;
+ }
}
diff --git a/lib/Service/DashboardService.php b/lib/Service/DashboardService.php
new file mode 100644
index 000000000..41519dbed
--- /dev/null
+++ b/lib/Service/DashboardService.php
@@ -0,0 +1,163 @@
+
+ *
+ * @author Julius Härtl
+ * @author Maxence Lange
+ *
+ * @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 .
+ *
+ */
+
+namespace OCA\Deck\Service;
+
+use OCA\Deck\Activity\ActivityManager;
+use OCA\Deck\Activity\ChangeSet;
+use OCA\Deck\Db\Acl;
+use OCA\Deck\Db\AclMapper;
+use OCA\Deck\Db\AssignedUsersMapper;
+use OCA\Deck\Db\ChangeHelper;
+use OCA\Deck\Db\IPermissionMapper;
+use OCA\Deck\Db\CardMapper;
+use OCA\Deck\Db\Label;
+use OCA\Deck\Db\Stack;
+use OCA\Deck\Db\StackMapper;
+use OCA\Deck\NoPermissionException;
+use OCA\Deck\Notification\NotificationHelper;
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\IGroupManager;
+use OCP\IL10N;
+use OCA\Deck\Db\Board;
+use OCA\Deck\Db\BoardMapper;
+use OCA\Deck\Db\LabelMapper;
+use OCP\IUserManager;
+use OCA\Deck\BadRequestException;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\GenericEvent;
+
+class DashboardService {
+ private $boardMapper;
+ private $stackMapper;
+ private $labelMapper;
+ private $aclMapper;
+ private $cardMapper;
+ private $l10n;
+ private $permissionService;
+ private $notificationHelper;
+ private $assignedUsersMapper;
+ private $userManager;
+ private $groupManager;
+ private $userId;
+ private $activityManager;
+ /** @var EventDispatcherInterface */
+ private $eventDispatcher;
+ private $changeHelper;
+
+ public function __construct(
+ BoardMapper $boardMapper,
+ StackMapper $stackMapper,
+ IL10N $l10n,
+ LabelMapper $labelMapper,
+ AclMapper $aclMapper,
+ CardMapper $cardMapper,
+ PermissionService $permissionService,
+ NotificationHelper $notificationHelper,
+ AssignedUsersMapper $assignedUsersMapper,
+ IUserManager $userManager,
+ IGroupManager $groupManager,
+ ActivityManager $activityManager,
+ EventDispatcherInterface $eventDispatcher,
+ ChangeHelper $changeHelper,
+ $userId
+ ) {
+ $this->boardMapper = $boardMapper;
+ $this->stackMapper = $stackMapper;
+ $this->labelMapper = $labelMapper;
+ $this->aclMapper = $aclMapper;
+ $this->cardMapper = $cardMapper;
+ $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;
+ }
+
+ /**
+ * Set a different user than the current one, e.g. when no user is available in occ
+ *
+ * @param string $userId
+ */
+ public function setUserId(string $userId): void {
+ $this->userId = $userId;
+ }
+
+
+ /**
+ * @return array
+ */
+ public function findAllWithDue($userId) {
+ $userInfo = $this->getBoardPrerequisites();
+ $userBoards = $this->findAllBoardsFromUser($userInfo);
+ $allDueCards = [];
+ foreach ($userBoards as $userBoard) {
+ $allDueCards[] = $this->cardMapper->findAllWithDue($userBoard->getId());
+ }
+ return $allDueCards;
+ }
+
+ /**
+ * @return array
+ */
+ public function findMyAssignedCards($userId) {
+ $userInfo = $this->getBoardPrerequisites();
+ $userBoards = $this->findAllBoardsFromUser($userInfo);
+ $allAssignedCards = [];
+ foreach ($userBoards as $userBoard) {
+ $allAssignedCards[] = $this->cardMapper->findMyAssignedCards($userBoard->getId(), $this->userId);
+ }
+ return $allAssignedCards;
+ }
+
+ /**
+ * @return array
+ */
+ private function findAllBoardsFromUser($userInfo, $since = -1) {
+ $userBoards = $this->boardMapper->findAllByUser($userInfo['user'], null, null, $since);
+ $groupBoards = $this->boardMapper->findAllByGroups($userInfo['user'], $userInfo['groups'],null, null, $since);
+ $circleBoards = $this->boardMapper->findAllByCircles($userInfo['user'], null, null, $since);
+ return array_merge($userBoards, $groupBoards, $circleBoards);
+ }
+
+ /**
+ * @return array
+ */
+ private function getBoardPrerequisites() {
+ $groups = $this->groupManager->getUserGroupIds(
+ $this->userManager->get($this->userId)
+ );
+ return [
+ 'user' => $this->userId,
+ 'groups' => $groups
+ ];
+ }
+
+
+}
diff --git a/src/App.vue b/src/App.vue
index c5237165f..ee190cd62 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -85,6 +85,7 @@ export default {
created() {
this.$store.dispatch('loadBoards')
this.$store.dispatch('loadSharees')
+ this.$store.dispatch('loadDashboards')
},
}
diff --git a/src/components/Controls.vue b/src/components/Controls.vue
index 6a4fbb309..258bae031 100644
--- a/src/components/Controls.vue
+++ b/src/components/Controls.vue
@@ -30,6 +30,10 @@
({{ t('deck', 'Archived cards') }})
+
+ -
+ - @author Julius Härtl
+ -
+ - @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 .
+ -
+ -->
+
+
+
+
+
+
+
+
overdue
+
+
+ {{ card.title }}
+
+
+
+
+
today
+ {{ withDueDashboardGroup.today }}
+
+
+
+
tomorrow
+ {{ withDueDashboardGroup.tomorrow }}
+
+
+
+
this week
+ {{ withDueDashboardGroup.thisWeek }}
+
+
+
+
+
+
overdue
+
+ {{ card.title }}
+
+
+
+
+
today
+ {{ assignedCardsDashboardGroup.today }}
+
+
+
+
tomorrow
+ {{ assignedCardsDashboardGroup.tomorrow }}
+
+
+
+
this week
+ {{ assignedCardsDashboardGroup.thisWeek }}
+
+
+
+
+
+
+
+
+
diff --git a/src/components/navigation/AppNavigation.vue b/src/components/navigation/AppNavigation.vue
index ffd16a029..6430bfd28 100644
--- a/src/components/navigation/AppNavigation.vue
+++ b/src/components/navigation/AppNavigation.vue
@@ -23,6 +23,14 @@
+
+
{
+ return {
+ filter: route.params.filter,
+ }
+ },
+ },
+ },
{
path: '/board',
name: 'boards',
diff --git a/src/services/CardApi.js b/src/services/CardApi.js
index 114556d05..d52623dc2 100644
--- a/src/services/CardApi.js
+++ b/src/services/CardApi.js
@@ -195,4 +195,24 @@ export class CardApi {
})
}
+ findAllWithDue(data) {
+ return axios.get(this.url(`/dashboard/due`))
+ .then(
+ (response) => Promise.resolve(response.data),
+ (err) => Promise.reject(err)
+ )
+ .catch((err) => Promise.reject(err)
+ )
+ }
+
+ findMyAssignedCards(data) {
+ return axios.get(this.url(`/dashboard/assigned`))
+ .then(
+ (response) => Promise.resolve(response.data),
+ (err) => Promise.reject(err)
+ )
+ .catch((err) => Promise.reject(err)
+ )
+ }
+
}
diff --git a/src/store/dashboard.js b/src/store/dashboard.js
new file mode 100644
index 000000000..d5d2d030c
--- /dev/null
+++ b/src/store/dashboard.js
@@ -0,0 +1,63 @@
+/*
+ * @copyright Copyright (c) 2020 Jakob Röhrl
+ *
+ * @author Jakob Röhrl
+ *
+ * @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 .
+ *
+ */
+
+import Vue from 'vue'
+import Vuex from 'vuex'
+import { CardApi } from '../services/CardApi'
+Vue.use(Vuex)
+
+const apiClient = new CardApi()
+export default {
+ state: {
+ withDue: [],
+ assignedCards: [],
+ },
+ getters: {
+ withDueDashboard: state => {
+ return state.withDue
+ },
+ assignedCardsDashboard: state => {
+ return state.assignedCards
+ },
+ },
+ mutations: {
+ setWithDueDashboard(state, withDue) {
+ state.withDue = withDue
+ },
+ setAssignedCards(state, assignedCards) {
+ state.assignedCards = assignedCards
+ },
+
+ },
+ actions: {
+ async loadDashboards({ commit }) {
+ const withDue = await apiClient.findAllWithDue()
+ const withDueFlat = withDue.flat()
+ commit('setWithDueDashboard', withDueFlat)
+
+ const assignedCards = await apiClient.findMyAssignedCards()
+ const assignedCardsFlat = assignedCards.flat()
+ commit('setAssignedCards', assignedCardsFlat)
+
+ },
+ },
+}
diff --git a/src/store/main.js b/src/store/main.js
index 6189fd934..024051b2f 100644
--- a/src/store/main.js
+++ b/src/store/main.js
@@ -32,6 +32,7 @@ import card from './card'
import comment from './comment'
import trashbin from './trashbin'
import attachment from './attachment'
+import dashboard from './dashboard'
import debounce from 'lodash/debounce'
Vue.use(Vuex)
@@ -51,6 +52,7 @@ export default new Vuex.Store({
comment,
trashbin,
attachment,
+ dashboard,
},
strict: debug,
state: {
From 07481330b1cad4b934243cc937b1b20f7442718b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Julius=20H=C3=A4rtl?=
Date: Sat, 11 Jul 2020 10:44:25 +0200
Subject: [PATCH 02/13] Enrich card results
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Julius Härtl
---
lib/Service/DashboardService.php | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/lib/Service/DashboardService.php b/lib/Service/DashboardService.php
index 41519dbed..000c2bc8c 100644
--- a/lib/Service/DashboardService.php
+++ b/lib/Service/DashboardService.php
@@ -100,6 +100,18 @@ class DashboardService {
$this->userId = $userId;
}
+ public function enrich($card) {
+ $cardId = $card->getId();
+ $this->cardMapper->mapOwner($card);
+ $card->setAssignedUsers($this->assignedUsersMapper->find($cardId));
+ $card->setLabels($this->labelMapper->findAssignedLabelsForCard($cardId));
+ //$card->setAttachmentCount($this->attachmentService->count($cardId));
+ //$user = $this->userManager->get($this->userId);
+ //$lastRead = $this->commentsManager->getReadMark('deckCard', (string)$card->getId(), $user);
+ //$count = $this->commentsManager->getNumberOfCommentsForObject('deckCard', (string)$card->getId(), $lastRead);
+ //$card->setCommentsUnread($count);
+ }
+
/**
* Set a different user than the current one, e.g. when no user is available in occ
*
@@ -118,7 +130,13 @@ class DashboardService {
$userBoards = $this->findAllBoardsFromUser($userInfo);
$allDueCards = [];
foreach ($userBoards as $userBoard) {
- $allDueCards[] = $this->cardMapper->findAllWithDue($userBoard->getId());
+ $service = $this;
+ $allDueCards[] = array_map(function ($card) use ($service, $userBoard) {
+ $service->enrich($card);
+ $cardData = $card->jsonSerialize();
+ $cardData['boardId'] = $userBoard->getId();
+ return $cardData;
+ }, $this->cardMapper->findAllWithDue($userBoard->getId()));
}
return $allDueCards;
}
@@ -131,7 +149,13 @@ class DashboardService {
$userBoards = $this->findAllBoardsFromUser($userInfo);
$allAssignedCards = [];
foreach ($userBoards as $userBoard) {
- $allAssignedCards[] = $this->cardMapper->findMyAssignedCards($userBoard->getId(), $this->userId);
+ $service = $this;
+ $allAssignedCards[] = array_map(function ($card) use ($service, $userBoard) {
+ $service->enrich($card);
+ $cardData = $card->jsonSerialize();
+ $cardData['boardId'] = $userBoard->getId();
+ return $cardData;
+ }, $this->cardMapper->findMyAssignedCards($userBoard->getId(), $this->userId));
}
return $allAssignedCards;
}
From 3a4bbac6d4c0e9eb8765179b4fd43ab6c0d37635 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Julius=20H=C3=A4rtl?=
Date: Sat, 11 Jul 2020 11:08:55 +0200
Subject: [PATCH 03/13] Move scss variables to dedicated file
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Julius Härtl
---
src/components/board/Board.vue | 7 ++-----
src/components/board/Stack.vue | 3 +--
src/components/cards/CardItem.vue | 4 +---
src/components/dashboards/Dashboards.vue | 19 ++++++++++---------
src/css/variables.scss | 5 +++++
5 files changed, 19 insertions(+), 19 deletions(-)
create mode 100644 src/css/variables.scss
diff --git a/src/components/board/Board.vue b/src/components/board/Board.vue
index 32eab0ec2..7e7fda6f6 100644
--- a/src/components/board/Board.vue
+++ b/src/components/board/Board.vue
@@ -157,11 +157,8 @@ export default {
diff --git a/src/css/variables.scss b/src/css/variables.scss
new file mode 100644
index 000000000..ff339e192
--- /dev/null
+++ b/src/css/variables.scss
@@ -0,0 +1,5 @@
+$card-spacing: 10px;
+$card-padding: 10px;
+$stack-spacing: 10px;
+$stack-width: 260px;
+$board-spacing: 15px;
From 348fc669bebe43985d2a6bc5b9c6ff6661f5254d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Julius=20H=C3=A4rtl?=
Date: Sat, 11 Jul 2020 11:10:47 +0200
Subject: [PATCH 04/13] Allow to use card item without being available in
global card store
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Julius Härtl
---
appinfo/routes.php | 10 ++--
lib/Controller/CardController.php | 16 -------
lib/Controller/DashboardApiController.php | 56 +++++++++++++++++++++++
lib/Db/CardMapper.php | 2 +-
lib/Service/CardService.php | 4 +-
lib/Service/DashboardService.php | 4 +-
src/App.vue | 1 -
src/components/cards/CardBadges.vue | 11 ++---
src/components/cards/CardItem.vue | 15 ++++--
src/components/dashboards/Dashboards.vue | 34 ++++++++++----
src/services/DashboardApi.js | 53 +++++++++++++++++++++
src/store/dashboard.js | 6 +--
12 files changed, 160 insertions(+), 52 deletions(-)
create mode 100644 lib/Controller/DashboardApiController.php
create mode 100644 src/services/DashboardApi.js
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 96774f444..506cebd7b 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -66,10 +66,6 @@ return [
['name' => 'card#assignUser', 'url' => '/cards/{cardId}/assign', 'verb' => 'POST'],
['name' => 'card#unassignUser', 'url' => '/cards/{cardId}/unassign', 'verb' => 'PUT'],
- // dashboard
- ['name' => 'card#findAllWithDue', 'url' => '/dashboard/due', 'verb' => 'GET'],
- ['name' => 'card#findMyAssignedCards', 'url' => '/dashboard/assigned', 'verb' => 'GET'],
-
// attachments
['name' => 'attachment#getAll', 'url' => '/cards/{cardId}/attachments', 'verb' => 'GET'],
['name' => 'attachment#create', 'url' => '/cards/{cardId}/attachment', 'verb' => 'POST'],
@@ -138,5 +134,9 @@ return [
['name' => 'comments_api#create', 'url' => '/api/v1.0/cards/{cardId}/comments', 'verb' => 'POST'],
['name' => 'comments_api#update', 'url' => '/api/v1.0/cards/{cardId}/comments/{commentId}', 'verb' => 'PUT'],
['name' => 'comments_api#delete', 'url' => '/api/v1.0/cards/{cardId}/comments/{commentId}', 'verb' => 'DELETE'],
+
+ // dashboard
+ ['name' => 'dashboard_api#findAllWithDue', 'url' => '/api/v1.0/dashboard/dashboard/due', 'verb' => 'GET'],
+ ['name' => 'dashboard_api#findAssignedCards', 'url' => '/api/v1.0/dashboard/assigned', 'verb' => 'GET'],
]
-];
+];
\ No newline at end of file
diff --git a/lib/Controller/CardController.php b/lib/Controller/CardController.php
index db6bc08bd..ce36b81a6 100644
--- a/lib/Controller/CardController.php
+++ b/lib/Controller/CardController.php
@@ -167,20 +167,4 @@ class CardController extends Controller {
public function unassignUser($cardId, $userId, $type = 0) {
return $this->assignmentService->unassignUser($cardId, $userId, $type);
}
-
- /**
- * @NoAdminRequired
- * @return array
- */
- public function findAllWithDue($userId) {
- return $this->dashboardService->findAllWithDue($userId);
- }
-
- /**
- * @NoAdminRequired
- * @return array
- */
- public function findMyAssignedCards($userId) {
- return $this->dashboardService->findMyAssignedCards($userId);
- }
}
diff --git a/lib/Controller/DashboardApiController.php b/lib/Controller/DashboardApiController.php
new file mode 100644
index 000000000..df989b8c8
--- /dev/null
+++ b/lib/Controller/DashboardApiController.php
@@ -0,0 +1,56 @@
+
+ *
+ * @author Jakob Röhrl
+ *
+ * @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 .
+ *
+ */
+
+namespace OCA\Deck\Controller;
+
+
+use OCA\Deck\Service\DashboardService;
+use OCP\IRequest;
+use OCP\AppFramework\Controller;
+
+class DashboardApiController extends OCSController {
+ private $userId;
+ private $cardService;
+
+ public function __construct($appName, IRequest $request, DashboardService $dashboardService, $userId) {
+ parent::__construct($appName, $request);
+ $this->userId = $userId;
+ $this->dashboardService = $dashboardService;
+ }
+
+ /**
+ * @NoAdminRequired
+ * @return array
+ */
+ public function findAllWithDue($userId) {
+ return $this->dashboardService->findAllWithDue($userId);
+ }
+
+ /**
+ * @NoAdminRequired
+ * @return array
+ */
+ public function findAssignedCards($userId) {
+ return $this->dashboardService->findAssignedCards($userId);
+ }
+}
diff --git a/lib/Db/CardMapper.php b/lib/Db/CardMapper.php
index 1a77dac0d..bbbcdb560 100644
--- a/lib/Db/CardMapper.php
+++ b/lib/Db/CardMapper.php
@@ -149,7 +149,7 @@ class CardMapper extends DeckMapper implements IPermissionMapper {
return $this->findEntities($sql, [$boardId]);
}
- public function findMyAssignedCards($boardId, $username) {
+ public function findAssignedCards($boardId, $username) {
$sql = 'SELECT c.* FROM `*PREFIX*deck_cards` c
INNER JOIN `*PREFIX*deck_stacks` s ON s.id = c.stack_id
INNER JOIN `*PREFIX*deck_boards` b ON b.id = s.board_id
diff --git a/lib/Service/CardService.php b/lib/Service/CardService.php
index 4b969709a..9d4867705 100644
--- a/lib/Service/CardService.php
+++ b/lib/Service/CardService.php
@@ -583,8 +583,8 @@ class CardService {
* @throws \OCA\Deck\NoPermissionException
* @throws BadRequestException
*/
- public function findMyAssignedCards($userId) {
- $cards = $this->cardMapper->findMyAssignedCards($userId);
+ public function findAssignedCards($userId) {
+ $cards = $this->cardMapper->findAssignedCards($userId);
return $cards;
}
diff --git a/lib/Service/DashboardService.php b/lib/Service/DashboardService.php
index 000c2bc8c..316c6df60 100644
--- a/lib/Service/DashboardService.php
+++ b/lib/Service/DashboardService.php
@@ -144,7 +144,7 @@ class DashboardService {
/**
* @return array
*/
- public function findMyAssignedCards($userId) {
+ public function findAssignedCards($userId) {
$userInfo = $this->getBoardPrerequisites();
$userBoards = $this->findAllBoardsFromUser($userInfo);
$allAssignedCards = [];
@@ -155,7 +155,7 @@ class DashboardService {
$cardData = $card->jsonSerialize();
$cardData['boardId'] = $userBoard->getId();
return $cardData;
- }, $this->cardMapper->findMyAssignedCards($userBoard->getId(), $this->userId));
+ }, $this->cardMapper->findAssignedCards($userBoard->getId(), $this->userId));
}
return $allAssignedCards;
}
diff --git a/src/App.vue b/src/App.vue
index ee190cd62..c5237165f 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -85,7 +85,6 @@ export default {
created() {
this.$store.dispatch('loadBoards')
this.$store.dispatch('loadSharees')
- this.$store.dispatch('loadDashboards')
},
}
diff --git a/src/components/cards/CardBadges.vue b/src/components/cards/CardBadges.vue
index cdef86f03..59b124615 100644
--- a/src/components/cards/CardBadges.vue
+++ b/src/components/cards/CardBadges.vue
@@ -21,7 +21,7 @@
-->
-
+
diff --git a/src/components/cards/CardItem.vue b/src/components/cards/CardItem.vue
index ddae4f234..291202afe 100644
--- a/src/components/cards/CardItem.vue
+++ b/src/components/cards/CardItem.vue
@@ -25,7 +25,7 @@
-->
-
+
@@ -95,6 +95,10 @@ export default {
type: Number,
default: null,
},
+ item: {
+ type: Object,
+ default: null,
+ },
},
data() {
return {
@@ -113,10 +117,10 @@ export default {
'isArchived',
]),
card() {
- return this.$store.getters.cardById(this.id)
+ return this.item ? this.item : this.$store.getters.cardById(this.id)
},
currentCard() {
- return this.$route.params.cardId === this.id
+ return this.card && this.$route && this.$route.params.cardId === this.card.id
},
relativeDate() {
const diff = moment(this.$root.time).diff(this.card.duedate, 'seconds')
@@ -144,7 +148,8 @@ export default {
},
methods: {
openCard() {
- this.$router.push({ name: 'card', params: { cardId: this.id } }).catch(() => {})
+ const boardId = this.item ? this.item.boardId : this.$route.params.id
+ this.$router.push({ name: 'card', params: { id: boardId, cardId: this.card.id } }).catch(() => {})
},
startEditing(card) {
this.copiedCard = Object.assign({}, card)
diff --git a/src/components/dashboards/Dashboards.vue b/src/components/dashboards/Dashboards.vue
index 58497bb11..beec57d0e 100644
--- a/src/components/dashboards/Dashboards.vue
+++ b/src/components/dashboards/Dashboards.vue
@@ -28,24 +28,29 @@
overdue
-
- {{ card.title }}
+
today
- {{ withDueDashboardGroup.today }}
+
+
+
tomorrow
- {{ withDueDashboardGroup.tomorrow }}
+
+
+
this week
- {{ withDueDashboardGroup.thisWeek }}
+
+
+
@@ -53,26 +58,31 @@
overdue
- {{ card.title }}
+
today
- {{ assignedCardsDashboardGroup.today }}
+
+
+
tomorrow
- {{ assignedCardsDashboardGroup.tomorrow }}
+
+
+
this week
- {{ assignedCardsDashboardGroup.thisWeek }}
+
+
+
-
@@ -81,6 +91,7 @@
import Controls from '../Controls'
import CardItem from '../cards/CardItem'
import { mapGetters } from 'vuex'
+import moment from '@nextcloud/moment'
export default {
name: 'Dashboards',
@@ -106,6 +117,9 @@ export default {
return this.groupByDue(this.assignedCardsDashboard)
},
},
+ created() {
+ this.$store.dispatch('loadDashboards')
+ },
methods: {
groupByDue(dataset) {
const all = {
diff --git a/src/services/DashboardApi.js b/src/services/DashboardApi.js
new file mode 100644
index 000000000..7b67980f0
--- /dev/null
+++ b/src/services/DashboardApi.js
@@ -0,0 +1,53 @@
+/*
+ * @copyright Copyright (c) 2020 Jakob Röhrl
+ *
+ * @author Jakob Röhrl
+ *
+ * @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 .
+ *
+ */
+
+import axios from '@nextcloud/axios'
+import { generateOcsUrl, generateRemoteUrl } from '@nextcloud/router'
+
+export class DashboardApi {
+
+ url(url) {
+ url = `/apps/deck${url}`
+ return generateOcsUrl(url)
+ }
+
+ findAllWithDue(data) {
+ return axios.get(this.url(`/api/v1.0/dashboard/dashboard/due`))
+ .then(
+ (response) => Promise.resolve(response.data),
+ (err) => Promise.reject(err)
+ )
+ .catch((err) => Promise.reject(err)
+ )
+ }
+
+ findMyAssignedCards(data) {
+ return axios.get(this.url(`/ocs/v2.php/apps/deck/api/v1.0/dashboard/assigned`))
+ .then(
+ (response) => Promise.resolve(response.data),
+ (err) => Promise.reject(err)
+ )
+ .catch((err) => Promise.reject(err)
+ )
+ }
+
+}
diff --git a/src/store/dashboard.js b/src/store/dashboard.js
index d5d2d030c..d02ddd8d0 100644
--- a/src/store/dashboard.js
+++ b/src/store/dashboard.js
@@ -22,10 +22,10 @@
import Vue from 'vue'
import Vuex from 'vuex'
-import { CardApi } from '../services/CardApi'
+import { DashboardApi } from '../services/DashboardApi'
Vue.use(Vuex)
-const apiClient = new CardApi()
+const apiClient = new DashboardApi()
export default {
state: {
withDue: [],
@@ -57,7 +57,7 @@ export default {
const assignedCards = await apiClient.findMyAssignedCards()
const assignedCardsFlat = assignedCards.flat()
commit('setAssignedCards', assignedCardsFlat)
-
+
},
},
}
From 014d7aa8fff9d52bffc3c48651c7a52f3289f760 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Julius=20H=C3=A4rtl?=
Date: Mon, 13 Jul 2020 09:50:59 +0200
Subject: [PATCH 05/13] Fix api routes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Julius Härtl
---
lib/Controller/DashboardApiController.php | 10 ++++++----
src/services/DashboardApi.js | 11 +++++++----
2 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/lib/Controller/DashboardApiController.php b/lib/Controller/DashboardApiController.php
index df989b8c8..58f029de2 100644
--- a/lib/Controller/DashboardApiController.php
+++ b/lib/Controller/DashboardApiController.php
@@ -25,6 +25,8 @@ namespace OCA\Deck\Controller;
use OCA\Deck\Service\DashboardService;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\OCSController;
use OCP\IRequest;
use OCP\AppFramework\Controller;
@@ -40,17 +42,17 @@ class DashboardApiController extends OCSController {
/**
* @NoAdminRequired
- * @return array
+ * @return DataResponse
*/
public function findAllWithDue($userId) {
- return $this->dashboardService->findAllWithDue($userId);
+ return new DataResponse($this->dashboardService->findAllWithDue($userId));
}
/**
* @NoAdminRequired
- * @return array
+ * @return DataResponse
*/
public function findAssignedCards($userId) {
- return $this->dashboardService->findAssignedCards($userId);
+ return new DataResponse($this->dashboardService->findAssignedCards($userId));
}
}
diff --git a/src/services/DashboardApi.js b/src/services/DashboardApi.js
index 7b67980f0..acf8311c5 100644
--- a/src/services/DashboardApi.js
+++ b/src/services/DashboardApi.js
@@ -26,12 +26,13 @@ import { generateOcsUrl, generateRemoteUrl } from '@nextcloud/router'
export class DashboardApi {
url(url) {
- url = `/apps/deck${url}`
- return generateOcsUrl(url)
+ return generateOcsUrl(`apps/deck/api/v1.0`) + url
}
findAllWithDue(data) {
- return axios.get(this.url(`/api/v1.0/dashboard/dashboard/due`))
+ return axios.get(this.url(`dashboard/dashboard/due`), {
+ headers: { 'OCS-APIRequest': 'true' },
+ })
.then(
(response) => Promise.resolve(response.data),
(err) => Promise.reject(err)
@@ -41,7 +42,9 @@ export class DashboardApi {
}
findMyAssignedCards(data) {
- return axios.get(this.url(`/ocs/v2.php/apps/deck/api/v1.0/dashboard/assigned`))
+ return axios.get(this.url(`dashboard/assigned`), {
+ headers: { 'OCS-APIRequest': 'true' },
+ })
.then(
(response) => Promise.resolve(response.data),
(err) => Promise.reject(err)
From 818ffa2d57fa9a3c5f62305188798366f1d5a782 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakob=20R=C3=B6hrl?=
Date: Mon, 13 Jul 2020 10:57:24 +0200
Subject: [PATCH 06/13] ocs route
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: Jakob Röhrl
---
appinfo/routes.php | 2 +-
src/components/cards/CardBadges.vue | 2 +-
src/components/cards/CardItem.vue | 2 +-
src/components/cards/CardMenu.vue | 12 ++++--
src/components/dashboards/Dashboards.vue | 55 ++++++++++++++++++------
src/services/DashboardApi.js | 8 ++--
6 files changed, 58 insertions(+), 23 deletions(-)
diff --git a/appinfo/routes.php b/appinfo/routes.php
index 506cebd7b..4a4e4d5f9 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -136,7 +136,7 @@ return [
['name' => 'comments_api#delete', 'url' => '/api/v1.0/cards/{cardId}/comments/{commentId}', 'verb' => 'DELETE'],
// dashboard
- ['name' => 'dashboard_api#findAllWithDue', 'url' => '/api/v1.0/dashboard/dashboard/due', 'verb' => 'GET'],
+ ['name' => 'dashboard_api#findAllWithDue', 'url' => '/api/v1.0/dashboard/due', 'verb' => 'GET'],
['name' => 'dashboard_api#findAssignedCards', 'url' => '/api/v1.0/dashboard/assigned', 'verb' => 'GET'],
]
];
\ No newline at end of file
diff --git a/src/components/cards/CardBadges.vue b/src/components/cards/CardBadges.vue
index 59b124615..d019bb1e3 100644
--- a/src/components/cards/CardBadges.vue
+++ b/src/components/cards/CardBadges.vue
@@ -34,7 +34,7 @@
-
+