Skip to content

Commit 6b86d8a

Browse files
authored
Merge pull request #709 from nextcloud/enhancement/noid/activity-settings
Add dedicated setting for description change activities
2 parents e1080ff + 4279e09 commit 6b86d8a

File tree

12 files changed

+216
-21
lines changed

12 files changed

+216
-21
lines changed

appinfo/database.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@
135135
<type>clob</type>
136136
<notnull>false</notnull>
137137
</field>
138+
<field>
139+
<name>description_prev</name>
140+
<type>clob</type>
141+
<notnull>false</notnull>
142+
</field>
138143
<field>
139144
<name>stack_id</name>
140145
<type>integer</type>
@@ -155,6 +160,12 @@
155160
<notnull>false</notnull>
156161
<unsigned>true</unsigned>
157162
</field>
163+
<field>
164+
<name>last_editor</name>
165+
<type>text</type>
166+
<notnull>false</notnull>
167+
<length>64</length>
168+
</field>
158169
<field>
159170
<name>created_at</name>
160171
<type>integer</type>

appinfo/info.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
- 🚀 Get your project organized
1818

1919
</description>
20-
<version>0.5.0</version>
20+
<version>0.5.1-dev2</version>
2121
<licence>agpl</licence>
2222
<author>Julius Härtl</author>
2323
<namespace>Deck</namespace>
@@ -41,6 +41,7 @@
4141
<background-jobs>
4242
<job>OCA\Deck\Cron\DeleteCron</job>
4343
<job>OCA\Deck\Cron\ScheduledNotifications</job>
44+
<job>OCA\Deck\Cron\CardDescriptionActivity</job>
4445
</background-jobs>
4546
<repair-steps>
4647
<post-migration>
@@ -53,6 +54,7 @@
5354
<activity>
5455
<settings>
5556
<setting>OCA\Deck\Activity\Setting</setting>
57+
<setting>OCA\Deck\Activity\DescriptionSetting</setting>
5658
</settings>
5759
<filters>
5860
<filter>OCA\Deck\Activity\Filter</filter>

lib/Activity/ActivityManager.php

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,12 @@ public function getActivityFormat($subjectIdentifier, $subjectParams = [], $ownA
239239
return $subject;
240240
}
241241

242-
public function triggerEvent($objectType, $entity, $subject, $additionalParams = []) {
242+
public function triggerEvent($objectType, $entity, $subject, $additionalParams = [], $author = null) {
243243
try {
244-
$event = $this->createEvent($objectType, $entity, $subject, $additionalParams);
245-
$this->sendToUsers($event);
244+
$event = $this->createEvent($objectType, $entity, $subject, $additionalParams, $author);
245+
if ($event !== null) {
246+
$this->sendToUsers($event);
247+
}
246248
} catch (\Exception $e) {
247249
// Ignore exception for undefined activities on update events
248250
}
@@ -262,23 +264,25 @@ public function triggerUpdateEvents($objectType, ChangeSet $changeSet, $subject)
262264
if ($previousEntity !== null) {
263265
foreach ($entity->getUpdatedFields() as $field => $value) {
264266
$getter = 'get' . ucfirst($field);
265-
$subject = $subject . '_' . $field;
267+
$subjectComplete = $subject . '_' . $field;
266268
$changes = [
267269
'before' => $previousEntity->$getter(),
268270
'after' => $entity->$getter()
269271
];
270272
if ($changes['before'] !== $changes['after']) {
271273
try {
272-
$event = $this->createEvent($objectType, $entity, $subject, $changes);
273-
$events[] = $event;
274+
$event = $this->createEvent($objectType, $entity, $subjectComplete, $changes);
275+
if ($event !== null) {
276+
$events[] = $event;
277+
}
274278
} catch (\Exception $e) {
275279
// Ignore exception for undefined activities on update events
276280
}
277281
}
278282
}
279283
} else {
280284
try {
281-
$events = [$this->createEvent($objectType, $entity, $subject)];
285+
$events = [$this->createEvent($objectType, $entity, $subject, $author)];
282286
} catch (\Exception $e) {
283287
// Ignore exception for undefined activities on update events
284288
}
@@ -293,10 +297,10 @@ public function triggerUpdateEvents($objectType, ChangeSet $changeSet, $subject)
293297
* @param $entity
294298
* @param $subject
295299
* @param array $additionalParams
296-
* @return IEvent
300+
* @return IEvent|null
297301
* @throws \Exception
298302
*/
299-
private function createEvent($objectType, $entity, $subject, $additionalParams = []) {
303+
private function createEvent($objectType, $entity, $subject, $additionalParams = [], $author = null) {
300304
try {
301305
$object = $this->findObjectForEntity($objectType, $entity);
302306
} catch (DoesNotExistException $e) {
@@ -309,6 +313,7 @@ private function createEvent($objectType, $entity, $subject, $additionalParams =
309313
* Automatically fetch related details for subject parameters
310314
* depending on the subject
311315
*/
316+
$eventType = 'deck';
312317
$subjectParams = [];
313318
$message = null;
314319
switch ($subject) {
@@ -371,7 +376,12 @@ private function createEvent($objectType, $entity, $subject, $additionalParams =
371376
}
372377

373378
if ($subject === self::SUBJECT_CARD_UPDATE_DESCRIPTION){
379+
$card = $subjectParams['card'];
380+
if ($card->getLastEditor() === $this->userId) {
381+
return null;
382+
}
374383
$subjectParams['diff'] = true;
384+
$eventType = 'deck_card_description';
375385
}
376386
if ($subject === self::SUBJECT_CARD_UPDATE_STACKID) {
377387
$subjectParams['stackBefore'] = $this->stackMapper->find($additionalParams['before']);
@@ -382,8 +392,8 @@ private function createEvent($objectType, $entity, $subject, $additionalParams =
382392

383393
$event = $this->manager->generateEvent();
384394
$event->setApp('deck')
385-
->setType('deck')
386-
->setAuthor($this->userId)
395+
->setType($eventType)
396+
->setAuthor($author === null ? $this->userId : $author)
387397
->setObject($objectType, (int)$object->getId(), $object->getTitle())
388398
->setSubject($subject, array_merge($subjectParams, $additionalParams))
389399
->setTimestamp(time());

lib/Activity/DescriptionSetting.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/**
3+
* @copyright Copyright (c) 2018 Julius Härtl <[email protected]>
4+
*
5+
* @author Julius Härtl <[email protected]>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
namespace OCA\Deck\Activity;
25+
26+
27+
class DescriptionSetting extends Setting {
28+
29+
/**
30+
* @return string Lowercase a-z and underscore only identifier
31+
* @since 11.0.0
32+
*/
33+
public function getIdentifier() {
34+
return 'deck_card_description';
35+
}
36+
37+
/**
38+
* @return string A translated string
39+
* @since 11.0.0
40+
*/
41+
public function getName() {
42+
return $this->l->t('A <strong>card description</strong> inside the Deck app has been changed');
43+
}
44+
45+
}

lib/Activity/Setting.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,20 @@
2424
namespace OCA\Deck\Activity;
2525

2626

27+
use OCP\IL10N;
28+
2729
class Setting implements \OCP\Activity\ISetting {
2830

31+
/** @var IL10N */
32+
protected $l;
33+
34+
/**
35+
* @param IL10N $l
36+
*/
37+
public function __construct(IL10N $l) {
38+
$this->l = $l;
39+
}
40+
2941
/**
3042
* @return string Lowercase a-z and underscore only identifier
3143
* @since 11.0.0
@@ -39,7 +51,7 @@ public function getIdentifier() {
3951
* @since 11.0.0
4052
*/
4153
public function getName() {
42-
return 'Deck';
54+
return $this->l->t('Changes in the <strong>Deck app</strong>');
4355
}
4456

4557
/**

lib/Cron/CardDescriptionActivity.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
/**
3+
* @copyright Copyright (c) 2018 Julius Härtl <[email protected]>
4+
*
5+
* @author Julius Härtl <[email protected]>
6+
*
7+
* @license GNU AGPL version 3 or any later version
8+
*
9+
* This program is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Affero General Public License as
11+
* published by the Free Software Foundation, either version 3 of the
12+
* License, or (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU Affero General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Affero General Public License
20+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21+
*
22+
*/
23+
24+
25+
namespace OCA\Deck\Cron;
26+
27+
use OC\BackgroundJob\Job;
28+
use OCA\Deck\Activity\ActivityManager;
29+
use OCA\Deck\Activity\ChangeSet;
30+
use OCA\Deck\Db\AttachmentMapper;
31+
use OCA\Deck\Db\BoardMapper;
32+
use OCA\Deck\Db\Card;
33+
use OCA\Deck\Db\CardMapper;
34+
use OCA\Deck\InvalidAttachmentType;
35+
use OCA\Deck\Service\AttachmentService;
36+
use OCA\Deck\Service\CardService;
37+
38+
class CardDescriptionActivity extends Job {
39+
40+
/** @var ActivityManager */
41+
private $activityManager;
42+
/** @var CardMapper */
43+
private $cardMapper;
44+
45+
public function __construct(ActivityManager $activityManager, CardMapper $cardMapper) {
46+
$this->activityManager = $activityManager;
47+
$this->cardMapper = $cardMapper;
48+
}
49+
50+
/**
51+
* @param $argument
52+
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
53+
*/
54+
public function run($argument) {
55+
$cards = $this->cardMapper->findUnexposedDescriptionChances();
56+
foreach ($cards as $card) {
57+
$this->activityManager->triggerEvent(
58+
ActivityManager::DECK_OBJECT_CARD,
59+
$card,
60+
ActivityManager::SUBJECT_CARD_UPDATE_DESCRIPTION,
61+
[
62+
'before' => $card->getDescriptionPrev(),
63+
'after' => $card->getDescription()
64+
],
65+
$card->getLastEditor()
66+
);
67+
68+
$card->setDescriptionPrev(null);
69+
$card->setLastEditor(null);
70+
$this->cardMapper->update($card, false);
71+
}
72+
}
73+
74+
}

lib/Db/Card.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ class Card extends RelationalEntity {
2929

3030
protected $title;
3131
protected $description;
32+
protected $descriptionPrev;
3233
protected $stackId;
3334
protected $type;
3435
protected $lastModified;
36+
protected $lastEditor;
3537
protected $createdAt;
3638
protected $labels;
3739
protected $assignedUsers;
@@ -113,6 +115,7 @@ public function jsonSerialize() {
113115
}
114116
$json['duedate'] = $this->getDuedate(true);
115117
unset($json['notified']);
118+
unset($json['descriptionPrev']);
116119
return $json;
117120
}
118121

lib/Db/CardMapper.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@ public function findOverdue() {
147147
return $this->findEntities($sql);
148148
}
149149

150+
public function findUnexposedDescriptionChances() {
151+
$sql = 'SELECT id,title,duedate,notified,description_prev,last_editor,description from `*PREFIX*deck_cards` WHERE last_editor IS NOT NULL AND description_prev IS NOT NULL';
152+
return $this->findEntities($sql);
153+
}
154+
150155
public function delete(Entity $entity) {
151156
// delete assigned labels
152157
$this->labelMapper->deleteLabelAssignmentsForCard($entity->getId());

lib/Db/ChangeHelper.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,13 @@ class ChangeHelper {
4141
public function __construct(
4242
IDBConnection $db,
4343
ICacheFactory $cacheFactory,
44-
IRequest $request
44+
IRequest $request,
45+
$userId
4546
) {
4647
$this->db = $db;
4748
$this->cache = $cacheFactory->createDistributed('deck_changes');
4849
$this->request = $request;
50+
$this->userId = $userId;
4951
}
5052

5153
public function boardChanged($boardId) {
@@ -61,8 +63,8 @@ public function cardChanged($cardId, $updateCard = true) {
6163
$etag = md5($time . microtime());
6264
$this->cache->set(self::TYPE_CARD . '-' .$cardId, $etag);
6365
if ($updateCard) {
64-
$sql = 'UPDATE `*PREFIX*deck_cards` SET `last_modified` = ? WHERE `id` = ?';
65-
$this->db->executeUpdate($sql, [time(), $cardId]);
66+
$sql = 'UPDATE `*PREFIX*deck_cards` SET `last_modified` = ?, `last_editor` = ? WHERE `id` = ?';
67+
$this->db->executeUpdate($sql, [time(), $this->userId, $cardId]);
6668
}
6769

6870
$sql = 'SELECT s.board_id as id, c.stack_id as stack_id FROM `*PREFIX*deck_stacks` as s inner join `*PREFIX*deck_cards` as c ON c.stack_id = s.id WHERE c.id = ?';

lib/Service/CardService.php

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,18 +259,41 @@ public function update($id, $title, $stackId, $type, $order = 0, $description =
259259
throw new StatusException('Operation not allowed. This card is archived.');
260260
}
261261
$changes = new ChangeSet($card);
262+
if ($card->getLastEditor() !== $this->currentUser && $card->getLastEditor() !== null) {
263+
$this->activityManager->triggerEvent(
264+
ActivityManager::DECK_OBJECT_CARD,
265+
$card,
266+
ActivityManager::SUBJECT_CARD_UPDATE_DESCRIPTION,
267+
[
268+
'before' => $card->getDescriptionPrev(),
269+
'after' => $card->getDescription()
270+
],
271+
$card->getLastEditor()
272+
);
273+
274+
$card->setDescriptionPrev($card->getDescription());
275+
$card->setLastEditor($this->currentUser);
276+
}
262277
$card->setTitle($title);
263278
$card->setStackId($stackId);
264279
$card->setType($type);
265280
$card->setOrder($order);
266281
$card->setOwner($owner);
267-
$card->setDescription($description);
268282
$card->setDuedate($duedate);
269283
$card->setDeletedAt($deletedAt);
284+
285+
// Trigger update events before setting description as it is handled separately
270286
$changes->setAfter($card);
271-
$card = $this->cardMapper->update($card);
272287
$this->activityManager->triggerUpdateEvents(ActivityManager::DECK_OBJECT_CARD, $changes, ActivityManager::SUBJECT_CARD_UPDATE);
273-
$this->changeHelper->cardChanged($card->getId(), false);
288+
289+
if ($card->getDescriptionPrev() === null) {
290+
$card->setDescriptionPrev($card->getDescription());
291+
}
292+
$card->setDescription($description);
293+
294+
295+
$card = $this->cardMapper->update($card);
296+
$this->changeHelper->cardChanged($card->getId(), true);
274297
return $card;
275298
}
276299

0 commit comments

Comments
 (0)