Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/Capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class Capabilities implements IPublicCapability {
'multi-room-users',
'favorites',
'last-room-activity',
'last-metadata-activity',
'no-ping',
'system-messages',
'delete-messages',
Expand Down
8 changes: 4 additions & 4 deletions lib/Chat/ChatManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public function addSystemMessage(
bool $sendNotifications,
?string $referenceId = null,
?IComment $replyTo = null,
bool $shouldSkipLastMessageUpdate = false,
bool $shouldSkipLastMessageUpdate = true,
bool $silent = false,
int $threadId = 0,
): IComment {
Expand Down Expand Up @@ -473,15 +473,15 @@ public function sendMessage(
if (!$fromScheduledMessage && $participant instanceof Participant) {
$this->participantService->updateLastReadMessage($participant, $messageId);
}

// Update last_message
if ($comment->getActorType() !== Attendee::ACTOR_BOTS
|| $comment->getActorId() === Attendee::ACTOR_ID_CHANGELOG
|| str_starts_with((string)$comment->getActorId(), Attendee::ACTOR_BOT_PREFIX)) {
$this->roomService->setLastMessage($chat, $comment);
$this->roomService->setLastMessageInfo($chat, (int)$comment->getId(), $comment->getCreationDateTime());
$this->roomService->setLastMetadataActivity($chat, $comment->getCreationDateTime());
$this->unreadCountCache->clear($chat->getId() . '-');
} else {
$this->roomService->setLastActivity($chat, $comment->getCreationDateTime());
$this->roomService->setLastMetadataActivity($chat, $comment->getCreationDateTime);
}

$alreadyNotifiedUsers = [];
Expand Down
4 changes: 3 additions & 1 deletion lib/Chat/SystemMessage/Listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ protected function fixMimeTypeOfVoiceMessage(ShareCreatedEvent|BeforeDuplicateSh
}

protected function attendeesAddedEvent(AttendeesAddedEvent $event): void {
$event->setShouldSkipLastActivityUpdate(true);
foreach ($event->getAttendees() as $attendee) {
$this->logger->debug($attendee->getActorType() . ' "' . $attendee->getActorId() . '" added to room "' . $event->getRoom()->getToken() . '"', ['app' => 'spreed-bfp']);
if ($attendee->getActorType() === Attendee::ACTOR_GROUPS) {
Expand All @@ -493,6 +494,7 @@ protected function attendeesAddedEvent(AttendeesAddedEvent $event): void {
}

protected function attendeesRemovedEvent(AttendeesRemovedEvent $event): void {
$event->setShouldSkipLastActivityUpdate(true);
foreach ($event->getAttendees() as $attendee) {
$this->logger->debug($attendee->getActorType() . ' "' . $attendee->getActorId() . '" removed from room "' . $event->getRoom()->getToken() . '"', ['app' => 'spreed-bfp']);
if ($attendee->getActorType() === Attendee::ACTOR_GROUPS) {
Expand All @@ -512,7 +514,7 @@ protected function sendSystemMessage(
string $message,
array $parameters = [],
?Participant $participant = null,
bool $shouldSkipLastMessageUpdate = false,
bool $shouldSkipLastMessageUpdate = true,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we keep this we need to check all the calls in this file. E.g. currently posting a file does not update the last message anymore.
Other cases where I would still bump would be: lobby_none, lobby_timer_reached, breakout_rooms_started, breakout_rooms_stopped, call_left, call_joined, call_started, setCallRecording

bool $silent = false,
bool $forceSystemAsActor = false,
?int $replyTo = null,
Expand Down
4 changes: 4 additions & 0 deletions lib/Controller/RoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ public function getRooms(int $noStatusUpdate = 0, bool $includeStatus = false, i
// Include rooms which had activity
return true;
}
if ($room->getLastMetadataActivity() && $room->getLastMetadataActivity()->getTimestamp() >= $modifiedSince) {
// Include rooms which had metadata activity
return true;
}

// Include rooms where only attendee level things changed,
// e.g. favorite, read-marker update, notification setting
Expand Down
2 changes: 1 addition & 1 deletion lib/Controller/ThreadController.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public function getSubscribedThreads(int $limit = 100, int $offset = 0): DataRes
}
}

// Sort by last activity again
// Sort by last message activity again
usort($threads, static function (Thread $a, Thread $b): int {
if ($b->getLastActivity() === $a->getLastActivity()) {
return $b->getId() <=> $a->getId();
Expand Down
1 change: 1 addition & 0 deletions lib/Events/ARoomSyncedEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@

abstract class ARoomSyncedEvent extends ARoomEvent {
public const PROPERTY_LAST_ACTIVITY = 'lastActivity';
public const PROPERTY_LAST_METADATA_ACTIVITY = 'lastMetadataActivity';
}
10 changes: 9 additions & 1 deletion lib/Events/ASystemMessageSentEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function __construct(
?Participant $participant = null,
bool $silent = false,
?IComment $parent = null,
protected bool $skipLastActivityUpdate = false,
private bool $skipLastActivityUpdate = true,
) {
parent::__construct(
$room,
Expand All @@ -44,4 +44,12 @@ public function __construct(
public function shouldSkipLastActivityUpdate(): bool {
return $this->skipLastActivityUpdate;
}

/**
* public setter for shouldSkipLastAcitvityUpdate
* @param bool $pShouldSkipLastActivity
*/
public function setShouldSkipLastActivityUpdate(bool $pShouldSkipLastActivity) {
$this->$skipLastActivityUpdate = $pShouldSkipLastactivity;
Comment on lines +50 to +53

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param bool $pShouldSkipLastActivity
*/
public function setShouldSkipLastActivityUpdate(bool $pShouldSkipLastActivity) {
$this->$skipLastActivityUpdate = $pShouldSkipLastactivity;
*/
public function setShouldSkipLastActivityUpdate(bool $shouldSkipLastActivity) {
$this->skipLastActivityUpdate = $shouldSkipLastActivity;

}
}
6 changes: 5 additions & 1 deletion lib/Events/AttendeesAddedEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class AttendeesAddedEvent extends AttendeesEvent {
public function __construct(
Room $room,
array $attendees,
private readonly bool $skipLastMessageUpdate = false,
private bool $skipLastMessageUpdate = true,
) {
parent::__construct($room, $attendees);
}
Expand All @@ -30,6 +30,10 @@ public function shouldSkipLastMessageUpdate(): bool {
return $this->skipLastMessageUpdate;
}

public function setShouldSkipLastActivityUpdate(bool $pShouldSkipLastActivityUpdate) {
$this->shouldSkipLastMessageUpdate = $pShouldSkipLastActivityUpdate;
Comment on lines +33 to +34

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public function setShouldSkipLastActivityUpdate(bool $pShouldSkipLastActivityUpdate) {
$this->shouldSkipLastMessageUpdate = $pShouldSkipLastActivityUpdate;
public function setShouldSkipLastMessageUpdate(bool $shouldSkipLastMessageUpdate) {
$this->shouldSkipLastMessageUpdate = $shouldSkipLastMessageUpdate;

}

public function setLastMessage(IComment $lastMessage): void {
$this->lastMessage = $lastMessage;
}
Expand Down
10 changes: 10 additions & 0 deletions lib/Events/AttendeesRemovedEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,14 @@
namespace OCA\Talk\Events;

class AttendeesRemovedEvent extends AttendeesEvent {

private bool $shouldSkipLastMessageUpdate = true;

public function shouldSkipLastMessageUpdate() : bool {
return $this->shouldSkipLastMessageUpdate;
}

public function setShouldSkipLastActivityUpdate(bool $pShouldSkipLastActivityUpdate) {
$this->shouldSkipLastMessageUpdate = $pShouldSkipLastActivityUpdate;
}
}
7 changes: 7 additions & 0 deletions lib/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public function createRoomObjectFromData(array $data): Room {
'call_flag' => 0,
'active_since' => null,
'last_activity' => null,
'last_metadata_activity' => null,
'last_message' => 0,
'comment_id' => null,
'lobby_timer' => null,
Expand Down Expand Up @@ -135,6 +136,10 @@ public function createRoomObject(array $row): Room {
if (!empty($row['last_activity'])) {
$lastActivity = $this->timeFactory->getDateTime($row['last_activity']);
}
$lastMetadataActivity = null;
if (!empty($row['last_metadata_activity'])) {
$lastMetadataActivity = $this->timeFactory->getDateTime($row['last_metadata_activity']);
}

$lobbyTimer = null;
if (!empty($row['lobby_timer'])) {
Expand Down Expand Up @@ -171,6 +176,7 @@ public function createRoomObject(array $row): Room {
(int)$row['call_flag'],
$activeSince,
$lastActivity,
$lastMetadataActivity,
(int)$row['last_message'],
$lastMessage,
$lobbyTimer,
Expand Down Expand Up @@ -321,6 +327,7 @@ public function getInactiveRooms(\DateTime $inactiveSince): array {
$helper->selectRoomsTable($query);
$query->from('talk_rooms', 'r')
->andWhere($query->expr()->lte('r.last_activity', $query->createNamedParameter($inactiveSince, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
->andWhere($query->expr()->lte('r.last_metadata_activity', $query->createNamedParameter($inactiveSince, IQueryBuilder::PARAM_DATETIME_MUTABLE)))
->andWhere($query->expr()->neq('r.read_only', $query->createNamedParameter(Room::READ_ONLY, IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->in('r.type', $query->createNamedParameter([Room::TYPE_PUBLIC, Room::TYPE_GROUP], IQueryBuilder::PARAM_INT_ARRAY)))
->andWhere($query->expr()->emptyString('remoteServer'))
Expand Down
65 changes: 65 additions & 0 deletions lib/Migration/Version24000Date20260510193300.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Talk\Migration;

use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use Override;

class Version24000Date20260510193300 extends SimpleMigrationStep {

public function __construct(
private readonly IDBConnection $connection,
) {
}

/**
* @param IOutput $output
* @param Closure(): ISchemaWrapper $schemaClosure
* @param array $options
* @return null|ISchemaWrapper
*/
#[Override]
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();

$table = $schema->getTable('talk_rooms');

if (!$table->hasColumn('last_metadata_activity')) {
$table->addColumn('last_metadata_activity', Types::DATETIME, [
'notnull' => false,
]);
$table->addIndex(['last_metadata_activity'], 'talkroom_lastmetadataactive');

}

return $schema;
}

/**
* @param IOutput $output
* @param Closure(): ISchemaWrapper $schemaClosure
* @param array $options
*/
#[Override]
public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) : void {
$update = $this->connection->getQueryBuilder();
$update->update('talk_rooms')
->set('last_metadata_activity', 'last_activity');
$update->executeStatement();
}

}
8 changes: 6 additions & 2 deletions lib/ResponseDefinitions.php
Original file line number Diff line number Diff line change
Expand Up @@ -503,8 +503,10 @@
* isCustomAvatar: bool,
* // Flag if the conversation is favorited by the user
* isFavorite: bool,
* // Timestamp of the last activity in the conversation, in seconds and UTC time zone
* // Timestamp of the last message activity in the conversation, in seconds and UTC time zone
* lastActivity: int,
* // Timestamp of the last activity (metadata, not messages) in the conversation, in seconds and UTC time zone
* lastMetadataActivity: int
* // ID of the last message read by every user that has read privacy set to public in a room. When the user themself has it set to private the value is `0` (only available with `chat-read-status` capability)
* lastCommonReadMessage: int,
* // Last message in a conversation if available, otherwise empty. **Note:** Even when given the message will not contain the `parent` or `reactionsSelf` attribute due to performance reasons
Expand Down Expand Up @@ -725,8 +727,10 @@
* title: string,
* // ID of the last message in the thread
* lastMessageId: non-negative-int,
* // UNIX timestamp of the last activity in the thread
* // UNIX timestamp of the last message activity in the thread
* lastActivity: non-negative-int,
* // UNIX timestamp of the last metadata, not message, activity in the thread
Comment thread
sudormant marked this conversation as resolved.
* lastMetadataActivity: int
Comment on lines +732 to +733

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you reverted the thread change by now, so this sould be reverted as well

* // Number of replies in the thread
* numReplies: non-negative-int,
* }
Expand Down
8 changes: 8 additions & 0 deletions lib/Room.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ public function __construct(
private int $callFlag,
private ?\DateTime $activeSince,
private ?\DateTime $lastActivity,
private ?\DateTime $lastMetadataActivity,
private int $lastMessageId,
private ?IComment $lastMessage,
private ?\DateTime $lobbyTimer,
Expand Down Expand Up @@ -314,6 +315,13 @@ public function getLastActivity(): ?\DateTime {
public function setLastActivity(\DateTime $now): void {
$this->lastActivity = $now;
}
public function getLastMetadataActivity(): ?\DateTime {
return $this->lastMetadataActivity;
}

public function setLastMetadataActivity(\DateTime $now): void {
$this->lastMetadataActivity = $now;
}

public function getLastMessageId(): int {
return $this->lastMessageId;
Expand Down
2 changes: 1 addition & 1 deletion lib/Service/BreakoutRoomService.php
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ protected function setAssistanceRequest(Room $breakoutRoom, int $status): void {
}

$this->roomService->setBreakoutRoomStatus($breakoutRoom, $status);
$this->roomService->setLastActivity($breakoutRoom, $this->timeFactory->getDateTime());
$this->roomService->setLastMetadataActivity($breakoutRoom, $this->timeFactory->getDateTime());
}

/**
Expand Down
25 changes: 20 additions & 5 deletions lib/Service/ParticipantService.php
Original file line number Diff line number Diff line change
Expand Up @@ -737,25 +737,37 @@ public function addUsers(Room $room, array $participants, ?IUser $addedBy = null
$event = new AttendeesAddedEvent($room, $attendees, true);
$this->dispatcher->dispatchTyped($event);

$lastMessage = $event->getLastMessage();
if ($lastMessage instanceof IComment) {
$this->updateRoomLastMessage($room, $lastMessage);
// getLastMessage doesn't exist for all event types, e.g. room creation
if (($event->getLastMessage() ?? null) !== null) {
$lastMessage = $event->getLastMessage();
// TODO: is there any better getter / way to access message type?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this whole logic is "local" to the event. so it only contains last messages of adding users and can be applied/skipped unconditionally.

$lastMessageType = json_decode($lastMessage->getMessage(), true)['message'] ?? '';
if ($lastMessage instanceof IComment || !in_array($lastMessageType, ['user_added', 'user_removed', 'moderator_promoted', 'moderator_demoted'], true)) {
// do not update the room message to the status message, so the conversion / thread will not be bumped by activity to the top
// left to do is to update the last message in the preview in the room list, without bumping it up.
} elseif ($lastMessage instanceof IComment) {
$this->updateRoomLastMessage($room, $lastMessage);
}
}
$now = $this->timeFactory->getDateTime();
$room->setLastMetadataActivity($now);

return $attendees;
}

protected function updateRoomLastMessage(Room $room, IComment $message): void {
/** @var RoomService $roomService */
$roomService = Server::get(RoomService::class);
$roomService->setLastMessage($room, $message);
$roomService->setLastMessageInfo($room, (int)$message->getId(), $message->getCreationDateTime());
$now = $this->timeFactory->getDateTime();
$room->setLastMetadataActivity($now);

$lastMessageCache = $this->cacheFactory->createDistributed(CachePrefix::CHAT_LAST_MESSAGE_ID);
$lastMessageCache->remove($room->getToken());
$unreadCountCache = $this->cacheFactory->createDistributed(CachePrefix::CHAT_UNREAD_COUNT);
$unreadCountCache->clear($room->getId() . '-');

$event = new SystemMessagesMultipleSentEvent($room, $message);
$event = new SystemMessagesMultipleSentEvent($room, $message, skipLastActivityUpdate: true);
$this->dispatcher->dispatchTyped($event);
}

Expand Down Expand Up @@ -1255,6 +1267,9 @@ public function removeUser(Room $room, IUser $user, string $reason): void {
return;
}

$now = $this->timeFactory->getDateTime();
$room->setLastMetadataActivity($now);

$attendee = $participant->getAttendee();
$sessions = $this->sessionService->getAllSessionsForAttendee($attendee);

Expand Down
9 changes: 9 additions & 0 deletions lib/Service/RoomFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public function formatRoomV4(
'callRecording' => Room::RECORDING_NONE,
'canStartCall' => false,
'lastActivity' => 0,
'lastMetadataActivity' => 0,
'lastReadMessage' => 0,
'unreadMessages' => 0,
'unreadMention' => false,
Expand Down Expand Up @@ -172,6 +173,12 @@ public function formatRoomV4(
} else {
$lastActivity = 0;
}
$lastMetadataActivity = $room->getLastMetadataActivity();
if ($lastMetadataActivity instanceof \DateTimeInterface) {
$lastMetadataActivity = $lastMetadataActivity->getTimestamp();
} else {
$lastMetadataActivity = 0;
}

$this->roomService->validateLobbyTimer($room);

Expand All @@ -195,6 +202,7 @@ public function formatRoomV4(
'readOnly' => $room->getReadOnly(),
'hasCall' => $room->getActiveSince() instanceof \DateTimeInterface,
'lastActivity' => $lastActivity,
'lastMetadataActivity' => $lastMetadataActivity,
'callFlag' => $room->getCallFlag(),
'lobbyState' => $room->getLobbyState(),
'lobbyTimer' => $lobbyTimer,
Expand Down Expand Up @@ -227,6 +235,7 @@ public function formatRoomV4(
'callRecording' => $room->getCallRecording(),
'recordingConsent' => $this->talkConfig->recordingConsentRequired() === RecordingService::CONSENT_REQUIRED_OPTIONAL ? $room->getRecordingConsent() : $this->talkConfig->recordingConsentRequired(),
'lastActivity' => $lastActivity,
'lastMetadataActivity' => $lastMetadataActivity,
'callFlag' => $room->getCallFlag(),
'isFavorite' => $attendee->isFavorite(),
'notificationLevel' => $attendee->getNotificationLevel(),
Expand Down
Loading