diff options
author | Joas Schilling <213943+nickvergessen@users.noreply.github.com> | 2020-03-02 18:50:49 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-02 18:50:49 +0300 |
commit | 0949866ee9fc849b740da4ca61cb58adee764a51 (patch) | |
tree | d22d39061b58bd1511f758dbe7352f97c438f50f | |
parent | dd906a7fc65e7ad209fb6db6de50d714edb01b72 (diff) | |
parent | 8e8b5af1f8fdbbe8689afbd0b8fccae4e145f780 (diff) |
Merge pull request #3038 from nextcloud/backport/2260/stable18
[stable18] Get room properties for the signaling server from separate function.
-rw-r--r-- | docs/events.md | 6 | ||||
-rw-r--r-- | lib/Chat/SystemMessage/Listener.php | 31 | ||||
-rw-r--r-- | lib/Controller/CallController.php | 1 | ||||
-rw-r--r-- | lib/Controller/SignalingController.php | 5 | ||||
-rw-r--r-- | lib/Events/SignalingRoomPropertiesEvent.php | 56 | ||||
-rw-r--r-- | lib/Room.php | 55 | ||||
-rw-r--r-- | lib/Signaling/BackendNotifier.php | 20 | ||||
-rw-r--r-- | src/App.vue | 14 | ||||
-rw-r--r-- | src/views/MainView.vue | 12 | ||||
-rw-r--r-- | tests/php/Controller/SignalingControllerTest.php | 48 | ||||
-rw-r--r-- | tests/php/Signaling/BackendNotifierTest.php | 73 |
11 files changed, 262 insertions, 59 deletions
diff --git a/docs/events.md b/docs/events.md index 7212789e9..c4701df75 100644 --- a/docs/events.md +++ b/docs/events.md @@ -195,3 +195,9 @@ Explanations: * Event class: `OCA\Talk\Events\SignalingEvent` * Event name: `OCA\Talk\Controller\SignalingController::EVENT_BACKEND_SIGNALING_ROOMS` * Since: 8.0.0 + +### Get conversation properties for signaling + +* Event class: `OCA\Talk\Events\SignalingRoomPropertiesEvent` +* Event name: `OCA\Talk\Room::EVENT_BEFORE_SIGNALING_PROPERTIES` +* Since: 8.0.5 diff --git a/lib/Chat/SystemMessage/Listener.php b/lib/Chat/SystemMessage/Listener.php index 71ea8c625..2fa0ce69f 100644 --- a/lib/Chat/SystemMessage/Listener.php +++ b/lib/Chat/SystemMessage/Listener.php @@ -78,10 +78,16 @@ class Listener { }); $dispatcher->addListener(Room::EVENT_AFTER_SESSION_LEAVE_CALL, static function(ModifyParticipantEvent $event) { $room = $event->getRoom(); + + if ($event->getParticipant()->getInCallFlags() === Participant::FLAG_DISCONNECTED) { + // This happens in case the user was kicked/lobbied + return; + } + /** @var self $listener */ $listener = \OC::$server->query(self::class); - $listener->sendSystemMessage($room, 'call_left'); + $listener->sendSystemMessage($room, 'call_left', [], $event->getParticipant()); }); $dispatcher->addListener(Room::EVENT_AFTER_ROOM_CREATE, static function(RoomEvent $event) { @@ -239,15 +245,22 @@ class Listener { $dispatcher->addListener(RoomShareProvider::class . '::' . 'share_file_again', $listener); } - protected function sendSystemMessage(Room $room, string $message, array $parameters = []): void { - $user = $this->userSession->getUser(); - if (!$user instanceof IUser) { - $actorType = 'guests'; - $sessionId = $this->talkSession->getSessionForRoom($room->getToken()); - $actorId = $sessionId ? sha1($sessionId) : 'failed-to-get-session'; + protected function sendSystemMessage(Room $room, string $message, array $parameters = [], Participant $participant = null): void { + if ($participant instanceof Participant) { + $actorType = $participant->isGuest() ? 'guests' : 'users'; + $sessionId = $participant->getSessionId(); + $sessionHash = $sessionId ? sha1($sessionId) : 'failed-to-get-session'; + $actorId = $participant->isGuest() ? $sessionHash : $participant->getUser(); } else { - $actorType = 'users'; - $actorId = $user->getUID(); + $user = $this->userSession->getUser(); + if (!$user instanceof IUser) { + $actorType = 'guests'; + $sessionId = $this->talkSession->getSessionForRoom($room->getToken()); + $actorId = $sessionId ? sha1($sessionId) : 'failed-to-get-session'; + } else { + $actorType = 'users'; + $actorId = $user->getUID(); + } } $this->chatManager->addSystemMessage( diff --git a/lib/Controller/CallController.php b/lib/Controller/CallController.php index dd8a34514..3f743538a 100644 --- a/lib/Controller/CallController.php +++ b/lib/Controller/CallController.php @@ -102,7 +102,6 @@ class CallController extends AEnvironmentAwareController { /** * @PublicPage * @RequireParticipant - * @RequireModeratorOrNoLobby * * @return DataResponse */ diff --git a/lib/Controller/SignalingController.php b/lib/Controller/SignalingController.php index 8bf0f372b..c4d76dbf4 100644 --- a/lib/Controller/SignalingController.php +++ b/lib/Controller/SignalingController.php @@ -436,10 +436,7 @@ class SignalingController extends OCSController { 'room' => [ 'version' => '1.0', 'roomid' => $room->getToken(), - 'properties' => [ - 'name' => $room->getDisplayName((string) $userId), - 'type' => $room->getType(), - ], + 'properties' => $room->getPropertiesForSignaling((string) $userId), ], ]; if ($event->getSession()) { diff --git a/lib/Events/SignalingRoomPropertiesEvent.php b/lib/Events/SignalingRoomPropertiesEvent.php new file mode 100644 index 000000000..e689be3f5 --- /dev/null +++ b/lib/Events/SignalingRoomPropertiesEvent.php @@ -0,0 +1,56 @@ +<?php +declare(strict_types=1); +/** + * @copyright Copyright (c) 2019 Joas Schilling <coding@schilljs.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Talk\Events; + + +use OCA\Talk\Room; + +class SignalingRoomPropertiesEvent extends RoomEvent { + + /** @var string|null */ + protected $userId; + /** @var array */ + protected $properties; + + public function __construct(Room $room, ?string $userId, array $properties) { + parent::__construct($room); + $this->userId = $userId; + $this->properties = $properties; + } + + public function getUserId(): ?string { + return $this->userId; + } + + public function getProperties(): array { + return $this->properties; + } + + public function setProperty(string $property, $data): void { + $this->properties[$property] = $data; + } + + public function unsetProperty(string $property): void { + unset($this->properties[$property]); + } +} diff --git a/lib/Room.php b/lib/Room.php index 8420b51d2..d77380093 100644 --- a/lib/Room.php +++ b/lib/Room.php @@ -36,6 +36,7 @@ use OCA\Talk\Events\ParticipantEvent; use OCA\Talk\Events\RemoveParticipantEvent; use OCA\Talk\Events\RemoveUserEvent; use OCA\Talk\Events\RoomEvent; +use OCA\Talk\Events\SignalingRoomPropertiesEvent; use OCA\Talk\Events\VerifyRoomPasswordEvent; use OCA\Talk\Exceptions\InvalidPasswordException; use OCA\Talk\Exceptions\ParticipantNotFoundException; @@ -100,6 +101,7 @@ class Room { public const EVENT_AFTER_SESSION_JOIN_CALL = self::class . '::postSessionJoinCall'; public const EVENT_BEFORE_SESSION_LEAVE_CALL = self::class . '::preSessionLeaveCall'; public const EVENT_AFTER_SESSION_LEAVE_CALL = self::class . '::postSessionLeaveCall'; + public const EVENT_BEFORE_SIGNALING_PROPERTIES = self::class . '::beforeSignalingProperties'; /** @var Manager */ private $manager; @@ -279,6 +281,27 @@ class Room { } /** + * Return the room properties to send to the signaling server. + * + * @param string $userId + * @return array + */ + public function getPropertiesForSignaling(string $userId): array { + $properties = [ + 'name' => $this->getDisplayName($userId), + 'type' => $this->getType(), + 'lobby-state' => $this->getLobbyState(), + 'lobby-timer' => $this->getLobbyTimer(), + 'read-only' => $this->getReadOnly(), + 'active-since' => $this->getActiveSince(), + ]; + + $event = new SignalingRoomPropertiesEvent($this, $userId, $properties); + $this->dispatcher->dispatch(self::EVENT_BEFORE_SIGNALING_PROPERTIES, $event); + return $event->getProperties(); + } + + /** * @param string|null $userId * @return Participant * @throws ParticipantNotFoundException When the user is not a participant @@ -597,6 +620,17 @@ class Room { $this->dispatcher->dispatch(self::EVENT_AFTER_LOBBY_STATE_SET, $event); + if ($newState === Webinary::LOBBY_NON_MODERATORS) { + $participants = $this->getParticipantsInCall(); + foreach ($participants as $participant) { + if ($participant->hasModeratorPermissions()) { + continue; + } + + $this->changeInCall($participant, Participant::FLAG_DISCONNECTED); + } + } + return true; } @@ -962,6 +996,27 @@ class Room { } /** + * @return Participant[] + */ + public function getParticipantsInCall(): array { + $query = $this->db->getQueryBuilder(); + $query->select('*') + ->from('talk_participants') + ->where($query->expr()->eq('room_id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT))) + ->andWhere($query->expr()->neq('in_call', $query->createNamedParameter(Participant::FLAG_DISCONNECTED))); + + $result = $query->execute(); + + $participants = []; + while ($row = $result->fetch()) { + $participants[] = $this->manager->createParticipantObject($this, $row); + } + $result->closeCursor(); + + return $participants; + } + + /** * @param int $lastPing When the last ping is older than the given timestamp, the user is ignored * @return array[] Array of users with [users => [userId => [lastPing, sessionId]], guests => [[lastPing, sessionId]]] * @deprecated Use self::getParticipants() instead diff --git a/lib/Signaling/BackendNotifier.php b/lib/Signaling/BackendNotifier.php index 642fc19d2..5750e0d14 100644 --- a/lib/Signaling/BackendNotifier.php +++ b/lib/Signaling/BackendNotifier.php @@ -131,10 +131,7 @@ class BackendNotifier { // TODO(fancycode): We should try to get rid of 'alluserids' and // find a better way to notify existing users to update the room. 'alluserids' => $room->getParticipantUserIds(), - 'properties' => [ - 'name' => $room->getDisplayName(''), - 'type' => $room->getType(), - ], + 'properties' => $room->getPropertiesForSignaling(''), ], ]); } @@ -155,10 +152,7 @@ class BackendNotifier { // TODO(fancycode): We should try to get rid of 'alluserids' and // find a better way to notify existing users to update the room. 'alluserids' => $room->getParticipantUserIds(), - 'properties' => [ - 'name' => $room->getDisplayName(''), - 'type' => $room->getType(), - ], + 'properties' => $room->getPropertiesForSignaling(''), ], ]); } @@ -179,10 +173,7 @@ class BackendNotifier { // TODO(fancycode): We should try to get rid of 'alluserids' and // find a better way to notify existing users to update the room. 'alluserids' => $room->getParticipantUserIds(), - 'properties' => [ - 'name' => $room->getDisplayName(''), - 'type' => $room->getType(), - ], + 'properties' => $room->getPropertiesForSignaling(''), ], ]); } @@ -199,10 +190,7 @@ class BackendNotifier { 'type' => 'update', 'update' => [ 'userids' => $room->getParticipantUserIds(), - 'properties' => [ - 'name' => $room->getDisplayName(''), - 'type' => $room->getType(), - ], + 'properties' => $room->getPropertiesForSignaling(''), ], ]); } diff --git a/src/App.vue b/src/App.vue index 61c78e077..682b43ed4 100644 --- a/src/App.vue +++ b/src/App.vue @@ -155,6 +155,9 @@ export default { }, beforeDestroy() { + if (!getCurrentUser()) { + EventBus.$off('shouldRefreshConversations', this.refreshCurrentConversation) + } document.removeEventListener('visibilitychange', this.changeWindowVisibility) }, @@ -163,6 +166,7 @@ export default { EventBus.$once('joinedConversation', () => { this.fixmeDelayedSetupOfGuestUsers() }) + EventBus.$on('shouldRefreshConversations', this.refreshCurrentConversation) } if (this.$route.name === 'conversation') { @@ -199,7 +203,7 @@ export default { && !this.$store.getters.conversations[this.token]) { if (!params.singleConversation) { console.info('Conversations received, but the current conversation is not in the list, trying to get potential public conversation manually') - this.fetchSingleConversation(this.token) + this.refreshCurrentConversation() } else { console.info('Conversation received, but the current conversation is not in the list. Redirecting to /apps/spreed') this.$router.push('/apps/spreed/not-found') @@ -278,13 +282,17 @@ export default { fixmeDelayedSetupOfGuestUsers() { // FIXME Refresh the data now that the user joined the conversation // The join request returns this data already, but it's lost in the signaling code - this.fetchSingleConversation(this.token) + this.refreshCurrentConversation() window.setInterval(() => { - this.fetchSingleConversation(this.token) + this.refreshCurrentConversation() }, 30000) }, + refreshCurrentConversation() { + this.fetchSingleConversation(this.token) + }, + changeWindowVisibility() { this.$store.dispatch('setWindowVisibility', !document.hidden) if (this.windowIsVisible) { diff --git a/src/views/MainView.vue b/src/views/MainView.vue index 4e3867f16..5b938bfb4 100644 --- a/src/views/MainView.vue +++ b/src/views/MainView.vue @@ -48,6 +48,18 @@ export default { }, */ + watch: { + isInLobby: function(isInLobby) { + // User is now blocked by the lobby + if (isInLobby && this.participant.inCall !== PARTICIPANT.CALL_FLAG.DISCONNECTED) { + this.$store.dispatch('leaveCall', { + token: this.token, + participantIdentifier: this.$store.getters.getParticipantIdentifier(), + }) + } + }, + }, + computed: { conversation() { return this.$store.getters.conversations[this.token] diff --git a/tests/php/Controller/SignalingControllerTest.php b/tests/php/Controller/SignalingControllerTest.php index 930a4a140..a536d37d7 100644 --- a/tests/php/Controller/SignalingControllerTest.php +++ b/tests/php/Controller/SignalingControllerTest.php @@ -367,10 +367,6 @@ class SignalingControllerTest extends \Test\TestCase { $participant = $this->createMock(Participant::class); $room->expects($this->once()) - ->method('getDisplayName') - ->with($this->userId) - ->willReturn($roomName); - $room->expects($this->once()) ->method('getParticipant') ->with($this->userId) ->willReturn($participant); @@ -378,8 +374,12 @@ class SignalingControllerTest extends \Test\TestCase { ->method('getToken') ->willReturn($roomToken); $room->expects($this->once()) - ->method('getType') - ->willReturn(Room::ONE_TO_ONE_CALL); + ->method('getPropertiesForSignaling') + ->with($this->userId) + ->willReturn([ + 'name' => $roomName, + 'type' => Room::ONE_TO_ONE_CALL, + ]); $result = $this->performBackendRequest([ 'type' => 'room', @@ -414,10 +414,6 @@ class SignalingControllerTest extends \Test\TestCase { $participant = $this->createMock(Participant::class); $room->expects($this->once()) - ->method('getDisplayName') - ->with('') - ->willReturn($roomName); - $room->expects($this->once()) ->method('getParticipantBySession') ->with($sessionId) ->willReturn($participant); @@ -425,8 +421,12 @@ class SignalingControllerTest extends \Test\TestCase { ->method('getToken') ->willReturn($roomToken); $room->expects($this->once()) - ->method('getType') - ->willReturn(Room::PUBLIC_CALL); + ->method('getPropertiesForSignaling') + ->with('') + ->willReturn([ + 'name' => $roomName, + 'type' => Room::PUBLIC_CALL, + ]); $result = $this->performBackendRequest([ 'type' => 'room', @@ -461,10 +461,6 @@ class SignalingControllerTest extends \Test\TestCase { $participant = $this->createMock(Participant::class); $room->expects($this->once()) - ->method('getDisplayName') - ->with($this->userId) - ->willReturn($roomName); - $room->expects($this->once()) ->method('getParticipant') ->with($this->userId) ->willThrowException(new ParticipantNotFoundException()); @@ -476,8 +472,12 @@ class SignalingControllerTest extends \Test\TestCase { ->method('getToken') ->willReturn($roomToken); $room->expects($this->once()) - ->method('getType') - ->willReturn(Room::PUBLIC_CALL); + ->method('getPropertiesForSignaling') + ->with($this->userId) + ->willReturn([ + 'name' => $roomName, + 'type' => Room::PUBLIC_CALL, + ]); $result = $this->performBackendRequest([ 'type' => 'room', @@ -550,10 +550,6 @@ class SignalingControllerTest extends \Test\TestCase { $participant = $this->createMock(Participant::class); $room->expects($this->once()) - ->method('getDisplayName') - ->with($this->userId) - ->willReturn($roomName); - $room->expects($this->once()) ->method('getParticipant') ->with($this->userId) ->willReturn($participant); @@ -561,8 +557,12 @@ class SignalingControllerTest extends \Test\TestCase { ->method('getToken') ->willReturn($roomToken); $room->expects($this->once()) - ->method('getType') - ->willReturn(Room::ONE_TO_ONE_CALL); + ->method('getPropertiesForSignaling') + ->with($this->userId) + ->willReturn([ + 'name' => $roomName, + 'type' => Room::ONE_TO_ONE_CALL, + ]); $result = $this->performBackendRequest([ 'type' => 'room', diff --git a/tests/php/Signaling/BackendNotifierTest.php b/tests/php/Signaling/BackendNotifierTest.php index f73653e52..e645328a9 100644 --- a/tests/php/Signaling/BackendNotifierTest.php +++ b/tests/php/Signaling/BackendNotifierTest.php @@ -25,6 +25,7 @@ namespace OCA\Talk\Tests\php\Signaling; use OCA\Talk\AppInfo\Application; use OCA\Talk\Chat\CommentsManager; use OCA\Talk\Config; +use OCA\Talk\Events\SignalingRoomPropertiesEvent; use OCA\Talk\Manager; use OCA\Talk\Participant; use OCA\Talk\Room; @@ -42,6 +43,7 @@ use OCP\IUserManager; use OCP\Security\IHasher; use OCP\Security\ISecureRandom; use PHPUnit\Framework\MockObject\MockObject; +use Symfony\Component\EventDispatcher\GenericEvent; class CustomBackendNotifier extends BackendNotifier { @@ -92,6 +94,8 @@ class BackendNotifierTest extends \Test\TestCase { protected $app; /** @var BackendNotifier */ protected $originalBackendNotifier; + /** @var IEventDispatcher */ + private $dispatcher; public function setUp(): void { parent::setUp(); @@ -125,7 +129,7 @@ class BackendNotifierTest extends \Test\TestCase { }); $dbConnection = \OC::$server->getDatabaseConnection(); - $dispatcher = \OC::$server->query(IEventDispatcher::class); + $this->dispatcher = \OC::$server->query(IEventDispatcher::class); $this->manager = new Manager( $dbConnection, $config, @@ -133,7 +137,7 @@ class BackendNotifierTest extends \Test\TestCase { $this->createMock(IUserManager::class), $this->createMock(CommentsManager::class), $this->createMock(TalkSession::class), - $dispatcher, + $this->dispatcher, $this->timeFactory, $this->createMock(IHasher::class), $this->createMock(IL10N::class) @@ -200,6 +204,10 @@ class BackendNotifierTest extends \Test\TestCase { 'properties' => [ 'name' => $room->getDisplayName(''), 'type' => $room->getType(), + 'lobby-state' => Webinary::LOBBY_NONE, + 'lobby-timer' => null, + 'read-only' => Room::READ_WRITE, + 'active-since' => null, ], ], ], $bodies); @@ -233,6 +241,10 @@ class BackendNotifierTest extends \Test\TestCase { 'properties' => [ 'name' => $room->getDisplayName(''), 'type' => $room->getType(), + 'lobby-state' => Webinary::LOBBY_NONE, + 'lobby-timer' => null, + 'read-only' => Room::READ_WRITE, + 'active-since' => null, ], ], ], $bodies); @@ -254,6 +266,10 @@ class BackendNotifierTest extends \Test\TestCase { 'properties' => [ 'name' => $room->getDisplayName(''), 'type' => $room->getType(), + 'lobby-state' => Webinary::LOBBY_NONE, + 'lobby-timer' => null, + 'read-only' => Room::READ_WRITE, + 'active-since' => null, ], ], ], $bodies); @@ -275,6 +291,10 @@ class BackendNotifierTest extends \Test\TestCase { 'properties' => [ 'name' => $room->getDisplayName(''), 'type' => $room->getType(), + 'lobby-state' => Webinary::LOBBY_NONE, + 'lobby-timer' => null, + 'read-only' => Room::READ_WRITE, + 'active-since' => null, ], ], ], $bodies); @@ -296,6 +316,10 @@ class BackendNotifierTest extends \Test\TestCase { 'properties' => [ 'name' => $room->getDisplayName(''), 'type' => $room->getType(), + 'lobby-state' => Webinary::LOBBY_NONE, + 'lobby-timer' => null, + 'read-only' => Room::READ_WRITE, + 'active-since' => null, ], ], ], $bodies); @@ -317,6 +341,10 @@ class BackendNotifierTest extends \Test\TestCase { 'properties' => [ 'name' => $room->getDisplayName(''), 'type' => $room->getType(), + 'lobby-state' => Webinary::LOBBY_NONE, + 'lobby-timer' => null, + 'read-only' => Room::READ_ONLY, + 'active-since' => null, ], ], ], $bodies); @@ -338,6 +366,10 @@ class BackendNotifierTest extends \Test\TestCase { 'properties' => [ 'name' => $room->getDisplayName(''), 'type' => $room->getType(), + 'lobby-state' => Webinary::LOBBY_NON_MODERATORS, + 'lobby-timer' => null, + 'read-only' => Room::READ_WRITE, + 'active-since' => null, ], ], ], $bodies); @@ -474,4 +506,41 @@ class BackendNotifierTest extends \Test\TestCase { ], $bodies); } + public function testRoomPropertiesEvent(): void { + $listener = static function(SignalingRoomPropertiesEvent $event) { + $room = $event->getRoom(); + $event->setProperty('foo', 'bar'); + $event->setProperty('room', $room->getToken()); + }; + + $this->dispatcher->addListener(Room::EVENT_BEFORE_SIGNALING_PROPERTIES, $listener); + + $room = $this->manager->createPublicRoom(); + $this->controller->clearRequests(); + $room->setName('Test room'); + + $requests = $this->controller->getRequests(); + $bodies = array_map(function($request) use ($room) { + return json_decode($this->validateBackendRequest($this->baseUrl . '/api/v1/room/' . $room->getToken(), $request), true); + }, $requests); + + $this->assertContains([ + 'type' => 'update', + 'update' => [ + 'userids' => [ + ], + 'properties' => [ + 'name' => $room->getDisplayName(''), + 'type' => $room->getType(), + 'lobby-state' => Webinary::LOBBY_NONE, + 'lobby-timer' => null, + 'read-only' => Room::READ_WRITE, + 'active-since' => null, + 'foo' => 'bar', + 'room' => $room->getToken(), + ], + ], + ], $bodies); + } + } |