diff --git a/app/Http/Controllers/api/v1/RoomPersonalizedLinkController.php b/app/Http/Controllers/api/v1/RoomPersonalizedLinkController.php index 4b29b87a83..f5c930b2da 100644 --- a/app/Http/Controllers/api/v1/RoomPersonalizedLinkController.php +++ b/app/Http/Controllers/api/v1/RoomPersonalizedLinkController.php @@ -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 @@ -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.'%'); } } @@ -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); } /** @@ -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); } @@ -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(); } diff --git a/app/Http/Requests/JoinMeetingRequest.php b/app/Http/Requests/JoinMeetingRequest.php index 44f053cc3a..11299a30a2 100644 --- a/app/Http/Requests/JoinMeetingRequest.php +++ b/app/Http/Requests/JoinMeetingRequest.php @@ -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'], ]; diff --git a/app/Http/Requests/RoomPersonalizedLinkIndexRequest.php b/app/Http/Requests/RoomPersonalizedLinkIndexRequest.php index 06b43625a1..4a24c10ca0 100644 --- a/app/Http/Requests/RoomPersonalizedLinkIndexRequest.php +++ b/app/Http/Requests/RoomPersonalizedLinkIndexRequest.php @@ -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'])], ]; } diff --git a/app/Http/Requests/RoomPersonalizedLinkRequest.php b/app/Http/Requests/RoomPersonalizedLinkRequest.php index b7dd630de6..683fa1c238 100644 --- a/app/Http/Requests/RoomPersonalizedLinkRequest.php +++ b/app/Http/Requests/RoomPersonalizedLinkRequest.php @@ -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])], ]; } diff --git a/app/Http/Requests/StartMeetingRequest.php b/app/Http/Requests/StartMeetingRequest.php index 8fa084fcab..4107d266a6 100644 --- a/app/Http/Requests/StartMeetingRequest.php +++ b/app/Http/Requests/StartMeetingRequest.php @@ -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'], ]; diff --git a/app/Http/Resources/RoomPersonalizedLinkResource.php b/app/Http/Resources/RoomPersonalizedLinkResource.php index 698e7170d9..4337fdab7f 100644 --- a/app/Http/Resources/RoomPersonalizedLinkResource.php +++ b/app/Http/Resources/RoomPersonalizedLinkResource.php @@ -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, diff --git a/app/Http/Resources/RoomResource.php b/app/Http/Resources/RoomResource.php index cc784db201..8f1573dfdf 100644 --- a/app/Http/Resources/RoomResource.php +++ b/app/Http/Resources/RoomResource.php @@ -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), diff --git a/app/Models/RoomPersonalizedLink.php b/app/Models/RoomPersonalizedLink.php index 4dcd65f06f..c1413bac64 100644 --- a/app/Models/RoomPersonalizedLink.php +++ b/app/Models/RoomPersonalizedLink.php @@ -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 * diff --git a/app/Services/MeetingService.php b/app/Services/MeetingService.php index 45822b46fd..21d6e64e0d 100644 --- a/app/Services/MeetingService.php +++ b/app/Services/MeetingService.php @@ -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; } diff --git a/database/migrations/2026_08_13_124758_refactor_names_in_room_personalized_links.php b/database/migrations/2026_08_13_124758_refactor_names_in_room_personalized_links.php new file mode 100644 index 0000000000..4e3a028b19 --- /dev/null +++ b/database/migrations/2026_08_13_124758_refactor_names_in_room_personalized_links.php @@ -0,0 +1,53 @@ +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']); + }); + }); + } +}; diff --git a/lang/en/rooms.php b/lang/en/rooms.php index b658415765..7c76ab83e5 100644 --- a/lang/en/rooms.php +++ b/lang/en/rooms.php @@ -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' => [ @@ -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', diff --git a/lang/en/validation.php b/lang/en/validation.php index ead0a02820..249b77a048 100644 --- a/lang/en/validation.php +++ b/lang/en/validation.php @@ -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', diff --git a/resources/js/components/RoomTabPersonalizedLinks.vue b/resources/js/components/RoomTabPersonalizedLinks.vue index 6b663ae9b4..f5ff4700f4 100644 --- a/resources/js/components/RoomTabPersonalizedLinks.vue +++ b/resources/js/components/RoomTabPersonalizedLinks.vue @@ -163,7 +163,7 @@ >
- {{ item.firstname }} {{ item.lastname }} + {{ item.description }}