summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJoas Schilling <213943+nickvergessen@users.noreply.github.com>2024-03-06 22:37:58 +0100
committerGitHub <noreply@github.com>2024-03-06 22:37:58 +0100
commit9e5194963281e7e046a6f845bf310b87bbc4a9c3 (patch)
tree4c540f4a16f9eacaf9e8d6eb103df46db3107982 /lib
parent232cb8ee8a4f81ba0a8643233904b6b76c6788b2 (diff)
parentcdc988c7ffc28f212f6df847a02f8136ada0d9ea (diff)
Merge pull request #11691 from nextcloud/feat/11272/notifications
feat(federation): Implement notifications for mentions, reply and full
Diffstat (limited to 'lib')
-rw-r--r--lib/Chat/ChatManager.php29
-rw-r--r--lib/Chat/MessageParser.php26
-rw-r--r--lib/Chat/Parser/SystemMessage.php2
-rw-r--r--lib/Chat/Parser/UserMention.php2
-rw-r--r--lib/Chat/SystemMessage/Listener.php5
-rw-r--r--lib/Controller/ChatController.php2
-rw-r--r--lib/Events/AMessageSentEvent.php5
-rw-r--r--lib/Events/ASystemMessageSentEvent.php4
-rw-r--r--lib/Federation/BackendNotifier.php1
-rw-r--r--lib/Federation/CloudFederationProviderTalk.php39
-rw-r--r--lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php14
-rw-r--r--lib/Federation/Proxy/TalkV1/UserConverter.php22
-rw-r--r--lib/Manager.php10
-rw-r--r--lib/Migration/Version19000Date20240305115243.php63
-rw-r--r--lib/Model/Message.php21
-rw-r--r--lib/Model/ProxyCacheMessage.php (renamed from lib/Model/ProxyCacheMessages.php)32
-rw-r--r--lib/Model/ProxyCacheMessageMapper.php (renamed from lib/Model/ProxyCacheMessagesMapper.php)26
-rw-r--r--lib/Notification/FederationChatNotifier.php140
-rw-r--r--lib/Notification/Notifier.php64
-rw-r--r--lib/Service/RoomFormatter.php6
20 files changed, 430 insertions, 83 deletions
diff --git a/lib/Chat/ChatManager.php b/lib/Chat/ChatManager.php
index 7a731213d..6c0d3b478 100644
--- a/lib/Chat/ChatManager.php
+++ b/lib/Chat/ChatManager.php
@@ -34,6 +34,7 @@ use OCA\Talk\Events\SystemMessageSentEvent;
use OCA\Talk\Exceptions\MessagingNotAllowedException;
use OCA\Talk\Exceptions\ParticipantNotFoundException;
use OCA\Talk\Model\Attendee;
+use OCA\Talk\Model\Message;
use OCA\Talk\Model\Poll;
use OCA\Talk\Participant;
use OCA\Talk\Room;
@@ -165,7 +166,7 @@ class ChatManager {
if ($silent) {
$comment->setMetaData([
- 'silent' => true,
+ Message::METADATA_SILENT => true,
]);
}
@@ -173,7 +174,7 @@ class ChatManager {
$shouldFlush = $this->notificationManager->defer();
- $event = new BeforeSystemMessageSentEvent($chat, $comment, silent: $silent, skipLastActivityUpdate: $shouldSkipLastMessageUpdate);
+ $event = new BeforeSystemMessageSentEvent($chat, $comment, silent: $silent, skipLastActivityUpdate: $shouldSkipLastMessageUpdate, parent: $replyTo);
$this->dispatcher->dispatchTyped($event);
try {
$this->commentsManager->save($comment);
@@ -228,7 +229,7 @@ class ChatManager {
}
}
- $event = new SystemMessageSentEvent($chat, $comment, silent: $silent, skipLastActivityUpdate: $shouldSkipLastMessageUpdate);
+ $event = new SystemMessageSentEvent($chat, $comment, silent: $silent, skipLastActivityUpdate: $shouldSkipLastMessageUpdate, parent: $replyTo);
$this->dispatcher->dispatchTyped($event);
} catch (NotFoundException $e) {
}
@@ -322,11 +323,11 @@ class ChatManager {
if ($silent) {
$comment->setMetaData([
- 'silent' => true,
+ Message::METADATA_SILENT => true,
]);
}
- $event = new BeforeChatMessageSentEvent($chat, $comment, $participant, $silent);
+ $event = new BeforeChatMessageSentEvent($chat, $comment, $participant, $silent, $replyTo);
$this->dispatcher->dispatchTyped($event);
$shouldFlush = $this->notificationManager->defer();
@@ -371,7 +372,7 @@ class ChatManager {
// User was not mentioned, send a normal notification
$this->notifier->notifyOtherParticipant($chat, $comment, $alreadyNotifiedUsers, $silent);
- $event = new ChatMessageSentEvent($chat, $comment, $participant, $silent);
+ $event = new ChatMessageSentEvent($chat, $comment, $participant, $silent, $replyTo);
$this->dispatcher->dispatchTyped($event);
} catch (NotFoundException $e) {
}
@@ -500,11 +501,11 @@ class ChatManager {
$comment->setVerb(self::VERB_MESSAGE_DELETED);
$metaData = $comment->getMetaData() ?? [];
- if (isset($metaData['last_edited_by_type'])) {
+ if (isset($metaData[Message::METADATA_LAST_EDITED_BY_TYPE])) {
unset(
- $metaData['last_edited_by_type'],
- $metaData['last_edited_by_id'],
- $metaData['last_edited_time']
+ $metaData[Message::METADATA_LAST_EDITED_BY_TYPE],
+ $metaData[Message::METADATA_LAST_EDITED_BY_ID],
+ $metaData[Message::METADATA_LAST_EDITED_TIME],
);
$comment->setMetaData($metaData);
}
@@ -557,12 +558,12 @@ class ChatManager {
}
$metaData = $comment->getMetaData() ?? [];
- $metaData['last_edited_by_type'] = $participant->getAttendee()->getActorType();
- $metaData['last_edited_by_id'] = $participant->getAttendee()->getActorId();
- $metaData['last_edited_time'] = $editTime->getTimestamp();
+ $metaData[Message::METADATA_LAST_EDITED_BY_TYPE] = $participant->getAttendee()->getActorType();
+ $metaData[Message::METADATA_LAST_EDITED_BY_ID] = $participant->getAttendee()->getActorId();
+ $metaData[Message::METADATA_LAST_EDITED_TIME] = $editTime->getTimestamp();
$comment->setMetaData($metaData);
- $wasSilent = $metaData['silent'] ?? false;
+ $wasSilent = $metaData[Message::METADATA_SILENT] ?? false;
if (!$wasSilent) {
$mentionsBefore = $comment->getMentions();
diff --git a/lib/Chat/MessageParser.php b/lib/Chat/MessageParser.php
index 77e42316a..de88ab506 100644
--- a/lib/Chat/MessageParser.php
+++ b/lib/Chat/MessageParser.php
@@ -29,6 +29,7 @@ use OCA\Talk\Exceptions\ParticipantNotFoundException;
use OCA\Talk\MatterbridgeManager;
use OCA\Talk\Model\Attendee;
use OCA\Talk\Model\Message;
+use OCA\Talk\Model\ProxyCacheMessage;
use OCA\Talk\Participant;
use OCA\Talk\Room;
use OCA\Talk\Service\BotService;
@@ -51,10 +52,10 @@ class MessageParser {
protected array $botNames = [];
public function __construct(
- protected IEventDispatcher $dispatcher,
- protected IUserManager $userManager,
+ protected IEventDispatcher $dispatcher,
+ protected IUserManager $userManager,
protected ParticipantService $participantService,
- protected BotService $botService,
+ protected BotService $botService,
) {
}
@@ -62,6 +63,25 @@ class MessageParser {
return new Message($room, $participant, $comment, $l);
}
+ public function createMessageFromProxyCache(Room $room, ?Participant $participant, ProxyCacheMessage $proxy, IL10N $l): Message {
+ $message = new Message($room, $participant, null, $l, $proxy);
+
+ $message->setActor(
+ $proxy->getActorType(),
+ $proxy->getActorId(),
+ $proxy->getActorDisplayName(),
+ );
+
+ $message->setMessageType($proxy->getMessageType());
+
+ $message->setMessage(
+ $proxy->getMessage(),
+ $proxy->getParsedMessageParameters()
+ );
+
+ return $message;
+ }
+
public function parseMessage(Message $message): void {
$message->setMessage($message->getComment()->getMessage(), []);
diff --git a/lib/Chat/Parser/SystemMessage.php b/lib/Chat/Parser/SystemMessage.php
index d7f48e611..645e0e147 100644
--- a/lib/Chat/Parser/SystemMessage.php
+++ b/lib/Chat/Parser/SystemMessage.php
@@ -207,7 +207,7 @@ class SystemMessage implements IEventListener {
}
} elseif ($message === 'call_started') {
$metaData = $comment->getMetaData() ?? [];
- $silentCall = $metaData['silent'] ?? false;
+ $silentCall = $metaData[Message::METADATA_SILENT] ?? false;
if ($silentCall) {
if ($currentUserIsActor) {
$parsedMessage = $this->l->t('You started a silent call');
diff --git a/lib/Chat/Parser/UserMention.php b/lib/Chat/Parser/UserMention.php
index 257ae64ee..1b241088e 100644
--- a/lib/Chat/Parser/UserMention.php
+++ b/lib/Chat/Parser/UserMention.php
@@ -162,7 +162,7 @@ class UserMention implements IEventListener {
$messageParameters[$mentionParameterId] = [
'type' => $mention['type'],
'id' => $chatMessage->getRoom()->getToken(),
- 'name' => $chatMessage->getRoom()->getDisplayName($userId),
+ 'name' => $chatMessage->getRoom()->getDisplayName($userId, true),
'call-type' => $this->getRoomType($chatMessage->getRoom()),
'icon-url' => $this->avatarService->getAvatarUrl($chatMessage->getRoom()),
];
diff --git a/lib/Chat/SystemMessage/Listener.php b/lib/Chat/SystemMessage/Listener.php
index ddd680ab2..8f0ff6839 100644
--- a/lib/Chat/SystemMessage/Listener.php
+++ b/lib/Chat/SystemMessage/Listener.php
@@ -43,6 +43,7 @@ use OCA\Talk\Events\RoomModifiedEvent;
use OCA\Talk\Manager;
use OCA\Talk\Model\Attendee;
use OCA\Talk\Model\BreakoutRoom;
+use OCA\Talk\Model\Message;
use OCA\Talk\Model\Session;
use OCA\Talk\Participant;
use OCA\Talk\Room;
@@ -425,8 +426,8 @@ class Listener implements IEventListener {
}
}
- if (isset($metaData['silent'])) {
- $silent = (bool) $metaData['silent'];
+ if (isset($metaData[Message::METADATA_SILENT])) {
+ $silent = (bool) $metaData[Message::METADATA_SILENT];
} else {
$silent = false;
}
diff --git a/lib/Controller/ChatController.php b/lib/Controller/ChatController.php
index 5b6a98049..bad6ee7ea 100644
--- a/lib/Controller/ChatController.php
+++ b/lib/Controller/ChatController.php
@@ -530,7 +530,7 @@ class ChatController extends AEnvironmentAwareController {
$message = $this->messageParser->createMessage($this->room, $this->participant, $comment, $this->l);
$this->messageParser->parseMessage($message);
- $expireDate = $message->getComment()->getExpireDate();
+ $expireDate = $message->getExpirationDateTime();
if ($expireDate instanceof \DateTime && $expireDate < $now) {
$commentIdToIndex[$id] = null;
continue;
diff --git a/lib/Events/AMessageSentEvent.php b/lib/Events/AMessageSentEvent.php
index 8f3654c31..9c8a5d7f4 100644
--- a/lib/Events/AMessageSentEvent.php
+++ b/lib/Events/AMessageSentEvent.php
@@ -33,6 +33,7 @@ abstract class AMessageSentEvent extends ARoomEvent {
protected IComment $comment,
protected ?Participant $participant = null,
protected bool $silent = false,
+ protected ?IComment $parent = null,
) {
parent::__construct(
$room,
@@ -50,4 +51,8 @@ abstract class AMessageSentEvent extends ARoomEvent {
public function isSilentMessage(): bool {
return $this->silent;
}
+
+ public function getParent(): ?IComment {
+ return $this->parent;
+ }
}
diff --git a/lib/Events/ASystemMessageSentEvent.php b/lib/Events/ASystemMessageSentEvent.php
index a540edc5a..4dd55374b 100644
--- a/lib/Events/ASystemMessageSentEvent.php
+++ b/lib/Events/ASystemMessageSentEvent.php
@@ -33,13 +33,15 @@ abstract class ASystemMessageSentEvent extends AMessageSentEvent {
IComment $comment,
?Participant $participant = null,
bool $silent = false,
+ ?IComment $parent = null,
protected bool $skipLastActivityUpdate = false,
) {
parent::__construct(
$room,
$comment,
$participant,
- $silent
+ $silent,
+ $parent,
);
}
diff --git a/lib/Federation/BackendNotifier.php b/lib/Federation/BackendNotifier.php
index 1b13b260e..ccb422b23 100644
--- a/lib/Federation/BackendNotifier.php
+++ b/lib/Federation/BackendNotifier.php
@@ -313,6 +313,7 @@ class BackendNotifier {
* Send information to remote participants that a message was posted
* Sent from Host server to Remote participant server
*
+ * @param array{remoteMessageId: int, actorType: string, actorId: string, actorDisplayName: string, messageType: string, systemMessage: string, expirationDatetime: string, message: string, messageParameter: string, creationDatetime: string, metaData: string} $messageData
* @param array{unreadMessages: int, unreadMention: bool, unreadMentionDirect: bool} $unreadInfo
*/
public function sendMessageUpdate(
diff --git a/lib/Federation/CloudFederationProviderTalk.php b/lib/Federation/CloudFederationProviderTalk.php
index adf439b65..abe0dccd6 100644
--- a/lib/Federation/CloudFederationProviderTalk.php
+++ b/lib/Federation/CloudFederationProviderTalk.php
@@ -34,13 +34,15 @@ use OCA\Talk\Events\ARoomModifiedEvent;
use OCA\Talk\Events\AttendeesAddedEvent;
use OCA\Talk\Exceptions\ParticipantNotFoundException;
use OCA\Talk\Exceptions\RoomNotFoundException;
+use OCA\Talk\Federation\Proxy\TalkV1\UserConverter;
use OCA\Talk\Manager;
use OCA\Talk\Model\Attendee;
use OCA\Talk\Model\AttendeeMapper;
use OCA\Talk\Model\Invitation;
use OCA\Talk\Model\InvitationMapper;
-use OCA\Talk\Model\ProxyCacheMessages;
-use OCA\Talk\Model\ProxyCacheMessagesMapper;
+use OCA\Talk\Model\ProxyCacheMessage;
+use OCA\Talk\Model\ProxyCacheMessageMapper;
+use OCA\Talk\Notification\FederationChatNotifier;
use OCA\Talk\Participant;
use OCA\Talk\Room;
use OCA\Talk\Service\ParticipantService;
@@ -87,7 +89,9 @@ class CloudFederationProviderTalk implements ICloudFederationProvider {
private ISession $session,
private IEventDispatcher $dispatcher,
private LoggerInterface $logger,
- private ProxyCacheMessagesMapper $proxyCacheMessagesMapper,
+ private ProxyCacheMessageMapper $proxyCacheMessageMapper,
+ private FederationChatNotifier $federationChatNotifier,
+ private UserConverter $userConverter,
ICacheFactory $cacheFactory,
) {
$this->proxyCacheMessages = $cacheFactory->isAvailable() ? $cacheFactory->createDistributed('talk/pcm/') : null;
@@ -316,7 +320,7 @@ class CloudFederationProviderTalk implements ICloudFederationProvider {
/**
* @param int $remoteAttendeeId
- * @param array{remoteServerUrl: string, sharedSecret: string, remoteToken: string, messageData: array{remoteMessageId: int, actorType: string, actorId: string, actorDisplayName: string, messageType: string, systemMessage: string, expirationDatetime: string, message: string, messageParameter: string}, unreadInfo: array{unreadMessages: int, unreadMention: bool, unreadMentionDirect: bool}} $notification
+ * @param array{remoteServerUrl: string, sharedSecret: string, remoteToken: string, messageData: array{remoteMessageId: int, actorType: string, actorId: string, actorDisplayName: string, messageType: string, systemMessage: string, expirationDatetime: string, message: string, messageParameter: string, creationDatetime: string, metaData: string}, unreadInfo: array{unreadMessages: int, unreadMention: bool, unreadMentionDirect: bool}} $notification
* @return array
* @throws ActionNotSupportedException
* @throws AuthenticationFailedException
@@ -335,7 +339,7 @@ class CloudFederationProviderTalk implements ICloudFederationProvider {
throw new ShareNotFound();
}
- $message = new ProxyCacheMessages();
+ $message = new ProxyCacheMessage();
$message->setLocalToken($room->getToken());
$message->setRemoteServerUrl($notification['remoteServerUrl']);
$message->setRemoteToken($notification['remoteToken']);
@@ -346,12 +350,25 @@ class CloudFederationProviderTalk implements ICloudFederationProvider {
$message->setMessageType($notification['messageData']['messageType']);
$message->setSystemMessage($notification['messageData']['systemMessage']);
if ($notification['messageData']['expirationDatetime']) {
- $message->setExpirationDatetime(new \DateTimeImmutable($notification['messageData']['expirationDatetime']));
+ $message->setExpirationDatetime(new \DateTime($notification['messageData']['expirationDatetime']));
}
+
+ // We transform the parameters when storing in the PCM, so we only have
+ // to do it once for each message.
+ $convertedParameters = $this->userConverter->convertMessageParameters($room, [
+ 'message' => $notification['messageData']['message'],
+ 'messageParameters' => json_decode($notification['messageData']['messageParameter'], true, flags: JSON_THROW_ON_ERROR),
+ ]);
+ $notification['messageData']['message'] = $convertedParameters['message'];
+ $notification['messageData']['messageParameter'] = json_encode($convertedParameters['messageParameters'], JSON_THROW_ON_ERROR);
+
$message->setMessage($notification['messageData']['message']);
$message->setMessageParameters($notification['messageData']['messageParameter']);
+ $message->setCreationDatetime(new \DateTime($notification['messageData']['creationDatetime']));
+ $message->setMetaData($notification['messageData']['metaData']);
+
try {
- $this->proxyCacheMessagesMapper->insert($message);
+ $this->proxyCacheMessageMapper->insert($message);
$lastMessageId = $room->getLastMessageId();
if ($notification['messageData']['remoteMessageId'] > $lastMessageId) {
@@ -374,6 +391,12 @@ class CloudFederationProviderTalk implements ICloudFederationProvider {
$this->logger->error('Error saving proxy cache message failed: ' . $e->getMessage(), ['exception' => $e]);
throw $e;
}
+
+ $message = $this->proxyCacheMessageMapper->findByRemote(
+ $notification['remoteServerUrl'],
+ $notification['remoteToken'],
+ $notification['messageData']['remoteMessageId'],
+ );
}
try {
@@ -390,6 +413,8 @@ class CloudFederationProviderTalk implements ICloudFederationProvider {
$notification['unreadInfo']['unreadMentionDirect'],
);
+ $this->federationChatNotifier->handleChatMessage($room, $participant, $message, $notification);
+
return [];
}
diff --git a/lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php b/lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php
index e6920cc06..fb795b804 100644
--- a/lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php
+++ b/lib/Federation/Proxy/TalkV1/Notifier/MessageSentListener.php
@@ -32,7 +32,9 @@ use OCA\Talk\Events\SystemMessageSentEvent;
use OCA\Talk\Events\SystemMessagesMultipleSentEvent;
use OCA\Talk\Federation\BackendNotifier;
use OCA\Talk\Model\Attendee;
+use OCA\Talk\Model\ProxyCacheMessage;
use OCA\Talk\Service\ParticipantService;
+use OCP\Comments\IComment;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Federation\ICloudIdManager;
@@ -78,6 +80,14 @@ class MessageSentListener implements IEventListener {
}
$expireDate = $event->getComment()->getExpireDate();
+ $creationDate = $event->getComment()->getCreationDateTime();
+
+ $metaData = $event->getComment()->getMetaData() ?? [];
+ $parent = $event->getParent();
+ if ($parent instanceof IComment) {
+ $metaData[ProxyCacheMessage::METADATA_REPLYTO_TYPE] = $parent->getActorType();
+ $metaData[ProxyCacheMessage::METADATA_REPLYTO_ID] = $parent->getActorId();
+ }
$messageData = [
'remoteMessageId' => (int) $event->getComment()->getId(),
@@ -88,7 +98,9 @@ class MessageSentListener implements IEventListener {
'systemMessage' => $chatMessage->getMessageType() === ChatManager::VERB_SYSTEM ? $chatMessage->getMessageRaw() : '',
'expirationDatetime' => $expireDate ? $expireDate->format(\DateTime::ATOM) : '',
'message' => $chatMessage->getMessage(),
- 'messageParameter' => json_encode($chatMessage->getMessageParameters()),
+ 'messageParameter' => json_encode($chatMessage->getMessageParameters(), JSON_THROW_ON_ERROR),
+ 'creationDatetime' => $creationDate->format(\DateTime::ATOM),
+ 'metaData' => json_encode($metaData, JSON_THROW_ON_ERROR),
];
$participants = $this->participantService->getParticipantsByActorType($event->getRoom(), Attendee::ACTOR_FEDERATED_USERS);
diff --git a/lib/Federation/Proxy/TalkV1/UserConverter.php b/lib/Federation/Proxy/TalkV1/UserConverter.php
index debc01883..d58aa8e40 100644
--- a/lib/Federation/Proxy/TalkV1/UserConverter.php
+++ b/lib/Federation/Proxy/TalkV1/UserConverter.php
@@ -45,6 +45,26 @@ class UserConverter {
) {
}
+ /**
+ * @return array{type: string, id: string}
+ */
+ public function convertTypeAndId(Room $room, string $type, string $id): array {
+ if ($type === Attend