mirror of
https://github.com/nextcloud/spreed.git
synced 2025-12-18 05:20:50 +01:00
fix(federation): Sync room properties on join
Signed-off-by: Joas Schilling <coding@schilljs.com>
This commit is contained in:
parent
5e850a1b47
commit
1fda7a31e2
15 changed files with 330 additions and 29 deletions
|
|
@ -34,6 +34,17 @@ See the general [Nextcloud Developers - Events](https://docs.nextcloud.com/serve
|
|||
* After event: `OCA\Talk\Events\LobbyModifiedEvent`
|
||||
* Since: 18.0.0
|
||||
|
||||
### Federated conversation synced
|
||||
|
||||
When multiple properties of a federated conversation are synced, the individual
|
||||
"Conversation modified" and "Lobby modified" events are still triggered, but a
|
||||
listener could decide to not follow up individual but only after all properties
|
||||
where modified.
|
||||
|
||||
* Before event: `OCA\Talk\Events\BeforeRoomSyncedEvent`
|
||||
* After event: `OCA\Talk\Events\RoomSyncedEvent`
|
||||
* Since: 20.0.0
|
||||
|
||||
### Call started
|
||||
|
||||
* Before event: `OCA\Talk\Events\BeforeCallStartedEvent`
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ use OCA\Talk\Events\BeforeGuestJoinedRoomEvent;
|
|||
use OCA\Talk\Events\BeforeParticipantModifiedEvent;
|
||||
use OCA\Talk\Events\BeforeRoomDeletedEvent;
|
||||
use OCA\Talk\Events\BeforeRoomsFetchEvent;
|
||||
use OCA\Talk\Events\BeforeRoomSyncedEvent;
|
||||
use OCA\Talk\Events\BeforeSessionLeftRoomEvent;
|
||||
use OCA\Talk\Events\BeforeUserJoinedRoomEvent;
|
||||
use OCA\Talk\Events\BotDisabledEvent;
|
||||
|
|
@ -61,6 +62,7 @@ use OCA\Talk\Events\ParticipantModifiedEvent;
|
|||
use OCA\Talk\Events\RoomCreatedEvent;
|
||||
use OCA\Talk\Events\RoomDeletedEvent;
|
||||
use OCA\Talk\Events\RoomModifiedEvent;
|
||||
use OCA\Talk\Events\RoomSyncedEvent;
|
||||
use OCA\Talk\Events\SessionLeftRoomEvent;
|
||||
use OCA\Talk\Events\SystemMessageSentEvent;
|
||||
use OCA\Talk\Events\SystemMessagesMultipleSentEvent;
|
||||
|
|
@ -286,6 +288,8 @@ class Application extends App implements IBootstrap {
|
|||
$context->registerEventListener(CallEndedForEveryoneEvent::class, SignalingListener::class);
|
||||
$context->registerEventListener(GuestsCleanedUpEvent::class, SignalingListener::class);
|
||||
$context->registerEventListener(LobbyModifiedEvent::class, SignalingListener::class);
|
||||
$context->registerEventListener(BeforeRoomSyncedEvent::class, SignalingListener::class);
|
||||
$context->registerEventListener(RoomSyncedEvent::class, SignalingListener::class);
|
||||
|
||||
$context->registerEventListener(ChatMessageSentEvent::class, SignalingListener::class);
|
||||
$context->registerEventListener(SystemMessageSentEvent::class, SignalingListener::class);
|
||||
|
|
|
|||
|
|
@ -1660,6 +1660,10 @@ class RoomController extends AEnvironmentAwareController {
|
|||
return new DataResponse([], Http::STATUS_NOT_FOUND);
|
||||
}
|
||||
|
||||
/** @var TalkRoom $data */
|
||||
$data = $response->getData();
|
||||
$this->roomService->syncPropertiesFromHostRoom($room, $data);
|
||||
|
||||
$proxyHeaders = $response->getHeaders();
|
||||
if (isset($proxyHeaders['X-Nextcloud-Talk-Proxy-Hash'])) {
|
||||
$headers['X-Nextcloud-Talk-Proxy-Hash'] = $proxyHeaders['X-Nextcloud-Talk-Proxy-Hash'];
|
||||
|
|
@ -1675,8 +1679,8 @@ class RoomController extends AEnvironmentAwareController {
|
|||
* The session id can be null only for requests from Talk < 20.
|
||||
*
|
||||
* @param string $token Token of the room
|
||||
* @param string $sessionId Federated session id to join with
|
||||
* @return DataResponse<Http::STATUS_OK, array<empty>, array{X-Nextcloud-Talk-Hash: string}>|DataResponse<Http::STATUS_NOT_FOUND, null, array{}>
|
||||
* @param ?string $sessionId Federated session id to join with
|
||||
* @return DataResponse<Http::STATUS_OK, TalkRoom, array{X-Nextcloud-Talk-Hash: string}>|DataResponse<Http::STATUS_NOT_FOUND, null, array{}>
|
||||
*
|
||||
* 200: Federated user joined the room
|
||||
* 404: Room not found
|
||||
|
|
@ -1711,14 +1715,16 @@ class RoomController extends AEnvironmentAwareController {
|
|||
if ($session instanceof Session) {
|
||||
$this->sessionService->updateLastPing($session, $this->timeFactory->getTime());
|
||||
}
|
||||
} else {
|
||||
$participant = $this->participantService->getParticipantByActor($room, Attendee::ACTOR_FEDERATED_USERS, $this->federationAuthenticator->getCloudId());
|
||||
}
|
||||
|
||||
// Let the clients know if they need to reload capabilities
|
||||
$capabilities = $this->capabilities->getCapabilities();
|
||||
return new DataResponse([], Http::STATUS_OK, [
|
||||
return new DataResponse($this->formatRoom($room, $participant), Http::STATUS_OK, [
|
||||
'X-Nextcloud-Talk-Hash' => sha1(json_encode($capabilities)),
|
||||
]);
|
||||
} catch (RoomNotFoundException|UnauthorizedException) {
|
||||
} catch (RoomNotFoundException|ParticipantNotFoundException|UnauthorizedException) {
|
||||
$response = new DataResponse(null, Http::STATUS_NOT_FOUND);
|
||||
$response->throttle(['token' => $token, 'action' => 'talkFederationAccess']);
|
||||
return $response;
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ abstract class ARoomModifiedEvent extends ARoomEvent {
|
|||
public const PROPERTY_LISTABLE = 'listable';
|
||||
public const PROPERTY_LOBBY = 'lobby';
|
||||
public const PROPERTY_MESSAGE_EXPIRATION = 'messageExpiration';
|
||||
public const PROPERTY_MENTION_PERMISSIONS = 'mentionPermissions';
|
||||
public const PROPERTY_NAME = 'name';
|
||||
public const PROPERTY_PASSWORD = 'password';
|
||||
public const PROPERTY_READ_ONLY = 'readOnly';
|
||||
public const PROPERTY_RECORDING_CONSENT = 'recordingConsent';
|
||||
public const PROPERTY_SIP_ENABLED = 'sipEnabled';
|
||||
public const PROPERTY_TYPE = 'type';
|
||||
public const PROPERTY_MENTION_PERMISSIONS = 'mentionPermissions';
|
||||
|
||||
/**
|
||||
* @param self::PROPERTY_* $property
|
||||
|
|
|
|||
13
lib/Events/ARoomSyncedEvent.php
Normal file
13
lib/Events/ARoomSyncedEvent.php
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Talk\Events;
|
||||
|
||||
abstract class ARoomSyncedEvent extends ARoomEvent {
|
||||
public const PROPERTY_LAST_ACTIVITY = 'lastActivity';
|
||||
}
|
||||
12
lib/Events/BeforeRoomSyncedEvent.php
Normal file
12
lib/Events/BeforeRoomSyncedEvent.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Talk\Events;
|
||||
|
||||
class BeforeRoomSyncedEvent extends ARoomSyncedEvent {
|
||||
}
|
||||
30
lib/Events/RoomSyncedEvent.php
Normal file
30
lib/Events/RoomSyncedEvent.php
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Talk\Events;
|
||||
|
||||
use OCA\Talk\Room;
|
||||
|
||||
class RoomSyncedEvent extends ARoomSyncedEvent {
|
||||
/**
|
||||
* @param array<array-key, ARoomModifiedEvent::PROPERTY_*|ARoomSyncedEvent::PROPERTY_*> $properties
|
||||
*/
|
||||
public function __construct(
|
||||
Room $room,
|
||||
protected array $properties,
|
||||
) {
|
||||
parent::__construct($room);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<array-key, ARoomModifiedEvent::PROPERTY_*|ARoomSyncedEvent::PROPERTY_*>
|
||||
*/
|
||||
public function getProperties(): array {
|
||||
return $this->properties;
|
||||
}
|
||||
}
|
||||
|
|
@ -322,6 +322,8 @@ class CloudFederationProviderTalk implements ICloudFederationProvider {
|
|||
}
|
||||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_AVATAR) {
|
||||
$this->roomService->setAvatar($room, $notification['newValue']);
|
||||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_CALL_RECORDING) {
|
||||
$this->roomService->setCallRecording($room, $notification['newValue']);
|
||||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_DESCRIPTION) {
|
||||
$this->roomService->setDescription($room, $notification['newValue']);
|
||||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_IN_CALL) {
|
||||
|
|
@ -329,6 +331,10 @@ class CloudFederationProviderTalk implements ICloudFederationProvider {
|
|||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_LOBBY) {
|
||||
$dateTime = !empty($notification['dateTime']) ? \DateTime::createFromFormat('U', $notification['dateTime']) : null;
|
||||
$this->roomService->setLobby($room, $notification['newValue'], $dateTime, $notification['timerReached'] ?? false);
|
||||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_MENTION_PERMISSIONS) {
|
||||
$this->roomService->setMentionPermissions($room, $notification['newValue']);
|
||||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_MESSAGE_EXPIRATION) {
|
||||
$this->roomService->setMessageExpiration($room, $notification['newValue']);
|
||||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_NAME) {
|
||||
$this->roomService->setName($room, $notification['newValue'], $notification['oldValue']);
|
||||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_READ_ONLY) {
|
||||
|
|
@ -336,6 +342,8 @@ class CloudFederationProviderTalk implements ICloudFederationProvider {
|
|||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_RECORDING_CONSENT) {
|
||||
/** @psalm-suppress InvalidArgument */
|
||||
$this->roomService->setRecordingConsent($room, $notification['newValue']);
|
||||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_SIP_ENABLED) {
|
||||
$this->roomService->setSIPEnabled($room, $notification['newValue']);
|
||||
} elseif ($notification['changedProperty'] === ARoomModifiedEvent::PROPERTY_TYPE) {
|
||||
$this->roomService->setType($room, $notification['newValue']);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -91,7 +91,12 @@ class RoomController {
|
|||
|
||||
$headers = ['X-Nextcloud-Talk-Proxy-Hash' => $this->proxy->overwrittenRemoteTalkHash($proxy->getHeader('X-Nextcloud-Talk-Hash'))];
|
||||
|
||||
return new DataResponse([], $statusCode, $headers);
|
||||
/** @var TalkRoom[] $data */
|
||||
$data = $this->proxy->getOCSData($proxy);
|
||||
|
||||
$data = $this->userConverter->convertAttendee($room, $data, 'actorType', 'actorId', 'displayName');
|
||||
|
||||
return new DataResponse($data, $statusCode, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -49,17 +49,25 @@ class RoomModifiedListener implements IEventListener {
|
|||
if (!in_array($event->getProperty(), [
|
||||
ARoomModifiedEvent::PROPERTY_ACTIVE_SINCE,
|
||||
ARoomModifiedEvent::PROPERTY_AVATAR,
|
||||
ARoomModifiedEvent::PROPERTY_CALL_RECORDING,
|
||||
ARoomModifiedEvent::PROPERTY_DESCRIPTION,
|
||||
ARoomModifiedEvent::PROPERTY_IN_CALL,
|
||||
ARoomModifiedEvent::PROPERTY_LOBBY,
|
||||
ARoomModifiedEvent::PROPERTY_MENTION_PERMISSIONS,
|
||||
ARoomModifiedEvent::PROPERTY_MESSAGE_EXPIRATION,
|
||||
ARoomModifiedEvent::PROPERTY_NAME,
|
||||
ARoomModifiedEvent::PROPERTY_READ_ONLY,
|
||||
ARoomModifiedEvent::PROPERTY_RECORDING_CONSENT,
|
||||
ARoomModifiedEvent::PROPERTY_SIP_ENABLED,
|
||||
ARoomModifiedEvent::PROPERTY_TYPE,
|
||||
], true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($event->getRoom()->isFederatedConversation()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$participants = $this->participantService->getParticipantsByActorType($event->getRoom(), Attendee::ACTOR_FEDERATED_USERS);
|
||||
foreach ($participants as $participant) {
|
||||
$cloudId = $this->cloudIdManager->resolveCloudId($participant->getAttendee()->getActorId());
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ namespace OCA\Talk\Recording;
|
|||
|
||||
use OCA\Talk\AppInfo\Application;
|
||||
use OCA\Talk\Events\ACallEndedEvent;
|
||||
use OCA\Talk\Events\ARoomEvent;
|
||||
use OCA\Talk\Events\CallEndedEvent;
|
||||
use OCA\Talk\Events\CallEndedForEveryoneEvent;
|
||||
use OCA\Talk\Events\RoomDeletedEvent;
|
||||
|
|
@ -42,6 +43,10 @@ class Listener implements IEventListener {
|
|||
return;
|
||||
}
|
||||
|
||||
if ($event instanceof ARoomEvent && $event->getRoom()->isFederatedConversation()) {
|
||||
return;
|
||||
}
|
||||
|
||||
match (get_class($event)) {
|
||||
RoomDeletedEvent::class => $this->roomDeleted($event),
|
||||
CallEndedEvent::class,
|
||||
|
|
|
|||
|
|
@ -12,22 +12,26 @@ use InvalidArgumentException;
|
|||
use OCA\Talk\Config;
|
||||
use OCA\Talk\Events\AParticipantModifiedEvent;
|
||||
use OCA\Talk\Events\ARoomModifiedEvent;
|
||||
use OCA\Talk\Events\ARoomSyncedEvent;
|
||||
use OCA\Talk\Events\BeforeCallEndedEvent;
|
||||
use OCA\Talk\Events\BeforeCallStartedEvent;
|
||||
use OCA\Talk\Events\BeforeLobbyModifiedEvent;
|
||||
use OCA\Talk\Events\BeforeRoomDeletedEvent;
|
||||
use OCA\Talk\Events\BeforeRoomModifiedEvent;
|
||||
use OCA\Talk\Events\BeforeRoomSyncedEvent;
|
||||
use OCA\Talk\Events\CallEndedEvent;
|
||||
use OCA\Talk\Events\CallStartedEvent;
|
||||
use OCA\Talk\Events\LobbyModifiedEvent;
|
||||
use OCA\Talk\Events\RoomDeletedEvent;
|
||||
use OCA\Talk\Events\RoomModifiedEvent;
|
||||
use OCA\Talk\Events\RoomPasswordVerifyEvent;
|
||||
use OCA\Talk\Events\RoomSyncedEvent;
|
||||
use OCA\Talk\Exceptions\RoomNotFoundException;
|
||||
use OCA\Talk\Manager;
|
||||
use OCA\Talk\Model\Attendee;
|
||||
use OCA\Talk\Model\BreakoutRoom;
|
||||
use OCA\Talk\Participant;
|
||||
use OCA\Talk\ResponseDefinitions;
|
||||
use OCA\Talk\Room;
|
||||
use OCA\Talk\Webinary;
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
|
|
@ -42,7 +46,11 @@ use OCP\Log\Audit\CriticalActionPerformedEvent;
|
|||
use OCP\Security\Events\ValidatePasswordPolicyEvent;
|
||||
use OCP\Security\IHasher;
|
||||
use OCP\Share\IManager as IShareManager;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* @psalm-import-type TalkRoom from ResponseDefinitions
|
||||
*/
|
||||
class RoomService {
|
||||
|
||||
public function __construct(
|
||||
|
|
@ -55,6 +63,7 @@ class RoomService {
|
|||
protected IHasher $hasher,
|
||||
protected IEventDispatcher $dispatcher,
|
||||
protected IJobList $jobList,
|
||||
protected LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -435,7 +444,8 @@ class RoomService {
|
|||
* @throws InvalidArgumentException When trying to start
|
||||
*/
|
||||
public function setCallRecording(Room $room, int $status = Room::RECORDING_NONE, ?Participant $participant = null): void {
|
||||
if (!$this->config->isRecordingEnabled() && $status !== Room::RECORDING_NONE) {
|
||||
$syncFederatedRoom = $room->getRemoteServer() && $room->getRemoteToken();
|
||||
if (!$syncFederatedRoom && !$this->config->isRecordingEnabled() && $status !== Room::RECORDING_NONE) {
|
||||
throw new InvalidArgumentException('config');
|
||||
}
|
||||
|
||||
|
|
@ -999,6 +1009,154 @@ class RoomService {
|
|||
$room->setLastActivity($now);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-param TalkRoom $host
|
||||
*/
|
||||
public function syncPropertiesFromHostRoom(Room $local, array $host): void {
|
||||
$event = new BeforeRoomSyncedEvent($local);
|
||||
$this->dispatcher->dispatchTyped($event);
|
||||
|
||||
/** @var array<array-key, ARoomModifiedEvent::PROPERTY_*> $changed */
|
||||
$changed = [];
|
||||
if (isset($host['type']) && $host['type'] !== $local->getType()) {
|
||||
$success = $this->setType($local, $host['type']);
|
||||
if (!$success) {
|
||||
$this->logger->error('An error occurred while trying to sync type of ' . $local->getId() . ' to ' . $host['type']);
|
||||
} else {
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_TYPE;
|
||||
}
|
||||
}
|
||||
if (isset($host['name']) && $host['name'] !== $local->getName()) {
|
||||
$success = $this->setName($local, $host['name'], $local->getName());
|
||||
if (!$success) {
|
||||
$this->logger->error('An error occurred while trying to sync name of ' . $local->getId() . ' to ' . $host['name']);
|
||||
} else {
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_NAME;
|
||||
}
|
||||
}
|
||||
if (isset($host['description']) && $host['description'] !== $local->getDescription()) {
|
||||
try {
|
||||
$success = $this->setDescription($local, $host['description']);
|
||||
if (!$success) {
|
||||
$this->logger->error('An error occurred while trying to sync description of ' . $local->getId() . ' to ' . $host['description']);
|
||||
} else {
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_DESCRIPTION;
|
||||
}
|
||||
} catch (\LengthException $e) {
|
||||
$this->logger->error('A \LengthException occurred while trying to sync description of ' . $local->getId() . ' to ' . $host['description'], ['exception' => $e]);
|
||||
}
|
||||
}
|
||||
if (isset($host['callRecording']) && $host['callRecording'] !== $local->getCallRecording()) {
|
||||
try {
|
||||
$this->setCallRecording($local, $host['callRecording']);
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_CALL_RECORDING;
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error('An error (' . $e->getMessage() . ') occurred while trying to sync callRecording of ' . $local->getId() . ' to ' . $host['callRecording'], ['exception' => $e]);
|
||||
}
|
||||
}
|
||||
if (isset($host['defaultPermissions']) && $host['defaultPermissions'] !== $local->getDefaultPermissions()) {
|
||||
$success = $this->setPermissions($local, 'default', Attendee::PERMISSIONS_MODIFY_SET, $host['defaultPermissions'], false);
|
||||
if (!$success) {
|
||||
$this->logger->error('An error occurred while trying to sync defaultPermissions of ' . $local->getId() . ' to ' . $host['defaultPermissions']);
|
||||
} else {
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_DEFAULT_PERMISSIONS;
|
||||
}
|
||||
}
|
||||
if (isset($host['avatarVersion']) && $host['avatarVersion'] !== $local->getAvatar()) {
|
||||
$hostAvatar = $host['avatarVersion'];
|
||||
if ($hostAvatar) {
|
||||
// Add a fake suffix as we explode by the dot in the AvatarService, but the version doesn't have one.
|
||||
$hostAvatar .= '.fed';
|
||||
}
|
||||
$success = $this->setAvatar($local, $hostAvatar);
|
||||
if (!$success) {
|
||||
$this->logger->error('An error occurred while trying to sync avatarVersion of ' . $local->getId() . ' to ' . $host['avatarVersion']);
|
||||
} else {
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_AVATAR;
|
||||
}
|
||||
}
|
||||
if (isset($host['lastActivity']) && $host['lastActivity'] !== 0 && $host['lastActivity'] !== ((int) $local->getLastActivity()?->getTimestamp())) {
|
||||
$lastActivity = $this->timeFactory->getDateTime('@' . $host['lastActivity']);
|
||||
$this->setLastActivity($local, $lastActivity);
|
||||
$changed[] = ARoomSyncedEvent::PROPERTY_LAST_ACTIVITY;
|
||||
}
|
||||
if (isset($host['lobbyState'], $host['lobbyTimer']) && ($host['lobbyState'] !== $local->getLobbyState(false) || $host['lobbyTimer'] !== ((int) $local->getLobbyTimer(false)?->getTimestamp()))) {
|
||||
$hostTimer = $host['lobbyTimer'] === 0 ? null : $this->timeFactory->getDateTime('@' . $host['lobbyTimer']);
|
||||
$success = $this->setLobby($local, $host['lobbyState'], $hostTimer);
|
||||
if (!$success) {
|
||||
$this->logger->error('An error occurred while trying to sync lobby of ' . $local->getId() . ' to ' . $host['lobbyState'] . ' with timer to ' . $host['lobbyTimer']);
|
||||
} else {
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_LOBBY;
|
||||
}
|
||||
}
|
||||
if (isset($host['callStartTime'], $host['callFlag'])) {
|
||||
$localCallStartTime = (int) $local->getActiveSince()?->getTimestamp();
|
||||
if ($host['callStartTime'] === 0 && ($host['callStartTime'] !== $localCallStartTime || $host['callFlag'] !== $local->getCallFlag())) {
|
||||
$this->resetActiveSince($local, null);
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_ACTIVE_SINCE;
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_IN_CALL;
|
||||
} elseif ($host['callStartTime'] !== 0 && ($host['callStartTime'] !== $localCallStartTime || $host['callFlag'] !== $local->getCallFlag())) {
|
||||
$startDateTime = $this->timeFactory->getDateTime('@' . $host['callStartTime']);
|
||||
$this->setActiveSince($local, null, $startDateTime, $host['callFlag'], true);
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_ACTIVE_SINCE;
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_IN_CALL;
|
||||
}
|
||||
}
|
||||
if (isset($host['mentionPermissions']) && $host['mentionPermissions'] !== $local->getMentionPermissions()) {
|
||||
try {
|
||||
$this->setMentionPermissions($local, $host['mentionPermissions']);
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_MENTION_PERMISSIONS;
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error('An error (' . $e->getMessage() . ') occurred while trying to sync mentionPermissions of ' . $local->getId() . ' to ' . $host['mentionPermissions'], ['exception' => $e]);
|
||||
}
|
||||
}
|
||||
if (isset($host['messageExpiration']) && $host['messageExpiration'] !== $local->getMessageExpiration()) {
|
||||
try {
|
||||
$this->setMessageExpiration($local, $host['messageExpiration']);
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_MESSAGE_EXPIRATION;
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error('An error (' . $e->getMessage() . ') occurred while trying to sync messageExpiration of ' . $local->getId() . ' to ' . $host['messageExpiration'], ['exception' => $e]);
|
||||
}
|
||||
}
|
||||
if (isset($host['readOnly']) && $host['readOnly'] !== $local->getReadOnly()) {
|
||||
$success = $this->setReadOnly($local, $host['readOnly']);
|
||||
if (!$success) {
|
||||
$this->logger->error('An error occurred while trying to sync readOnly of ' . $local->getId() . ' to ' . $host['readOnly']);
|
||||
} else {
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_READ_ONLY;
|
||||
}
|
||||
}
|
||||
if (isset($host['recordingConsent']) && $host['recordingConsent'] !== $local->getRecordingConsent()) {
|
||||
try {
|
||||
$this->setRecordingConsent($local, $host['recordingConsent'], true);
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_RECORDING_CONSENT;
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->logger->error('An error (' . $e->getMessage() . ') occurred while trying to sync recordingConsent of ' . $local->getId() . ' to ' . $host['recordingConsent'], ['exception' => $e]);
|
||||
}
|
||||
}
|
||||
if (isset($host['sipEnabled']) && $host['sipEnabled'] !== $local->getSIPEnabled()) {
|
||||
$success = $this->setSIPEnabled($local, $host['sipEnabled']);
|
||||
if (!$success) {
|
||||
$this->logger->error('An error occurred while trying to sync sipEnabled of ' . $local->getId() . ' to ' . $host['sipEnabled']);
|
||||
} else {
|
||||
$changed[] = ARoomModifiedEvent::PROPERTY_SIP_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore for now, so the conversation is not found by other users on this federated participants server
|
||||
// if (isset($host['listable']) && $host['listable'] !== $local->getListable()) {
|
||||
// $success = $this->setListable($local, $host['listable']);
|
||||
// if (!$success) {
|
||||
// $this->logger->error('An error occurred while trying to sync listable of ' . $local->getId() . ' to ' . $host['listable']);
|
||||
// } else {
|
||||
// $changed[] = ARoomModifiedEvent::PROPERTY_LISTABLE;
|
||||
// }
|
||||
// }
|
||||
|
||||
$event = new RoomSyncedEvent($local, $changed);
|
||||
$this->dispatcher->dispatchTyped($event);
|
||||
}
|
||||
|
||||
public function deleteRoom(Room $room): void {
|
||||
$event = new BeforeRoomDeletedEvent($room);
|
||||
$this->dispatcher->dispatchTyped($event);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ namespace OCA\Talk\Signaling;
|
|||
use OCA\Talk\Config;
|
||||
use OCA\Talk\Events\AMessageSentEvent;
|
||||
use OCA\Talk\Events\AParticipantModifiedEvent;
|
||||
use OCA\Talk\Events\ARoomEvent;
|
||||
use OCA\Talk\Events\ARoomModifiedEvent;
|
||||
use OCA\Talk\Events\ASystemMessageSentEvent;
|
||||
use OCA\Talk\Events\AttendeeRemovedEvent;
|
||||
|
|
@ -18,6 +19,7 @@ use OCA\Talk\Events\AttendeesAddedEvent;
|
|||
use OCA\Talk\Events\AttendeesRemovedEvent;
|
||||
use OCA\Talk\Events\BeforeAttendeeRemovedEvent;
|
||||
use OCA\Talk\Events\BeforeRoomDeletedEvent;
|
||||
use OCA\Talk\Events\BeforeRoomSyncedEvent;
|
||||
use OCA\Talk\Events\BeforeSessionLeftRoomEvent;
|
||||
use OCA\Talk\Events\CallEndedForEveryoneEvent;
|
||||
use OCA\Talk\Events\ChatMessageSentEvent;
|
||||
|
|
@ -26,6 +28,7 @@ use OCA\Talk\Events\GuestsCleanedUpEvent;
|
|||
use OCA\Talk\Events\LobbyModifiedEvent;
|
||||
use OCA\Talk\Events\ParticipantModifiedEvent;
|
||||
use OCA\Talk\Events\RoomModifiedEvent;
|
||||
use OCA\Talk\Events\RoomSyncedEvent;
|
||||
use OCA\Talk\Events\SessionLeftRoomEvent;
|
||||
use OCA\Talk\Events\SystemMessageSentEvent;
|
||||
use OCA\Talk\Events\SystemMessagesMultipleSentEvent;
|
||||
|
|
@ -44,6 +47,24 @@ use OCP\Server;
|
|||
* @template-implements IEventListener<Event>
|
||||
*/
|
||||
class Listener implements IEventListener {
|
||||
public const EXTERNAL_SIGNALING_PROPERTIES = [
|
||||
ARoomModifiedEvent::PROPERTY_BREAKOUT_ROOM_MODE,
|
||||
ARoomModifiedEvent::PROPERTY_BREAKOUT_ROOM_STATUS,
|
||||
ARoomModifiedEvent::PROPERTY_CALL_RECORDING,
|
||||
ARoomModifiedEvent::PROPERTY_CALL_PERMISSIONS,
|
||||
ARoomModifiedEvent::PROPERTY_DEFAULT_PERMISSIONS,
|
||||
ARoomModifiedEvent::PROPERTY_DESCRIPTION,
|
||||
ARoomModifiedEvent::PROPERTY_LISTABLE,
|
||||
ARoomModifiedEvent::PROPERTY_LOBBY,
|
||||
ARoomModifiedEvent::PROPERTY_NAME,
|
||||
ARoomModifiedEvent::PROPERTY_PASSWORD,
|
||||
ARoomModifiedEvent::PROPERTY_READ_ONLY,
|
||||
ARoomModifiedEvent::PROPERTY_SIP_ENABLED,
|
||||
ARoomModifiedEvent::PROPERTY_TYPE,
|
||||
];
|
||||
|
||||
protected bool $pauseRoomModifiedListener = false;
|
||||
|
||||
public function __construct(
|
||||
protected Config $talkConfig,
|
||||
protected Messages $internalSignaling,
|
||||
|
|
@ -106,6 +127,8 @@ class Listener implements IEventListener {
|
|||
match (get_class($event)) {
|
||||
RoomModifiedEvent::class,
|
||||
LobbyModifiedEvent::class => $this->notifyRoomModified($event),
|
||||
BeforeRoomSyncedEvent::class => $this->pauseRoomModifiedListener(),
|
||||
RoomSyncedEvent::class => $this->notifyRoomSynced($event),
|
||||
BeforeRoomDeletedEvent::class => $this->notifyBeforeRoomDeleted($event),
|
||||
CallEndedForEveryoneEvent::class => $this->notifyCallEndedForEveryone($event),
|
||||
GuestsCleanedUpEvent::class => $this->notifyGuestsCleanedUp($event),
|
||||
|
|
@ -121,22 +144,12 @@ class Listener implements IEventListener {
|
|||
};
|
||||
}
|
||||
|
||||
protected function pauseRoomModifiedListener(): void {
|
||||
$this->pauseRoomModifiedListener = true;
|
||||
}
|
||||
|
||||
protected function notifyRoomModified(ARoomModifiedEvent $event): void {
|
||||
if (!in_array($event->getProperty(), [
|
||||
ARoomModifiedEvent::PROPERTY_BREAKOUT_ROOM_MODE,
|
||||
ARoomModifiedEvent::PROPERTY_BREAKOUT_ROOM_STATUS,
|
||||
ARoomModifiedEvent::PROPERTY_CALL_RECORDING,
|
||||
ARoomModifiedEvent::PROPERTY_CALL_PERMISSIONS,
|
||||
ARoomModifiedEvent::PROPERTY_DEFAULT_PERMISSIONS,
|
||||
ARoomModifiedEvent::PROPERTY_DESCRIPTION,
|
||||
ARoomModifiedEvent::PROPERTY_LISTABLE,
|
||||
ARoomModifiedEvent::PROPERTY_LOBBY,
|
||||
ARoomModifiedEvent::PROPERTY_NAME,
|
||||
ARoomModifiedEvent::PROPERTY_PASSWORD,
|
||||
ARoomModifiedEvent::PROPERTY_READ_ONLY,
|
||||
ARoomModifiedEvent::PROPERTY_SIP_ENABLED,
|
||||
ARoomModifiedEvent::PROPERTY_TYPE,
|
||||
], true)) {
|
||||
if (!in_array($event->getProperty(), self::EXTERNAL_SIGNALING_PROPERTIES, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -156,12 +169,34 @@ class Listener implements IEventListener {
|
|||
$this->externalSignaling->roomModified($event->getRoom());
|
||||
}
|
||||
|
||||
protected function notifyRoomRecordingModified(ARoomModifiedEvent $event): void {
|
||||
protected function notifyRoomSynced(RoomSyncedEvent $event): void {
|
||||
$this->pauseRoomModifiedListener = false;
|
||||
if (empty(array_intersect($event->getProperties(), self::EXTERNAL_SIGNALING_PROPERTIES))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (in_array(ARoomModifiedEvent::PROPERTY_CALL_PERMISSIONS, $event->getProperties(), true)
|
||||
|| in_array(ARoomModifiedEvent::PROPERTY_DEFAULT_PERMISSIONS, $event->getProperties(), true)) {
|
||||
$this->notifyRoomPermissionsModified($event);
|
||||
}
|
||||
|
||||
if (in_array(ARoomModifiedEvent::PROPERTY_CALL_RECORDING, $event->getProperties(), true)) {
|
||||
$this->notifyRoomRecordingModified($event);
|
||||
}
|
||||
|
||||
if (in_array(ARoomModifiedEvent::PROPERTY_BREAKOUT_ROOM_STATUS, $event->getProperties(), true)) {
|
||||
$this->notifyBreakoutRoomStatusModified($event);
|
||||
}
|
||||
|
||||
$this->externalSignaling->roomModified($event->getRoom());
|
||||
}
|
||||
|
||||
protected function notifyRoomRecordingModified(ARoomEvent $event): void {
|
||||
$room = $event->getRoom();
|
||||
$message = [
|
||||
'type' => 'recording',
|
||||
'recording' => [
|
||||
'status' => $event->getNewValue(),
|
||||
'status' => $room->getCallRecording(),
|
||||
],
|
||||
];
|
||||
|
||||
|
|
@ -243,7 +278,7 @@ class Listener implements IEventListener {
|
|||
$this->externalSignaling->participantsModified($event->getRoom(), $sessionIds);
|
||||
}
|
||||
|
||||
protected function notifyRoomPermissionsModified(ARoomModifiedEvent $event): void {
|
||||
protected function notifyRoomPermissionsModified(ARoomEvent $event): void {
|
||||
$sessionIds = [];
|
||||
|
||||
// Setting the room permissions resets the permissions of all
|
||||
|
|
@ -327,7 +362,7 @@ class Listener implements IEventListener {
|
|||
}
|
||||
}
|
||||
|
||||
protected function notifyBreakoutRoomStatusModified(ARoomModifiedEvent $event): void {
|
||||
protected function notifyBreakoutRoomStatusModified(ARoomEvent $event): void {
|
||||
$room = $event->getRoom();
|
||||
if ($room->getBreakoutRoomStatus() === BreakoutRoom::STATUS_STARTED) {
|
||||
$this->notifyBreakoutRoomStarted($room);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class RoomServiceTest extends TestCase {
|
|||
protected IHasher&MockObject $hasher;
|
||||
protected IEventDispatcher&MockObject $dispatcher;
|
||||
protected IJobList&MockObject $jobList;
|
||||
protected LoggerInterface&MockObject $logger;
|
||||
protected ?RoomService $service = null;
|
||||
|
||||
public function setUp(): void {
|
||||
|
|
@ -58,6 +59,7 @@ class RoomServiceTest extends TestCase {
|
|||
$this->hasher = $this->createMock(IHasher::class);
|
||||
$this->dispatcher = $this->createMock(IEventDispatcher::class);
|
||||
$this->jobList = $this->createMock(IJobList::class);
|
||||
$this->logger = $this->createMock(LoggerInterface::class);
|
||||
$this->service = new RoomService(
|
||||
$this->manager,
|
||||
$this->participantService,
|
||||
|
|
@ -67,7 +69,8 @@ class RoomServiceTest extends TestCase {
|
|||
$this->config,
|
||||
$this->hasher,
|
||||
$this->dispatcher,
|
||||
$this->jobList
|
||||
$this->jobList,
|
||||
$this->logger,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -327,7 +330,8 @@ class RoomServiceTest extends TestCase {
|
|||
$this->config,
|
||||
$this->hasher,
|
||||
$dispatcher,
|
||||
$this->jobList
|
||||
$this->jobList,
|
||||
$this->logger,
|
||||
);
|
||||
|
||||
$room = new Room(
|
||||
|
|
|
|||
|
|
@ -117,6 +117,8 @@ class ListenerTest extends TestCase {
|
|||
|
||||
public function testRecordingStatusChanged(): void {
|
||||
$room = $this->createMock(Room::class);
|
||||
$room->method('getCallRecording')
|
||||
->willReturn(Room::RECORDING_VIDEO);
|
||||
|
||||
$event = new RoomModifiedEvent(
|
||||
$room,
|
||||
|
|
@ -131,7 +133,7 @@ class ListenerTest extends TestCase {
|
|||
->with($room, [
|
||||
'type' => 'recording',
|
||||
'recording' => [
|
||||
'status' => $event->getNewValue(),
|
||||
'status' => Room::RECORDING_VIDEO,
|
||||
],
|
||||
]);
|
||||
$this->listener->handle($event);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue