Skip to content

Commit 7c10d9a

Browse files
authored
Merge pull request #2430 from nextcloud/enh/due-notify-settings
2 parents 22d8477 + 229bc87 commit 7c10d9a

18 files changed

Lines changed: 712 additions & 106 deletions

css/icons.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
@include icon-black-white('filter_set', 'deck', 1);
1010
@include icon-black-white('attach', 'deck', 1);
1111
@include icon-black-white('reply', 'deck', 1);
12+
@include icon-black-white('notifications-dark', 'deck', 1);
1213

1314
.icon-toggle-compact-collapsed {
1415
@include icon-color('toggle-view-expand', 'deck', $color-black);

docs/API.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ Returns an array of board items
115115
"deletedAt": 0,
116116
"id": 10,
117117
"lastModified": 1586269585,
118+
"settings": {
119+
"notify-due": "off",
120+
"calendar": true
121+
}
118122
}
119123
]
120124
```
@@ -952,6 +956,77 @@ For now only `deck_file` is supported as an attachment type.
952956
The following endpoints are available through the Nextcloud OCS endpoint, which is available at `/ocs/v2.php/apps/deck/api/v1.0/`.
953957
This has the benefit that both the web UI as well as external integrations can use the same API.
954958

959+
## Config
960+
961+
Deck stores user and app configuration values globally and per board. The GET endpoint allows to fetch the current global configuration while board settings will be exposed through the board element on the regular API endpoints.
962+
963+
### GET /api/v1.0/config - Fetch app configuration values
964+
965+
#### Response
966+
967+
| Config key | Description | Value |
968+
| --- | --- |
969+
| calendar | Determines if the calendar/tasks integration through the CalDAV backend is enabled for the user (boolean) |
970+
| groupLimit | Determines if creating new boards is limited to certain groups of the instance. The resulting output is an array of group objects with the id and the displayname (Admin only)|
971+
972+
```
973+
{
974+
"ocs": {
975+
"meta": {
976+
"status": "ok",
977+
"statuscode": 200,
978+
"message": "OK"
979+
},
980+
"data": {
981+
"calendar": true,
982+
"groupLimit": [
983+
{
984+
"id": "admin",
985+
"displayname": "admin"
986+
}
987+
]
988+
}
989+
}
990+
}
991+
992+
```
993+
994+
### POST /api/v1.0/config/{id}/{key} - Set a config value
995+
996+
997+
#### Request parameters
998+
999+
| Parameter | Type | Description |
1000+
| --------- | ------- | --------------------------------------- |
1001+
| id | Integer | The id of the board |
1002+
| key | String | The config key to set, prefixed with `board:{boardId}:` for board specific settings |
1003+
| value | String | The value that should be stored for the config key |
1004+
1005+
##### Board configuration
1006+
1007+
| Key | Value |
1008+
| --- | ----- |
1009+
| notify-due | `off`, `assigned` or `all` |
1010+
| calendar | Boolean |
1011+
1012+
#### Example request
1013+
1014+
```
1015+
curl -X POST 'https://admin:admin@nextcloud.local/ocs/v2.php/apps/deck/api/v1.0/config/calendar' -H 'Accept: application/json' -H "Content-Type: application/json" -H 'OCS-APIRequest: true' --data-raw '{"value":false}'
1016+
1017+
{
1018+
"ocs": {
1019+
"meta": {
1020+
"status": "ok",
1021+
"statuscode": 200,
1022+
"message": "OK"
1023+
},
1024+
"data": false
1025+
}
1026+
}
1027+
1028+
```
1029+
9551030
## Comments
9561031

9571032
### GET /cards/{cardId}/comments - List comments

img/notifications-dark.svg

Lines changed: 4 additions & 0 deletions
Loading

lib/DAV/CalendarPlugin.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@ class CalendarPlugin implements ICalendarProvider {
3333

3434
/** @var DeckCalendarBackend */
3535
private $backend;
36+
/** @var ConfigService */
37+
private $configService;
3638
/** @var bool */
3739
private $calendarIntegrationEnabled;
3840

3941
public function __construct(DeckCalendarBackend $backend, ConfigService $configService) {
4042
$this->backend = $backend;
43+
$this->configService = $configService;
4144
$this->calendarIntegrationEnabled = $configService->get('calendar');
4245
}
4346

@@ -50,9 +53,12 @@ public function fetchAllForCalendarHome(string $principalUri): array {
5053
return [];
5154
}
5255

56+
$configService = $this->configService;
5357
return array_map(function (Board $board) use ($principalUri) {
5458
return new Calendar($principalUri, 'board-' . $board->getId(), $board, $this->backend);
55-
}, $this->backend->getBoards());
59+
}, array_filter($this->backend->getBoards(), function ($board) use ($configService) {
60+
return $configService->isCalendarEnabled($board->getId());
61+
}));
5662
}
5763

5864
public function hasCalendarInCalendarHome(string $principalUri, string $calendarUri): bool {

lib/Db/AssignedUsersMapper.php

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,35 @@
2121
*
2222
*/
2323

24+
declare(strict_types=1);
2425

2526
namespace OCA\Deck\Db;
2627

28+
use OCA\Deck\NotFoundException;
29+
use OCA\Deck\Service\CirclesService;
2730
use OCP\AppFramework\Db\Entity;
31+
use OCP\AppFramework\Db\QBMapper;
2832
use OCP\IDBConnection;
2933
use OCP\IGroupManager;
3034
use OCP\IUserManager;
3135

32-
class AssignedUsersMapper extends DeckMapper implements IPermissionMapper {
36+
class AssignedUsersMapper extends QBMapper implements IPermissionMapper {
37+
38+
/** @var CardMapper */
3339
private $cardMapper;
40+
/** @var IUserManager */
3441
private $userManager;
35-
/**
36-
* @var IGroupManager
37-
*/
42+
/** @var IGroupManager */
3843
private $groupManager;
44+
/** @var CirclesService */
45+
private $circleService;
3946

40-
public function __construct(IDBConnection $db, CardMapper $cardMapper, IUserManager $userManager, IGroupManager $groupManager) {
47+
public function __construct(IDBConnection $db, CardMapper $cardMapper, IUserManager $userManager, IGroupManager $groupManager, CirclesService $circleService) {
4148
parent::__construct($db, 'deck_assigned_users', AssignedUsers::class);
4249
$this->cardMapper = $cardMapper;
4350
$this->userManager = $userManager;
4451
$this->groupManager = $groupManager;
52+
$this->circleService = $circleService;
4553
}
4654

4755
/**
@@ -51,19 +59,25 @@ public function __construct(IDBConnection $db, CardMapper $cardMapper, IUserMana
5159
* @return array|Entity
5260
*/
5361
public function find($cardId) {
54-
$sql = 'SELECT * FROM `*PREFIX*deck_assigned_users` ' .
55-
'WHERE `card_id` = ?';
56-
$users = $this->findEntities($sql, [$cardId]);
62+
$qb = $this->db->getQueryBuilder();
63+
$qb->select('*')
64+
->from('deck_assigned_users')
65+
->where($qb->expr()->eq('card_id', $qb->createNamedParameter($cardId)));
66+
/** @var AssignedUsers[] $users */
67+
$users = $this->findEntities($qb);
5768
foreach ($users as &$user) {
5869
$this->mapParticipant($user);
5970
}
6071
return $users;
6172
}
6273

6374
public function findByUserId($uid) {
64-
$sql = 'SELECT * FROM `*PREFIX*deck_assigned_users` ' .
65-
'WHERE `participant` = ?';
66-
return $this->findEntities($sql, [$uid]);
75+
$qb = $this->db->getQueryBuilder();
76+
$qb->select('*')
77+
->from('deck_assigned_users')
78+
->where($qb->expr()->eq('participant', $qb->createNamedParameter($uid)));
79+
/** @var AssignedUsers[] $users */
80+
return $this->findEntities($qb);
6781
}
6882

6983

@@ -81,24 +95,43 @@ public function findBoardId($cardId) {
8195
* @param Entity $entity
8296
* @return null|Entity
8397
*/
84-
public function insert(Entity $entity) {
98+
public function insert(Entity $entity): Entity {
8599
$origin = $this->getOrigin($entity);
86-
if ($origin !== null) {
87-
/** @var AssignedUsers $assignment */
88-
$assignment = parent::insert($entity);
89-
$this->mapParticipant($assignment);
90-
return $assignment;
100+
if ($origin === null) {
101+
throw new NotFoundException('No origin found for assignment');
91102
}
92-
return null;
103+
/** @var AssignedUsers $assignment */
104+
$assignment = parent::insert($entity);
105+
$this->mapParticipant($assignment);
106+
return $assignment;
93107
}
94108

95-
public function mapParticipant(AssignedUsers &$assignment) {
109+
public function mapParticipant(AssignedUsers $assignment): void {
96110
$self = $this;
97111
$assignment->resolveRelation('participant', function () use (&$self, &$assignment) {
98112
return $self->getOrigin($assignment);
99113
});
100114
}
101115

116+
public function isUserAssigned($cardId, $userId): bool {
117+
$assignments = $this->find($cardId);
118+
/** @var AssignedUsers $assignment */
119+
foreach ($assignments as $assignment) {
120+
$origin = $this->getOrigin($assignment);
121+
if ($origin instanceof User && $assignment->getParticipant() === $userId) {
122+
return true;
123+
}
124+
if ($origin instanceof Group && $this->groupManager->isInGroup($userId, $assignment->getParticipant())) {
125+
return true;
126+
}
127+
if ($origin instanceof Circle && $this->circleService->isUserInCircle($assignment->getParticipant(), $userId)) {
128+
return true;
129+
}
130+
}
131+
132+
return false;
133+
}
134+
102135
private function getOrigin(AssignedUsers $assignment) {
103136
if ($assignment->getType() === AssignedUsers::TYPE_USER) {
104137
$origin = $this->userManager->get($assignment->getParticipant());
@@ -109,7 +142,7 @@ private function getOrigin(AssignedUsers $assignment) {
109142
return $origin ? new Group($origin) : null;
110143
}
111144
if ($assignment->getType() === AssignedUsers::TYPE_CIRCLE) {
112-
$origin = $this->groupManager->get($assignment->getParticipant());
145+
$origin = $this->circleService->getCircle($assignment->getParticipant());
113146
return $origin ? new Circle($origin) : null;
114147
}
115148
return null;

lib/Db/Board.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class Board extends RelationalEntity {
3737
protected $deletedAt = 0;
3838
protected $lastModified = 0;
3939

40+
protected $settings = [];
41+
4042
public function __construct() {
4143
$this->addType('id', 'integer');
4244
$this->addType('shared', 'integer');
@@ -49,6 +51,7 @@ public function __construct() {
4951
$this->addRelation('users');
5052
$this->addRelation('permissions');
5153
$this->addRelation('stacks');
54+
$this->addRelation('settings');
5255
$this->addResolvable('owner');
5356
$this->shared = -1;
5457
}

lib/Db/CardMapper.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
use Exception;
2727
use OCP\AppFramework\Db\Entity;
28-
2928
use OCP\AppFramework\Db\QBMapper;
3029
use OCP\DB\QueryBuilder\IQueryBuilder;
3130
use OCP\IDBConnection;
@@ -82,7 +81,8 @@ public function update(Entity $entity, $updateModified = true): Entity {
8281
}
8382

8483
// make sure we only reset the notification flag if the duedate changes
85-
if (in_array('duedate', $entity->getUpdatedFields(), true)) {
84+
$updatedFields = $entity->getUpdatedFields();
85+
if (isset($updatedFields['duedate']) && $updatedFields['duedate']) {
8686
try {
8787
/** @var Card $existing */
8888
$existing = $this->find($entity->getId());
@@ -243,6 +243,7 @@ public function findOverdue() {
243243
$qb->select('id','title','duedate','notified')
244244
->from('deck_cards')
245245
->where($qb->expr()->lt('duedate', $qb->createFunction('NOW()')))
246+
->andWhere($qb->expr()->eq('notified', $qb->createNamedParameter(false)))
246247
->andWhere($qb->expr()->eq('archived', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)))
247248
->andWhere($qb->expr()->eq('deleted_at', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)));
248249
return $this->findEntities($qb);

lib/Db/RelationalObject.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,8 @@ public function getObjectSerialization() {
5757
throw new \Exception('jsonSerialize is not implemented on ' . get_class($this));
5858
}
5959
}
60+
61+
public function getPrimaryKey(): string {
62+
return $this->primaryKey;
63+
}
6064
}

0 commit comments

Comments
 (0)