UPSTREAM BASELINE: nextcloud/spreed v22.0.12 (без изменений)
Type checking / changes (push) Has been cancelled
Type checking / test (push) Has been cancelled
Type checking / typescript-summary (push) Has been cancelled
Node tests / changes (push) Has been cancelled
Node tests / test (push) Has been cancelled
Node tests / test-summary (push) Has been cancelled
Type checking / changes (push) Has been cancelled
Type checking / test (push) Has been cancelled
Type checking / typescript-summary (push) Has been cancelled
Node tests / changes (push) Has been cancelled
Node tests / test (push) Has been cancelled
Node tests / test-summary (push) Has been cancelled
Источник: https://github.com/nextcloud/spreed/archive/refs/tags/v22.0.12.tar.gz С этого коммита ветка официального Nextcloud Talk отрезана (решение владельца 2026-07-06). Все дальнейшие изменения — только наши; версии релизов: 22.0.12-f7.N.
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Talk\Notification;
|
||||
|
||||
use OCA\Talk\Federation\Proxy\TalkV1\UserConverter;
|
||||
use OCA\Talk\Model\Attendee;
|
||||
use OCA\Talk\Model\Message;
|
||||
use OCA\Talk\Model\ProxyCacheMessage;
|
||||
use OCA\Talk\Model\Session;
|
||||
use OCA\Talk\Participant;
|
||||
use OCA\Talk\Room;
|
||||
use OCA\Talk\Service\ThreadService;
|
||||
use OCP\AppFramework\Services\IAppConfig;
|
||||
use OCP\Notification\IManager;
|
||||
use OCP\Notification\INotification;
|
||||
|
||||
class FederationChatNotifier {
|
||||
public function __construct(
|
||||
protected IAppConfig $appConfig,
|
||||
protected IManager $notificationManager,
|
||||
protected UserConverter $userConverter,
|
||||
protected ThreadService $threadService,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @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, lastReadMessage: int}} $inboundNotification
|
||||
*/
|
||||
public function handleChatMessage(Room $room, Participant $participant, ProxyCacheMessage $message, array $inboundNotification): void {
|
||||
if (!empty($inboundNotification['messageData']['systemMessage'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($participant->getAttendee()->getActorType() === $inboundNotification['messageData']['actorType']
|
||||
&& $participant->getAttendee()->getActorId() === $inboundNotification['messageData']['actorId']) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var array{silent?: bool, last_edited_time?: int, last_edited_by_type?: string, last_edited_by_id?: string, replyToActorType?: string, replyToActorId?: string, thread_id?: int} $metaData */
|
||||
$metaData = json_decode($inboundNotification['messageData']['metaData'] ?? '', true, flags: JSON_THROW_ON_ERROR);
|
||||
|
||||
if (isset($metaData[Message::METADATA_SILENT])) {
|
||||
// Silent message, skip notification handling
|
||||
return;
|
||||
}
|
||||
|
||||
$threadId = null;
|
||||
if (isset($metaData[Message::METADATA_THREAD_ID])) {
|
||||
$threadId = (int)$metaData[Message::METADATA_THREAD_ID];
|
||||
}
|
||||
|
||||
if ($participant->getSession() instanceof Session && $participant->getSession()->getState() === Session::STATE_ACTIVE) {
|
||||
// User has an active session
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$notificationLevel = $participant->getAttendee()->getNotificationLevel();
|
||||
if ($threadId !== null) {
|
||||
$threadAttendees = $this->threadService->findAttendeeByThreadIds($participant->getAttendee(), [$threadId]);
|
||||
$threadAttendee = $threadAttendees[$threadId] ?? null;
|
||||
|
||||
if ($threadAttendee !== null
|
||||
&& $threadAttendee->getNotificationLevel() !== Participant::NOTIFY_DEFAULT) {
|
||||
$notificationLevel = $threadAttendee->getNotificationLevel();
|
||||
}
|
||||
}
|
||||
|
||||
// Also notify default participants in one-to-one chats or when the admin default is "always"
|
||||
$defaultLevel = $this->appConfig->getAppValueInt('default_group_notification', Participant::NOTIFY_MENTION);
|
||||
if ($notificationLevel === Participant::NOTIFY_MENTION
|
||||
|| ($defaultLevel !== Participant::NOTIFY_NEVER && $notificationLevel === Participant::NOTIFY_DEFAULT)) {
|
||||
if ($this->isRepliedTo($room, $participant, $metaData)) {
|
||||
$notification = $this->createNotification($room, $message, 'reply', threadId: $threadId);
|
||||
$notification->setUser($participant->getAttendee()->getActorId());
|
||||
$this->notificationManager->notify($notification);
|
||||
} elseif ($this->isMentioned($participant, $message)) {
|
||||
$notification = $this->createNotification($room, $message, 'mention', threadId: $threadId);
|
||||
$notification->setUser($participant->getAttendee()->getActorId());
|
||||
$this->notificationManager->notify($notification);
|
||||
} elseif ($this->isMentionedAll($room, $message)) {
|
||||
$notification = $this->createNotification($room, $message, 'mention_all', threadId: $threadId);
|
||||
$notification->setUser($participant->getAttendee()->getActorId());
|
||||
$this->notificationManager->notify($notification);
|
||||
}
|
||||
} elseif ($participant->getAttendee()->getNotificationLevel() === Participant::NOTIFY_ALWAYS
|
||||
|| ($defaultLevel === Participant::NOTIFY_ALWAYS && $notificationLevel === Participant::NOTIFY_DEFAULT)) {
|
||||
if ($this->isUserMessageOrRelevantSystemMessage($message->getSystemMessage())) {
|
||||
$notification = $this->createNotification($room, $message, 'chat', threadId: $threadId);
|
||||
$notification->setUser($participant->getAttendee()->getActorId());
|
||||
$this->notificationManager->notify($notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{silent?: bool, last_edited_time?: int, last_edited_by_type?: string, last_edited_by_id?: string, replyToActorType?: string, replyToActorId?: string, thread_id?: int} $metaData
|
||||
*/
|
||||
protected function isRepliedTo(Room $room, Participant $participant, array $metaData): bool {
|
||||
if (!isset($metaData[ProxyCacheMessage::METADATA_REPLY_TO_ACTOR_TYPE])
|
||||
|| !isset($metaData[ProxyCacheMessage::METADATA_REPLY_TO_ACTOR_ID])
|
||||
|| $metaData[ProxyCacheMessage::METADATA_REPLY_TO_ACTOR_TYPE] !== Attendee::ACTOR_FEDERATED_USERS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$repliedTo = $this->userConverter->convertTypeAndId($room, $metaData[ProxyCacheMessage::METADATA_REPLY_TO_ACTOR_TYPE], $metaData[ProxyCacheMessage::METADATA_REPLY_TO_ACTOR_ID]);
|
||||
return $repliedTo['type'] === $participant->getAttendee()->getActorType()
|
||||
&& $repliedTo['id'] === $participant->getAttendee()->getActorId();
|
||||
}
|
||||
|
||||
protected function isMentioned(Participant $participant, ProxyCacheMessage $message): bool {
|
||||
if ($participant->getAttendee()->getActorType() !== Attendee::ACTOR_USERS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($message->getParsedMessageParameters() as $parameter) {
|
||||
if ($parameter['type'] === 'user' // RichObjectDefinition, not Attendee::ACTOR_USERS
|
||||
&& $parameter['id'] === $participant->getAttendee()->getActorId()
|
||||
&& empty($parameter['server'])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isMentionedAll(Room $room, ProxyCacheMessage $message): bool {
|
||||
foreach ($message->getParsedMessageParameters() as $parameter) {
|
||||
if ($parameter['type'] === 'call' // RichObjectDefinition
|
||||
&& $parameter['id'] === $room->getToken()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isUserMessageOrRelevantSystemMessage(?string $systemMessage): bool {
|
||||
return $systemMessage === null
|
||||
|| $systemMessage === ''
|
||||
|| $systemMessage === 'object_shared'
|
||||
|| $systemMessage === 'poll_closed'
|
||||
|| $systemMessage === 'file_shared';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a notification for the given proxy message and mentioned users
|
||||
*/
|
||||
protected function createNotification(Room $chat, ProxyCacheMessage $message, string $subject, array $subjectData = [], ?int $threadId = null): INotification {
|
||||
$subjectData['userType'] = $message->getActorType();
|
||||
$subjectData['userId'] = $message->getActorId();
|
||||
|
||||
$notificationParameters = [
|
||||
'proxyId' => $message->getId(),
|
||||
];
|
||||
if ($threadId !== null) {
|
||||
$notificationParameters['threadId'] = $threadId;
|
||||
}
|
||||
|
||||
$notification = $this->notificationManager->createNotification();
|
||||
$notification
|
||||
->setApp('spreed')
|
||||
->setObject('chat', $chat->getToken())
|
||||
->setSubject($subject, $subjectData)
|
||||
->setMessage($message->getMessageType(), $notificationParameters)
|
||||
->setDateTime($message->getCreationDatetime());
|
||||
|
||||
return $notification;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2017 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Talk\Notification;
|
||||
|
||||
use OCA\Talk\AppInfo\Application;
|
||||
use OCA\Talk\Controller\ChatController;
|
||||
use OCA\Talk\Events\AParticipantModifiedEvent;
|
||||
use OCA\Talk\Events\AttendeesAddedEvent;
|
||||
use OCA\Talk\Events\BeforeCallStartedEvent;
|
||||
use OCA\Talk\Events\CallNotificationSendEvent;
|
||||
use OCA\Talk\Events\CallStartedEvent;
|
||||
use OCA\Talk\Events\ParticipantModifiedEvent;
|
||||
use OCA\Talk\Events\UserJoinedRoomEvent;
|
||||
use OCA\Talk\Model\Attendee;
|
||||
use OCA\Talk\Participant;
|
||||
use OCA\Talk\Room;
|
||||
use OCA\Talk\Service\ParticipantService;
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\EventDispatcher\IEventListener;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
use OCP\Notification\IManager;
|
||||
use OCP\Notification\INotification;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @template-implements IEventListener<Event>
|
||||
*/
|
||||
class Listener implements IEventListener {
|
||||
|
||||
protected bool $shouldSendCallNotification = false;
|
||||
/** @var array<string, INotification> $preparedCallNotifications Map of language => parsed notification in that language */
|
||||
protected array $preparedCallNotifications = [];
|
||||
|
||||
public function __construct(
|
||||
protected IConfig $serverConfig,
|
||||
protected IDBConnection $connection,
|
||||
protected IManager $notificationManager,
|
||||
protected Notifier $notificationProvider,
|
||||
protected ParticipantService $participantsService,
|
||||
protected IEventDispatcher $dispatcher,
|
||||
protected IUserSession $userSession,
|
||||
protected ITimeFactory $timeFactory,
|
||||
protected LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
|
||||
#[\Override]
|
||||
public function handle(Event $event): void {
|
||||
match (get_class($event)) {
|
||||
CallNotificationSendEvent::class => $this->sendCallNotification($event->getRoom(), $event->getActor()?->getAttendee(), $event->getTarget()->getAttendee()),
|
||||
AttendeesAddedEvent::class => $this->generateInvitation($event->getRoom(), $event->getAttendees()),
|
||||
UserJoinedRoomEvent::class => $this->handleUserJoinedRoomEvent($event),
|
||||
BeforeCallStartedEvent::class => $this->checkCallNotifications($event),
|
||||
ParticipantModifiedEvent::class => $this->afterParticipantJoinedCall($event),
|
||||
CallStartedEvent::class => $this->afterCallStarted($event),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Room invitation: "{actor} invited you to {call}"
|
||||
*
|
||||
* @param Room $room
|
||||
* @param Attendee[] $attendees
|
||||
*/
|
||||
protected function generateInvitation(Room $room, array $attendees): void {
|
||||
if ($room->getType() === Room::TYPE_ONE_TO_ONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($room->getObjectType() === Room::OBJECT_TYPE_FILE) {
|
||||
return;
|
||||
}
|
||||
|
||||
$actor = $this->userSession->getUser();
|
||||
if (!$actor instanceof IUser) {
|
||||
return;
|
||||
}
|
||||
$actorId = $actor->getUID();
|
||||
|
||||
$notification = $this->notificationManager->createNotification();
|
||||
$shouldFlush = $this->notificationManager->defer();
|
||||
$dateTime = $this->timeFactory->getDateTime();
|
||||
try {
|
||||
$notification->setApp(Application::APP_ID)
|
||||
->setDateTime($dateTime)
|
||||
->setObject('room', $room->getToken())
|
||||
->setSubject('invitation', [
|
||||
'actorId' => $actor->getUID(),
|
||||
]);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
if ($shouldFlush) {
|
||||
$this->notificationManager->flush();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($attendees as $attendee) {
|
||||
if ($attendee->getActorType() !== Attendee::ACTOR_USERS) {
|
||||
// No user => no activity
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($actorId === $attendee->getActorId()) {
|
||||
// No activity for self-joining and the creator
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$notification->setUser($attendee->getActorId());
|
||||
$this->notificationManager->notify($notification);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($shouldFlush) {
|
||||
$this->notificationManager->flush();
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleUserJoinedRoomEvent(UserJoinedRoomEvent $event): void {
|
||||
$this->markInvitationRead($event->getRoom(), $event->getUser());
|
||||
$this->markReactionNotificationsRead($event->getRoom(), $event->getUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Room invitation: "{actor} invited you to {call}"
|
||||
*/
|
||||
protected function markInvitationRead(Room $room, IUser $user): void {
|
||||
if ($room->getType() === Room::TYPE_ONE_TO_ONE
|
||||
|| $room->getType() === Room::TYPE_ONE_TO_ONE_FORMER) {
|
||||
// No notifications for one-to-one, save a query
|
||||
return;
|
||||
}
|
||||
|
||||
$notification = $this->notificationManager->createNotification();
|
||||
try {
|
||||
$notification->setApp(Application::APP_ID)
|
||||
->setUser($user->getUID())
|
||||
->setObject('room', $room->getToken())
|
||||
->setSubject('invitation');
|
||||
$this->notificationManager->markProcessed($notification);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reaction: "{user} reacted with {reaction} in {call}"
|
||||
*
|
||||
* We should not mark reactions read based on the read-status of the comment
|
||||
* they apply to, but the point in time when the reaction was done.
|
||||
* However, these messages are not visible and don't update the read marker,
|
||||
* so we purge them on joining the conversation.
|
||||
* This already happened before on the initial loading of a chat with
|
||||
* {@see ChatController::getMessageContext()}, but not on follow-up visits
|
||||
* (when the room history was not empty in the browser storage) this does
|
||||
* not trigger, so it was possible to end a session with all messages read,
|
||||
* but still having notifications about reactions.
|
||||
* For normal chat messages this happens in {@see Notifier::parseChatMessage()}
|
||||
*/
|
||||
protected function markReactionNotificationsRead(Room $room, IUser $user): void {
|
||||
$notification = $this->notificationManager->createNotification();
|
||||
try {
|
||||
$notification->setApp(Application::APP_ID)
|
||||
->setUser($user->getUID())
|
||||
->setObject('chat', $room->getToken())
|
||||
->setSubject('reaction');
|
||||
$this->notificationManager->markProcessed($notification);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call notification: "{user} wants to talk with you"
|
||||
*/
|
||||
protected function checkCallNotifications(BeforeCallStartedEvent $event): void {
|
||||
if ($event->getDetail(AParticipantModifiedEvent::DETAIL_IN_CALL_SILENT)) {
|
||||
$this->shouldSendCallNotification = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event->getRoom()->getObjectType() === Room::OBJECT_TYPE_FILE) {
|
||||
$this->shouldSendCallNotification = false;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->shouldSendCallNotification = true;
|
||||
}
|
||||
|
||||
protected function afterParticipantJoinedCall(ParticipantModifiedEvent $event): void {
|
||||
if ($event->getProperty() !== AParticipantModifiedEvent::PROPERTY_IN_CALL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event->getOldValue() !== Participant::FLAG_DISCONNECTED
|
||||
|| $event->getNewValue() === Participant::FLAG_DISCONNECTED) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Purge received call notifications on joining
|
||||
$this->markCallNotificationsRead($event->getRoom());
|
||||
}
|
||||
|
||||
protected function afterCallStarted(CallStartedEvent $event): void {
|
||||
if ($event->getDetail(AParticipantModifiedEvent::DETAIL_IN_CALL_SILENT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->shouldSendCallNotification || $event->getRoom()->isFederatedConversation()) {
|
||||
$this->sendCallNotifications($event->getRoom(), $event->getDetailList(AParticipantModifiedEvent::DETAIL_IN_CALL_SILENT_FOR));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call notification: "{user} wants to talk with you"
|
||||
*
|
||||
* @param Room $room
|
||||
*/
|
||||
protected function markCallNotificationsRead(Room $room): void {
|
||||
$currentUser = $this->userSession->getUser();
|
||||
if (!$currentUser instanceof IUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
$notification = $this->notificationManager->createNotification();
|
||||
try {
|
||||
$notification->setApp(Application::APP_ID)
|
||||
->setUser($currentUser->getUID())
|
||||
->setObject('call', $room->getToken())
|
||||
->setSubject('call');
|
||||
$this->notificationManager->markProcessed($notification);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call notification: "{user} wants to talk with you"
|
||||
*
|
||||
* @param list<string> $silentFor
|
||||
*/
|
||||
protected function sendCallNotifications(Room $room, array $silentFor = []): void {
|
||||
$actor = $this->userSession->getUser();
|
||||
$actorId = $actor instanceof IUser ? $actor->getUID() :'';
|
||||
|
||||
$notification = $this->notificationManager->createNotification();
|
||||
$shouldFlush = $this->notificationManager->defer();
|
||||
$dateTime = $this->timeFactory->getDateTime();
|
||||
try {
|
||||
// Remove all old notifications for this room
|
||||
$notification->setApp(Application::APP_ID)
|
||||
->setObject('room', $room->getToken());
|
||||
$this->notificationManager->markProcessed($notification);
|
||||
|
||||
$notification->setObject('call', $room->getToken());
|
||||
$this->notificationManager->markProcessed($notification);
|
||||
|
||||
$notification->setSubject('call', [
|
||||
'callee' => $actorId,
|
||||
])
|
||||
->setDateTime($dateTime);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
if ($shouldFlush) {
|
||||
$this->notificationManager->flush();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$this->preparedCallNotifications = [];
|
||||
$users = $this->participantsService->getParticipantUsersForCallNotifications($room);
|
||||
|
||||
if (!empty($silentFor)) {
|
||||
// Remove users for which the call should be silent
|
||||
foreach ($silentFor as $userId) {
|
||||
unset($users[$userId]);
|
||||
}
|
||||
}
|
||||
|
||||
// Room name depends on the notification user for one-to-one,
|
||||
// so we avoid pre-parsing it there. Also, it comes with some base load,
|
||||
// so we only do it for "big enough" calls.
|
||||
$preparseNotificationForPush = count($users) > 10;
|
||||
if ($preparseNotificationForPush) {
|
||||
$fallbackLang = $this->serverConfig->getSystemValue('force_language', null);
|
||||
if (is_string($fallbackLang)) {
|
||||
/** @psalm-var array<string, string> $userLanguages */
|
||||
$userLanguages = [];
|
||||
} else {
|
||||
$fallbackLang = $this->serverConfig->getSystemValueString('default_language', 'en');
|
||||
/** @psalm-var array<string, string> $userLanguages */
|
||||
$userLanguages = $this->serverConfig->getUserValueForUsers('core', 'lang', array_map('strval', array_keys($users)));
|
||||
}
|
||||
}
|
||||
|
||||
$this->connection->beginTransaction();
|
||||
try {
|
||||
foreach ($users as $userId => $isImportant) {
|
||||
$userId = (string)$userId;
|
||||
if ($actorId === $userId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($preparseNotificationForPush) {
|
||||
// Get the settings for this particular user, then check if we have notifications to email them
|
||||
$languageCode = $userLanguages[$userId] ?? $fallbackLang;
|
||||
|
||||
if (!isset($this->preparedCallNotifications[$languageCode])) {
|
||||
$translatedNotification = clone $notification;
|
||||
|
||||
$this->notificationManager->setPreparingPushNotification(true);
|
||||
$this->preparedCallNotifications[$languageCode] = $this->notificationProvider->prepare($translatedNotification, $languageCode);
|
||||
$this->notificationManager->setPreparingPushNotification(false);
|
||||
}
|
||||
$userNotification = $this->preparedCallNotifications[$languageCode];
|
||||
} else {
|
||||
$userNotification = $notification;
|
||||
}
|
||||
|
||||
try {
|
||||
$userNotification->setUser($userId);
|
||||
$userNotification->setPriorityNotification($isImportant);
|
||||
$this->notificationManager->notify($userNotification);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$this->connection->rollBack();
|
||||
throw $e;
|
||||
}
|
||||
$this->connection->commit();
|
||||
|
||||
if ($shouldFlush) {
|
||||
$this->notificationManager->flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forced call notification when ringing a single participant again
|
||||
*/
|
||||
protected function sendCallNotification(Room $room, ?Attendee $actor, Attendee $target): void {
|
||||
try {
|
||||
// Remove previous call notifications
|
||||
$notification = $this->notificationManager->createNotification();
|
||||
$notification->setApp(Application::APP_ID)
|
||||
->setObject('call', $room->getToken())
|
||||
->setUser($target->getActorId());
|
||||
$this->notificationManager->markProcessed($notification);
|
||||
|
||||
$dateTime = $this->timeFactory->getDateTime();
|
||||
$notification->setSubject('call', [
|
||||
'callee' => $actor?->getActorId(),
|
||||
])
|
||||
->setDateTime($dateTime)
|
||||
->setPriorityNotification($target->isImportant());
|
||||
$this->notificationManager->notify($notification);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user