mirror of https://github.com/sualko/cloud_bbb
feat: custom end meeting url with restriction
parent
b7aee468b2
commit
bec283e60d
|
@ -170,7 +170,7 @@ class API {
|
||||||
$createMeetingParams->setModeratorPW($room->moderatorPassword);
|
$createMeetingParams->setModeratorPW($room->moderatorPassword);
|
||||||
$createMeetingParams->setRecord($room->record);
|
$createMeetingParams->setRecord($room->record);
|
||||||
$createMeetingParams->setAllowStartStopRecording($room->record);
|
$createMeetingParams->setAllowStartStopRecording($room->record);
|
||||||
$createMeetingParams->setLogoutURL($this->urlGenerator->getBaseUrl());
|
$createMeetingParams->setLogoutURL($room->logoutURL);
|
||||||
$createMeetingParams->setMuteOnStart($room->getJoinMuted());
|
$createMeetingParams->setMuteOnStart($room->getJoinMuted());
|
||||||
|
|
||||||
$createMeetingParams->addMeta('bbb-origin-version', $this->appManager->getAppVersion(Application::ID));
|
$createMeetingParams->addMeta('bbb-origin-version', $this->appManager->getAppVersion(Application::ID));
|
||||||
|
|
|
@ -83,7 +83,8 @@ class RestrictionController extends Controller {
|
||||||
int $maxRooms,
|
int $maxRooms,
|
||||||
array $roomTypes,
|
array $roomTypes,
|
||||||
int $maxParticipants,
|
int $maxParticipants,
|
||||||
bool $allowRecording
|
bool $allowRecording,
|
||||||
|
bool $allowLogoutURL
|
||||||
): DataResponse {
|
): DataResponse {
|
||||||
return $this->handleNotFound(function () use (
|
return $this->handleNotFound(function () use (
|
||||||
$id,
|
$id,
|
||||||
|
@ -91,14 +92,16 @@ class RestrictionController extends Controller {
|
||||||
$maxRooms,
|
$maxRooms,
|
||||||
$roomTypes,
|
$roomTypes,
|
||||||
$maxParticipants,
|
$maxParticipants,
|
||||||
$allowRecording) {
|
$allowRecording,
|
||||||
|
$allowLogoutURL) {
|
||||||
return $this->service->update(
|
return $this->service->update(
|
||||||
$id,
|
$id,
|
||||||
$groupId,
|
$groupId,
|
||||||
$maxRooms,
|
$maxRooms,
|
||||||
$roomTypes,
|
$roomTypes,
|
||||||
$maxParticipants,
|
$maxParticipants,
|
||||||
$allowRecording
|
$allowRecording,
|
||||||
|
$allowLogoutURL
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,8 @@ class RoomController extends Controller {
|
||||||
bool $listenOnly,
|
bool $listenOnly,
|
||||||
bool $mediaCheck,
|
bool $mediaCheck,
|
||||||
bool $cleanLayout,
|
bool $cleanLayout,
|
||||||
bool $joinMuted
|
bool $joinMuted,
|
||||||
|
string $logoutURL
|
||||||
): DataResponse {
|
): DataResponse {
|
||||||
$room = $this->service->find($id);
|
$room = $this->service->find($id);
|
||||||
|
|
||||||
|
@ -137,13 +138,17 @@ class RoomController extends Controller {
|
||||||
return new DataResponse(['message' => 'Not allowed to enable recordings.'], Http::STATUS_BAD_REQUEST);
|
return new DataResponse(['message' => 'Not allowed to enable recordings.'], Http::STATUS_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$restriction->getallowLogoutURL() && $logoutURL !== $room->getlogoutURL()) {
|
||||||
|
return new DataResponse(['message' => 'Not allowed to enable custom logout URLs'], Https::STATUS_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
$disabledRoomTypes = \json_decode($restriction->getRoomTypes());
|
$disabledRoomTypes = \json_decode($restriction->getRoomTypes());
|
||||||
if ((in_array($access, $disabledRoomTypes) && $access !== $room->getAccess()) || !in_array($access, Room::ACCESS)) {
|
if ((in_array($access, $disabledRoomTypes) && $access !== $room->getAccess()) || !in_array($access, Room::ACCESS)) {
|
||||||
return new DataResponse(['message' => 'Access type not allowed.'], Http::STATUS_BAD_REQUEST);
|
return new DataResponse(['message' => 'Access type not allowed.'], Http::STATUS_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->handleNotFound(function () use ($id, $name, $welcome, $maxParticipants, $record, $access, $everyoneIsModerator, $requireModerator, $moderatorToken, $listenOnly, $mediaCheck, $cleanLayout, $joinMuted) {
|
return $this->handleNotFound(function () use ($id, $name, $welcome, $maxParticipants, $record, $access, $everyoneIsModerator, $requireModerator, $moderatorToken, $listenOnly, $mediaCheck, $cleanLayout, $joinMuted, $logoutURL) {
|
||||||
return $this->service->update($id, $name, $welcome, $maxParticipants, $record, $access, $everyoneIsModerator, $requireModerator, $moderatorToken, $listenOnly, $mediaCheck, $cleanLayout, $joinMuted);
|
return $this->service->update($id, $name, $welcome, $maxParticipants, $record, $access, $everyoneIsModerator, $requireModerator, $moderatorToken, $listenOnly, $mediaCheck, $cleanLayout, $joinMuted, $logoutURL);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,12 @@ use OCP\AppFramework\Db\Entity;
|
||||||
* @method string getRoomTypes()
|
* @method string getRoomTypes()
|
||||||
* @method int getMaxParticipants()
|
* @method int getMaxParticipants()
|
||||||
* @method bool getAllowRecording()
|
* @method bool getAllowRecording()
|
||||||
|
* @method bool getAllowLogoutURL()
|
||||||
* @method void setRoomId(string $id)
|
* @method void setRoomId(string $id)
|
||||||
* @method void setMaxRooms(int $number)
|
* @method void setMaxRooms(int $number)
|
||||||
* @method void setMaxParticipants(int $number)
|
* @method void setMaxParticipants(int $number)
|
||||||
* @method void setAllowRecording(bool $allow)
|
* @method void setAllowRecording(bool $allow)
|
||||||
|
* @method void setAllowLogoutURL(bool $allow)
|
||||||
*/
|
*/
|
||||||
class Restriction extends Entity implements JsonSerializable {
|
class Restriction extends Entity implements JsonSerializable {
|
||||||
public const ALL_ID = '';
|
public const ALL_ID = '';
|
||||||
|
@ -25,11 +27,13 @@ class Restriction extends Entity implements JsonSerializable {
|
||||||
protected $roomTypes = '[]';
|
protected $roomTypes = '[]';
|
||||||
protected $maxParticipants = -1;
|
protected $maxParticipants = -1;
|
||||||
protected $allowRecording = true;
|
protected $allowRecording = true;
|
||||||
|
protected $allowLogoutURL = true;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->addType('maxRooms', 'integer');
|
$this->addType('maxRooms', 'integer');
|
||||||
$this->addType('maxParticipants', 'integer');
|
$this->addType('maxParticipants', 'integer');
|
||||||
$this->addType('allowRecording', 'boolean');
|
$this->addType('allowRecording', 'boolean');
|
||||||
|
$this->addType('allowLogoutURL', 'boolean');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function jsonSerialize(): array {
|
public function jsonSerialize(): array {
|
||||||
|
@ -40,6 +44,7 @@ class Restriction extends Entity implements JsonSerializable {
|
||||||
'roomTypes' => \json_decode($this->roomTypes),
|
'roomTypes' => \json_decode($this->roomTypes),
|
||||||
'maxParticipants' => (int) $this->maxParticipants,
|
'maxParticipants' => (int) $this->maxParticipants,
|
||||||
'allowRecording' => boolval($this->allowRecording),
|
'allowRecording' => boolval($this->allowRecording),
|
||||||
|
'allowLogoutURL' => boolval($this->allowLogoutURL),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ use OCP\AppFramework\Db\Entity;
|
||||||
* @method bool getMediaCheck()
|
* @method bool getMediaCheck()
|
||||||
* @method bool getCleanLayout()
|
* @method bool getCleanLayout()
|
||||||
* @method bool getJoinMuted()
|
* @method bool getJoinMuted()
|
||||||
|
* @method string getLogoutURL()
|
||||||
* @method void setUid(string $uid)
|
* @method void setUid(string $uid)
|
||||||
* @method void setName(string $name)
|
* @method void setName(string $name)
|
||||||
* @method void setAttendeePassword(string $pw)
|
* @method void setAttendeePassword(string $pw)
|
||||||
|
@ -42,6 +43,7 @@ use OCP\AppFramework\Db\Entity;
|
||||||
* @method void setMediaCheck(bool $mediaCheck)
|
* @method void setMediaCheck(bool $mediaCheck)
|
||||||
* @method void setCleanLayout(bool $cleanLayout)
|
* @method void setCleanLayout(bool $cleanLayout)
|
||||||
* @method void setJoinMuted(bool $joinMuted)
|
* @method void setJoinMuted(bool $joinMuted)
|
||||||
|
* @method void setLogoutURL(string $logoutURL)
|
||||||
*/
|
*/
|
||||||
class Room extends Entity implements JsonSerializable {
|
class Room extends Entity implements JsonSerializable {
|
||||||
public const ACCESS_PUBLIC = 'public';
|
public const ACCESS_PUBLIC = 'public';
|
||||||
|
@ -71,6 +73,7 @@ class Room extends Entity implements JsonSerializable {
|
||||||
public $mediaCheck;
|
public $mediaCheck;
|
||||||
public $cleanLayout;
|
public $cleanLayout;
|
||||||
public $joinMuted;
|
public $joinMuted;
|
||||||
|
public $logoutURL;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->addType('maxParticipants', 'integer');
|
$this->addType('maxParticipants', 'integer');
|
||||||
|
@ -95,6 +98,7 @@ class Room extends Entity implements JsonSerializable {
|
||||||
'record' => boolval($this->record),
|
'record' => boolval($this->record),
|
||||||
'access' => $this->access,
|
'access' => $this->access,
|
||||||
'password' => $this->password,
|
'password' => $this->password,
|
||||||
|
'logoutURL' => $this->logoutURL,
|
||||||
'everyoneIsModerator' => boolval($this->everyoneIsModerator),
|
'everyoneIsModerator' => boolval($this->everyoneIsModerator),
|
||||||
'requireModerator' => boolval($this->requireModerator),
|
'requireModerator' => boolval($this->requireModerator),
|
||||||
'shared' => boolval($this->shared),
|
'shared' => boolval($this->shared),
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Migration;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use OCP\DB\ISchemaWrapper;
|
||||||
|
use OCP\Migration\IOutput;
|
||||||
|
use OCP\Migration\SimpleMigrationStep;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated migration step: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
class Version000000Date20220316125900 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 {
|
||||||
|
$schema = $schemaClosure();
|
||||||
|
|
||||||
|
if ($schema->hasTable('bbb_rooms')) {
|
||||||
|
$table = $schema->getTable('bbb_rooms');
|
||||||
|
|
||||||
|
if (!$table->hasColumn('logout_u_r_l')) {
|
||||||
|
$table->addColumn('logout_u_r_l', 'string', [
|
||||||
|
'notnull' => false,
|
||||||
|
'length' => 200
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace OCA\BigBlueButton\Migration;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use OCP\DB\ISchemaWrapper;
|
||||||
|
use OCP\Migration\IOutput;
|
||||||
|
use OCP\Migration\SimpleMigrationStep;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated migration step: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
class Version000000Date20220316165602 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 {
|
||||||
|
$schema = $schemaClosure();
|
||||||
|
|
||||||
|
if ($schema->hasTable('bbb_restrictions')) {
|
||||||
|
$table = $schema->getTable('bbb_restrictions');
|
||||||
|
|
||||||
|
if (!$table->hasColumn('allow_logout_u_r_l')) {
|
||||||
|
$table->addColumn('allow_logout_u_r_l', 'boolean', [
|
||||||
|
'notnull' => false,
|
||||||
|
'default' => false
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,6 +57,10 @@ class RestrictionService {
|
||||||
if (!$restriction->getAllowRecording() && $r->getAllowRecording()) {
|
if (!$restriction->getAllowRecording() && $r->getAllowRecording()) {
|
||||||
$restriction->setAllowRecording($r->getAllowRecording());
|
$restriction->setAllowRecording($r->getAllowRecording());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$restriction->getallowLogoutURL() && $r->getallowLogoutURL()) {
|
||||||
|
$restriction->setallowLogoutURL($r->getallowLogoutURL());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$restriction->setId(0);
|
$restriction->setId(0);
|
||||||
|
@ -82,7 +86,7 @@ class RestrictionService {
|
||||||
return $this->mapper->insert($restriction);
|
return $this->mapper->insert($restriction);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update(int $id, string $groupId, int $maxRooms, array $roomTypes, int $maxParticipants, bool $allowRecording): Restriction {
|
public function update(int $id, string $groupId, int $maxRooms, array $roomTypes, int $maxParticipants, bool $allowRecording, bool $allowLogoutURL): Restriction {
|
||||||
try {
|
try {
|
||||||
$restriction = $this->mapper->find($id);
|
$restriction = $this->mapper->find($id);
|
||||||
|
|
||||||
|
@ -91,6 +95,7 @@ class RestrictionService {
|
||||||
$restriction->setRoomTypes(\json_encode($roomTypes));
|
$restriction->setRoomTypes(\json_encode($roomTypes));
|
||||||
$restriction->setMaxParticipants(\max($maxParticipants, -1));
|
$restriction->setMaxParticipants(\max($maxParticipants, -1));
|
||||||
$restriction->setAllowRecording($allowRecording);
|
$restriction->setAllowRecording($allowRecording);
|
||||||
|
$restriction->setallowLogoutURL($allowLogoutURL);
|
||||||
|
|
||||||
return $this->mapper->update($restriction);
|
return $this->mapper->update($restriction);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ use OCA\BigBlueButton\Db\Room;
|
||||||
use OCA\BigBlueButton\Db\RoomMapper;
|
use OCA\BigBlueButton\Db\RoomMapper;
|
||||||
use OCA\BigBlueButton\Event\RoomCreatedEvent;
|
use OCA\BigBlueButton\Event\RoomCreatedEvent;
|
||||||
|
|
||||||
|
use OCP\IURLGenerator;
|
||||||
use OCA\BigBlueButton\Event\RoomDeletedEvent;
|
use OCA\BigBlueButton\Event\RoomDeletedEvent;
|
||||||
use OCP\AppFramework\Db\DoesNotExistException;
|
use OCP\AppFramework\Db\DoesNotExistException;
|
||||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||||
|
@ -17,6 +18,9 @@ use OCP\Security\ISecureRandom;
|
||||||
|
|
||||||
class RoomService {
|
class RoomService {
|
||||||
|
|
||||||
|
/** @var IURLGenerator */
|
||||||
|
private $urlGenerator;
|
||||||
|
|
||||||
/** @var RoomMapper */
|
/** @var RoomMapper */
|
||||||
private $mapper;
|
private $mapper;
|
||||||
|
|
||||||
|
@ -30,10 +34,12 @@ class RoomService {
|
||||||
private $random;
|
private $random;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
IURLGenerator $urlGenerator,
|
||||||
RoomMapper $mapper,
|
RoomMapper $mapper,
|
||||||
IConfig $config,
|
IConfig $config,
|
||||||
IEventDispatcher $eventDispatcher,
|
IEventDispatcher $eventDispatcher,
|
||||||
ISecureRandom $random) {
|
ISecureRandom $random) {
|
||||||
|
$this->urlGenerator = $urlGenerator;
|
||||||
$this->mapper = $mapper;
|
$this->mapper = $mapper;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->eventDispatcher = $eventDispatcher;
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
|
@ -103,6 +109,7 @@ class RoomService {
|
||||||
$room->setMediaCheck($mediaCheck);
|
$room->setMediaCheck($mediaCheck);
|
||||||
$room->setCleanLayout(false);
|
$room->setCleanLayout(false);
|
||||||
$room->setJoinMuted(false);
|
$room->setJoinMuted(false);
|
||||||
|
$room->setLogoutURL($this->urlGenerator->getBaseUrl());
|
||||||
|
|
||||||
if ($access === Room::ACCESS_PASSWORD) {
|
if ($access === Room::ACCESS_PASSWORD) {
|
||||||
$room->setPassword($this->humanReadableRandom(8));
|
$room->setPassword($this->humanReadableRandom(8));
|
||||||
|
@ -133,7 +140,8 @@ class RoomService {
|
||||||
bool $listenOnly,
|
bool $listenOnly,
|
||||||
bool $mediaCheck,
|
bool $mediaCheck,
|
||||||
bool $cleanLayout,
|
bool $cleanLayout,
|
||||||
bool $joinMuted) {
|
bool $joinMuted,
|
||||||
|
string $logoutURL) {
|
||||||
try {
|
try {
|
||||||
$room = $this->mapper->find($id);
|
$room = $this->mapper->find($id);
|
||||||
|
|
||||||
|
@ -156,6 +164,7 @@ class RoomService {
|
||||||
$room->setMediaCheck($mediaCheck);
|
$room->setMediaCheck($mediaCheck);
|
||||||
$room->setCleanLayout($cleanLayout);
|
$room->setCleanLayout($cleanLayout);
|
||||||
$room->setJoinMuted($joinMuted);
|
$room->setJoinMuted($joinMuted);
|
||||||
|
$room->setLogoutURL($logoutURL);
|
||||||
|
|
||||||
return $this->mapper->update($room);
|
return $this->mapper->update($room);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
|
|
@ -67,6 +67,7 @@ class RestrictionServiceTest extends TestCase {
|
||||||
$this->assertEquals(10, $updatedRestriction->getMaxRooms());
|
$this->assertEquals(10, $updatedRestriction->getMaxRooms());
|
||||||
$this->assertEquals(15, $updatedRestriction->getMaxParticipants());
|
$this->assertEquals(15, $updatedRestriction->getMaxParticipants());
|
||||||
$this->assertEquals(false, $updatedRestriction->getAllowRecording());
|
$this->assertEquals(false, $updatedRestriction->getAllowRecording());
|
||||||
|
$this->assertEqauls(false, $updatedRestriction->getAllowLogoutURL());
|
||||||
|
|
||||||
$this->service->delete($restriction->getId());
|
$this->service->delete($restriction->getId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,12 +25,14 @@ class RestrictionServiceTest extends TestCase {
|
||||||
$restriction0->setRoomTypes(\json_encode([Room::ACCESS_INTERNAL]));
|
$restriction0->setRoomTypes(\json_encode([Room::ACCESS_INTERNAL]));
|
||||||
$restriction0->setMaxParticipants(50);
|
$restriction0->setMaxParticipants(50);
|
||||||
$restriction0->setAllowRecording(false);
|
$restriction0->setAllowRecording(false);
|
||||||
|
$restriction0->setAllowLogoutURL(false);
|
||||||
|
|
||||||
$restriction1 = new Restriction();
|
$restriction1 = new Restriction();
|
||||||
$restriction1->setRoomTypes(\json_encode([Room::ACCESS_INTERNAL, Room::ACCESS_INTERNAL_RESTRICTED]));
|
$restriction1->setRoomTypes(\json_encode([Room::ACCESS_INTERNAL, Room::ACCESS_INTERNAL_RESTRICTED]));
|
||||||
$restriction1->setMaxRooms(10);
|
$restriction1->setMaxRooms(10);
|
||||||
$restriction1->setMaxParticipants(100);
|
$restriction1->setMaxParticipants(100);
|
||||||
$restriction1->setAllowRecording(true);
|
$restriction1->setAllowRecording(true);
|
||||||
|
$restriction1->setAllowRecording(true);
|
||||||
|
|
||||||
$this->mapper
|
$this->mapper
|
||||||
->expects($this->once())
|
->expects($this->once())
|
||||||
|
@ -48,5 +50,6 @@ class RestrictionServiceTest extends TestCase {
|
||||||
$this->assertEquals(-1, $result->getMaxRooms());
|
$this->assertEquals(-1, $result->getMaxRooms());
|
||||||
$this->assertEquals(100, $result->getMaxParticipants());
|
$this->assertEquals(100, $result->getMaxParticipants());
|
||||||
$this->assertTrue($result->getAllowRecording());
|
$this->assertTrue($result->getAllowRecording());
|
||||||
|
$this->assertTrue($result->getAllowLogoutURL());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ export interface Restriction {
|
||||||
roomTypes: string[];
|
roomTypes: string[];
|
||||||
maxParticipants: number;
|
maxParticipants: number;
|
||||||
allowRecording: boolean;
|
allowRecording: boolean;
|
||||||
|
allowLogoutURL: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Room {
|
export interface Room {
|
||||||
|
@ -44,6 +45,7 @@ export interface Room {
|
||||||
mediaCheck: boolean,
|
mediaCheck: boolean,
|
||||||
cleanLayout: boolean,
|
cleanLayout: boolean,
|
||||||
joinMuted: boolean,
|
joinMuted: boolean,
|
||||||
|
logoutURL: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RoomShare {
|
export interface RoomShare {
|
||||||
|
|
|
@ -21,6 +21,7 @@ const descriptions: { [key: string]: string } = {
|
||||||
mediaCheck: t('bbb', 'If enabled, the user has not to perform an echo call and webcam preview on the first join (available since BBB server 2.3).'),
|
mediaCheck: t('bbb', 'If enabled, the user has not to perform an echo call and webcam preview on the first join (available since BBB server 2.3).'),
|
||||||
cleanLayout: t('bbb', 'If enabled, the user list, chat area and presentation are hidden by default.'),
|
cleanLayout: t('bbb', 'If enabled, the user list, chat area and presentation are hidden by default.'),
|
||||||
joinMuted: t('bbb', 'If enabled, all users will join the meeting muted.'),
|
joinMuted: t('bbb', 'If enabled, all users will join the meeting muted.'),
|
||||||
|
logoutURL: t('bbb', 'After the meeting ends, all users will be redirected to this URL'),
|
||||||
};
|
};
|
||||||
|
|
||||||
const LOGO_QR = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGnSURBVFiF7de9TxRBHMbxzxG5BonRBOGsVRJfIvGFPwFKX0tjJGqsrfwvCC0YtbJSQyT4J0hB1BhtjZFCI4FoqTRCsbO43g24e+5Q3ZNsZm9+z8zzvZns7Rw9/a0jeIx1bNZ8rYe5WzuFt7CSILj9WsFwHtooADzA7XD/DG/CgDrUwHlcDZ/ncLfdtBoCn9cUGtN8yPiWd/QVikOhfZcQ4G1oD8cA8u2oa9ljyufe3vq+HYx7ph7Avv8YO4Rx2b4uy35oKqubFWhiBl+wiJf4imn0V52smxWYxc22vn7cwwHcqjJZ1RUYi4QXNYUzKQEm/1FvYCIlwEAJz/6UAB9KeN6nBFjAp13qH2VPRjKADdkr9Uek9h3XgicZwGk8wcFI7VConUoFMIZXOLGL5ySWVHgUywI08RSDJbyDwdusE+AGjpb0wjFcrxPgSoXwXJerAnScVgo63gXAaKSv49RVBFgL7dnIwN9dAMR0LrSreUfxbfgCd3BJdix/7Q/pBn5WDPuF++G+gQu4WMjq0Ii9+WPyWeFU3K4WHsm2o+7gNTwMX7SnbW0BScCZl0uGVe8AAAAASUVORK5CYII=';
|
const LOGO_QR = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGnSURBVFiF7de9TxRBHMbxzxG5BonRBOGsVRJfIvGFPwFKX0tjJGqsrfwvCC0YtbJSQyT4J0hB1BhtjZFCI4FoqTRCsbO43g24e+5Q3ZNsZm9+z8zzvZns7Rw9/a0jeIx1bNZ8rYe5WzuFt7CSILj9WsFwHtooADzA7XD/DG/CgDrUwHlcDZ/ncLfdtBoCn9cUGtN8yPiWd/QVikOhfZcQ4G1oD8cA8u2oa9ljyufe3vq+HYx7ph7Avv8YO4Rx2b4uy35oKqubFWhiBl+wiJf4imn0V52smxWYxc22vn7cwwHcqjJZ1RUYi4QXNYUzKQEm/1FvYCIlwEAJz/6UAB9KeN6nBFjAp13qH2VPRjKADdkr9Uek9h3XgicZwGk8wcFI7VConUoFMIZXOLGL5ySWVHgUywI08RSDJbyDwdusE+AGjpb0wjFcrxPgSoXwXJerAnScVgo63gXAaKSv49RVBFgL7dnIwN9dAMR0LrSreUfxbfgCd3BJdix/7Q/pBn5WDPuF++G+gQu4WMjq0Ii9+WPyWeFU3K4WHsm2o+7gNTwMX7SnbW0BScCZl0uGVe8AAAAASUVORK5CYII=';
|
||||||
|
@ -75,6 +76,19 @@ const EditRoomDialog: React.FC<Props> = ({ room, restriction, updateProperty, op
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function inputElementRestricted(label: string, field: string, type: 'text' | 'number' = 'text', restricted: boolean) {
|
||||||
|
return (
|
||||||
|
<div className="bbb-form-element">
|
||||||
|
<label htmlFor={`bbb-${field}`}>
|
||||||
|
<h3>{label}</h3>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<SubmitInput initialValue={room[field]} type={type} name={field} onSubmitValue={value => updateProperty(field, value)} disabled={restricted} />
|
||||||
|
{descriptions[field] && <em>{descriptions[field]}</em>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function selectElement(label: string, field: string, value: string, options: { [key: string]: string }, onChange: (value: string) => void) {
|
function selectElement(label: string, field: string, value: string, options: { [key: string]: string }, onChange: (value: string) => void) {
|
||||||
return (
|
return (
|
||||||
<div className="bbb-form-element">
|
<div className="bbb-form-element">
|
||||||
|
@ -123,6 +137,8 @@ const EditRoomDialog: React.FC<Props> = ({ room, restriction, updateProperty, op
|
||||||
updateProperty('access', value);
|
updateProperty('access', value);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
|
{inputElementRestricted(t('bbb', 'Custom redirect after meeting'), 'logoutURL', 'text', !restriction?.allowLogoutURL)}
|
||||||
|
|
||||||
{room.access === Access.InternalRestricted && <div className="bbb-form-element bbb-form-shareWith">
|
{room.access === Access.InternalRestricted && <div className="bbb-form-element bbb-form-shareWith">
|
||||||
<ShareWith permission={Permission.User} room={room} shares={shares} setShares={setShares} />
|
<ShareWith permission={Permission.User} room={room} shares={shares} setShares={setShares} />
|
||||||
<em>{descriptions.internalRestrictedShareWith}</em>
|
<em>{descriptions.internalRestrictedShareWith}</em>
|
||||||
|
|
|
@ -10,6 +10,7 @@ export interface SubmitInputProps extends InputHTMLAttributes<HTMLInputElement>
|
||||||
name: string;
|
name: string;
|
||||||
onSubmitValue: (value: string) => void;
|
onSubmitValue: (value: string) => void;
|
||||||
focus?: boolean;
|
focus?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SubmitInputState {
|
export interface SubmitInputState {
|
||||||
|
@ -42,6 +43,7 @@ export class SubmitInput extends Component<SubmitInputProps, SubmitInputState> {
|
||||||
autoFocus={this.props.focus}
|
autoFocus={this.props.focus}
|
||||||
min={this.props.min}
|
min={this.props.min}
|
||||||
max={this.props.max}
|
max={this.props.max}
|
||||||
|
disabled={this.props.disabled}
|
||||||
/>
|
/>
|
||||||
</form>;
|
</form>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,10 @@ const App: React.FC<Props> = () => {
|
||||||
<th>
|
<th>
|
||||||
{t('bbb', 'Recording')}
|
{t('bbb', 'Recording')}
|
||||||
</th>
|
</th>
|
||||||
<th/>
|
<th>
|
||||||
|
{t('bbb', 'Custom redirect after meeting')}
|
||||||
|
</th>
|
||||||
|
<th />
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
|
@ -71,6 +71,16 @@ const RestrictionRoom: React.FC<Props> = (props) => {
|
||||||
<label htmlFor={`bbb-record-${restriction.id}`}></label>
|
<label htmlFor={`bbb-record-${restriction.id}`}></label>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<td className="logoutURL bbb-shrink">
|
||||||
|
<input
|
||||||
|
id={`bbb-logoutURL-${restriction.id}`}
|
||||||
|
type="checkbox"
|
||||||
|
className="checkbox"
|
||||||
|
checked={restriction.allowLogoutURL}
|
||||||
|
onChange={(event) => updateRestriction('allowLogoutURL', event.target.checked)} />
|
||||||
|
<label htmlFor={`bbb-logoutURL-${restriction.id}`}></label>
|
||||||
|
</td>
|
||||||
|
|
||||||
<td className="remove icon-col">
|
<td className="remove icon-col">
|
||||||
<button disabled={!restriction.groupId} className="action-item" onClick={deleteRow as any} title={t('bbb', 'Delete')}>
|
<button disabled={!restriction.groupId} className="action-item" onClick={deleteRow as any} title={t('bbb', 'Delete')}>
|
||||||
<span className="icon icon-delete icon-visible"></span>
|
<span className="icon icon-delete icon-visible"></span>
|
||||||
|
|
Loading…
Reference in New Issue