Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/spreed.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2022-11-10 19:15:42 +0300
committerJoas Schilling <coding@schilljs.com>2022-11-11 13:58:54 +0300
commitefc00cf580c4aaf7805e7f813e10fefada4e44e9 (patch)
tree1c15deb97b27f3d597045323e4b136343951309f
parentc30fdd409e61505dac1f993f24b90056c7c518d3 (diff)
API endpoint to create and remove breakout rooms
Signed-off-by: Joas Schilling <coding@schilljs.com>
-rw-r--r--appinfo/info.xml2
-rw-r--r--appinfo/routes/routesBreakoutRoomController.php38
-rw-r--r--lib/Controller/BreakoutRoomController.php74
-rw-r--r--lib/Manager.php28
-rw-r--r--lib/Migration/Version16000Date20221110151714.php60
-rw-r--r--lib/Model/BreakoutRoom.php35
-rw-r--r--lib/Model/SelectHelper.php1
-rw-r--r--lib/Room.php19
-rw-r--r--lib/Service/BreakoutRoomService.php207
-rw-r--r--lib/Service/RoomService.php27
-rw-r--r--tests/php/Service/RoomServiceTest.php4
11 files changed, 485 insertions, 10 deletions
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 15db83ec5..a244379e9 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -16,7 +16,7 @@ And in the works for the [coming versions](https://github.com/nextcloud/spreed/m
]]></description>
- <version>16.0.0-beta.4</version>
+ <version>16.0.0-dev.1</version>
<licence>agpl</licence>
<author>Daniel Calviño Sánchez</author>
diff --git a/appinfo/routes/routesBreakoutRoomController.php b/appinfo/routes/routesBreakoutRoomController.php
new file mode 100644
index 000000000..eb038cb80
--- /dev/null
+++ b/appinfo/routes/routesBreakoutRoomController.php
@@ -0,0 +1,38 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com>
+ *
+ * @author 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/>.
+ *
+ */
+
+$requirements = [
+ 'apiVersion' => 'v(1)',
+ 'token' => '^[a-z0-9]{4,30}$',
+];
+
+return [
+ 'ocs' => [
+ /** @see \OCA\Talk\Controller\BreakoutRoomController::configureBreakoutRooms() */
+ ['name' => 'BreakoutRoom#getPeersForCall', 'url' => '/api/{apiVersion}/breakout-rooms/{token}', 'verb' => 'POST', 'requirements' => $requirements],
+ /** @see \OCA\Talk\Controller\BreakoutRoomController::removeBreakoutRooms() */
+ ['name' => 'BreakoutRoom#joinCall', 'url' => '/api/{apiVersion}/breakout-rooms/{token}', 'verb' => 'DELETE', 'requirements' => $requirements],
+ ],
+];
diff --git a/lib/Controller/BreakoutRoomController.php b/lib/Controller/BreakoutRoomController.php
new file mode 100644
index 000000000..ea93276f2
--- /dev/null
+++ b/lib/Controller/BreakoutRoomController.php
@@ -0,0 +1,74 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com>
+ *
+ * @author 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\Controller;
+
+use InvalidArgumentException;
+use OCA\Talk\Service\BreakoutRoomService;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\IRequest;
+
+class BreakoutRoomController extends AEnvironmentAwareController {
+ protected BreakoutRoomService $breakoutRoomService;
+
+ public function __construct(string $appName,
+ IRequest $request,
+ BreakoutRoomService $breakoutRoomService) {
+ parent::__construct($appName, $request);
+ $this->breakoutRoomService = $breakoutRoomService;
+ }
+
+ /**
+ * @NoAdminRequired
+ * @RequireLoggedInModeratorParticipant
+ *
+ * @param int $mode
+ * @param int $amount
+ * @param string $attendeeMap
+ * @return DataResponse
+ */
+ public function configureBreakoutRooms(int $mode, int $amount, string $attendeeMap): DataResponse {
+ try {
+ $this->breakoutRoomService->setupBreakoutRooms($this->room, $mode, $amount, $attendeeMap);
+ } catch (InvalidArgumentException $e) {
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ // FIXME make a useful response?
+ return new DataResponse();
+ }
+
+ /**
+ * @NoAdminRequired
+ * @RequireLoggedInModeratorParticipant
+ *
+ * @return DataResponse
+ */
+ public function removeBreakoutRooms(): DataResponse {
+ $this->breakoutRoomService->removeBreakoutRooms($this->room);
+ return new DataResponse();
+ }
+}
diff --git a/lib/Manager.php b/lib/Manager.php
index 3b8814ec4..314a9d3c0 100644
--- a/lib/Manager.php
+++ b/lib/Manager.php
@@ -160,7 +160,6 @@ class Manager {
$this->db,
$this->dispatcher,
$this->timeFactory,
- $this->hasher,
(int) $row['r_id'],
(int) $row['type'],
(int) $row['read_only'],
@@ -185,7 +184,8 @@ class Manager {
$lastMessage,
$lobbyTimer,
(string) $row['object_type'],
- (string) $row['object_id']
+ (string) $row['object_id'],
+ (int) $row['breakout_room_mode']
);
}
@@ -766,6 +766,30 @@ class Manager {
}
/**
+ * @param string $objectType
+ * @param string $objectId
+ * @return Room[]
+ */
+ public function getMultipleRoomsByObject(string $objectType, string $objectId): array {
+ $query = $this->db->getQueryBuilder();
+ $helper = new SelectHelper();
+ $helper->selectRoomsTable($query);
+ $query->from('talk_rooms', 'r')
+ ->where($query->expr()->eq('r.object_type', $query->createNamedParameter($objectType)))
+ ->andWhere($query->expr()->eq('r.object_id', $query->createNamedParameter($objectId)));
+
+ $result = $query->executeQuery();
+ $rooms = [];
+ while ($row = $result->fetch()) {
+ $room = $this->createRoomObject($row);
+ $rooms[] = $room;
+ }
+ $result->closeCursor();
+
+ return $rooms;
+ }
+
+ /**
* @param string|null $userId
* @param string|null $sessionId
* @return Room
diff --git a/lib/Migration/Version16000Date20221110151714.php b/lib/Migration/Version16000Date20221110151714.php
new file mode 100644
index 000000000..84bdf8802
--- /dev/null
+++ b/lib/Migration/Version16000Date20221110151714.php
@@ -0,0 +1,60 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com>
+ *
+ * @author 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\Migration;
+
+use Closure;
+use OCP\DB\ISchemaWrapper;
+use OCP\DB\Types;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+/**
+ * Breakout rooms configuration
+ */
+class Version16000Date20221110151714 extends SimpleMigrationStep {
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ * @return null|ISchemaWrapper
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+
+ $table = $schema->getTable('talk_rooms');
+
+ if (!$table->hasColumn('breakout_room_mode')) {
+ $table->addColumn('breakout_room_mode', Types::INTEGER, [
+ 'default' => 0,
+ ]);
+ return $schema;
+ }
+
+ return null;
+ }
+}
diff --git a/lib/Model/BreakoutRoom.php b/lib/Model/BreakoutRoom.php
new file mode 100644
index 000000000..a410f4fc3
--- /dev/null
+++ b/lib/Model/BreakoutRoom.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com>
+ *
+ * @author 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\Model;
+
+class BreakoutRoom {
+ public const MODE_NOT_CONFIGURED = 0;
+ public const MODE_AUTOMATIC = 1;
+ public const MODE_MANUAL = 2;
+ public const MODE_FREE = 3;
+
+ public const MINIMUM_ROOM_AMOUNT = 2;
+}
diff --git a/lib/Model/SelectHelper.php b/lib/Model/SelectHelper.php
index 9ad2b5f09..d8f530410 100644
--- a/lib/Model/SelectHelper.php
+++ b/lib/Model/SelectHelper.php
@@ -54,6 +54,7 @@ class SelectHelper {
->addSelect($alias . 'message_expiration')
->addSelect($alias . 'remote_server')
->addSelect($alias . 'remote_token')
+ ->addSelect($alias . 'breakout_room_mode')
->selectAlias($alias . 'id', 'r_id');
}
diff --git a/lib/Room.php b/lib/Room.php
index 3042ebe9f..e0af364c1 100644
--- a/lib/Room.php
+++ b/lib/Room.php
@@ -38,7 +38,6 @@ use OCP\AppFramework\Utility\ITimeFactory;
use OCP\Comments\IComment;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IDBConnection;
-use OCP\Security\IHasher;
use OCP\Server;
class Room {
@@ -144,6 +143,8 @@ class Room {
public const EVENT_BEFORE_SIGNALING_PROPERTIES = self::class . '::beforeSignalingProperties';
public const EVENT_BEFORE_SET_MESSAGE_EXPIRATION = self::class . '::beforeSetMessageExpiration';
public const EVENT_AFTER_SET_MESSAGE_EXPIRATION = self::class . '::afterSetMessageExpiration';
+ public const EVENT_BEFORE_SET_BREAKOUT_ROOM_MODE = self::class . '::beforeSetBreakoutRoomMode';
+ public const EVENT_AFTER_SET_BREAKOUT_ROOM_MODE = self::class . '::afterSetBreakoutRoomMode';
public const DESCRIPTION_MAXIMUM_LENGTH = 500;
@@ -151,7 +152,6 @@ class Room {
private IDBConnection $db;
private IEventDispatcher $dispatcher;
private ITimeFactory $timeFactory;
- private IHasher $hasher;
private int $id;
private int $type;
@@ -178,6 +178,7 @@ class Room {
private ?IComment $lastMessage;
private string $objectType;
private string $objectId;
+ private int $breakoutRoomMode;
protected ?string $currentUser = null;
protected ?Participant $participant = null;
@@ -186,7 +187,6 @@ class Room {
IDBConnection $db,
IEventDispatcher $dispatcher,
ITimeFactory $timeFactory,
- IHasher $hasher,
int $id,
int $type,
int $readOnly,
@@ -211,12 +211,12 @@ class Room {
?IComment $lastMessage,
?\DateTime $lobbyTimer,
string $objectType,
- string $objectId) {
+ string $objectId,
+ int $breakoutRoomMode) {
$this->manager = $manager;
$this->db = $db;
$this->dispatcher = $dispatcher;
$this->timeFactory = $timeFactory;
- $this->hasher = $hasher;
$this->id = $id;
$this->type = $type;
$this->readOnly = $readOnly;
@@ -242,6 +242,7 @@ class Room {
$this->lobbyTimer = $lobbyTimer;
$this->objectType = $objectType;
$this->objectId = $objectId;
+ $this->breakoutRoomMode = $breakoutRoomMode;
}
public function getId(): int {
@@ -597,4 +598,12 @@ class Room {
$this->activeGuests++;
}
}
+
+ public function getBreakoutRoomMode(): int {
+ return $this->breakoutRoomMode;
+ }
+
+ public function setBreakoutRoomMode(int $mode): void {
+ $this->breakoutRoomMode = $mode;
+ }
}
diff --git a/lib/Service/BreakoutRoomService.php b/lib/Service/BreakoutRoomService.php
new file mode 100644
index 000000000..691e25bf4
--- /dev/null
+++ b/lib/Service/BreakoutRoomService.php
@@ -0,0 +1,207 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2022 Joas Schilling <coding@schilljs.com>
+ *
+ * @author 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\Service;
+
+use InvalidArgumentException;
+use OCA\Talk\Manager;
+use OCA\Talk\Model\Attendee;
+use OCA\Talk\Model\BreakoutRoom;
+use OCA\Talk\Participant;
+use OCA\Talk\Room;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\IL10N;
+
+class BreakoutRoomService {
+ protected Manager $manager;
+ protected RoomService $roomService;
+ protected ParticipantService $participantService;
+ protected IEventDispatcher $dispatcher;
+ protected IL10N $l;
+
+ public function __construct(Manager $manager,
+ RoomService $roomService,
+ ParticipantService $participantService,
+ IEventDispatcher $dispatcher,
+ IL10N $l) {
+ $this->manager = $manager;
+ $this->roomService = $roomService;
+ $this->participantService = $participantService;
+ $this->dispatcher = $dispatcher;
+ $this->l = $l;
+ }
+
+ /**
+ * @param Room $parent
+ * @param int $mode
+ * @psalm-param 0|1|2|3 $mode
+ * @param int $amount
+ * @param string $attendeeMap
+ * @return Room[]
+ * @throws InvalidArgumentException When the breakout rooms are configured already
+ */
+ public function setupBreakoutRooms(Room $parent, int $mode, int $amount, string $attendeeMap): array {
+ if ($parent->getBreakoutRoomMode() !== BreakoutRoom::MODE_NOT_CONFIGURED) {
+ throw new InvalidArgumentException('room');
+ }
+
+ if (!$this->roomService->setBreakoutRoomMode($parent, $mode)) {
+ throw new InvalidArgumentException('mode');
+ }
+
+ if ($amount < BreakoutRoom::MINIMUM_ROOM_AMOUNT) {
+ throw new InvalidArgumentException('amount');
+ }
+
+ if ($mode === BreakoutRoom::MODE_MANUAL) {
+ try {
+ $attendeeMap = json_decode($attendeeMap, true, 2, JSON_THROW_ON_ERROR);
+ } catch (\JsonException $e) {
+ throw new InvalidArgumentException('map');
+ }
+ }
+
+ $breakoutRooms = $this->createBreakoutRooms($parent, $amount);
+
+ $participants = $this->participantService->getParticipantsForRoom($parent);
+ // TODO Removing any non-users here as breakout rooms only support logged in users in version 1
+ $participants = array_filter($participants, static fn (Participant $participant) => $participant->getAttendee()->getActorType() === Attendee::ACTOR_USERS);
+
+ $moderators = array_filter($participants, static fn (Participant $participant) => $participant->hasModeratorPermissions());
+ $this->addModeratorsToBreakoutRooms($breakoutRooms, $moderators);
+
+ $others = array_filter($participants, static fn (Participant $participant) => !$participant->hasModeratorPermissions());
+ if ($mode === BreakoutRoom::MODE_AUTOMATIC) {
+ // Shuffle the attendees, so they are not always distributed in the same way
+ shuffle($others);
+
+ $map = [];
+ foreach ($others as $index => $participant) {
+ $map[$index % $amount] ??= [];
+ $map[$index % $amount][] = $participant;
+ }
+
+ $this->addOthersToBreakoutRooms($breakoutRooms, $map);
+ } elseif ($mode === BreakoutRoom::MODE_MANUAL) {
+ $map = [];
+ foreach ($others as $participant) {
+ $roomNumber = $attendeeMap[$participant->getAttendee()->getId()] ?? null;
+ if ($roomNumber === null) {
+ continue;
+ }
+
+ $roomNumber = (int) $roomNumber;
+
+ $map[$roomNumber] ??= [];
+ $map[$roomNumber][] = $participant;
+ }
+
+ $this->addOthersToBreakoutRooms($breakoutRooms, $map);
+ }
+
+
+ return $breakoutRooms;
+ }
+
+ /**
+ * @param Room[] $rooms
+ * @param Participant[] $moderators
+ */
+ protected function addModeratorsToBreakoutRooms(array $rooms, array $moderators): void {
+ $moderatorsToAdd = [];
+ foreach ($moderators as $moderator) {
+ $attendee = $moderator->getAttendee();
+
+ $moderatorsToAdd[] = [
+ 'actorType' => $attendee->getActorType(),
+ 'actorId' => $attendee->getActorId(),
+ 'displayName' => $attendee->getDisplayName(),
+ 'participantType' => $attendee->getParticipantType(),
+ ];
+ }
+
+ foreach ($rooms as $room) {
+ $this->participantService->addUsers($room, $moderatorsToAdd);
+ }
+ }
+
+ /**
+ * @param array $rooms
+ * @param Participant[][] $participantsMap
+ */
+ protected function addOthersToBreakoutRooms(array $rooms, array $participantsMap): void {
+ foreach ($rooms as $roomNumber => $room) {
+ $toAdd = [];
+
+ $participants = $participantsMap[$roomNumber] ?? [];
+ foreach ($participants as $participant) {
+ $attendee = $participant->getAttendee();
+
+ $toAdd[] = [
+ 'actorType' => $attendee->getActorType(),
+ 'actorId' => $attendee->getActorId(),
+ 'displayName' => $attendee->getDisplayName(),
+ 'participantType' => $attendee->getParticipantType(),
+ ];
+ }
+
+ if (empty($toAdd)) {
+ continue;
+ }
+
+ $this->participantService->addUsers($room, $toAdd);
+ }
+ }
+
+ public function createBreakoutRooms(Room $parent, int $amount): array {
+ // Safety caution cleaning up potential orphan rooms
+ $this->deleteBreakoutRooms($parent);
+
+ $rooms = [];
+ for ($i = 1; $i <= $amount; $i++) {
+ $rooms[] = $this->roomService->createConversation(
+ $parent->getType(),
+ str_replace('{number}', (string) $i, $this->l->t('Room {number}')),
+ null,
+ 'room',
+ $parent->getToken()
+ );
+ }
+
+ return $rooms;
+ }
+
+ public function removeBreakoutRooms(Room $parent): void {
+ $this->deleteBreakoutRooms($parent);
+ $this->roomService->setBreakoutRoomMode($parent, BreakoutRoom::MODE_NOT_CONFIGURED);
+ }
+
+ protected function deleteBreakoutRooms(Room $parent): void {
+ $breakoutRooms = $this->manager->getMultipleRoomsByObject('room', $parent->getToken());
+ foreach ($breakoutRooms as $breakoutRoom) {
+ $this->roomService->deleteRoom($breakoutRoom);
+ }
+ }
+}
diff --git a/lib/Service/RoomService.php b/lib/Service/RoomService.php
index f0e9bec8e..7699d15fe 100644
--- a/lib/Service/RoomService.php
+++ b/lib/Service/RoomService.php
@@ -31,6 +31,7 @@ use OCA\Talk\Events\VerifyRoomPasswordEvent;
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\Room;
use OCA\Talk\Webinary;
@@ -577,6 +578,32 @@ class RoomService {
$this->dispatcher->dispatch(Room::EVENT_AFTER_SET_MESSAGE_EXPIRATION, $event);
}
+ public function setBreakoutRoomMode(Room $room, int $mode): bool {
+ if (!in_array($mode, [
+ BreakoutRoom::MODE_NOT_CONFIGURED,
+ BreakoutRoom::MODE_AUTOMATIC,
+ BreakoutRoom::MODE_MANUAL,
+ BreakoutRoom::MODE_FREE
+ ], true)) {
+ return false;
+ }
+
+ $event = new ModifyRoomEvent($room, 'breakoutRoomMode', $mode);
+ $this->dispatcher->dispatch(Room::EVENT_BEFORE_SET_BREAKOUT_ROOM_MODE, $event);
+
+ $update = $this->db->getQueryBuilder();
+ $update->update('talk_rooms')
+ ->set('breakout_room_mode', $update->createNamedParameter($mode, IQueryBuilder::PARAM_INT))
+ ->where($update->expr()->eq('id', $update->createNamedParameter($room->getId(), IQueryBuilder::PARAM_INT)));
+ $update->executeStatement();
+
+ $room->setBreakoutRoomMode($mode);
+
+ $this->dispatcher->dispatch(Room::EVENT_AFTER_SET_BREAKOUT_ROOM_MODE, $event);
+
+ return true;
+ }
+
public function resetActiveSince(Room $room): bool {
$update = $this->db->getQueryBuilder();
$update->update('talk_rooms')
diff --git a/tests/php/Service/RoomServiceTest.php b/tests/php/Service/RoomServiceTest.php
index 5c858f745..9d5ed9ed1 100644
--- a/tests/php/Service/RoomServiceTest.php
+++ b/tests/php/Service/RoomServiceTest.php
@@ -359,7 +359,6 @@ class RoomServiceTest extends TestCase {
$this->createMock(IDBConnection::class),
$dispatcher,
$this->createMock(ITimeFactory::class),
- $this->createMock(IHasher::class),
1,
Room::TYPE_PUBLIC,
Room::READ_WRITE,
@@ -384,7 +383,8 @@ class RoomServiceTest extends TestCase {
null,
null,
'',
- ''
+ '',
+ 0
);
$verificationResult = $service->verifyPassword($room, '1234');