Skip to content
Draft
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
34 changes: 15 additions & 19 deletions app/Http/Controllers/api/v1/RoomPersonalizedLinkController.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ public function index(Room $room, RoomPersonalizedLinkIndexRequest $request)
{
$additional = [];

// Sort by column, fallback/default is firstname
// Sort by column, fallback/default is description
$sortBy = match ($request->query('sort_by')) {
'lastname' => 'LOWER(lastname)',
'last_usage' => 'last_usage',
default => 'LOWER(firstname)',
default => 'LOWER(description)',
};

// Sort direction, fallback/default is asc
Expand Down Expand Up @@ -62,13 +61,10 @@ public function index(Room $room, RoomPersonalizedLinkIndexRequest $request)

// Apply search query if set
if ($request->filled('query')) {
// Split search query into single words and search for them in firstname and lastname
// Split search query into single words and search for them in description
$searchQueries = explode(' ', preg_replace('/\s\s+/', ' ', $request->query('query')));
foreach ($searchQueries as $searchQuery) {
$resource = $resource->where(function ($query) use ($searchQuery) {
$query->whereLike('firstname', '%'.$searchQuery.'%')
->orWhereLike('lastname', '%'.$searchQuery.'%');
});
$resource = $resource->whereLike('description', '%'.$searchQuery.'%');
}
}

Expand All @@ -87,15 +83,15 @@ public function index(Room $room, RoomPersonalizedLinkIndexRequest $request)
*/
public function store(Room $room, RoomPersonalizedLinkRequest $request)
{
$link = new RoomPersonalizedLink;
$link->firstname = $request->firstname;
$link->lastname = $request->lastname;
$link->role = $request->role;
$room->personalizedLinks()->save($link);
$personalizedLink = new RoomPersonalizedLink;
$personalizedLink->description = $request->description;
$personalizedLink->enforced_name = $request->enforced_name;
$personalizedLink->role = $request->role;
$room->personalizedLinks()->save($personalizedLink);

Log::info('Created new personalized room link for guest {name} with the role {role} for room {room}', ['room' => $room->getLogLabel(), 'role' => $link->role->label(), 'name' => $link->fullname]);
Log::info('Created new personalized room link for {description} with the role {role} for room {room}', ['room' => $room->getLogLabel(), 'role' => $personalizedLink->role->label(), 'description' => $personalizedLink->description]);

return new RoomPersonalizedLinkResource($link);
return new RoomPersonalizedLinkResource($personalizedLink);
}

/**
Expand All @@ -105,12 +101,12 @@ public function store(Room $room, RoomPersonalizedLinkRequest $request)
*/
public function update(Room $room, RoomPersonalizedLink $personalizedLink, RoomPersonalizedLinkRequest $request)
{
$personalizedLink->firstname = $request->firstname;
$personalizedLink->lastname = $request->lastname;
$personalizedLink->description = $request->description;
$personalizedLink->enforced_name = $request->enforced_name;
$personalizedLink->role = $request->role;
$personalizedLink->save();

Log::info('Updated personalized room link for guest {name} with the role {role} for room {room}', ['room' => $room->getLogLabel(), 'role' => $personalizedLink->role->label(), 'name' => $personalizedLink->fullname]);
Log::info('Updated personalized room link for {description} with the role {role} for room {room}', ['room' => $room->getLogLabel(), 'role' => $personalizedLink->role->label(), 'description' => $personalizedLink->description]);

return new RoomPersonalizedLinkResource($personalizedLink);
}
Expand All @@ -126,7 +122,7 @@ public function destroy(Room $room, RoomPersonalizedLink $personalizedLink)
{
$personalizedLink->delete();

Log::info('Removed personalized room link for guest {name} with the role {role} for room {room}', ['room' => $room->getLogLabel(), 'role' => $personalizedLink->role->label(), 'name' => $personalizedLink->fullname]);
Log::info('Removed personalized room link for {description} with the role {role} for room {room}', ['room' => $room->getLogLabel(), 'role' => $personalizedLink->role->label(), 'description' => $personalizedLink->description]);

return response()->noContent();
}
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Requests/JoinMeetingRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public function rules(): array
$personalizedLink = Context::getHidden("room.{$this->room->id}.personalized_link");

$rules = [
'name' => auth()->check() || $personalizedLink ? [] : ValidateParticipantNameRequest::participantNameValidationRules(),
'name' => auth()->check() || $personalizedLink?->enforced_name ? [] : ValidateParticipantNameRequest::participantNameValidationRules(),
'dark_mode' => ['sometimes', 'boolean'],
];

Expand Down
2 changes: 1 addition & 1 deletion app/Http/Requests/RoomPersonalizedLinkIndexRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function rules(): array
return [
'query' => ['nullable', 'string'],
'filter' => [Rule::in(['participant_role', 'moderator_role'])],
'sort_by' => [Rule::in(['firstname', 'lastname', 'last_usage'])],
'sort_by' => [Rule::in(['description', 'last_usage'])],
'sort_direction' => [Rule::in(['asc', 'desc'])],
];
}
Expand Down
4 changes: 2 additions & 2 deletions app/Http/Requests/RoomPersonalizedLinkRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class RoomPersonalizedLinkRequest extends FormRequest
public function rules()
{
return [
'firstname' => ['bail', 'required', 'min:2', 'max:50', new ValidName],
'lastname' => ['bail', 'required', 'min:2', 'max:50', new ValidName],
'description' => ['bail', 'required', 'min:2', 'max:50'],
'enforced_name' => ['bail', 'nullable', 'min:2', 'max:50', new ValidName],
'role' => ['required', Rule::in([RoomUserRole::USER, RoomUserRole::MODERATOR])],
];
}
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Requests/StartMeetingRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public function rules(): array
$personalizedLink = Context::getHidden("room.{$this->room->id}.personalized_link");

$rules = [
'name' => auth()->check() || $personalizedLink ? [] : ValidateParticipantNameRequest::participantNameValidationRules(),
'name' => auth()->check() || $personalizedLink?->enforced_name ? [] : ValidateParticipantNameRequest::participantNameValidationRules(),
'dark_mode' => ['sometimes', 'boolean'],
];

Expand Down
4 changes: 2 additions & 2 deletions app/Http/Resources/RoomPersonalizedLinkResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public function toArray($request)
return [
'id' => $this->id,
'token' => $this->token,
'firstname' => $this->firstname,
'lastname' => $this->lastname,
'description' => $this->description,
'enforced_name' => $this->enforced_name,
'role' => $this->role,
'expires' => $this->expires,
'last_usage' => $this->last_usage,
Expand Down
2 changes: 1 addition & 1 deletion app/Http/Resources/RoomResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public function getDetails($latestMeeting)
}

return [
'username' => $this->when(! empty($this->personalizedLink), $this->personalizedLink?->fullname),
'username' => $this->when($this->personalizedLink?->enforced_name !== null, $this->personalizedLink?->enforced_name),
'authenticated' => $this->authenticated,
'legacy_code' => $this->hasLegacyCode,
'description' => $this->when($this->authenticated, $this->description),
Expand Down
10 changes: 0 additions & 10 deletions app/Models/RoomPersonalizedLink.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,6 @@ public function room()
return $this->belongsTo(Room::class);
}

/**
* Full name of the links owner.
*
* @return string
*/
public function getFullnameAttribute()
{
return $this->firstname.' '.$this->lastname;
}

/**
* Expire datetime of the link
*
Expand Down
4 changes: 2 additions & 2 deletions app/Services/MeetingService.php
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,8 @@ public function getJoinUrl(JoinMeetingRequest|StartMeetingRequest $request): str
$personalizedLink = Context::getHidden("room.{$this->meeting->room->id}.personalized_link");

if (Auth::guest()) {
if ($personalizedLink) {
$name = $personalizedLink->fullname;
if ($personalizedLink?->enforced_name) {
$name = $personalizedLink->enforced_name;
} else {
$name = $request->name;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

declare(strict_types=1);

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

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('room_personalized_links', function (Blueprint $table) {
$table->string('description')->after('room_id');
$table->string('enforced_name')->after('description')->nullable();
});

DB::table('room_personalized_links')->update([
'enforced_name' => DB::raw('CONCAT(firstname, " ", lastname)'),
'description' => DB::raw('CONCAT(firstname, " ", lastname)'),
]);

Schema::table('room_personalized_links', function (Blueprint $table) {
$table->dropColumn(['firstname', 'lastname']);
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('room_personalized_links', function (Blueprint $table) {
Schema::table('room_personalized_links', function (Blueprint $table) {
$table->string('firstname')->after('room_id');
$table->string('lastname')->after('firstname');
});

DB::table('room_personalized_links')->update([
'firstname' => DB::raw('enforced_name'),
'lastname' => '',
]);

Schema::table('room_personalized_links', function (Blueprint $table) {
$table->dropColumn(['description', 'enforced_name']);
});
});
}
};
12 changes: 7 additions & 5 deletions lang/en/rooms.php
Original file line number Diff line number Diff line change
Expand Up @@ -320,13 +320,15 @@
'only_used_by_authenticated_users' => 'This room can only be used by authenticated users.',
'personalized_links' => [
'add' => 'Add personalized room link',
'confirm_delete' => 'Do you really want to delete the personalized room link for :firstname :lastname?',
'confirm_delete' => 'Do you really want to delete the personalized room link for :description ?',
'copy' => 'Copy personalized room link to clipboard',
'copy_aria' => 'Copy personalized room link for :firstname :lastname to clipboard',
'copy_aria' => 'Copy personalized room link for :description to clipboard',
'delete' => 'Delete personalized room link',
'delete_aria' => 'Delete personalized room link for :firstname :lastname',
'delete_aria' => 'Delete personalized room link for :description',
'edit' => 'Edit personalized room link',
'edit_aria' => 'Edit personalized room link for :firstname :lastname',
'edit_aria' => 'Edit personalized room link for :description',
'enforced_name' => '(Optional) Name in video conference',
'enforced_name_hint' => 'If provided, the user cannot change the name. If left blank, the user is asked to enter a name.',
'expires' => 'Expiry date',
'expires_at' => 'Expires at :date',
'filter' => [
Expand All @@ -340,7 +342,7 @@
'last_used_never' => 'Never used',
'nodata' => 'No personalized room links available!',
'reload_aria' => 'Reload personalized room links',
'room_link_copied' => 'The personalized room link for :firstname :lastname was copied to your clipboard.',
'room_link_copied' => 'The personalized room link for :description was copied to your clipboard.',
'search_aria' => 'Search personalized room links',
'sort_ascending' => 'Sort personalized room links ascending',
'sort_by' => 'Sort personalized room links by',
Expand Down
1 change: 1 addition & 0 deletions lang/en/validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
'download' => 'Downloadable',
'duration' => 'Max. duration',
'email' => 'Email',
'enforced_name' => 'Name in video conference',
'everyone_can_start' => 'Everyone can start the meeting',
'excerpt' => 'Excerpt',
'expert_mode' => 'Expert mode',
Expand Down
17 changes: 7 additions & 10 deletions resources/js/components/RoomTabPersonalizedLinks.vue
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
>
<div class="flex flex-col gap-2">
<p class="m-0 text-lg font-semibold">
{{ item.firstname }} {{ item.lastname }}
{{ item.description }}
</p>
<div class="flex flex-col items-start gap-2">
<div class="flex flex-row items-center gap-2">
Expand Down Expand Up @@ -209,17 +209,16 @@
<RoomTabPersonalizedLinksCopyButton
:room-id="props.room.id"
:token="item.token"
:firstname="item.firstname"
:lastname="item.lastname"
:description="item.description"
:disabled="isBusy"
/>
<!-- edit -->
<RoomTabPersonalizedLinksEditButton
v-if="userPermissions.can('manageSettings', props.room)"
:id="item.id"
:room-id="props.room.id"
:firstname="item.firstname"
:lastname="item.lastname"
:description="item.description"
:enforced-name="item.enforced_name"
:role="item.role"
:disabled="isBusy"
@edited="loadData()"
Expand All @@ -230,8 +229,7 @@
v-if="userPermissions.can('manageSettings', props.room)"
:id="item.id"
:room-id="props.room.id"
:firstname="item.firstname"
:lastname="item.lastname"
:description="item.description"
:disabled="isBusy"
@deleted="loadData()"
@not-found="loadData()"
Expand Down Expand Up @@ -268,14 +266,13 @@ const { t } = useI18n();
const personalizedLinks = ref([]);
const isBusy = ref(false);
const loadingError = ref(false);
const sortField = ref("lastname");
const sortField = ref("description");
const sortOrder = ref(1);
const search = ref("");
const filter = ref("all");

const sortFields = computed(() => [
{ name: t("app.firstname"), value: "firstname" },
{ name: t("app.lastname"), value: "lastname" },
{ name: t("app.description"), value: "description" },
{ name: t("rooms.personalized_links.last_usage"), value: "last_usage" },
]);

Expand Down
49 changes: 29 additions & 20 deletions resources/js/components/RoomTabPersonalizedLinksAddButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,29 +46,38 @@
:disabled="isLoadingAction"
@submit="save"
>
<!-- first name -->
<div class="field mt-6 flex flex-col gap-2" data-test="firstname-field">
<label for="firstname">{{ $t("app.firstname") }}</label>
<!-- description -->
<div class="field mt-6 flex flex-col gap-2" data-test="description-field">
<label for="description">{{ $t("app.description") }}</label>
<InputText
id="firstname"
v-model.trim="firstname"
id="description"
v-model.trim="description"
autofocus
:disabled="isLoadingAction"
:invalid="formErrors.fieldInvalid('firstname')"
:invalid="formErrors.fieldInvalid('description')"
/>
<FormError :errors="formErrors.fieldError('firstname')" />
<FormError :errors="formErrors.fieldError('description')" />
</div>

<!-- last name -->
<div class="field mt-6 flex flex-col gap-2" data-test="lastname-field">
<label for="lastname">{{ $t("app.lastname") }}</label>
<!-- enforced name -->
<div
class="field mt-6 flex flex-col gap-2"
data-test="enforced-name-field"
>
<label for="enforced-name">{{
$t("rooms.personalized_links.enforced_name")
}}</label>
<InputText
id="lastname"
v-model.trim="lastname"
id="enforced-name"
v-model.trim="enforced_name"
aria-describedby="enforced-name-hint"
:disabled="isLoadingAction"
:invalid="formErrors.fieldInvalid('lastname')"
:invalid="formErrors.fieldInvalid('enforced_name')"
/>
<FormError :errors="formErrors.fieldError('lastname')" />
<small id="enforced-name-hint">{{
$t("rooms.personalized_links.enforced_name_hint")
}}</small>
<FormError :errors="formErrors.fieldError('enforced_name')" />
</div>

<!-- select role -->
Expand Down Expand Up @@ -136,17 +145,17 @@ const api = useApi();
const formErrors = useFormErrors();

const modalVisible = ref(false);
const firstname = ref(null);
const lastname = ref(null);
const description = ref(null);
const enforced_name = ref(null);
const role = ref(null);
const isLoadingAction = ref(false);

/**
* show modal
*/
function showModal() {
firstname.value = null;
lastname.value = null;
description.value = null;
enforced_name.value = null;
role.value = null;
formErrors.clear();
modalVisible.value = true;
Expand All @@ -162,8 +171,8 @@ function save() {
const config = {
method: "post",
data: {
firstname: firstname.value,
lastname: lastname.value,
description: description.value,
enforced_name: enforced_name.value,
role: role.value,
},
};
Expand Down
Loading
Loading