From 02d842f8abee7d9a2494183ddf4170fbd0fbc3c9 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 26 Nov 2021 15:54:58 +0100 Subject: Recognize voice messages, object and file shares as unread messages Signed-off-by: Joas Schilling --- lib/Chat/ChatManager.php | 12 ++++++++++-- lib/Chat/CommentsManager.php | 26 ++++++++++++++++++++++++++ lib/Chat/MessageParser.php | 7 ++++++- tests/php/Chat/ChatManagerTest.php | 4 ++-- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/lib/Chat/ChatManager.php b/lib/Chat/ChatManager.php index ec38cc887..da9947024 100644 --- a/lib/Chat/ChatManager.php +++ b/lib/Chat/ChatManager.php @@ -141,7 +141,15 @@ class ChatManager { if ($parentId !== null) { $comment->setParentId((string) $parentId); } - $comment->setVerb('system'); + + $messageDecoded = json_decode($message, true); + $messageType = $messageDecoded['message'] ?? ''; + + if ($messageType === 'object_shared' || $messageType === 'file_shared') { + $comment->setVerb('object_shared'); + } else { + $comment->setVerb('system'); + } $event = new ChatEvent($chat, $comment); $this->dispatcher->dispatch(self::EVENT_BEFORE_SYSTEM_MESSAGE_SEND, $event); @@ -359,7 +367,7 @@ class ChatManager { $key = $chat->getId() . '-' . $lastReadMessage; $unreadCount = $this->unreadCountCache->get($key); if ($unreadCount === null) { - $unreadCount = $this->commentsManager->getNumberOfCommentsForObjectSinceComment('chat', (string) $chat->getId(), $lastReadMessage, 'comment'); + $unreadCount = $this->commentsManager->getNumberOfCommentsWithVerbsForObjectSinceComment('chat', (string) $chat->getId(), $lastReadMessage, ['comment', 'object_shared']); $this->unreadCountCache->set($key, $unreadCount, 1800); } return $unreadCount; diff --git a/lib/Chat/CommentsManager.php b/lib/Chat/CommentsManager.php index 12a758e86..8ad4f849b 100644 --- a/lib/Chat/CommentsManager.php +++ b/lib/Chat/CommentsManager.php @@ -26,6 +26,7 @@ namespace OCA\Talk\Chat; use OC\Comments\Comment; use OC\Comments\Manager; use OCP\Comments\IComment; +use OCP\DB\QueryBuilder\IQueryBuilder; class CommentsManager extends Manager { /** @@ -39,4 +40,29 @@ class CommentsManager extends Manager { $comment->setMessage($message, ChatManager::MAX_CHAT_LENGTH); return $comment; } + + /** + * TODO Remove when server version with https://github.com/nextcloud/server/pull/29921 is required + * + * @param string $objectType + * @param string $objectId + * @param int $lastRead + * @param string[] $verbs + * @return int + */ + public function getNumberOfCommentsWithVerbsForObjectSinceComment(string $objectType, string $objectId, int $lastRead, array $verbs): int { + $query = $this->dbConn->getQueryBuilder(); + $query->select($query->func()->count('id', 'num_messages')) + ->from('comments') + ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType))) + ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId))) + ->andWhere($query->expr()->gt('id', $query->createNamedParameter($lastRead))) + ->andWhere($query->expr()->in('verb', $query->createNamedParameter($verbs, IQueryBuilder::PARAM_STR_ARRAY))); + + $result = $query->executeQuery(); + $data = $result->fetch(); + $result->closeCursor(); + + return (int) ($data['num_messages'] ?? 0); + } } diff --git a/lib/Chat/MessageParser.php b/lib/Chat/MessageParser.php index ff944c2f4..db142107e 100644 --- a/lib/Chat/MessageParser.php +++ b/lib/Chat/MessageParser.php @@ -64,7 +64,12 @@ class MessageParser { public function parseMessage(Message $message): void { $message->setMessage($message->getComment()->getMessage(), []); - $message->setMessageType($message->getComment()->getVerb()); + + $verb = $message->getComment()->getVerb(); + if ($verb === 'object_shared') { + $verb = 'system'; + } + $message->setMessageType($verb); $this->setActor($message); $event = new ChatMessageEvent($message); diff --git a/tests/php/Chat/ChatManagerTest.php b/tests/php/Chat/ChatManagerTest.php index 123d15982..ad6cbd7c4 100644 --- a/tests/php/Chat/ChatManagerTest.php +++ b/tests/php/Chat/ChatManagerTest.php @@ -369,8 +369,8 @@ class ChatManagerTest extends TestCase { ->willReturn(23); $this->commentsManager->expects($this->once()) - ->method('getNumberOfCommentsForObjectSinceComment') - ->with('chat', 23, 42, 'comment'); + ->method('getNumberOfCommentsWithVerbsForObjectSinceComment') + ->with('chat', 23, 42, ['comment', 'object_shared']); $this->chatManager->getUnreadCount($chat, 42); } -- cgit v1.2.3 From d6b17bb0cc0cca2a36c1f25237b79bf539975e2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Calvi=C3=B1o=20S=C3=A1nchez?= Date: Wed, 1 Dec 2021 18:51:38 +0100 Subject: Add integration tests for unread messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Daniel Calviño Sánchez --- .../features/bootstrap/FeatureContext.php | 3 + .../features/chat/unread-messages.feature | 135 +++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 tests/integration/features/chat/unread-messages.feature diff --git a/tests/integration/features/bootstrap/FeatureContext.php b/tests/integration/features/bootstrap/FeatureContext.php index 37cba477b..fbee7a073 100644 --- a/tests/integration/features/bootstrap/FeatureContext.php +++ b/tests/integration/features/bootstrap/FeatureContext.php @@ -314,6 +314,9 @@ class FeatureContext implements Context, SnippetAcceptingContext { if (isset($expectedRoom['lastMessage'])) { $data['lastMessage'] = $room['lastMessage'] ? $room['lastMessage']['message'] : ''; } + if (isset($expectedRoom['unreadMessages'])) { + $data['unreadMessages'] = (int) $room['unreadMessages']; + } if (isset($expectedRoom['unreadMention'])) { $data['unreadMention'] = (int) $room['unreadMention']; } diff --git a/tests/integration/features/chat/unread-messages.feature b/tests/integration/features/chat/unread-messages.feature new file mode 100644 index 000000000..e6db18eba --- /dev/null +++ b/tests/integration/features/chat/unread-messages.feature @@ -0,0 +1,135 @@ +Feature: chat/unread-messages + Background: + Given user "participant1" exists + Given user "participant2" exists + + Scenario: sending a message clears unread counter for sender + Given user "participant1" creates room "group room" (v4) + | roomType | 2 | + | roomName | room | + And user "participant1" adds user "participant2" to room "group room" with 200 (v4) + When user "participant1" sends message "Message 1" to room "group room" with 201 + Then user "participant1" is participant of room "group room" (v4) + | unreadMessages | + | 0 | + And user "participant2" is participant of room "group room" (v4) + | unreadMessages | + | 1 | + + Scenario: sending several messages clears unread counter for sender + Given user "participant1" creates room "group room" (v4) + | roomType | 2 | + | roomName | room | + And user "participant1" adds user "participant2" to room "group room" with 200 (v4) + When user "participant1" sends message "Message 1" to room "group room" with 201 + And user "participant1" sends message "Message 2" to room "group room" with 201 + And user "participant1" sends message "Message 3" to room "group room" with 201 + Then user "participant1" is participant of room "group room" (v4) + | unreadMessages | + | 0 | + And user "participant2" is participant of room "group room" (v4) + | unreadMessages | + | 3 | + + Scenario: sending a message with previously unread messages clears unread counter for sender + Given user "participant1" creates room "group room" (v4) + | roomType | 2 | + | roomName | room | + And user "participant1" adds user "participant2" to room "group room" with 200 (v4) + And user "participant2" sends message "Message 1" to room "group room" with 201 + And user "participant2" sends message "Message 2" to room "group room" with 201 + When user "participant1" sends message "Message 3" to room "group room" with 201 + Then user "participant1" is participant of room "group room" (v4) + | unreadMessages | + | 0 | + And user "participant2" is participant of room "group room" (v4) + | unreadMessages | + | 1 | + + + + Scenario: reading all messages clears unread counter for reader + Given user "participant1" creates room "group room" (v4) + | roomType | 2 | + | roomName | room | + And user "participant1" adds user "participant2" to room "group room" with 200 (v4) + And user "participant1" sends message "Message 1" to room "group room" with 201 + And user "participant1" sends message "Message 2" to room "group room" with 201 + And user "participant1" sends message "Message 3" to room "group room" with 201 + When user "participant2" reads message "Message 3" in room "group room" with 200 + Then user "participant2" is participant of room "group room" (v4) + | unreadMessages | + | 0 | + + Scenario: reading some messages reduces unread counter for reader + Given user "participant1" creates room "group room" (v4) + | roomType | 2 | + | roomName | room | + And user "participant1" adds user "participant2" to room "group room" with 200 (v4) + And user "participant1" sends message "Message 1" to room "group room" with 201 + And user "participant1" sends message "Message 2" to room "group room" with 201 + And user "participant1" sends message "Message 3" to room "group room" with 201 + When user "participant2" reads message "Message 2" in room "group room" with 200 + Then user "participant2" is participant of room "group room" (v4) + | unreadMessages | + | 1 | + + + + Scenario: replies are taken into account in unread counter + Given user "participant1" creates room "group room" (v4) + | roomType | 2 | + | roomName | room | + And user "participant1" adds user "participant2" to room "group room" with 200 (v4) + And user "participant1" sends message "Message 1" to room "group room" with 201 + When user "participant1" sends reply "Message 1-1" on message "Message 1" to room "group room" with 201 + Then user "participant1" is participant of room "group room" (v4) + | unreadMessages | + | 0 | + And user "participant2" is participant of room "group room" (v4) + | unreadMessages | + | 2 | + + Scenario: rich object messages are taken into account in unread counter + Given user "participant1" creates room "group room" (v4) + | roomType | 2 | + | roomName | room | + And user "participant1" adds user "participant2" to room "group room" with 200 (v4) + When user "participant1" shares rich-object "call" "R4nd0mT0k3n" '{"name":"Another room","call-type":"group"}' to room "group room" with 201 (v1) + Then user "participant1" is participant of room "group room" (v4) + | unreadMessages | + | 0 | + And user "participant2" is participant of room "group room" (v4) + | unreadMessages | + | 1 | + + Scenario: shared file messages are taken into account in unread counter + Given user "participant1" creates room "group room" (v4) + | roomType | 2 | + | roomName | room | + And user "participant1" adds user "participant2" to room "group room" with 200 (v4) + When user "participant1" shares "welcome.txt" with room "group room" + # Unread counter for sender is not cleared in this case, as it is not + # possible to know whether the file was shared from Talk, which could clear + # the counter, or from the Files app, which should not clear it. + Then user "participant1" is participant of room "group room" (v4) + | unreadMessages | + | 1 | + And user "participant2" is participant of room "group room" (v4) + | unreadMessages | + | 1 | + + + + Scenario: system messages are not taken into account in unread counter + Given user "participant1" creates room "group room" (v4) + | roomType | 2 | + | roomName | room | + And user "participant1" adds user "participant2" to room "group room" with 200 (v4) + When user "participant1" makes room "group room" private with 200 (v4) + Then user "participant1" is participant of room "group room" (v4) + | unreadMessages | + | 0 | + And user "participant2" is participant of room "group room" (v4) + | unreadMessages | + | 0 | -- cgit v1.2.3 From bd1f460cd7e5c1bf9fced4674128a3eee9e93ba5 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Tue, 7 Dec 2021 10:42:55 +0100 Subject: Fix psalm Signed-off-by: Joas Schilling --- lib/Chat/ChatManager.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Chat/ChatManager.php b/lib/Chat/ChatManager.php index da9947024..92fd17fe4 100644 --- a/lib/Chat/ChatManager.php +++ b/lib/Chat/ChatManager.php @@ -64,7 +64,8 @@ class ChatManager { public const GEO_LOCATION_VALIDATOR = '/^geo:-?\d{1,2}(\.\d+)?,-?\d{1,3}(\.\d+)?(,-?\d+(\.\d+)?)?(;crs=wgs84)?(;u=\d+(\.\d+)?)?$/i'; - /** @var ICommentsManager */ + /** @var ICommentsManager|CommentsManager + */ private $commentsManager; /** @var IEventDispatcher */ private $dispatcher; -- cgit v1.2.3