diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6091cf7f4..ccafc0383 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Improved error handling when a room requires an access code but none was provided ([#3035])
+- Improved 404 error messages for better readability and clarity ([#86], [#3036])
+- Standardized 404 error handling on admin pages ([#1676], [#3036])
+- Improved and standardized room not found error handling in the room view ([#3036])
## [v4.14.2] - 2026-04-10
@@ -544,6 +547,7 @@ You can find the changelog for older versions there [here](https://github.com/TH
[#31]: https://github.com/THM-Health/PILOS/issues/31
[#75]: https://github.com/THM-Health/PILOS/issues/75
[#77]: https://github.com/THM-Health/PILOS/issues/77
+[#86]: https://github.com/THM-Health/PILOS/issues/86
[#300]: https://github.com/THM-Health/PILOS/issues/300
[#315]: https://github.com/THM-Health/PILOS/issues/315
[#372]: https://github.com/THM-Health/PILOS/issues/372
@@ -640,6 +644,7 @@ You can find the changelog for older versions there [here](https://github.com/TH
[#1636]: https://github.com/THM-Health/PILOS/issues/1636
[#1651]: https://github.com/THM-Health/PILOS/issues/1651
[#1675]: https://github.com/THM-Health/PILOS/issues/1675
+[#1676]: https://github.com/THM-Health/PILOS/issues/1676
[#1677]: https://github.com/THM-Health/PILOS/issues/1677
[#1678]: https://github.com/THM-Health/PILOS/pull/1678
[#1679]: https://github.com/THM-Health/PILOS/issues/1679
@@ -774,6 +779,7 @@ You can find the changelog for older versions there [here](https://github.com/TH
[#3028]: https://github.com/THM-Health/PILOS/issues/3028
[#3029]: https://github.com/THM-Health/PILOS/pull/3029
[#3035]: https://github.com/THM-Health/PILOS/pull/3035
+[#3036]: https://github.com/THM-Health/PILOS/pull/3036
[#3039]: https://github.com/THM-Health/PILOS/issues/3039
[#3040]: https://github.com/THM-Health/PILOS/pull/3040
[unreleased]: https://github.com/THM-Health/PILOS/compare/v4.14.2...develop
diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php
index f100a15d8..a57133302 100644
--- a/app/Exceptions/Handler.php
+++ b/app/Exceptions/Handler.php
@@ -4,12 +4,15 @@
namespace App\Exceptions;
+use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Foundation\ViteException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Str;
use Psr\Log\LogLevel;
use Spatie\LaravelIgnition\Exceptions\ViewException;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;
class Handler extends ExceptionHandler
@@ -77,5 +80,21 @@ public function register(): void
return null;
});
+
+ $this->renderable(function (NotFoundHttpException $e, Request $request) {
+ if ($request->expectsJson()) {
+ $modelNotFoundException = $e->getPrevious() instanceof ModelNotFoundException ? $e->getPrevious() : null;
+
+ if ($modelNotFoundException) {
+ $json = [
+ 'message' => 'model_not_found',
+ 'model' => Str::snake(class_basename($modelNotFoundException->getModel())),
+ 'ids' => $modelNotFoundException->getIds(),
+ ];
+
+ return response()->json($json, 404);
+ }
+ }
+ });
}
}
diff --git a/app/Http/Controllers/api/v1/RoomMemberController.php b/app/Http/Controllers/api/v1/RoomMemberController.php
index 35d8aa78d..3a255cadf 100644
--- a/app/Http/Controllers/api/v1/RoomMemberController.php
+++ b/app/Http/Controllers/api/v1/RoomMemberController.php
@@ -122,14 +122,11 @@ public function bulkImport(Room $room, BulkImportRequest $request)
*
* @return Response
*/
- public function update(Room $room, User $user, UpdateRoomMemberRequest $request)
+ public function update(Room $room, User $member, UpdateRoomMemberRequest $request)
{
- if (! $room->members->contains($user)) {
- abort(410, __('app.errors.not_member_of_room'));
- }
- $room->members()->updateExistingPivot($user, ['role' => $request->role]);
+ $room->members()->updateExistingPivot($member, ['role' => $request->role]);
- Log::info('Changed role for member {member} to {role} in room {room}', ['room' => $room->getLogLabel(), 'role' => RoomUserRole::from($request->role)->label(), 'member' => $user->getLogLabel()]);
+ Log::info('Changed role for member {member} to {role} in room {room}', ['room' => $room->getLogLabel(), 'role' => RoomUserRole::from($request->role)->label(), 'member' => $member->getLogLabel()]);
return response()->noContent();
}
@@ -155,14 +152,11 @@ public function bulkUpdate(Room $room, BulkUpdateRequest $request)
*
* @return Response
*/
- public function destroy(Room $room, User $user)
+ public function destroy(Room $room, User $member)
{
- if (! $room->members->contains($user)) {
- abort(410, __('app.errors.not_member_of_room'));
- }
- $room->members()->detach($user);
+ $room->members()->detach($member);
- Log::info('Removed member {member} from room {room}', ['room' => $room->getLogLabel(), 'member' => $user->getLogLabel()]);
+ Log::info('Removed member {member} from room {room}', ['room' => $room->getLogLabel(), 'member' => $member->getLogLabel()]);
return response()->noContent();
}
diff --git a/app/Http/Controllers/api/v1/RoomPersonalizedLinkController.php b/app/Http/Controllers/api/v1/RoomPersonalizedLinkController.php
index e7158bb51..4b29b87a8 100644
--- a/app/Http/Controllers/api/v1/RoomPersonalizedLinkController.php
+++ b/app/Http/Controllers/api/v1/RoomPersonalizedLinkController.php
@@ -103,20 +103,16 @@ public function store(Room $room, RoomPersonalizedLinkRequest $request)
*
* @return RoomPersonalizedLinkResource
*/
- public function update(Room $room, RoomPersonalizedLink $link, RoomPersonalizedLinkRequest $request)
+ public function update(Room $room, RoomPersonalizedLink $personalizedLink, RoomPersonalizedLinkRequest $request)
{
- if (! $link->room->is($room)) {
- abort(404, __('app.errors.personalized_link_not_found'));
- }
-
- $link->firstname = $request->firstname;
- $link->lastname = $request->lastname;
- $link->role = $request->role;
- $link->save();
+ $personalizedLink->firstname = $request->firstname;
+ $personalizedLink->lastname = $request->lastname;
+ $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' => $link->role->label(), 'name' => $link->fullname]);
+ 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]);
- return new RoomPersonalizedLinkResource($link);
+ return new RoomPersonalizedLinkResource($personalizedLink);
}
/**
@@ -126,15 +122,11 @@ public function update(Room $room, RoomPersonalizedLink $link, RoomPersonalizedL
*
* @throws \Exception
*/
- public function destroy(Room $room, RoomPersonalizedLink $link)
+ public function destroy(Room $room, RoomPersonalizedLink $personalizedLink)
{
- if (! $link->room->is($room)) {
- abort(404, __('app.errors.personalized_link_not_found'));
- }
-
- $link->delete();
+ $personalizedLink->delete();
- Log::info('Removed 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('Removed personalized room link for guest {name} with the role {role} for room {room}', ['room' => $room->getLogLabel(), 'role' => $personalizedLink->role->label(), 'name' => $personalizedLink->fullname]);
return response()->noContent();
}
diff --git a/lang/en/app.php b/lang/en/app.php
index 3782829de..fe001afa4 100644
--- a/lang/en/app.php
+++ b/lang/en/app.php
@@ -43,7 +43,7 @@
'membership_disabled' => 'Membership failed! Membership for this room is currently not available.',
'no_room_access' => 'You does not have the necessary permissions, to edit this room.',
'no_server_available' => 'Currently there are no servers available.',
- 'not_member_of_room' => 'The person is not a member of this room (anymore).',
+ 'not_member_of_room' => 'The user is not a member of this room.',
'not_running' => 'Joining the room has failed as it is currently closed.',
'personalized_link_not_found' => 'The personalized room link could not be found.',
'record_agreement_missing' => 'Consent to the recording is required.',
@@ -66,6 +66,10 @@
'flash' => [
'client_error' => 'An unknown error occurred in the application!',
'guests_only' => 'The request can only be made by guests!',
+ 'model_not_found' => [
+ 'title' => 'The :model was not found!',
+ 'details' => 'Ids: :ids',
+ ],
'server_error' => [
'empty_message' => 'An error occurred on the server during request!',
'error_code' => 'Error code: :statusCode',
@@ -97,10 +101,21 @@
'fr' => 'French',
],
'model' => [
+ 'meeting' => 'Meeting',
+ 'recording' => 'Recording',
+ 'recording_format' => 'Recording format',
+ 'role' => 'Role',
'roles' => 'role',
+ 'room' => 'Room',
+ 'room_file' => 'Room file',
+ 'room_personalized_link' => 'Room personalized link',
+ 'room_type' => 'Room type',
'room_types' => 'room type',
+ 'server' => 'Server',
+ 'server_pool' => 'Server pool',
'server_pools' => 'server pool',
'servers' => 'server',
+ 'user' => 'User',
'users' => 'user',
],
'model_name' => 'Name',
diff --git a/resources/js/components/RoomCard.vue b/resources/js/components/RoomCard.vue
index af48193fe..93617d18d 100644
--- a/resources/js/components/RoomCard.vue
+++ b/resources/js/components/RoomCard.vue
@@ -35,6 +35,7 @@