Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to save the log of a chat #1256

Closed
wants to merge 9 commits into from
18 changes: 18 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,24 @@
'token' => '^[a-z0-9]{4,30}$',
],
],
[
'name' => 'Chat#setReadMarker',
'url' => '/api/{apiVersion}/chat/{token}/read',
'verb' => 'POST',
'requirements' => [
'apiVersion' => 'v1',
'token' => '^[a-z0-9]{4,30}$',
],
],
[
'name' => 'Chat#saveChatLog',
'url' => '/api/{apiVersion}/chat/{token}/log',
'verb' => 'POST',
'requirements' => [
'apiVersion' => 'v1',
'token' => '^[a-z0-9]{4,30}$',
],
],
[
'name' => 'Chat#mentions',
'url' => '/api/{apiVersion}/chat/{token}/mentions',
Expand Down
20 changes: 20 additions & 0 deletions docs/api-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
- [Chat](#chat)
* [Receive chat messages of a room](#receive-chat-messages-of-a-room)
* [Sending a new chat message](#sending-a-new-chat-message)
* [Mark chat as read](#mark-chat-as-read)
* [Get mention autocomplete suggestions](#get-mention-autocomplete-suggestions)
- [Guests](#guests)
* [Set display name](#set-display-name)
- [Signaling](#signaling)
Expand Down Expand Up @@ -81,6 +83,7 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
### 5.0
* `invite-by-mail` - Guests can be invited with their email address
* `notification-levels` - Users can select when they want to be notified in conversations
* `new-chat-flow` - The read marker for the chat needs to be set manually, see [Better chat flow experience](https://github.com/nextcloud/spreed/issues/1164)

## Room management

Expand Down Expand Up @@ -145,6 +148,7 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
`notificationLevel` | int | The notification level for the user (one of `Participant::NOTIFY_*` (1-3))
`unreadMessages` | int | Number of unread chat messages in the room (only available with `chat-v2` capability)
`unreadMention` | bool | Flag if the user was mentioned since their last visit
`lastReadMessage` | int | ID of the last read message in a room
`lastMessage` | message | Last message in a room if available, otherwise empty
`objectType` | string | The type of object that the room is associated with; "share:password" if the room is used to request a password for a share, otherwise empty
`objectId` | string | Share token if "objectType" is "share:password", otherwise empty
Expand Down Expand Up @@ -570,6 +574,22 @@ Base endpoint is: `/ocs/v2.php/apps/spreed/api/v1`
- Data:
The full message array of the new message, as defined in [Receive chat messages of a room](#receive-chat-messages-of-a-room)

### Mark chat as read

* Method: `POST`
* Endpoint: `/chat/{token}/read`
* Data:

field | type | Description
------|------|------------
`lastReadMessage` | int | The last read message ID

* Response:
- Header:
+ `200 OK`
+ `404 Not Found` When the room could not be found for the participant,
or the participant is a guest.

### Get mention autocomplete suggestions

* Method: `GET`
Expand Down
2 changes: 1 addition & 1 deletion js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@
});
this._sidebarView.setCallInfoView(callInfoView);

this._messageCollection.setRoomToken(this.activeRoom.get('token'));
this._messageCollection.setRoomToken(this.activeRoom.get('token'), this.activeRoom.get('lastReadMessage'));
this._messageCollection.receiveMessages();
},
setPageTitle: function(title){
Expand Down
6 changes: 4 additions & 2 deletions js/models/chatmessagecollection.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,13 @@
* explicitly called if needed.
*
* @param {?string} token the token of the room.
* @param {?int} lastReadMessage the last read message in that room
*/
setRoomToken: function(token) {
setRoomToken: function(token, lastReadMessage) {
this.stopReceivingMessages();

this.token = token;
this.lastReadMessage = lastReadMessage || 0;

if (token !== null) {
this.signaling = OCA.SpreedMe.app.signaling;
Expand All @@ -103,7 +105,7 @@
receiveMessages: function() {
if (this.signaling) {
this.signaling.on("chatMessagesReceived", this._handler);
this.signaling.startReceiveMessages();
this.signaling.startReceiveMessages(this.lastReadMessage);
}
},

Expand Down
4 changes: 2 additions & 2 deletions js/signaling.js
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,10 @@
return defer;
};

OCA.Talk.Signaling.Base.prototype.startReceiveMessages = function() {
OCA.Talk.Signaling.Base.prototype.startReceiveMessages = function(lastKnownMessageId) {
this._waitTimeUntilRetry = 1;
this.receiveMessagesAgain = true;
this.lastKnownMessageId = 0;
this.lastKnownMessageId = lastKnownMessageId;

this._receiveChatMessages();
};
Expand Down
1 change: 1 addition & 0 deletions lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public function getCapabilities(): array {
'in-call-flags',
'invite-by-mail',
'notification-levels',
'new-chat-flow',
],
],
];
Expand Down
30 changes: 15 additions & 15 deletions lib/Chat/ChatManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public function sendMessage(Room $chat, $actorType, $actorId, $message, \DateTim

$mentionedUsers = $this->notifier->notifyMentionedUsers($chat, $comment);
if (!empty($mentionedUsers)) {
$chat->markUsersAsMentioned($mentionedUsers, $creationDateTime);
$chat->markUsersAsMentioned($notifiedUsers, (int) $comment->getId());
}

// User was not mentioned, send a normal notification
Expand All @@ -139,16 +139,21 @@ public function sendMessage(Room $chat, $actorType, $actorId, $message, \DateTim
return $comment;
}

public function getUnreadMarker(Room $chat, IUser $user): \DateTime {
public function getLastReadMessageFromLegacy(Room $chat, IUser $user): int {
$marker = $this->commentsManager->getReadMark('chat', $chat->getId(), $user);
if ($marker === null) {
$marker = new \DateTime('2000-01-01');
return 0;
}
return $marker;

return $this->getLastMessageBeforeDate($chat, $marker);
}

public function getLastMessageBeforeDate(Room $chat, \DateTime $dateTime): int {
return $this->commentsManager->getLastCommentBeforeDate('chat', (string) $chat->getId(), $dateTime, 'comment');
}

public function getUnreadCount(Room $chat, \DateTime $unreadSince): int {
return $this->commentsManager->getNumberOfCommentsForObject('chat', $chat->getId(), $unreadSince, 'comment');
public function getUnreadCount(Room $chat, int $lastReadMessage): int {
return $this->commentsManager->getNumberOfCommentsForObjectSinceComment('chat', (string) $chat->getId(), $lastReadMessage, 'comment');
}

/**
Expand All @@ -157,12 +162,12 @@ public function getUnreadCount(Room $chat, \DateTime $unreadSince): int {
* @param Room $chat
* @param int $offset Last known message id
* @param int $limit
* @param string $sort
* @return IComment[] the messages found (only the id, actor type and id,
* creation date and message are relevant), or an empty array if the
* timeout expired.
* creation date and message are relevant)
*/
public function getHistory(Room $chat, $offset, $limit): array {
return $this->commentsManager->getForObjectSince('chat', (string) $chat->getId(), $offset, 'desc', $limit);
public function getHistory(Room $chat, int $offset, int $limit, string $sort = 'desc'): array {
return $this->commentsManager->getForObjectSince('chat', (string) $chat->getId(), $offset, strtolower($sort), $limit);
}

/**
Expand Down Expand Up @@ -191,11 +196,6 @@ public function waitForNewMessages(Room $chat, $offset, $limit, $timeout, $user)
$elapsedTime = 0;

$comments = $this->commentsManager->getForObjectSince('chat', (string) $chat->getId(), $offset, 'asc', $limit);

if ($user instanceof IUser) {
$this->commentsManager->setReadMark('chat', (string) $chat->getId(), new \DateTime(), $user);
}

while (empty($comments) && $elapsedTime < $timeout) {
sleep(1);
$elapsedTime++;
Expand Down
39 changes: 39 additions & 0 deletions lib/Chat/CommentsManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,43 @@ public function getLastCommentDateByActor(

return $lastComments;
}

public function getNumberOfCommentsForObjectSinceComment(string $objectType, string $objectId, int $lastRead, string $verb = ''): int {
$query = $this->dbConn->getQueryBuilder();
$query->selectAlias($query->createFunction('COUNT(' . $query->getColumnName('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)));

if ($verb !== '') {
$query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
}

$result = $query->execute();
$data = $result->fetch();
$result->closeCursor();

return isset($data['num_messages']) ? (int) $data['num_messages'] : 0;
}

public function getLastCommentBeforeDate(string $objectType, string $objectId, \DateTime $beforeDate, string $verb = ''): int {
$query = $this->dbConn->getQueryBuilder();
$query->select('id')
->from('comments')
->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
->andWhere($query->expr()->lt('creation_timestamp', $query->createNamedParameter($beforeDate, IQueryBuilder::PARAM_DATE)))
->orderBy('creation_timestamp', 'desc');

if ($verb !== '') {
$query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
}

$result = $query->execute();
$data = $result->fetch();
$result->closeCursor();

return (int) ($data['id'] ?? 0);
}
}
Loading