Skip to content

Commit

Permalink
Added ability to mark card as done
Browse files Browse the repository at this point in the history
Closes #534

Signed-off-by: Thanos Kamber <thanos.kamber@gmail.com>
  • Loading branch information
TehThanos authored and juliusknorr committed Nov 8, 2023
1 parent 93e5ee7 commit c3b4ed6
Show file tree
Hide file tree
Showing 18 changed files with 406 additions and 20 deletions.
2 changes: 2 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
['name' => 'card#reorder', 'url' => '/cards/{cardId}/reorder', 'verb' => 'PUT'],
['name' => 'card#archive', 'url' => '/cards/{cardId}/archive', 'verb' => 'PUT'],
['name' => 'card#unarchive', 'url' => '/cards/{cardId}/unarchive', 'verb' => 'PUT'],
['name' => 'card#done', 'url' => '/cards/{cardId}/done', 'verb' => 'PUT'],
['name' => 'card#undone', 'url' => '/cards/{cardId}/undone', 'verb' => 'PUT'],
['name' => 'card#assignLabel', 'url' => '/cards/{cardId}/label/{labelId}', 'verb' => 'POST'],
['name' => 'card#removeLabel', 'url' => '/cards/{cardId}/label/{labelId}', 'verb' => 'DELETE'],
['name' => 'card#assignUser', 'url' => '/cards/{cardId}/assign', 'verb' => 'POST'],
Expand Down
7 changes: 7 additions & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ The board list endpoint supports setting an `If-Modified-Since` header to limit
"owner":"admin",
"order":999,
"archived":false,
"done":false,
"duedate": "2019-12-24T19:29:30+00:00",
"deletedAt":0,
"commentsUnread":0,
Expand Down Expand Up @@ -628,17 +629,23 @@ The board list endpoint supports setting an `If-Modified-Since` header to limit
| title | String | The title of the card, maximum length is limited to 255 characters |
| description | String | The markdown description of the card |
| type | String | Type of the card (for later use) use 'plain' for now |
| owner | String | The user that owns the card |
| order | Integer | Order for sorting the stacks |
| duedate | timestamp | The ISO-8601 formatted duedate of the card or null |
| archived | bool | Whether the card is archived or not |
| done | bool | Whether the card is marked as done or not |


```
{
"title": "Test card",
"description": "A card description",
"type": "plain",
"owner": "admin",
"order": 999,
"duedate": "2019-12-24T19:29:30+00:00",
"archived": false,
"done": false,
}
```

