Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom create parameters in room type settings #574

Merged
merged 5 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Search and filter options to list of personalized room links ([#1007])
- Recording management ([#31], [#896])
- Content-Security-Policy ([#315],[#1090])
- Custom create parameters in room type settings ([#574])

### Changed
- Refactor user interface for room search and home page ([#372], [#373])
Expand All @@ -57,6 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Layout of the personalized room links list ([#1007])
- Bumped docker compose mariadb version to 11 ([#1080])
- **Breaking:** Global application settings storage ([#958], [#989])
- **Breaking:** The learning dashboard is no longer disabled and the meeting layout is no longer always "custom". These settings can be set with create-api-parameters in the room type settings. ([#574])

### Fixed
- Issue frontend recompiled on every restart due to a hashing issue ([#792])
Expand Down
10 changes: 6 additions & 4 deletions app/Http/Controllers/api/v1/RoomTypeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class RoomTypeController extends Controller
public function __construct()
{
$this->authorizeResource(RoomType::class, 'roomType');
$this->middleware('check.stale:roomType,\App\Http\Resources\RoomType,withServerPool,withRoles', ['only' => 'update']);
$this->middleware('check.stale:roomType,\App\Http\Resources\RoomType,withDetails,withDefaultRoomSettings', ['only' => 'update']);
}

/**
Expand Down Expand Up @@ -74,7 +74,7 @@ public function index(Request $request)
public function show(RoomType $roomType)
{

return (new RoomTypeResource($roomType))->withServerPool()->withRoles()->withDefaultRoomSettings();
return (new RoomTypeResource($roomType))->withDetails()->withDefaultRoomSettings();
}

/**
Expand All @@ -90,6 +90,7 @@ public function update(RoomTypeRequest $request, RoomType $roomType)
$roomType->restrict = $request->restrict;
$roomType->max_participants = $request->max_participants;
$roomType->max_duration = $request->max_duration;
$roomType->create_parameters = $request->create_parameters;
$roomType->serverPool()->associate($request->server_pool);

// Save default room settings
Expand All @@ -107,7 +108,7 @@ public function update(RoomTypeRequest $request, RoomType $roomType)
$roomType->roles()->sync($request->roles);
}

return (new RoomTypeResource($roomType))->withServerPool()->withRoles()->withDefaultRoomSettings();
return (new RoomTypeResource($roomType))->withDetails()->withDefaultRoomSettings();
}

/**
Expand All @@ -124,6 +125,7 @@ public function store(RoomTypeRequest $request)
$roomType->restrict = $request->restrict;
$roomType->max_participants = $request->max_participants;
$roomType->max_duration = $request->max_duration;
$roomType->create_parameters = $request->create_parameters;
$roomType->serverPool()->associate($request->server_pool);

// Safe default room settings
Expand All @@ -141,7 +143,7 @@ public function store(RoomTypeRequest $request)
$roomType->roles()->sync($request->roles);
}

return (new RoomTypeResource($roomType))->withServerPool()->withRoles()->withDefaultRoomSettings();
return (new RoomTypeResource($roomType))->withDetails()->withDefaultRoomSettings();
}

/**
Expand Down
1 change: 1 addition & 0 deletions app/Http/Requests/RoomTypeRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public function rules()
'max_duration' => ['present', 'nullable', 'numeric', 'min:1'],
'max_participants' => ['present', 'nullable', 'numeric', 'min:1'],
'server_pool' => ['required', 'integer', 'exists:App\Models\ServerPool,id'],
'create_parameters' => ['nullable', 'string', 'max:65000'],
'restrict' => ['required', 'boolean'],
'roles' => [Rule::requiredIf($this->boolean('restrict')), 'array'],
'roles.*' => ['distinct', 'integer', 'exists:App\Models\Role,id'],
Expand Down
48 changes: 16 additions & 32 deletions app/Http/Resources/RoomType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,23 @@
class RoomType extends JsonResource
{
/**
* @var bool Indicates whether the server pool should be included or not.
* @var bool Indicates whether all details should be included or not.
*/
private $withServerPool = false;

/**
* @var bool Indicates whether the roles should be included or not.
*/
private $withRoles = false;
private $withDetails = false;

/**
* @var bool Indicates whether the default room settings should be included or not.
*/
private $withDefaultRoomSettings = false;

/**
* Sets the flag to also load the server pool
*
* @return $this The server pool resource instance.
*/
public function withServerPool(): self
{
$this->withServerPool = true;

return $this;
}

/**
* Sets the flag to also load the roles
* Sets the flag to also load all details
*
* @return $this The room type resource instance.
*/
public function withRoles(): self
public function withDetails(): self
{
$this->withRoles = true;
$this->withDetails = true;

return $this;
}
Expand Down Expand Up @@ -89,17 +72,18 @@ public function toArray($request)
'name' => $this->name,
'description' => $this->description,
'color' => $this->color,
'server_pool' => $this->when($this->withServerPool, function () {
return new ServerPool($this->serverPool);
}),
'model_name' => $this->model_name,
'updated_at' => $this->updated_at,
'restrict' => $this->restrict,
'max_participants' => $this->max_participants,
'max_duration' => $this->max_duration,
'roles' => $this->when($this->withRoles, function () {
return new RoleCollection($this->roles);
}),

$this->mergeWhen($this->withDetails, [
'server_pool' => new ServerPool($this->serverPool),
'updated_at' => $this->updated_at,
'restrict' => $this->restrict,
'max_participants' => $this->max_participants,
'max_duration' => $this->max_duration,
'create_parameters' => $this->create_parameters,
'roles' => new RoleCollection($this->roles),
]),

$this->mergeWhen($this->withDefaultRoomSettings, $this->getDefaultRoomSettings()),
];
}
Expand Down
79 changes: 72 additions & 7 deletions app/Services/MeetingService.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@
use App\Models\User;
use App\Settings\BigBlueButtonSettings;
use Auth;
use BigBlueButton\Core\MeetingLayout;
use BigBlueButton\Enum\Feature;
use BigBlueButton\Enum\Role;
use BigBlueButton\Parameters\CreateMeetingParameters;
use BigBlueButton\Parameters\EndMeetingParameters;
use BigBlueButton\Parameters\GetMeetingInfoParameters;
use BigBlueButton\Parameters\JoinMeetingParameters;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Log;

class MeetingService
Expand Down Expand Up @@ -66,6 +65,13 @@ public function start(): ?\BigBlueButton\Responses\CreateMeetingResponse
{
// Set meeting parameters
$meetingParams = new CreateMeetingParameters($this->meeting->id, $this->meeting->room->name);

// Apply custom create parameters of the room type
if ($this->meeting->room->roomType->create_parameters != null) {
$this->setCustomCreateMeetingParameters($meetingParams, $this->meeting->room->roomType->create_parameters);
}

// Room settings take precedence
$meetingParams
->setRecord($this->meeting->record)
->setAutoStartRecording($this->meeting->room->auto_start_recording)
Expand All @@ -82,11 +88,7 @@ public function start(): ?\BigBlueButton\Responses\CreateMeetingResponse
->setLockSettingsDisableNotes($this->meeting->room->getRoomSetting('lock_settings_disable_note'))
->setLockSettingsHideUserList($this->meeting->room->getRoomSetting('lock_settings_hide_user_list'))
->setLockSettingsLockOnJoin(true)
->setMuteOnStart($this->meeting->room->getRoomSetting('mute_on_start'))
->setMeetingLayout(MeetingLayout::CUSTOM_LAYOUT)
->setDisabledFeatures([Feature::LEARNING_DASHBOARD])
->setRemindRecordingIsOn(true)
->setNotifyRecordingIsOn(true);
->setMuteOnStart($this->meeting->room->getRoomSetting('mute_on_start'));

$meetingParams->addMeta('bbb-origin', 'PILOS');
$meetingParams->addMeta('pilos-sub-spool-dir', config('recording.spool-sub-directory'));
Expand Down Expand Up @@ -154,6 +156,69 @@ public function start(): ?\BigBlueButton\Responses\CreateMeetingResponse
return $result;
}

/**
* Set custom parameters for creating a meeting.
*
* It reads the custom parameters from the room type of the meeting room and applies them to the meeting parameters.
* Custom parameters are defined in the format "key=value" and separated by newlines.
* If a key starts with "meta_", it is added as a meta parameter.
* If a key corresponds to a property of the CreateMeetingParameters class, it is set by the corresponding setter method.
* If the property is an array, the value is exploded by comma before passing it to the setter method.
* If a key does not correspond to a meta parameter or a property of the CreateMeetingParameters class, a warning is logged.
*
* @param CreateMeetingParameters $meetingParams The meeting parameters to which the custom parameters should be applied
* @param string $createParameters The custom parameters in the format "key=value" and separated by newlines
*/
private function setCustomCreateMeetingParameters(CreateMeetingParameters $meetingParams, string $createParameters): void
{
// Load custom create parameters of room type
foreach (explode("\n", $createParameters) as $createParameter) {
$parameterParts = explode('=', $createParameter, 2);
$parameter = $parameterParts[0];

// Skip empty lines
if (empty($parameter)) {
continue;
}

// Log a warning if a parameter has no value
if (count($parameterParts) !== 2) {
Log::warning('Custom create parameter for {parameter} has no value', ['parameter' => $parameter]);

continue;
}

$value = $parameterParts[1];

// Set meta parameters
if (Str::startsWith($parameter, 'meta_')) {
$meta = Str::after($parameter, 'meta_');
$meetingParams->addMeta($meta, $value);

continue;
}

$reflection = new \ReflectionClass(CreateMeetingParameters::class);

// Check if the parameter corresponds to a property of the CreateMeetingParameters class
if ($reflection->hasProperty($parameter)) {
// Get the setter method for the parameter
$setParamMethod = 'set'.ucfirst($parameter);

// If the property of the CreateMeetingParameters class is an array, explode the value by comma
if (is_array($reflection->getProperty($parameter)->getDefaultValue())) {
$value = explode(',', $value);
}

// Set the parameter
$meetingParams->$setParamMethod($value);
} else {
// Log a warning if a parameter cannot be found
Log::warning('Custom create parameter for {parameter} can not be found', ['parameter' => $parameter]);
}
}
}

/**
* Is Meeting running
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('room_types', function (Blueprint $table) {
$table->text('create_parameters')->nullable();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('room_types', function (Blueprint $table) {
$table->dropColumn('create_parameters');

});
}
};
5 changes: 5 additions & 0 deletions lang/de/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@
'view' => 'Detaillierte Informationen für die Rolle :name',
],
'room_types' => [
'bbb_api' => [
'title' => 'BigBlueButton API',
'create_parameters' => 'Zusätzliche Create-API-Parameter',
'create_parameters_description' => 'Angabe als Attribut-Wert-Paar (eins pro Zeile, ohne Leerzeichen), z.B. webcamsOnlyForModerator=true',
],
'color' => 'Farbe',
'custom_color' => 'Eigene Farbe',
'default_room_settings' => [
Expand Down
5 changes: 5 additions & 0 deletions lang/en/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@
'view' => 'Detailed information for the role :name',
],
'room_types' => [
'bbb_api' => [
'title' => 'BigBlueButton API',
'create_parameters' => 'Additional Create API parameters',
'create_parameters_description' => 'Specify as attribute-value pair (one per line, without spaces), e.g. webcamsOnlyForModerator=true',
],
'color' => 'Color',
'custom_color' => 'Custom color',
'default_room_settings' => [
Expand Down
24 changes: 24 additions & 0 deletions resources/js/views/settings/roomTypes/View.vue
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,29 @@
</div>
</div>

<Divider/>
<!-- BBB api settings -->
<h4>{{ $t('settings.room_types.bbb_api.title') }}</h4>

<!-- Create meeting plugin config -->
<div class="field grid">
<label for="create-parameters" class="col-12 md:col-4 md:mb-0 align-items-start">{{$t('settings.room_types.bbb_api.create_parameters')}}</label>
<div class="col-12 md:col-8">
<Textarea
input-id="create-parameters"
class="w-full"
autoResize
v-model="model.create_parameters"
:invalid="formErrors.fieldInvalid('create_parameters')"
:disabled="isBusy || modelLoadingError || viewOnly"
aria-describedby="create-parameters-help"
:placeholder="viewOnly ? '': 'meetingLayout=PRESENTATION_FOCUS\nmeta_category=FINANCE\ndisabledFeatures=learningDashboard,virtualBackgrounds'"
/>
<p id="create-parameters-help">{{$t('settings.room_types.bbb_api.create_parameters_description')}}</p>
<p class="p-error" v-html="formErrors.fieldError('create_parameters')"></p>
</div>
</div>

<div v-if="!viewOnly">
<Divider/>
<div class="flex justify-content-end">
Expand Down Expand Up @@ -941,6 +964,7 @@ const model = ref({
server_pool: null,
max_duration: null,
max_participants: null,
create_parameters: null,
restrict: false,
roles: [],
webcams_only_for_moderator_default: false,
Expand Down
1 change: 0 additions & 1 deletion tests/Feature/api/v1/Room/RoomTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,6 @@ public function testRoomView()
'name' => $room->roomType->name,
'color' => $room->roomType->color,
'model_name' => 'RoomType',
'updated_at' => $room->roomType->updated_at->toJSON(),
],
'model_name' => 'Room',
'short_description' => $room->short_description,
Expand Down
Loading
Loading