Skip to content

Commit

Permalink
feat(federation): Mark conversation as directly mentioned for federat…
Browse files Browse the repository at this point in the history
…ed users

Signed-off-by: Joas Schilling <coding@schilljs.com>
  • Loading branch information
nickvergessen committed Feb 28, 2024
1 parent ce0cf49 commit cd72339
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 16 deletions.
24 changes: 20 additions & 4 deletions lib/Chat/ChatManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,25 +177,31 @@ public function addSystemMessage(
if ($sendNotifications) {
/** @var ?IComment $captionComment */
$captionComment = null;
$alreadyNotifiedUsers = $usersDirectlyMentioned = [];
$alreadyNotifiedUsers = $usersDirectlyMentioned = $federatedUsersDirectlyMentioned = [];
if ($messageType === 'file_shared') {
if (isset($messageDecoded['parameters']['metaData']['caption'])) {
$captionComment = clone $comment;
$captionComment->setMessage($messageDecoded['parameters']['metaData']['caption'], self::MAX_CHAT_LENGTH);
$usersDirectlyMentioned = $this->notifier->getMentionedUserIds($captionComment);
$federatedUsersDirectlyMentioned = $this->notifier->getMentionedCloudIds($captionComment);
}
if ($replyTo instanceof IComment) {
$alreadyNotifiedUsers = $this->notifier->notifyReplyToAuthor($chat, $comment, $replyTo, $silent);
if ($replyTo->getActorType() === Attendee::ACTOR_USERS) {
$usersDirectlyMentioned[] = $replyTo->getActorId();
} elseif ($replyTo->getActorType() === Attendee::ACTOR_FEDERATED_USERS) {
$federatedUsersDirectlyMentioned[] = $replyTo->getActorId();
}
}
}

$alreadyNotifiedUsers = $this->notifier->notifyMentionedUsers($chat, $captionComment ?? $comment, $alreadyNotifiedUsers, $silent);
if (!empty($alreadyNotifiedUsers)) {
$userIds = array_column($alreadyNotifiedUsers, 'id');
$this->participantService->markUsersAsMentioned($chat, $userIds, (int) $comment->getId(), $usersDirectlyMentioned);
$this->participantService->markUsersAsMentioned($chat, Attendee::ACTOR_USERS, $userIds, (int) $comment->getId(), $usersDirectlyMentioned);
}
if (!empty($federatedUsersDirectlyMentioned)) {
$this->participantService->markUsersAsMentioned($chat, Attendee::ACTOR_FEDERATED_USERS, $federatedUsersDirectlyMentioned, (int) $comment->getId(), $federatedUsersDirectlyMentioned);
}

$this->notifier->notifyOtherParticipant($chat, $comment, [], $silent);
Expand Down Expand Up @@ -326,17 +332,23 @@ public function sendMessage(Room $chat, ?Participant $participant, string $actor

$alreadyNotifiedUsers = [];
$usersDirectlyMentioned = $this->notifier->getMentionedUserIds($comment);
$federatedUsersDirectlyMentioned = $this->notifier->getMentionedCloudIds($comment);
if ($replyTo instanceof IComment) {
$alreadyNotifiedUsers = $this->notifier->notifyReplyToAuthor($chat, $comment, $replyTo, $silent);
if ($replyTo->getActorType() === Attendee::ACTOR_USERS) {
$usersDirectlyMentioned[] = $replyTo->getActorId();
} elseif ($replyTo->getActorType() === Attendee::ACTOR_FEDERATED_USERS) {
$federatedUsersDirectlyMentioned[] = $replyTo->getActorId();
}
}

$alreadyNotifiedUsers = $this->notifier->notifyMentionedUsers($chat, $comment, $alreadyNotifiedUsers, $silent);
if (!empty($alreadyNotifiedUsers)) {
$userIds = array_column($alreadyNotifiedUsers, 'id');
$this->participantService->markUsersAsMentioned($chat, $userIds, (int) $comment->getId(), $usersDirectlyMentioned);
$this->participantService->markUsersAsMentioned($chat, Attendee::ACTOR_USERS, $userIds, (int) $comment->getId(), $usersDirectlyMentioned);
}
if (!empty($federatedUsersDirectlyMentioned)) {
$this->participantService->markUsersAsMentioned($chat, Attendee::ACTOR_FEDERATED_USERS, $federatedUsersDirectlyMentioned, (int) $comment->getId(), $federatedUsersDirectlyMentioned);
}

// User was not mentioned, send a normal notification
Expand Down Expand Up @@ -561,12 +573,16 @@ public function editMessage(Room $chat, IComment $comment, Participant $particip

if (!empty($addedMentions)) {
$usersDirectlyMentionedAfter = $this->notifier->getMentionedUserIds($comment);
$federatedUsersDirectlyMentionedAfter = $this->notifier->getMentionedCloudIds($comment);
$addedUsersDirectMentioned = array_diff($usersDirectlyMentionedAfter, $usersDirectlyMentionedBefore);

$alreadyNotifiedUsers = $this->notifier->notifyMentionedUsers($chat, $comment, $usersToNotifyBefore, silent: false);
if (!empty($alreadyNotifiedUsers)) {
$userIds = array_column($alreadyNotifiedUsers, 'id');
$this->participantService->markUsersAsMentioned($chat, $userIds, (int) $comment->getId(), $addedUsersDirectMentioned);
$this->participantService->markUsersAsMentioned($chat, Attendee::ACTOR_USERS, $userIds, (int) $comment->getId(), $addedUsersDirectMentioned);
}
if (!empty($federatedUsersDirectlyMentionedAfter)) {
$this->participantService->markUsersAsMentioned($chat, Attendee::ACTOR_FEDERATED_USERS, $federatedUsersDirectlyMentionedAfter, (int) $comment->getId(), $federatedUsersDirectlyMentionedAfter);
}
}
}
Expand Down
56 changes: 53 additions & 3 deletions lib/Chat/Notifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,21 @@ private function addMentionAllToList(Room $chat, array $list): array {
* @psalm-return array<int, array{id: string, type: string, reason: string}>
*/
public function notifyReplyToAuthor(Room $chat, IComment $comment, IComment $replyTo, bool $silent): array {
if ($replyTo->getActorType() !== Attendee::ACTOR_USERS) {
// No reply notification when the replyTo-author was not a user
if ($replyTo->getActorType() !== Attendee::ACTOR_USERS && $replyTo->getActorType() !== Attendee::ACTOR_FEDERATED_USERS) {
// No reply notification when the replyTo-author was not a user or federated user
return [];
}

if ($replyTo->getActorType() === Attendee::ACTOR_FEDERATED_USERS) {
return [
[
'id' => $replyTo->getActorId(),
'type' => $replyTo->getActorType(),
'reason' => 'reply',
],
];
}

if (!$this->shouldMentionedUserBeNotified($replyTo->getActorId(), $comment, $chat)) {
return [];
}
Expand Down Expand Up @@ -407,6 +417,19 @@ public function getMentionedUserIds(IComment $comment): array {
}, $mentionedUsers);
}

/**
* Returns the cloud IDs of the federated users mentioned in the given comment.
*
* @param IComment $comment
* @return string[] the mentioned cloud IDs
*/
public function getMentionedCloudIds(IComment $comment): array {
$mentionedFederatedUsers = $this->getMentionedFederatedUsers($comment);
return array_map(static function ($mentionedUser) {
return $mentionedUser['id'];
}, $mentionedFederatedUsers);
}

/**
* @param IComment $comment
* @return array[]
Expand All @@ -427,7 +450,34 @@ private function getMentionedUsers(IComment $comment): array {

$mentionedUsers[] = [
'id' => $mention['id'],
'type' => 'users',
'type' => Attendee::ACTOR_USERS,
'reason' => 'direct',
];
}
return $mentionedUsers;
}

/**
* @param IComment $comment
* @return array[]
* @psalm-return array<int, array{type: string, id: string, reason: string}>
*/
private function getMentionedFederatedUsers(IComment $comment): array {
$mentions = $comment->getMentions();

if (empty($mentions)) {
return [];
}

$mentionedUsers = [];
foreach ($mentions as $mention) {
if ($mention['type'] !== 'federated_user') {
continue;
}

$mentionedUsers[] = [
'id' => $mention['id'],
'type' => Attendee::ACTOR_FEDERATED_USERS,
'reason' => 'direct',
];
}
Expand Down
16 changes: 7 additions & 9 deletions lib/Service/ParticipantService.php
Original file line number Diff line number Diff line change
Expand Up @@ -1283,28 +1283,26 @@ public function updateCallFlags(Room $room, Participant $participant, int $flags
}

/**
* @param Room $room
* @param string[] $userIds
* @param int $messageId
* @param string[] $actorIds
* @param string[] $usersDirectlyMentioned
*/
public function markUsersAsMentioned(Room $room, array $userIds, int $messageId, array $usersDirectlyMentioned): void {
public function markUsersAsMentioned(Room $room, string $actorType, array $actorIds, int $messageId, array $actorsDirectlyMentioned): void {
$update = $this->connection->getQueryBuilder();
$update->update('talk_attendees')
->set('last_mention_message', $update->createNamedParameter($messageId, IQueryBuilder::PARAM_INT))
->where($update->expr()->eq('room_id', $update->createNamedParameter($room->getId(), IQueryBuilder::PARAM_INT)))
->andWhere($update->expr()->eq('actor_type', $update->createNamedParameter(Attendee::ACTOR_USERS)))
->andWhere($update->expr()->in('actor_id', $update->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)))
->andWhere($update->expr()->eq('actor_type', $update->createNamedParameter($actorType)))
->andWhere($update->expr()->in('actor_id', $update->createNamedParameter($actorIds, IQueryBuilder::PARAM_STR_ARRAY)))
->andWhere($update->expr()->lt('last_mention_message', $update->createNamedParameter($messageId, IQueryBuilder::PARAM_INT)));
$update->executeStatement();

if (!empty($usersDirectlyMentioned)) {
if (!empty($actorsDirectlyMentioned)) {
$update = $this->connection->getQueryBuilder();
$update->update('talk_attendees')
->set('last_mention_direct', $update->createNamedParameter($messageId, IQueryBuilder::PARAM_INT))
->where($update->expr()->eq('room_id', $update->createNamedParameter($room->getId(), IQueryBuilder::PARAM_INT)))
->andWhere($update->expr()->eq('actor_type', $update->createNamedParameter(Attendee::ACTOR_USERS)))
->andWhere($update->expr()->in('actor_id', $update->createNamedParameter($usersDirectlyMentioned, IQueryBuilder::PARAM_STR_ARRAY)))
->andWhere($update->expr()->eq('actor_type', $update->createNamedParameter($actorType)))
->andWhere($update->expr()->in('actor_id', $update->createNamedParameter($actorsDirectlyMentioned, IQueryBuilder::PARAM_STR_ARRAY)))
->andWhere($update->expr()->lt('last_mention_direct', $update->createNamedParameter($messageId, IQueryBuilder::PARAM_INT)));
$update->executeStatement();
}
Expand Down

0 comments on commit cd72339

Please sign in to comment.