Expand Down
31 changes: 19 additions & 12 deletions docs/User_documentation_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ Overall, Deck is easy to use. You can create boards, add users, share the Deck,
1. [Create my first board](#1-create-my-first-board)
2. [Create stacks and cards](#2-create-stacks-and-cards)
3. [Handle cards options](#3-handle-cards-options)
4. [Archive old tasks](#4-archive-old-tasks)
5. [Manage your board](#5-manage-your-board)
6. [Import boards](#6-import-boards)
7. [Search](#7-search)
8. [New owner for the deck entities](#8-new-owner-for-the-deck-entities)
4. [Mark task as done](#4-mark-as-done)
5. [Archive old tasks](#5-archive-old-tasks)
6. [Manage your board](#6-manage-your-board)
7. [Import boards](#7-import-boards)
8. [Search](#8-search)
9. [New owner for the deck entities](#9-new-owner-for-the-deck-entities)

### 1. Create my first board
In this example, we're going to create a board and share it with an other nextcloud user.
Expand Down Expand Up @@ -53,12 +54,18 @@ And even :

![Gif for puting infos on tasks 2](resources/gifs/EN_put_infos_2.gif)

### 4. Archive old tasks
Once finished or obsolete, a task could be archived. The tasks is not deleted, it's just archived, and you can retrieve it later
### 4. Mark as done
Once a task has been completed, you can mark it as done. This will prevent it from becoming overdue and hide it from the upcoming cards.
You can mark it as not done at any time.

![Gif for puting infos on tasks 2](resources/gifs/EN_archive.gif)
![Gif for marking a card as done](resources/gifs/EN_done.gif)

### 5. Manage your board
### 5. Archive old tasks
Once obsolete, a task could be archived. The task is not deleted, it's just archived, and you can retrieve it later

![Gif for archiving a task](resources/gifs/EN_archive.gif)

### 6. Manage your board
You can manage the settings of your Deck once you are inside it, by clicking on the small wheel at the top right.
Once in this menu, you have access to several things:

Expand All @@ -72,7 +79,7 @@ The **sharing tab** allows you to add users or even groups to your boards.
**Deleted objects** allows you to return previously deleted stacks or cards.
The **Timeline** allows you to see everything that happened in your boards. Everything!

### 6. Import boards
### 7. Import boards

Importing can be done using the API or the `occ` `deck:import` command.

Expand Down Expand Up @@ -138,7 +145,7 @@ Example configuration file:
}
```

### 7. Search
### 8. Search

Deck provides a global search either through the unified search in the Nextcloud header or with the inline search next to the board controls.
This search allows advanced filtering of cards across all board of the logged in user.
Expand All @@ -161,7 +168,7 @@ Other text tokens will be used to perform a case-insensitive search on the card

In addition, quotes can be used to pass a query with spaces, e.g. `"Exact match with spaces"` or `title:"My card"`.

### 8. New owner for the deck entities
### 9. New owner for the deck entities
You can transfer ownership of boards, cards, etc to a new user, using `occ` command `deck:transfer-ownership`

```bash
Expand Down
Binary file added docs/resources/gifs/EN_done.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions lib/Activity/ActivityManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ class ActivityManager {
public const SUBJECT_CARD_UPDATE_DUEDATE = 'card_update_duedate';
public const SUBJECT_CARD_UPDATE_ARCHIVE = 'card_update_archive';
public const SUBJECT_CARD_UPDATE_UNARCHIVE = 'card_update_unarchive';
public const SUBJECT_CARD_UPDATE_DONE = 'card_update_done';
public const SUBJECT_CARD_UPDATE_UNDONE = 'card_update_undone';
public const SUBJECT_CARD_UPDATE_STACKID = 'card_update_stackId';
public const SUBJECT_CARD_USER_ASSIGN = 'card_user_assign';
public const SUBJECT_CARD_USER_UNASSIGN = 'card_user_unassign';
Expand Down Expand Up @@ -198,6 +200,12 @@ public function getActivityFormat($language, $subjectIdentifier, $subjectParams
case self::SUBJECT_CARD_UPDATE_UNARCHIVE:
$subject = $ownActivity ? $l->t('You have unarchived card {card} in list {stack} on board {board}') : $l->t('{user} has unarchived card {card} in list {stack} on board {board}');
break;
case self::SUBJECT_CARD_UPDATE_DONE:
$subject = $ownActivity ? $l->t('You have marked the card {card} as done in list {stack} on board {board}') : $l->t('{user} has marked card {card} as done in list {stack} on board {board}');
break;
case self::SUBJECT_CARD_UPDATE_UNDONE:
$subject = $ownActivity ? $l->t('You have marked the card {card} as undone in list {stack} on board {board}') : $l->t('{user} has marked the card {card} as undone in list {stack} on board {board}');
break;
case self::SUBJECT_CARD_UPDATE_DUEDATE:
if (!isset($subjectParams['after'])) {
$subject = $ownActivity ? $l->t('You have removed the due date of card {card}') : $l->t('{user} has removed the due date of card {card}');
Expand Down Expand Up @@ -357,6 +365,8 @@ private function createEvent($objectType, $entity, $subject, $additionalParams =
case self::SUBJECT_CARD_DELETE:
case self::SUBJECT_CARD_UPDATE_ARCHIVE:
case self::SUBJECT_CARD_UPDATE_UNARCHIVE:
case self::SUBJECT_CARD_UPDATE_DONE:
case self::SUBJECT_CARD_UPDATE_UNDONE:
case self::SUBJECT_CARD_UPDATE_TITLE:
case self::SUBJECT_CARD_UPDATE_DESCRIPTION:
case self::SUBJECT_CARD_UPDATE_DUEDATE:
Expand Down
4 changes: 2 additions & 2 deletions lib/Controller/CardApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ public function create($title, $type = 'plain', $order = 999, $description = '',
*
* Update a card
*/
public function update($title, $type, $owner, $description = '', $order = 0, $duedate = null, $archived = null) {
$card = $this->cardService->update($this->request->getParam('cardId'), $title, $this->request->getParam('stackId'), $type, $owner, $description, $order, $duedate, 0, $archived);
public function update($title, $type, $owner, $description = '', $order = 0, $duedate = null, $archived = null, ?bool $done = null) {
$card = $this->cardService->update($this->request->getParam('cardId'), $title, $this->request->getParam('stackId'), $type, $owner, $description, $order, $duedate, 0, $archived, $done);
return new DataResponse($card, HTTP::STATUS_OK);
}

Expand Down
18 changes: 18 additions & 0 deletions lib/Controller/CardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,24 @@ public function unarchive($cardId) {
return $this->cardService->unarchive($cardId);
}

/**
* @NoAdminRequired
* @param $cardId
* @return \OCP\AppFramework\Db\Entity
*/
public function done(int $cardId) {
return $this->cardService->done($cardId);
}

/**
* @NoAdminRequired
* @param $cardId
* @return \OCP\AppFramework\Db\Entity
*/
public function undone(int $cardId) {
return $this->cardService->undone($cardId);
}

/**
* @NoAdminRequired
* @param $cardId
Expand Down
2 changes: 2 additions & 0 deletions lib/Db/Card.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class Card extends RelationalEntity {
protected $owner;
protected $order;
protected $archived = false;
protected $done = false;
protected $duedate;
protected $notified = false;
protected $deletedAt = 0;
Expand All @@ -106,6 +107,7 @@ public function __construct() {
$this->addType('lastModified', 'integer');
$this->addType('createdAt', 'integer');
$this->addType('archived', 'boolean');
$this->addType('done', 'boolean');
$this->addType('notified', 'boolean');
$this->addType('deletedAt', 'integer');
$this->addType('duedate', 'datetime');
Expand Down
3 changes: 3 additions & 0 deletions lib/Db/CardMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ public function findAllWithDue(array $boardIds) {
->where($qb->expr()->in('s.board_id', $qb->createNamedParameter($boardIds, IQueryBuilder::PARAM_INT_ARRAY)))
->andWhere($qb->expr()->isNotNull('c.duedate'))
->andWhere($qb->expr()->eq('c.archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
->andWhere($qb->expr()->eq('c.done', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
->andWhere($qb->expr()->eq('c.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('s.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('b.archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
Expand All @@ -284,6 +285,7 @@ public function findToMeOrNotAssignedCards(array $boardIds, string $username) {
)
// Filter out archived/deleted cards and board
->andWhere($qb->expr()->eq('c.archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
->andWhere($qb->expr()->eq('c.done', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
->andWhere($qb->expr()->eq('c.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('s.deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('b.archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
Expand All @@ -298,6 +300,7 @@ public function findOverdue() {
->where($qb->expr()->lt('duedate', $qb->createFunction('NOW()')))
->andWhere($qb->expr()->eq('notified', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
->andWhere($qb->expr()->eq('archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
->andWhere($qb->expr()->eq('done', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
->andWhere($qb->expr()->eq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
return $this->findEntities($qb);
}
Expand Down
60 changes: 60 additions & 0 deletions lib/Migration/Version1011Date20230901010840.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2023 Thanos kamber <thanos.kamber@gmail.com>
*
* @author Thanos kamber <thanos.kamber@gmail.com>
*
* @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\Migration;

use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

/**
* Auto-generated migration step: Please modify to your needs!
*/
class Version1011Date20230901010840 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure $schemaClosure
* @param array $options
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();

$table = $schema->getTable('deck_cards');
if (!$table->hasColumn('done')) {
$table->addColumn('done', 'boolean', [
'default' => false,
'notnull' => true,
]);

return $schema;
}

return null;
}
}
59 changes: 58 additions & 1 deletion lib/Service/CardService.php
Original file line number Diff line number Diff line change
Expand Up @@ -284,14 +284,17 @@ public function delete($id) {
* @param $description
* @param $order
* @param $duedate
* @param $deletedAt
* @param $archived
* @param $done
* @return \OCP\AppFramework\Db\Entity
* @throws StatusException
* @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException
*/
public function update($id, $title, $stackId, $type, $owner, $description = '', $order = 0, $duedate = null, $deletedAt = null, $archived = null) {
public function update($id, $title, $stackId, $type, $owner, $description = '', $order = 0, $duedate = null, $deletedAt = null, $archived = null, ?bool $done = null) {
$this->cardServiceValidator->check(compact('id', 'title', 'stackId', 'type', 'owner', 'order'));

$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
Expand Down Expand Up @@ -341,6 +344,9 @@ public function update($id, $title, $stackId, $type, $owner, $description = '',
if ($archived !== null) {
$card->setArchived($archived);
}
if ($done !== null) {
$card->setDone($done);
}


// Trigger update events before setting description as it is handled separately
Expand Down Expand Up @@ -511,6 +517,57 @@ public function unarchive($id) {
return $newCard;
}

/**
* @param $id
* @return \OCA\Deck\Db\Card
* @throws StatusException
* @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException
*/
public function done(int $id): Card {
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
if ($this->boardService->isArchived($this->cardMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$card = $this->cardMapper->find($id);
$card->setDone(true);
$newCard = $this->cardMapper->update($card);
$this->notificationHelper->markDuedateAsRead($card);
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $newCard, ActivityManager::SUBJECT_CARD_UPDATE_DONE);
$this->changeHelper->cardChanged($id, false);

$this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card));

return $newCard;
}

/**
* @param $id
* @return \OCA\Deck\Db\Card
* @throws StatusException
* @throws \OCA\Deck\NoPermissionException
* @throws \OCP\AppFramework\Db\DoesNotExistException
* @throws \OCP\AppFramework\Db\MultipleObjectsReturnedException
* @throws BadRequestException
*/
public function undone(int $id): Card {
$this->permissionService->checkPermission($this->cardMapper, $id, Acl::PERMISSION_EDIT);
if ($this->boardService->isArchived($this->cardMapper, $id)) {
throw new StatusException('Operation not allowed. This board is archived.');
}
$card = $this->cardMapper->find($id);
$card->setDone(false);
$newCard = $this->cardMapper->update($card);
$this->activityManager->triggerEvent(ActivityManager::DECK_OBJECT_CARD, $newCard, ActivityManager::SUBJECT_CARD_UPDATE_UNDONE);
$this->changeHelper->cardChanged($id, false);

$this->eventDispatcher->dispatchTyped(new CardUpdatedEvent($card));

return $newCard;
}

/**
* @param $cardId
* @param $labelId
Expand Down
Loading

0 comments on commit c3b4ed6

Please sign in to comment.