From 306730742c6501c432ada34e5dd9cb5c0dbfed74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Fri, 13 Mar 2026 09:11:07 +0100 Subject: [PATCH 01/18] Improve not found error handling # Conflicts: # lang/en/app.php --- app/Exceptions/Handler.php | 18 ++++++ lang/en/app.php | 1 + .../components/SettingsRolesDeleteButton.vue | 7 ++- .../SettingsServerPoolsDeleteButton.vue | 12 +++- .../SettingsServersDeleteButton.vue | 7 ++- .../components/SettingsUsersDeleteButton.vue | 7 ++- .../SettingsUsersResetPasswordButton.vue | 6 ++ resources/js/services/Api.js | 26 ++++++++ resources/js/views/AdminRolesIndex.vue | 1 + resources/js/views/AdminRolesView.vue | 1 + resources/js/views/AdminRoomTypesView.vue | 1 + resources/js/views/AdminServerPoolsIndex.vue | 1 + resources/js/views/AdminServerPoolsView.vue | 1 + resources/js/views/AdminServersIndex.vue | 1 + resources/js/views/AdminServersView.vue | 9 +++ resources/js/views/AdminUsersIndex.vue | 2 + resources/js/views/AdminUsersView.vue | 2 + .../e2e/AdminRolesIndexRoleActions.cy.js | 48 +++++++++++++- .../e2e/AdminRolesViewRoleActions.cy.js | 30 +++++++++ .../AdminRoomTypesIndexRoomTypeActions.cy.js | 12 ++-- .../AdminRoomTypesViewRoomTypeActions.cy.js | 31 ++++++++++ ...minServerPoolsIndexServerPoolActions.cy.js | 53 +++++++++++++++- ...dminServerPoolsViewServerPoolActions.cy.js | 29 +++++++++ .../e2e/AdminServersIndexServerActions.cy.js | 50 ++++++++++++++- .../e2e/AdminServersViewServerActions.cy.js | 31 ++++++++++ .../e2e/AdminUsersIndexUserActions.cy.js | 48 +++++++++++++- .../e2e/AdminUsersViewUserActions.cy.js | 62 +++++++++++++++++++ 27 files changed, 482 insertions(+), 15 deletions(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index f258bdf18..18321caff 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -2,12 +2,14 @@ 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 Psr\Log\LogLevel; use Spatie\LaravelIgnition\Exceptions\ViewException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Throwable; class Handler extends ExceptionHandler @@ -75,5 +77,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' => class_basename($modelNotFoundException->getModel()), + 'ids' => $modelNotFoundException->getIds(), + ]; + + return response()->json($json, 404); + } + } + }); } } diff --git a/lang/en/app.php b/lang/en/app.php index cb8232260..880ca7f9c 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -64,6 +64,7 @@ 'flash' => [ 'client_error' => 'An unknown error occurred in the application!', 'guests_only' => 'The request can only be made by guests!', + 'model_not_found' => ':model with id :ids was not found!', 'server_error' => [ 'empty_message' => 'An error occurred on the server during request!', 'error_code' => 'Error code: :statusCode', diff --git a/resources/js/components/SettingsRolesDeleteButton.vue b/resources/js/components/SettingsRolesDeleteButton.vue index 61f2a9e1d..76a6afa7a 100644 --- a/resources/js/components/SettingsRolesDeleteButton.vue +++ b/resources/js/components/SettingsRolesDeleteButton.vue @@ -46,6 +46,7 @@ diff --git a/resources/js/components/RoomFavoriteButton.vue b/resources/js/components/RoomFavoriteButton.vue index 0e64e9ef8..1cd422a2f 100644 --- a/resources/js/components/RoomFavoriteButton.vue +++ b/resources/js/components/RoomFavoriteButton.vue @@ -33,6 +33,10 @@ const props = defineProps({ type: Boolean, default: true, }, + redirectOnRoomModelNotFound: { + type: Boolean, + default: false, + }, }); const isLoading = ref(false); @@ -57,6 +61,7 @@ function toggleFavorite() { .catch((error) => { api.error(error, { redirectOnUnauthenticated: props.redirectOnUnauthenticated, + redirectOnRoomModelNotFound: props.redirectOnRoomModelNotFound, }); }) .finally(() => { diff --git a/resources/js/components/RoomHeader.vue b/resources/js/components/RoomHeader.vue index 4f1ea5735..e0a87fb68 100644 --- a/resources/js/components/RoomHeader.vue +++ b/resources/js/components/RoomHeader.vue @@ -33,6 +33,7 @@ v-if="!hideFavorites && authStore.isAuthenticated" :room="props.room" :redirect-on-unauthenticated="false" + :redirect-on-room-model-not-found="true" @favorites-changed="emit('reload')" /> { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabDescription.vue b/resources/js/components/RoomTabDescription.vue index bb0eeef14..583b8e113 100644 --- a/resources/js/components/RoomTabDescription.vue +++ b/resources/js/components/RoomTabDescription.vue @@ -229,7 +229,10 @@ function save() { editorOpen.value = false; } // Handle other errors - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { // Disable saving indicator diff --git a/resources/js/components/RoomTabFiles.vue b/resources/js/components/RoomTabFiles.vue index e00bf354a..8fc21ff94 100644 --- a/resources/js/components/RoomTabFiles.vue +++ b/resources/js/components/RoomTabFiles.vue @@ -425,7 +425,10 @@ function loadData(page = null) { return emit("invalidRoomAuthToken"); } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); paginator.revertFirst(); loadingError.value = true; }) diff --git a/resources/js/components/RoomTabFilesDeleteButton.vue b/resources/js/components/RoomTabFilesDeleteButton.vue index 184663335..b933ea9e1 100644 --- a/resources/js/components/RoomTabFilesDeleteButton.vue +++ b/resources/js/components/RoomTabFilesDeleteButton.vue @@ -101,14 +101,20 @@ function deleteFile() { // deleting failed if (error.response) { // file not found - if (error.response.status === env.HTTP_NOT_FOUND) { + if ( + error.response.status === env.HTTP_NOT_FOUND && + error.response.data?.model !== "Room" + ) { toast.error(t("rooms.flash.file_gone")); emit("notFound"); modalVisible.value = false; return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabFilesEditButton.vue b/resources/js/components/RoomTabFilesEditButton.vue index 25362cdb5..a4c6bc3d5 100644 --- a/resources/js/components/RoomTabFilesEditButton.vue +++ b/resources/js/components/RoomTabFilesEditButton.vue @@ -195,7 +195,10 @@ function save() { // editing failed if (error.response) { // file not found - if (error.response.status === env.HTTP_NOT_FOUND) { + if ( + error.response.status === env.HTTP_NOT_FOUND && + error.response.data?.model !== "Room" + ) { toast.error(t("rooms.flash.file_gone")); emit("notFound"); modalVisible.value = false; @@ -207,7 +210,10 @@ function save() { return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabFilesUploadButton.vue b/resources/js/components/RoomTabFilesUploadButton.vue index c65a8018d..599e76fa4 100644 --- a/resources/js/components/RoomTabFilesUploadButton.vue +++ b/resources/js/components/RoomTabFilesUploadButton.vue @@ -265,7 +265,10 @@ function uploadFile(file) { return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }); } diff --git a/resources/js/components/RoomTabHistory.vue b/resources/js/components/RoomTabHistory.vue index c4efa78e0..c0a6424f0 100644 --- a/resources/js/components/RoomTabHistory.vue +++ b/resources/js/components/RoomTabHistory.vue @@ -298,7 +298,10 @@ function loadData(page = null) { }) .catch((error) => { paginator.revertFirst(); - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); loadingError.value = true; }) .finally(() => { diff --git a/resources/js/components/RoomTabMembers.vue b/resources/js/components/RoomTabMembers.vue index 184c344b0..031521eec 100644 --- a/resources/js/components/RoomTabMembers.vue +++ b/resources/js/components/RoomTabMembers.vue @@ -377,7 +377,10 @@ function loadData(page = null) { }) .catch((error) => { paginator.revertFirst(); - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); loadingError.value = true; }) .finally(() => { diff --git a/resources/js/components/RoomTabMembersAddSingleModal.vue b/resources/js/components/RoomTabMembersAddSingleModal.vue index 1ef150ca7..d99ccc778 100644 --- a/resources/js/components/RoomTabMembersAddSingleModal.vue +++ b/resources/js/components/RoomTabMembersAddSingleModal.vue @@ -192,7 +192,10 @@ function asyncFind(query) { }) .catch((error) => { tooManyResults.value = false; - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingSearch.value = false; diff --git a/resources/js/components/RoomTabMembersBulkDeleteButton.vue b/resources/js/components/RoomTabMembersBulkDeleteButton.vue index 077b18b1a..f3dd54e1e 100644 --- a/resources/js/components/RoomTabMembersBulkDeleteButton.vue +++ b/resources/js/components/RoomTabMembersBulkDeleteButton.vue @@ -130,7 +130,10 @@ function deleteMembers() { return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabMembersBulkEditButton.vue b/resources/js/components/RoomTabMembersBulkEditButton.vue index 273951c3c..1f13795f8 100644 --- a/resources/js/components/RoomTabMembersBulkEditButton.vue +++ b/resources/js/components/RoomTabMembersBulkEditButton.vue @@ -168,7 +168,10 @@ function save() { return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabMembersBulkImportModal.vue b/resources/js/components/RoomTabMembersBulkImportModal.vue index aeb8a9983..546f1a5af 100644 --- a/resources/js/components/RoomTabMembersBulkImportModal.vue +++ b/resources/js/components/RoomTabMembersBulkImportModal.vue @@ -341,7 +341,10 @@ function importUsers(firstRound = false) { return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabMembersDeleteButton.vue b/resources/js/components/RoomTabMembersDeleteButton.vue index cf30ba516..62c86c173 100644 --- a/resources/js/components/RoomTabMembersDeleteButton.vue +++ b/resources/js/components/RoomTabMembersDeleteButton.vue @@ -111,7 +111,10 @@ function deleteMember() { modalVisible.value = false; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabMembersEditButton.vue b/resources/js/components/RoomTabMembersEditButton.vue index 8a02bed35..098b2812c 100644 --- a/resources/js/components/RoomTabMembersEditButton.vue +++ b/resources/js/components/RoomTabMembersEditButton.vue @@ -178,7 +178,10 @@ function save() { return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabPersonalizedLinks.vue b/resources/js/components/RoomTabPersonalizedLinks.vue index 0a752d5b5..5fac0e884 100644 --- a/resources/js/components/RoomTabPersonalizedLinks.vue +++ b/resources/js/components/RoomTabPersonalizedLinks.vue @@ -317,7 +317,10 @@ function loadData(page = null) { }) .catch((error) => { paginator.revertFirst(); - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); loadingError.value = true; }) .finally(() => { diff --git a/resources/js/components/RoomTabPersonalizedLinksAddButton.vue b/resources/js/components/RoomTabPersonalizedLinksAddButton.vue index 2fbef8be3..e882dae91 100644 --- a/resources/js/components/RoomTabPersonalizedLinksAddButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksAddButton.vue @@ -171,7 +171,10 @@ function save() { ) { formErrors.set(error.response.data.errors); } else { - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); } }) .finally(() => { diff --git a/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue b/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue index cd2e998ad..98f3a4872 100644 --- a/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue @@ -120,14 +120,20 @@ function deleteLink() { // deleting failed if (error.response) { // personalized link not found - if (error.response.status === env.HTTP_NOT_FOUND) { + if ( + error.response.status === env.HTTP_NOT_FOUND && + error.response.data?.model !== "Room" + ) { toast.error(t("rooms.flash.personalized_link_gone")); modalVisible.value = false; emit("notFound"); return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabPersonalizedLinksEditButton.vue b/resources/js/components/RoomTabPersonalizedLinksEditButton.vue index 7dde482ad..e362983f5 100644 --- a/resources/js/components/RoomTabPersonalizedLinksEditButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksEditButton.vue @@ -189,7 +189,10 @@ function save() { // editing failed if (error.response) { // token not found - if (error.response.status === env.HTTP_NOT_FOUND) { + if ( + error.response.status === env.HTTP_NOT_FOUND && + error.response.data?.model !== "Room" + ) { toast.error(t("rooms.flash.personalized_link_gone")); modalVisible.value = false; emit("notFound"); @@ -200,7 +203,10 @@ function save() { formErrors.set(error.response.data.errors); return; } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); } }) .finally(() => { diff --git a/resources/js/components/RoomTabRecordings.vue b/resources/js/components/RoomTabRecordings.vue index 76dd9ada9..12294a175 100644 --- a/resources/js/components/RoomTabRecordings.vue +++ b/resources/js/components/RoomTabRecordings.vue @@ -440,7 +440,10 @@ function loadData(page = null) { } loadingError.value = true; paginator.revertFirst(); - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isBusy.value = false; diff --git a/resources/js/components/RoomTabRecordingsDeleteButton.vue b/resources/js/components/RoomTabRecordingsDeleteButton.vue index 326f8f533..a943d1030 100644 --- a/resources/js/components/RoomTabRecordingsDeleteButton.vue +++ b/resources/js/components/RoomTabRecordingsDeleteButton.vue @@ -97,13 +97,19 @@ function deleteRecording() { // editing failed if (error.response) { // recording not found - if (error.response.status === env.HTTP_NOT_FOUND) { + if ( + error.response.status === env.HTTP_NOT_FOUND && + error.response.data?.model !== "Room" + ) { toast.error(t("rooms.flash.recording_gone")); emit("notFound"); return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabRecordingsEditButton.vue b/resources/js/components/RoomTabRecordingsEditButton.vue index f07787a4d..97b412d65 100644 --- a/resources/js/components/RoomTabRecordingsEditButton.vue +++ b/resources/js/components/RoomTabRecordingsEditButton.vue @@ -236,7 +236,10 @@ function save() { // editing failed if (error.response) { // recording not found - if (error.response.status === env.HTTP_NOT_FOUND) { + if ( + error.response.status === env.HTTP_NOT_FOUND && + error.response.data?.model !== "Room" + ) { toast.error(t("rooms.flash.recording_gone")); modalVisible.value = false; emit("notFound"); @@ -248,7 +251,10 @@ function save() { return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabSettings.vue b/resources/js/components/RoomTabSettings.vue index 2b03e4877..24f20c6ad 100644 --- a/resources/js/components/RoomTabSettings.vue +++ b/resources/js/components/RoomTabSettings.vue @@ -429,7 +429,10 @@ function load() { loaded.value = true; }) .catch((error) => { - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); loadingError.value = true; }) .finally(() => { diff --git a/resources/js/components/RoomTabStreaming.vue b/resources/js/components/RoomTabStreaming.vue index 37d527e84..14f9d0f76 100644 --- a/resources/js/components/RoomTabStreaming.vue +++ b/resources/js/components/RoomTabStreaming.vue @@ -170,7 +170,7 @@ async function streamingCommand(command) { if (error.response.status === env.HTTP_ROOM_NOT_RUNNING) { emit("settingsChanged"); } - api.error(error); + api.error(error, { redirectOnRoomModelNotFound: true }); }) .finally(() => { autoReload(); diff --git a/resources/js/components/RoomTabStreamingConfigButton.vue b/resources/js/components/RoomTabStreamingConfigButton.vue index 9a34fd515..2842a8b10 100644 --- a/resources/js/components/RoomTabStreamingConfigButton.vue +++ b/resources/js/components/RoomTabStreamingConfigButton.vue @@ -272,7 +272,7 @@ function save() { ) { formErrors.set(error.response.data.errors); } else { - api.error(error); + api.error(error, { redirectOnRoomModelNotFound: true }); } }) .finally(() => { diff --git a/resources/js/components/RoomTransferOwnershipButton.vue b/resources/js/components/RoomTransferOwnershipButton.vue index 641abd82c..9e22b4269 100644 --- a/resources/js/components/RoomTransferOwnershipButton.vue +++ b/resources/js/components/RoomTransferOwnershipButton.vue @@ -235,7 +235,10 @@ function transferOwnership() { return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/services/Api.js b/resources/js/services/Api.js index 9f2ba0c93..abe8620da 100644 --- a/resources/js/services/Api.js +++ b/resources/js/services/Api.js @@ -119,16 +119,14 @@ export class Api { this.toast.error(this.t("app.flash.unauthorized")); } - handleModelNotFound(error) { - const model = - error.response && error.response.data - ? error.response.data.model - : undefined; - - const ids = - error.response && error.response.data - ? error.response.data.ids - : undefined; + handleModelNotFound(error, options) { + const data = error.response?.data; + const model = data?.model; + const ids = data?.ids; + + if (model === "Room" && options.redirectOnRoomModelNotFound === true) { + this.router.push({ name: "404" }); + } this.toast.error( this.t("app.flash.model_not_found", { diff --git a/resources/js/views/RoomsView.vue b/resources/js/views/RoomsView.vue index 7e4431f30..05be64e15 100644 --- a/resources/js/views/RoomsView.vue +++ b/resources/js/views/RoomsView.vue @@ -439,10 +439,9 @@ function load() { }) .catch((error) => { if (error.response) { - // Room not found + // Room not found (Always redirect to 404 view) if (error.response.status === env.HTTP_NOT_FOUND) { router.push({ name: "404" }); - return; } // Room auth token is invalid @@ -515,10 +514,9 @@ function reload() { }) .catch((error) => { if (error.response) { - // Room not found + // Room not found (Always redirect to 404 view) if (error.response.status === env.HTTP_NOT_FOUND) { router.push({ name: "404" }); - return; } // Room auth token is invalid @@ -674,7 +672,10 @@ function authenticate(type, codeOrToken) { return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { authLoading.value = false; diff --git a/tests/Frontend/e2e/RoomsViewGeneral.cy.js b/tests/Frontend/e2e/RoomsViewGeneral.cy.js index b5c433eb1..47babd3a3 100644 --- a/tests/Frontend/e2e/RoomsViewGeneral.cy.js +++ b/tests/Frontend/e2e/RoomsViewGeneral.cy.js @@ -2795,6 +2795,11 @@ describe("Room View general", function () { cy.url() .should("include", "/404") .should("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.server_error.message_{"message":"No query results for model [App\\\\Room] abc-def-123"}', + 'app.flash.server_error.error_code_{"statusCode":404}', + ]); }); it("auto-reload", function () { @@ -2930,6 +2935,11 @@ describe("Room View general", function () { cy.url() .should("include", "/404") .should("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.server_error.message_{"message":"No query results for model [App\\\\Room] abc-def-123"}', + 'app.flash.server_error.error_code_{"statusCode":404}', + ]); }); it("reload with access code errors", function () { From 5e14f884d7ea19aa2706212194455731a73421d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Tue, 17 Mar 2026 08:23:45 +0100 Subject: [PATCH 04/18] Adjust room tests --- .../js/components/RoomMembershipButton.vue | 5 +- .../RoomTabMembersAddSingleModal.vue | 10 +- .../RoomTabStreamingConfigButton.vue | 2 +- tests/Frontend/e2e/RoomsViewDescription.cy.js | 28 +++ tests/Frontend/e2e/RoomsViewFiles.cy.js | 21 +++ .../e2e/RoomsViewFilesFileActions.cy.js | 111 +++++++++++- tests/Frontend/e2e/RoomsViewGeneral.cy.js | 163 ++++++++++++++++++ tests/Frontend/e2e/RoomsViewHistory.cy.js | 25 +++ .../e2e/RoomsViewHistoryMeetingActions.cy.js | 24 +-- tests/Frontend/e2e/RoomsViewMeetings.cy.js | 148 ++++++++++++++++ tests/Frontend/e2e/RoomsViewMembers.cy.js | 25 +++ .../e2e/RoomsViewMembersBulkActions.cy.js | 114 ++++++++++++ .../e2e/RoomsViewMembersMemberActions.cy.js | 112 ++++++++++++ .../e2e/RoomsViewPersonalizedLinks.cy.js | 32 ++++ ...omsViewPersonalizedLinksTokenActions.cy.js | 99 +++++++++++ tests/Frontend/e2e/RoomsViewRecordings.cy.js | 22 +++ .../RoomsViewRecordingsRecordingActions.cy.js | 84 ++++++++- tests/Frontend/e2e/RoomsViewSettings.cy.js | 77 ++++++++- tests/Frontend/e2e/RoomsViewStreaming.cy.js | 20 +++ .../e2e/RoomsViewStreamingConfigActions.cy.js | 48 ++++++ 20 files changed, 1143 insertions(+), 27 deletions(-) diff --git a/resources/js/components/RoomMembershipButton.vue b/resources/js/components/RoomMembershipButton.vue index 4723d8da2..1b6955422 100644 --- a/resources/js/components/RoomMembershipButton.vue +++ b/resources/js/components/RoomMembershipButton.vue @@ -156,7 +156,10 @@ function leaveMembership() { modalVisible.value = false; }) .catch((error) => { - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabMembersAddSingleModal.vue b/resources/js/components/RoomTabMembersAddSingleModal.vue index d99ccc778..318d72781 100644 --- a/resources/js/components/RoomTabMembersAddSingleModal.vue +++ b/resources/js/components/RoomTabMembersAddSingleModal.vue @@ -192,10 +192,7 @@ function asyncFind(query) { }) .catch((error) => { tooManyResults.value = false; - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingSearch.value = false; @@ -242,7 +239,10 @@ function save() { return; } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: true, + }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabStreamingConfigButton.vue b/resources/js/components/RoomTabStreamingConfigButton.vue index 2842a8b10..36158d370 100644 --- a/resources/js/components/RoomTabStreamingConfigButton.vue +++ b/resources/js/components/RoomTabStreamingConfigButton.vue @@ -228,7 +228,7 @@ function loadConfig() { response.data.data.system_default_pause_image; }) .catch((error) => { - api.error(error); + api.error(error, { redirectOnRoomModelNotFound: true }); modelLoadingError.value = true; }) .finally(() => { diff --git a/tests/Frontend/e2e/RoomsViewDescription.cy.js b/tests/Frontend/e2e/RoomsViewDescription.cy.js index 58076a92c..f5882eb45 100644 --- a/tests/Frontend/e2e/RoomsViewDescription.cy.js +++ b/tests/Frontend/e2e/RoomsViewDescription.cy.js @@ -462,6 +462,34 @@ describe("Rooms view description", function () { "api/v1/rooms/abc-def-123/description", "description", ); + + // Reload page + cy.interceptRoomViewRequests(); + cy.reload(); + + // Check with 404 error (room not found) + cy.intercept("PUT", "api/v1/rooms/abc-def-123/description", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("saveDescriptionRequest"); + + cy.get('[data-test="room-description-edit-button"]').click(); + cy.get('[data-test="tip-tap-editor"]').should("be.visible"); + cy.get('[data-test="room-description-save-button"]').click(); + + cy.wait("@saveDescriptionRequest"); + + // Check that redirect to 404 page worked + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + + // Check that error message gets shown + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("description changes", function () { diff --git a/tests/Frontend/e2e/RoomsViewFiles.cy.js b/tests/Frontend/e2e/RoomsViewFiles.cy.js index 942f32a2c..0f2fd3611 100644 --- a/tests/Frontend/e2e/RoomsViewFiles.cy.js +++ b/tests/Frontend/e2e/RoomsViewFiles.cy.js @@ -721,6 +721,27 @@ describe("Rooms View Files", function () { cy.get('[data-test="paginator-page"]') .eq(0) .should("have.attr", "data-p-active", "true"); + + // Check with 404 error (room not found) + cy.intercept("GET", "api/v1/rooms/abc-def-123/files*", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("roomFilesRequest"); + + cy.reload(); + cy.wait("@roomFilesRequest"); + + // Check that redirect to 404 page worked + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + + // Check that error message gets shown + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("load files page out of range", function () { diff --git a/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js b/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js index ad8b086f8..55417004a 100644 --- a/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js @@ -332,6 +332,39 @@ describe("Rooms view files file actions", function () { "/api/v1/rooms/abc-def-123/files", "files", ); + + // Reload page + cy.interceptRoomViewRequests(); + cy.interceptRoomFilesRequest(true); + cy.reload(); + + // Check 404 error (room not found) + cy.intercept("POST", "/api/v1/rooms/abc-def-123/files", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("uploadFileRequest"); + + cy.get('[data-test="room-files-upload-button"]').click(); + cy.get('[data-test="room-files-upload-dialog"]') + .should("be.visible") + .find("#file") + .selectFile("tests/Frontend/fixtures/files/testFile.txt", { + force: true, + }); + + cy.wait("@uploadFileRequest"); + + // Check that redirect to 404 page worked + cy.url().should("include", "/404").and("not.include", "abc-def-123"); + + // Check that error message is shown + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("delete file", function () { @@ -417,7 +450,9 @@ describe("Rooms view files file actions", function () { cy.intercept("DELETE", "/api/v1/rooms/abc-def-123/files/3", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "RoomFile", + ids: [3], }, }).as("deleteFileRequest"); @@ -504,6 +539,41 @@ describe("Rooms view files file actions", function () { "/api/v1/rooms/abc-def-123/files/1", "files", ); + + // Reload page + cy.interceptRoomViewRequests(); + cy.interceptRoomFilesRequest(true); + cy.reload(); + + // Check with 404 error (room not found) + cy.intercept("DELETE", "/api/v1/rooms/abc-def-123/files/1", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("deleteFileRequest"); + + cy.get('[data-test="room-file-item"]') + .eq(0) + .find('[data-test="room-files-delete-button"]') + .click(); + + cy.get('[data-test="room-files-delete-dialog"]') + .should("be.visible") + .find('[data-test="dialog-continue-button"]') + .click(); + + cy.wait("@deleteFileRequest"); + + // Check that redirect to 404 page worked + cy.url().should("include", "/404").and("not.include", "abc-def-123"); + + // Check that error message is shown + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("change file settings", function () { @@ -613,7 +683,9 @@ describe("Rooms view files file actions", function () { cy.intercept("PUT", "/api/v1/rooms/abc-def-123/files/3", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "RoomFile", + ids: [3], }, }).as("editFileRequest"); @@ -724,6 +796,41 @@ describe("Rooms view files file actions", function () { "/api/v1/rooms/abc-def-123/files/1", "files", ); + + // Reload page + cy.interceptRoomViewRequests(); + cy.interceptRoomFilesRequest(true); + cy.reload(); + + // Check with 404 error (room not found) + cy.intercept("PUT", "/api/v1/rooms/abc-def-123/files/1", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("editFileRequest"); + + cy.get('[data-test="room-file-item"]') + .eq(0) + .find('[data-test="room-files-edit-button"]') + .click(); + + cy.get('[data-test="room-files-edit-dialog"]') + .should("be.visible") + .find('[data-test="dialog-save-button"]') + .click(); + + cy.wait("@editFileRequest"); + + // Check that redirect to 404 page worked + cy.url().should("include", "/404").and("not.include", "abc-def-123"); + + // Check that error message is shown + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("download file with terms of use", function () { diff --git a/tests/Frontend/e2e/RoomsViewGeneral.cy.js b/tests/Frontend/e2e/RoomsViewGeneral.cy.js index 47babd3a3..651f58c7f 100644 --- a/tests/Frontend/e2e/RoomsViewGeneral.cy.js +++ b/tests/Frontend/e2e/RoomsViewGeneral.cy.js @@ -2357,6 +2357,46 @@ describe("Room View general", function () { cy.contains("auth.login").should("be.visible"); + // Visit room page again + cy.fixture("room.json").then((room) => { + room.data.owner = { + id: 2, + name: "Max Doe", + }; + room.data.description = "

Test

"; + room.data.allow_membership = true; + + cy.intercept("GET", "api/v1/rooms/abc-def-123*", { + statusCode: 200, + body: room, + }).as("roomRequest"); + }); + + cy.visit("/rooms/abc-def-123"); + + cy.wait("@roomRequest"); + + // Check join membership with 404 error (room not found) + cy.intercept("POST", "api/v1/rooms/abc-def-123/membership*", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("joinMembershipRequest"); + + cy.get('[data-test="room-join-membership-button"]').click(); + + cy.wait("@joinMembershipRequest"); + + // Check that redirect worked and error message is shown + cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); + // Reload room with user being a member of the room cy.fixture("room.json").then((room) => { room.data.owner = { @@ -2448,6 +2488,46 @@ describe("Room View general", function () { // Check that access code overlay is shown cy.get('[data-test="room-access-code-overlay"]').should("be.visible"); + + // Reload room with user being a member of the room + cy.fixture("room.json").then((room) => { + room.data.owner = { + id: 2, + name: "Max Doe", + }; + room.data.description = "

Test

"; + room.data.allow_membership = true; + room.data.is_member = true; + + cy.intercept("GET", "api/v1/rooms/abc-def-123*", { + statusCode: 200, + body: room, + }).as("roomRequest"); + }); + + cy.visit("/rooms/abc-def-123"); + + cy.wait("@roomRequest"); + + // Check end membership with 404 error (room not found) + cy.intercept("DELETE", "api/v1/rooms/abc-def-123/membership", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("endMembershipRequest"); + + cy.get('[data-test="room-end-membership-button"]').click(); + + cy.get('[data-test="end-membership-dialog"]').should("be.visible"); + cy.get('[data-test="dialog-continue-button"]').click(); + + cy.wait("@endMembershipRequest"); + + // Check that redirect worked and error message is shown + cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); }); it("trigger favorites button", function () { @@ -2622,6 +2702,46 @@ describe("Room View general", function () { cy.contains("auth.login").should("be.visible"); + // Visit room page again + cy.fixture("room.json").then((room) => { + room.data.owner = { + id: 2, + name: "Max Doe", + }; + room.data.description = "

Test

"; + room.data.allow_membership = true; + + cy.intercept("GET", "api/v1/rooms/abc-def-123", { + statusCode: 200, + body: room, + }).as("roomRequest"); + }); + + cy.visit("/rooms/abc-def-123"); + + cy.wait("@roomRequest"); + + // Test add to favorites with 404 error (room not found) + cy.intercept("POST", "api/v1/rooms/abc-def-123/favorites", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("addFavoritesRequest"); + + cy.get('[data-test="room-favorites-button"]').click(); + + cy.wait("@addFavoritesRequest"); + + // Check that redirect worked and error message is shown + cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); + // Reload room but room is already in favorites cy.fixture("room.json").then((room) => { room.data.owner = { @@ -2696,6 +2816,49 @@ describe("Room View general", function () { // Check that access code overlay is shown cy.get('[data-test="room-access-code-overlay"]').should("be.visible"); + + // Reload room but room is already not in favorites + cy.fixture("room.json").then((room) => { + room.data.owner = { + id: 2, + name: "Max Doe", + }; + room.data.description = "

Test

"; + room.data.allow_membership = true; + room.data.is_favorite = true; + + cy.intercept("GET", "api/v1/rooms/abc-def-123", { + statusCode: 200, + body: room, + }).as("roomRequest"); + }); + + cy.reload(); + + cy.wait("@roomRequest"); + + // Test remove from favorites with 404 error (room not found) + cy.intercept("DELETE", "api/v1/rooms/abc-def-123/favorites", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("deleteFavoritesRequest"); + + cy.get('[data-test="room-favorites-button"]') + .should("have.attr", "aria-label", "rooms.favorites.remove") + .click(); + + cy.wait("@deleteFavoritesRequest"); + + // Check that redirect worked and error message is shown + cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("visit with guest forbidden", function () { diff --git a/tests/Frontend/e2e/RoomsViewHistory.cy.js b/tests/Frontend/e2e/RoomsViewHistory.cy.js index 7af126f5e..d1548e679 100644 --- a/tests/Frontend/e2e/RoomsViewHistory.cy.js +++ b/tests/Frontend/e2e/RoomsViewHistory.cy.js @@ -496,6 +496,31 @@ describe("Rooms view history", function () { "api/v1/rooms/abc-def-123/meetings*", "history", ); + + // Reload page + cy.interceptRoomViewRequests(); + cy.reload(); + + cy.wait("@roomRequest"); + + // Check with 404 error (room not found) + cy.intercept("GET", "api/v1/rooms/abc-def-123/meetings*", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("roomHistoryRequest"); + + cy.get("#tab-history").click(); + cy.wait("@roomHistoryRequest"); + + // Check that redirect to 404 page works and that error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("load history page out of range", function () { diff --git a/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js b/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js index edd734fd7..40371d111 100644 --- a/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js @@ -139,8 +139,9 @@ describe("Rooms view history meeting actions", function () { { statusCode: 404, body: { - message: - "No query results for model [App\\Models\\Meeting] 3a3e504a-d2c4-431c-8ca1-a62598e66761", + message: "model_not_found", + model: "Meeting", + ids: ["3a3e504a-d2c4-431c-8ca1-a62598e66761"], }, }, ).as("statsRequest"); @@ -153,10 +154,9 @@ describe("Rooms view history meeting actions", function () { cy.wait("@statsRequest"); // Check that error message is shown - cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model [App\\\\Models\\\\Meeting] 3a3e504a-d2c4-431c-8ca1-a62598e66761"}', - 'app.flash.server_error.error_code_{"statusCode":404}', - ]); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Meeting","ids":"3a3e504a-d2c4-431c-8ca1-a62598e66761"}', + ); // Check if dialog is closed cy.get('[data-test="room-history-statistic-dialog"]').should("not.exist"); @@ -477,8 +477,9 @@ describe("Rooms view history meeting actions", function () { { statusCode: 404, body: { - message: - "No query results for model [App\\Models\\Meeting] 3a3e504a-d2c4-431c-8ca1-a62598e66761", + message: "model_not_found", + model: "Meeting", + ids: ["3a3e504a-d2c4-431c-8ca1-a62598e66761"], }, }, ).as("attendanceRequest"); @@ -491,10 +492,9 @@ describe("Rooms view history meeting actions", function () { cy.wait("@attendanceRequest"); // Check that error message is shown - cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model [App\\\\Models\\\\Meeting] 3a3e504a-d2c4-431c-8ca1-a62598e66761"}', - 'app.flash.server_error.error_code_{"statusCode":404}', - ]); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Meeting","ids":"3a3e504a-d2c4-431c-8ca1-a62598e66761"}', + ); // Check if dialog is closed cy.get('[data-test="room-history-attendance-dialog"]').should("not.exist"); diff --git a/tests/Frontend/e2e/RoomsViewMeetings.cy.js b/tests/Frontend/e2e/RoomsViewMeetings.cy.js index b0d10adf7..aafc2a32d 100644 --- a/tests/Frontend/e2e/RoomsViewMeetings.cy.js +++ b/tests/Frontend/e2e/RoomsViewMeetings.cy.js @@ -1345,6 +1345,51 @@ describe("Rooms view meetings", function () { "have.text", "rooms.start", ); + + // Reload page + cy.fixture("room.json").then((room) => { + room.data.last_meeting = { + start: "2023-08-21T08:18:28.000000Z", + end: null, + }; + room.data.current_user = null; + + cy.intercept("GET", "api/v1/rooms/abc-def-123", { + statusCode: 200, + body: room, + }).as("roomRequest"); + }); + cy.reload(); + + // Test with 404 error (room not found) + cy.intercept("POST", "/api/v1/rooms/abc-def-123/join*", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("joinRequest"); + + // Try to join meeting + cy.get('[data-test="room-join-button"]').click(); + + cy.get('[data-test="room-join-dialog"]') + .should("be.visible") + .within(() => { + cy.get("#record-attendance-agreement").should("not.be.checked").click(); + cy.get("#record-agreement").should("not.be.checked").click(); + cy.get("#record-video-agreement").should("not.be.checked").click(); + cy.get('[data-test="dialog-continue-button"]').click(); + }); + + cy.wait("@joinRequest"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("join meeting load requirements errors", function () { @@ -1432,6 +1477,7 @@ describe("Rooms view meetings", function () { message: "require_code", }, }).as("preJoinRequest"); + cy.interceptRoomFilesRequest(); // Try to join meeting cy.get('[data-test="room-join-button"]').click(); @@ -1487,6 +1533,44 @@ describe("Rooms view meetings", function () { // Check dialog is closed cy.get('[data-test="room-join-dialog"]').should("not.exist"); + + // Reload room + cy.fixture("room.json").then((room) => { + room.data.last_meeting = { + start: "2023-08-21T08:18:28.000000Z", + end: null, + }; + room.data.current_user = null; + + cy.intercept("GET", "api/v1/rooms/abc-def-123*", { + statusCode: 200, + body: room, + }).as("roomRequest"); + }); + + cy.visit("/rooms/abc-def-123"); + + cy.wait("@roomRequest"); + + // Check with 404 error (room not found) + cy.intercept("OPTIONS", "api/v1/rooms/abc-def-123/join*", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("preJoinRequest"); + + // Try to join meeting + cy.get('[data-test="room-join-button"]').click(); + cy.wait("@preJoinRequest"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("join running meeting with dark mode", function () { @@ -2849,6 +2933,49 @@ describe("Rooms view meetings", function () { "eq", `${Cypress.expose("redirectBaseUrl")}/bigbluebutton?foo=a&bar=b`, ); + + // Reload room + cy.fixture("room.json").then((room) => { + room.data.current_user = null; + + cy.intercept("GET", "api/v1/rooms/abc-def-123", { + statusCode: 200, + body: room, + }).as("roomRequest"); + }); + + cy.visit("/rooms/abc-def-123"); + + cy.wait("@roomRequest"); + + // Try with 404 error (room not found) + cy.intercept("POST", "/api/v1/rooms/abc-def-123/start*", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("startRequest"); + + cy.get('[data-test="room-start-button"]').click(); + cy.get('[data-test="room-join-dialog"]') + .should("be.visible") + .within(() => { + cy.get("#record-attendance-agreement").should("not.be.checked").click(); + cy.get("#record-agreement").should("not.be.checked").click(); + cy.get("#record-video-agreement").should("not.be.checked").click(); + cy.get('[data-test="dialog-continue-button"]').click(); + }); + + cy.wait("@startRequest"); + + // Check if redirect worked and error message is shown + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("start meeting load requirements errors", function () { @@ -3012,6 +3139,27 @@ describe("Rooms view meetings", function () { // Check dialog is closed cy.get('[data-test="room-join-dialog"]').should("not.exist"); + + // Test 404 error (room not found) + cy.intercept("OPTIONS", "api/v1/rooms/abc-def-123/start*", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("preStartRequest"); + + // Try to start meeting + cy.get('[data-test="room-start-button"]').click(); + cy.wait("@preStartRequest"); + + // Check if redirect worked and error message is shown + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("start meeting with dark mode", function () { diff --git a/tests/Frontend/e2e/RoomsViewMembers.cy.js b/tests/Frontend/e2e/RoomsViewMembers.cy.js index 3f1215a14..4d4d459e3 100644 --- a/tests/Frontend/e2e/RoomsViewMembers.cy.js +++ b/tests/Frontend/e2e/RoomsViewMembers.cy.js @@ -484,6 +484,31 @@ describe("Rooms view members", function () { "api/v1/rooms/abc-def-123/member*", "members", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.reload(); + + // Test 404 error (room not found) + cy.intercept("GET", "api/v1/rooms/abc-def-123/member*", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("roomMembersRequest"); + + cy.get("#tab-members").click(); + + cy.wait("@roomMembersRequest"); + + // Check that redirect to 404 page works and error message is shown + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("load members page out of range", function () { diff --git a/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js b/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js index 52a7fd3e7..2261a03d5 100644 --- a/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js @@ -408,6 +408,43 @@ describe("Rooms view members bulk actions", function () { "api/v1/rooms/abc-def-123/member/bulk", "members", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.reload(); + + cy.wait("@roomRequest"); + + cy.get("#tab-members").should("be.visible").click(); + + // Select all users + cy.get('[data-test="room-members-select-all-checkbox"]').click(); + + // Test bulk edit with 404 error (room not found) + cy.intercept("PUT", "api/v1/rooms/abc-def-123/member/bulk", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("bulkEditRequest"); + + cy.get('[data-test="room-members-bulk-edit-button"]') + .should("be.visible") + .click(); + + cy.get('[data-test="room-members-bulk-edit-dialog"]').should("be.visible"); + cy.get('[data-test="dialog-save-button"]').click(); + + cy.wait("@bulkEditRequest"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("bulk delete members", function () { @@ -682,6 +719,45 @@ describe("Rooms view members bulk actions", function () { "api/v1/rooms/abc-def-123/member/bulk", "members", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.reload(); + + cy.wait("@roomRequest"); + + cy.get("#tab-members").should("be.visible").click(); + + // Select all users + cy.get('[data-test="room-members-select-all-checkbox"] > input').click(); + + // Test bulk delete with 404 error (room not found) + cy.intercept("DELETE", "api/v1/rooms/abc-def-123/member/bulk", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("bulkDeleteRequest"); + + cy.get('[data-test="room-members-bulk-delete-button"]') + .should("be.visible") + .click(); + + cy.get('[data-test="room-members-bulk-delete-dialog"]').should( + "be.visible", + ); + cy.get('[data-test="dialog-continue-button"]').click(); + + cy.wait("@bulkDeleteRequest"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("bulk import members", function () { @@ -1386,5 +1462,43 @@ describe("Rooms view members bulk actions", function () { "api/v1/rooms/abc-def-123/member/bulk", "members", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.reload(); + + cy.wait("@roomRequest"); + + cy.get("#tab-members").should("be.visible").click(); + + // Test bulk import with 404 error (room not found) + cy.intercept("POST", "api/v1/rooms/abc-def-123/member/bulk", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("bulkImportRequest"); + + cy.get('[data-test="room-members-add-button"]').click(); + cy.get("#overlay_menu_1") + .should("have.text", "rooms.members.bulk_import_users") + .click(); + + cy.get('[data-test="room-members-bulk-import-dialog"]').should( + "be.visible", + ); + cy.get("#user-emails").type("\n"); + cy.get('[data-test="dialog-continue-button"]').click(); + + cy.wait("@bulkImportRequest"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); }); diff --git a/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js b/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js index d2fea1dd4..ba9cd1949 100644 --- a/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js @@ -432,6 +432,44 @@ describe("Rooms view members member actions", function () { "/api/v1/rooms/abc-def-123/member", "members", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.interceptRoomMembersRequest(); + cy.reload(); + + cy.wait("@roomRequest"); + cy.wait("@roomMembersRequest"); + + cy.get("#tab-members").click(); + + // Test add new member with 404 error (room not found) + cy.get('[data-test="room-members-add-button"]').click(); + + cy.get("#overlay_menu_0") + .should("have.text", "rooms.members.add_single_user") + .click(); + + cy.get('[data-test="room-members-add-single-dialog"]').should("be.visible"); + + cy.intercept("POST", "/api/v1/rooms/abc-def-123/member", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("addUserRequest"); + + cy.get('[data-test="dialog-save-button"]').click(); + + cy.wait("@addUserRequest"); + + // Check that user is redirected to 404 page and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("edit member", function () { @@ -636,6 +674,43 @@ describe("Rooms view members member actions", function () { "/api/v1/rooms/abc-def-123/member/6", "members", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.interceptRoomMembersRequest(); + cy.reload(); + + cy.wait("@roomRequest"); + + cy.get("#tab-members").click(); + cy.wait("@roomMembersRequest"); + + // Test edit member with 404 error (room not found) + cy.get('[data-test="room-member-item"]') + .eq(0) + .find('[data-test="room-members-edit-button"]') + .click(); + + cy.get('[data-test="room-members-edit-dialog"]').should("be.visible"); + + cy.intercept("PUT", "/api/v1/rooms/abc-def-123/member/5", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("editUserRequest"); + + cy.get('[data-test="dialog-save-button"]').click(); + + cy.wait("@editUserRequest"); + + // Check that user is redirected to 404 page and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("delete member", function () { @@ -797,5 +872,42 @@ describe("Rooms view members member actions", function () { "/api/v1/rooms/abc-def-123/member/6", "members", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.interceptRoomMembersRequest(); + + cy.reload(); + + cy.wait("@roomRequest"); + cy.get("#tab-members").click(); + cy.wait("@roomMembersRequest"); + + // Test delete member with 404 error (room not found) + cy.get('[data-test="room-member-item"]') + .eq(0) + .find('[data-test="room-members-delete-button"]') + .click(); + + cy.get('[data-test="room-members-delete-dialog"]').should("be.visible"); + + cy.intercept("DELETE", "/api/v1/rooms/abc-def-123/member/5", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("deleteMemberRequest"); + + cy.get('[data-test="dialog-continue-button"]').click(); + + cy.wait("@deleteMemberRequest"); + + // Check that user is redirected to 404 page and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); }); diff --git a/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js b/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js index 721f7b187..95f1d2082 100644 --- a/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js +++ b/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js @@ -496,6 +496,38 @@ describe("Rooms view personalized links", function () { "api/v1/rooms/abc-def-123/personalizedLinks*", "tokens", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.reload(); + + cy.wait("@roomRequest"); + + // Check with 404 error (room not found) + cy.intercept( + { + method: "GET", + url: "api/v1/rooms/abc-def-123/personalizedLinks*", + }, + { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }, + ).as("roomPersonalizedLinksRequest"); + + cy.get("#tab-tokens").click(); + + cy.wait("@roomPersonalizedLinksRequest"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("load personalized links page out of range", function () { diff --git a/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js b/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js index ba56784e5..af6f97dda 100644 --- a/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js @@ -234,6 +234,37 @@ describe("Rooms view personalized links actions", function () { "/api/v1/rooms/abc-def-123/personalizedLinks/", "tokens", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.reload(); + cy.get("#tab-tokens").should("be.visible").click(); + cy.wait("@roomRequest"); + cy.wait("@roomPersonalizedLinksRequest"); + + // Test add personalized link with 404 error (room not found) + cy.intercept("POST", "/api/v1/rooms/abc-def-123/personalizedLinks/", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("addLinkRequest"); + + cy.get('[data-test="room-personalized-links-add-button"]').click(); + cy.get('[data-test="room-personalized-links-add-dialog"]').should( + "be.visible", + ); + cy.get('[data-test="dialog-save-button"]').click(); + + cy.wait("@addLinkRequest"); + + // Check that redirect to 404 page works and error message is shown + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("edit personalized link", function () { @@ -523,6 +554,40 @@ describe("Rooms view personalized links actions", function () { "/api/v1/rooms/abc-def-123/personalizedLinks/1", "tokens", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.reload(); + cy.get("#tab-tokens").should("be.visible").click(); + cy.wait("@roomRequest"); + cy.wait("@roomPersonalizedLinksRequest"); + + // Test edit personalized link with 404 error (room not found) + cy.intercept("PUT", "/api/v1/rooms/abc-def-123/personalizedLinks/1", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("editLinkRequest"); + + cy.get('[data-test="room-personalized-link-item"]') + .eq(0) + .find('[data-test="room-personalized-links-edit-button"]') + .click(); + cy.get('[data-test="room-personalized-links-edit-dialog"]').should( + "be.visible", + ); + cy.get('[data-test="dialog-save-button"]').click(); + + cy.wait("@editLinkRequest"); + + // Check that redirect to 404 page works and error message is shown + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("delete personalized link", function () { @@ -716,6 +781,40 @@ describe("Rooms view personalized links actions", function () { "/api/v1/rooms/abc-def-123/personalizedLinks/1", "tokens", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.reload(); + cy.get("#tab-tokens").should("be.visible").click(); + cy.wait("@roomRequest"); + cy.wait("@roomPersonalizedLinksRequest"); + + // Test delete personalized link with 404 error (room not found) + cy.intercept("DELETE", "/api/v1/rooms/abc-def-123/personalizedLinks/1", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("deleteLinkRequest"); + + cy.get('[data-test="room-personalized-link-item"]') + .eq(0) + .find('[data-test="room-personalized-links-delete-button"]') + .click(); + cy.get('[data-test="room-personalized-links-delete-dialog"]').should( + "be.visible", + ); + cy.get('[data-test="dialog-continue-button"]').click(); + + cy.wait("@deleteLinkRequest"); + + // Check that redirect to 404 page works and error message is shown + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("copy personalized link", function () { diff --git a/tests/Frontend/e2e/RoomsViewRecordings.cy.js b/tests/Frontend/e2e/RoomsViewRecordings.cy.js index 59d97b389..1de5fb405 100644 --- a/tests/Frontend/e2e/RoomsViewRecordings.cy.js +++ b/tests/Frontend/e2e/RoomsViewRecordings.cy.js @@ -760,6 +760,28 @@ describe("Rooms view recordings", function () { cy.get('[data-test="paginator-page"]') .eq(0) .should("have.attr", "data-p-active", "true"); + + // Check with 404 error (room not found) + cy.intercept("GET", "api/v1/rooms/abc-def-123/recordings*", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("roomRecordingsRequest"); + + // Reload page + cy.reload(); + + cy.wait("@roomRecordingsRequest"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("load recordings page out of range", function () { diff --git a/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js b/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js index 342a5899c..592c7e30e 100644 --- a/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js @@ -878,7 +878,9 @@ describe("Rooms view recordings recording actions", function () { { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "Recording", + ids: ["f9569db6d5e8fb2fd2f57d367d5482b36837b9d8-1663666775"], }, }, ).as("deleteRecordingRequest"); @@ -964,6 +966,45 @@ describe("Rooms view recordings recording actions", function () { "api/v1/rooms/abc-def-123/recordings/e0cfa18c5fd75a42bd7947d8549321b03abf1daf-1660728035", "recordings", ); + + // Reload room + cy.interceptRoomViewRequests(); + cy.interceptRoomRecordingsRequests(); + + cy.reload(); + cy.get("#tab-recordings").should("be.visible").click(); + + // Check with 404 error (room not found) + cy.intercept( + "DELETE", + "api/v1/rooms/abc-def-123/recordings/e0cfa18c5fd75a42bd7947d8549321b03abf1daf-1660728035", + { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }, + ).as("deleteRecordingRequest"); + + cy.get('[data-test="room-recording-item"]') + .eq(0) + .find('[data-test="room-recordings-delete-button"]') + .click(); + + cy.get('[data-test="room-recordings-delete-dialog"]') + .should("be.visible") + .find('[data-test="dialog-continue-button"]') + .click(); + + cy.wait("@deleteRecordingRequest"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("edit recording", function () { @@ -1317,5 +1358,46 @@ describe("Rooms view recordings recording actions", function () { "api/v1/rooms/abc-def-123/recordings/e0cfa18c5fd75a42bd7947d8549321b03abf1daf-1660728035", "recordings", ); + + // Reload room + cy.interceptRoomViewRequests(); + cy.interceptRoomRecordingsRequests(); + + cy.reload(); + cy.get("#tab-recordings").should("be.visible").click(); + + cy.wait("@roomRecordingsRequest"); + + // Check with 404 error (room not found) + cy.intercept( + "PUT", + "api/v1/rooms/abc-def-123/recordings/e0cfa18c5fd75a42bd7947d8549321b03abf1daf-1660728035", + { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }, + ).as("editRecordingRequest"); + + cy.get('[data-test="room-recording-item"]') + .eq(0) + .find('[data-test="room-recordings-edit-button"]') + .click(); + + cy.get('[data-test="room-recordings-edit-dialog"]') + .should("be.visible") + .find('[data-test="dialog-save-button"]') + .click(); + + cy.wait("@editRecordingRequest"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); }); diff --git a/tests/Frontend/e2e/RoomsViewSettings.cy.js b/tests/Frontend/e2e/RoomsViewSettings.cy.js index fb9eeed22..e99e27606 100644 --- a/tests/Frontend/e2e/RoomsViewSettings.cy.js +++ b/tests/Frontend/e2e/RoomsViewSettings.cy.js @@ -414,6 +414,32 @@ describe("Rooms view settings", function () { "api/v1/rooms/abc-def-123/settings", "settings", ); + + // Reload room + cy.interceptRoomViewRequests(); + cy.reload(); + + cy.wait("@roomRequest"); + + // Check with 404 error (room not found) + cy.intercept("GET", "api/v1/rooms/abc-def-123/settings", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("roomSettingsRequest"); + + cy.get("#tab-settings").click(); + + cy.wait("@roomSettingsRequest"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("load settings with different permissions", function () { @@ -1716,6 +1742,11 @@ describe("Rooms view settings", function () { // Check with 404 error cy.intercept("DELETE", "api/v1/rooms/abc-def-123", { statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, }).as("roomDeleteRequest"); cy.get("[data-test=room-delete-dialog]") @@ -1725,12 +1756,18 @@ describe("Rooms view settings", function () { cy.wait("@roomDeleteRequest"); - cy.checkToastMessage([ - "app.flash.server_error.empty_message", - 'app.flash.server_error.error_code_{"statusCode":404}', - ]); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); + + // Reload room page + cy.visit("/rooms/abc-def-123#tab=settings"); + + cy.wait("@roomSettingsRequest"); + + // Open delete dialog again + cy.get('[data-test="room-delete-button"]').click(); - // Check that modal stays open cy.get("[data-test=room-delete-dialog]").should("be.visible"); // Check with 500 error @@ -2257,5 +2294,35 @@ describe("Rooms view settings", function () { "api/v1/rooms/abc-def-123/transfer", "settings", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.reload(); + + cy.get("#tab-settings").click(); + + cy.wait("@roomSettingsRequest"); + + // Check with 404 error (room not found) + cy.intercept("POST", "api/v1/rooms/abc-def-123/transfer", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("transferOwnershipRequest"); + + cy.get('[data-test="room-transfer-ownership-button"]').click(); + cy.get('[data-test="room-transfer-ownership-dialog"]').should("be.visible"); + cy.get('[data-test="dialog-continue-button"]').click(); + + cy.wait("@transferOwnershipRequest"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); }); diff --git a/tests/Frontend/e2e/RoomsViewStreaming.cy.js b/tests/Frontend/e2e/RoomsViewStreaming.cy.js index ee3d562e5..6e10d107b 100644 --- a/tests/Frontend/e2e/RoomsViewStreaming.cy.js +++ b/tests/Frontend/e2e/RoomsViewStreaming.cy.js @@ -786,5 +786,25 @@ describe("Rooms view streaming", function () { "contain", "rooms.streaming.no_running_meeting", ); + + // Check 404 error on reload (room not found) + cy.intercept("GET", "api/v1/rooms/abc-def-123/streaming/status", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("roomStreamingStatus"); + + cy.get('[data-test="streaming-reload-button"]').click(); + cy.wait("@roomStreamingStatus"); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); }); diff --git a/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js b/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js index a24011106..92905de5f 100644 --- a/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js @@ -277,6 +277,27 @@ describe("Rooms view streaming config actions", function () { // Close dialog cy.get('[data-test="dialog-cancel-button"]').click(); }); + + // Check with 404 error (room not found) + cy.intercept("GET", "api/v1/rooms/abc-def-123/streaming/config", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("roomStreamingConfig"); + + cy.get('[data-test="streaming-config-button"]').should("be.visible"); + cy.get('[data-test="streaming-config-button"]').click(); + + cy.wait("@roomStreamingConfig"); + + // Check that redirect worked and error message is shown + cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("edit settings", function () { @@ -598,6 +619,33 @@ describe("Rooms view streaming config actions", function () { // Close dialog cy.get('[data-test="dialog-cancel-button"]').click(); }); + + // Check with 404 error (room not found) + cy.intercept("POST", "api/v1/rooms/abc-def-123/streaming/config", { + statusCode: 404, + body: { + message: "model_not_found", + model: "Room", + ids: ["abc-def-123"], + }, + }).as("saveConfigRequest"); + + cy.get('[data-test="streaming-config-button"]').click(); + cy.get('[data-test="room-streaming-config-dialog"]') + .should("be.visible") + .within(() => { + cy.get('[data-test="dialog-save-button"]') + .should("include.text", "app.save") + .click(); + }); + + cy.wait("@saveConfigRequest"); + + // Check that redirect worked and error message is shown + cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); + cy.checkToastMessage( + 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + ); }); it("view/edit settings with different permissions", function () { From c97057a0cb5e70ffbe86910582339efbfc33bb5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Wed, 18 Mar 2026 20:07:17 +0100 Subject: [PATCH 05/18] Improve error messages --- app/Exceptions/Handler.php | 3 ++- lang/en/app.php | 11 ++++++++++- .../components/RoomTabFilesDeleteButton.vue | 3 ++- .../js/components/RoomTabFilesEditButton.vue | 3 ++- .../RoomTabPersonalizedLinksDeleteButton.vue | 3 ++- .../RoomTabPersonalizedLinksEditButton.vue | 3 ++- .../RoomTabRecordingsDeleteButton.vue | 3 ++- .../RoomTabRecordingsEditButton.vue | 3 ++- resources/js/constants/modelNames.js | 1 + resources/js/services/Api.js | 16 +++++++++++----- .../e2e/AdminRolesIndexRoleActions.cy.js | 6 ++---- .../e2e/AdminRolesViewRoleActions.cy.js | 6 ++---- .../AdminRoomTypesIndexRoomTypeActions.cy.js | 6 ++---- .../AdminRoomTypesViewRoomTypeActions.cy.js | 6 ++---- ...minServerPoolsIndexServerPoolActions.cy.js | 6 ++---- ...dminServerPoolsViewServerPoolActions.cy.js | 6 ++---- .../e2e/AdminServersIndexServerActions.cy.js | 6 ++---- .../e2e/AdminServersViewServerActions.cy.js | 6 ++---- .../e2e/AdminUsersIndexUserActions.cy.js | 6 ++---- .../e2e/AdminUsersViewUserActions.cy.js | 12 ++++-------- tests/Frontend/e2e/RoomsViewDescription.cy.js | 4 ++-- tests/Frontend/e2e/RoomsViewFiles.cy.js | 4 ++-- .../e2e/RoomsViewFilesFileActions.cy.js | 16 ++++++++-------- tests/Frontend/e2e/RoomsViewGeneral.cy.js | 19 ++++++++++++------- tests/Frontend/e2e/RoomsViewHistory.cy.js | 4 ++-- .../e2e/RoomsViewHistoryMeetingActions.cy.js | 8 ++++---- tests/Frontend/e2e/RoomsViewMeetings.cy.js | 16 ++++++++-------- tests/Frontend/e2e/RoomsViewMembers.cy.js | 4 ++-- .../e2e/RoomsViewMembersBulkActions.cy.js | 12 ++++++------ .../e2e/RoomsViewMembersMemberActions.cy.js | 12 ++++++------ .../e2e/RoomsViewPersonalizedLinks.cy.js | 4 ++-- ...omsViewPersonalizedLinksTokenActions.cy.js | 12 ++++++------ tests/Frontend/e2e/RoomsViewRecordings.cy.js | 4 ++-- .../RoomsViewRecordingsRecordingActions.cy.js | 10 +++++----- tests/Frontend/e2e/RoomsViewSettings.cy.js | 12 ++++++------ tests/Frontend/e2e/RoomsViewStreaming.cy.js | 4 ++-- .../e2e/RoomsViewStreamingConfigActions.cy.js | 8 ++++---- tests/Frontend/fixtures/en.json | 16 +++++++++++++++- 38 files changed, 152 insertions(+), 132 deletions(-) create mode 100644 resources/js/constants/modelNames.js diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 18321caff..fdebd15bb 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -7,6 +7,7 @@ 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; @@ -85,7 +86,7 @@ public function register(): void if ($modelNotFoundException) { $json = [ 'message' => 'model_not_found', - 'model' => class_basename($modelNotFoundException->getModel()), + 'model' => Str::snake(class_basename($modelNotFoundException->getModel())), 'ids' => $modelNotFoundException->getIds(), ]; diff --git a/lang/en/app.php b/lang/en/app.php index 880ca7f9c..0b9adc4ed 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -64,7 +64,16 @@ 'flash' => [ 'client_error' => 'An unknown error occurred in the application!', 'guests_only' => 'The request can only be made by guests!', - 'model_not_found' => ':model with id :ids was not found!', + 'model_not_found' => [ + 'fallback' => 'The :model with the id :ids was not found!', + 'meeting' => 'The meeting with the id :ids was not found!', + 'role' => 'The role with the id :ids was not found!', + 'room' => 'The room with the id :ids was not found!', + 'room_type' => 'The room type with the id :ids was not found!', + 'server' => 'The server with the id :ids was not found!', + 'server_pool' => 'The server pool with the id :ids was not found!', + 'user' => 'The user with the id :ids was not found!', + ], 'server_error' => [ 'empty_message' => 'An error occurred on the server during request!', 'error_code' => 'Error code: :statusCode', diff --git a/resources/js/components/RoomTabFilesDeleteButton.vue b/resources/js/components/RoomTabFilesDeleteButton.vue index b933ea9e1..a05f61978 100644 --- a/resources/js/components/RoomTabFilesDeleteButton.vue +++ b/resources/js/components/RoomTabFilesDeleteButton.vue @@ -53,6 +53,7 @@ import { useApi } from "../composables/useApi.js"; import { ref } from "vue"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; +import { ROOM_MODEL } from "../constants/modelNames.js"; const props = defineProps({ roomId: { @@ -103,7 +104,7 @@ function deleteFile() { // file not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== "Room" + error.response.data?.model !== ROOM_MODEL ) { toast.error(t("rooms.flash.file_gone")); emit("notFound"); diff --git a/resources/js/components/RoomTabFilesEditButton.vue b/resources/js/components/RoomTabFilesEditButton.vue index a4c6bc3d5..4f2d2f074 100644 --- a/resources/js/components/RoomTabFilesEditButton.vue +++ b/resources/js/components/RoomTabFilesEditButton.vue @@ -100,6 +100,7 @@ import { ref, watch } from "vue"; import { useFormErrors } from "../composables/useFormErrors.js"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; +import { ROOM_MODEL } from "../constants/modelNames.js"; const props = defineProps({ roomId: { @@ -197,7 +198,7 @@ function save() { // file not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== "Room" + error.response.data?.model !== ROOM_MODEL ) { toast.error(t("rooms.flash.file_gone")); emit("notFound"); diff --git a/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue b/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue index 98f3a4872..1def73a01 100644 --- a/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue @@ -59,6 +59,7 @@ import { useApi } from "../composables/useApi.js"; import { ref } from "vue"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; +import { ROOM_MODEL } from "../constants/modelNames.js"; const props = defineProps({ roomId: { @@ -122,7 +123,7 @@ function deleteLink() { // personalized link not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== "Room" + error.response.data?.model !== ROOM_MODEL ) { toast.error(t("rooms.flash.personalized_link_gone")); modalVisible.value = false; diff --git a/resources/js/components/RoomTabPersonalizedLinksEditButton.vue b/resources/js/components/RoomTabPersonalizedLinksEditButton.vue index e362983f5..768956560 100644 --- a/resources/js/components/RoomTabPersonalizedLinksEditButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksEditButton.vue @@ -110,6 +110,7 @@ import { ref } from "vue"; import env from "../env.js"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; +import { ROOM_MODEL } from "../constants/modelNames.js"; const props = defineProps({ roomId: { @@ -191,7 +192,7 @@ function save() { // token not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== "Room" + error.response.data?.model !== ROOM_MODEL ) { toast.error(t("rooms.flash.personalized_link_gone")); modalVisible.value = false; diff --git a/resources/js/components/RoomTabRecordingsDeleteButton.vue b/resources/js/components/RoomTabRecordingsDeleteButton.vue index a943d1030..a3c7abf0f 100644 --- a/resources/js/components/RoomTabRecordingsDeleteButton.vue +++ b/resources/js/components/RoomTabRecordingsDeleteButton.vue @@ -53,6 +53,7 @@ import { useApi } from "../composables/useApi.js"; import { ref } from "vue"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; +import { ROOM_MODEL } from "../constants/modelNames.js"; const props = defineProps({ recordingId: { @@ -99,7 +100,7 @@ function deleteRecording() { // recording not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== "Room" + error.response.data?.model !== ROOM_MODEL ) { toast.error(t("rooms.flash.recording_gone")); emit("notFound"); diff --git a/resources/js/components/RoomTabRecordingsEditButton.vue b/resources/js/components/RoomTabRecordingsEditButton.vue index 97b412d65..2dfcfb140 100644 --- a/resources/js/components/RoomTabRecordingsEditButton.vue +++ b/resources/js/components/RoomTabRecordingsEditButton.vue @@ -130,6 +130,7 @@ import * as _ from "lodash-es"; import { useSettingsStore } from "../stores/settings.js"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; +import { ROOM_MODEL } from "../constants/modelNames.js"; const props = defineProps({ recordingId: { @@ -238,7 +239,7 @@ function save() { // recording not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== "Room" + error.response.data?.model !== ROOM_MODEL ) { toast.error(t("rooms.flash.recording_gone")); modalVisible.value = false; diff --git a/resources/js/constants/modelNames.js b/resources/js/constants/modelNames.js new file mode 100644 index 000000000..545d0b65c --- /dev/null +++ b/resources/js/constants/modelNames.js @@ -0,0 +1 @@ +export const ROOM_MODEL = "room"; diff --git a/resources/js/services/Api.js b/resources/js/services/Api.js index abe8620da..8943da5f4 100644 --- a/resources/js/services/Api.js +++ b/resources/js/services/Api.js @@ -6,6 +6,7 @@ import { useAuthStore } from "../stores/auth"; import { useRouter } from "vue-router"; import { EVENT_FORBIDDEN, EVENT_UNAUTHORIZED } from "../constants/events.js"; import EventBus from "./EventBus.js"; +import { ROOM_MODEL } from "../constants/modelNames.js"; axios.defaults.withCredentials = true; axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest"; @@ -16,6 +17,7 @@ export class Api { this.router = useRouter(); this.toast = useToast(); this.t = i18n.global.t; + this.te = i18n.global.te; } /** @@ -124,15 +126,19 @@ export class Api { const model = data?.model; const ids = data?.ids; - if (model === "Room" && options.redirectOnRoomModelNotFound === true) { + if (model === ROOM_MODEL && options.redirectOnRoomModelNotFound === true) { this.router.push({ name: "404" }); } this.toast.error( - this.t("app.flash.model_not_found", { - model: model, - ids: ids ? `${ids.join(", ")}` : "", - }), + this.te("app.flash.model_not_found." + model) + ? this.t("app.flash.model_not_found." + model, { + ids: ids ? `${ids.join(", ")}` : "", + }) + : this.t("app.flash.model_not_found.fallback", { + model: model, + ids: ids ? `${ids.join(", ")}` : "", + }), ); } diff --git a/tests/Frontend/e2e/AdminRolesIndexRoleActions.cy.js b/tests/Frontend/e2e/AdminRolesIndexRoleActions.cy.js index c52b00e6f..50b329bc2 100644 --- a/tests/Frontend/e2e/AdminRolesIndexRoleActions.cy.js +++ b/tests/Frontend/e2e/AdminRolesIndexRoleActions.cy.js @@ -179,7 +179,7 @@ describe("Admin roles index role actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Role", + model: "role", ids: [3], }, }).as("deleteRoleRequest"); @@ -193,9 +193,7 @@ describe("Admin roles index role actions", function () { // Check that dialog is closed and that error message is shown cy.get('[data-test="roles-delete-dialog"]').should("not.exist"); - cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Role","ids":"3"}', - ); + cy.checkToastMessage('app.flash.model_not_found.role_{"ids":"3"}'); // Check that role is not in the list anymore cy.get('[data-test="role-item"]').should("have.length", 2); diff --git a/tests/Frontend/e2e/AdminRolesViewRoleActions.cy.js b/tests/Frontend/e2e/AdminRolesViewRoleActions.cy.js index 32a204e61..0f250f6e2 100644 --- a/tests/Frontend/e2e/AdminRolesViewRoleActions.cy.js +++ b/tests/Frontend/e2e/AdminRolesViewRoleActions.cy.js @@ -142,7 +142,7 @@ describe("Admin roles view role actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Role", + model: "role", ids: [2], }, }).as("deleteRoleRequest"); @@ -155,9 +155,7 @@ describe("Admin roles view role actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/roles").and("not.include", "/2"); - cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Role","ids":"2"}', - ); + cy.checkToastMessage('app.flash.model_not_found.role_{"ids":"2"}'); // Reload view and open delete dialog again cy.visit("/admin/roles/2"); diff --git a/tests/Frontend/e2e/AdminRoomTypesIndexRoomTypeActions.cy.js b/tests/Frontend/e2e/AdminRoomTypesIndexRoomTypeActions.cy.js index 333a7cd1a..0a927ad0d 100644 --- a/tests/Frontend/e2e/AdminRoomTypesIndexRoomTypeActions.cy.js +++ b/tests/Frontend/e2e/AdminRoomTypesIndexRoomTypeActions.cy.js @@ -341,7 +341,7 @@ describe("Admin room types index room type actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "RoomType", + model: "room_type", ids: [3], }, }).as("deleteRoomTypeRequest"); @@ -357,9 +357,7 @@ describe("Admin room types index room type actions", function () { cy.get('[data-test="room-types-delete-dialog"]').should("not.exist"); // Check that error message is shown - cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"RoomType","ids":"3"}', - ); + cy.checkToastMessage('app.flash.model_not_found.room_type_{"ids":"3"}'); // Check that room type is not there anymore cy.get('[data-test="room-type-item"]').should("have.length", 2); diff --git a/tests/Frontend/e2e/AdminRoomTypesViewRoomTypeActions.cy.js b/tests/Frontend/e2e/AdminRoomTypesViewRoomTypeActions.cy.js index e852fd1e6..50405df27 100644 --- a/tests/Frontend/e2e/AdminRoomTypesViewRoomTypeActions.cy.js +++ b/tests/Frontend/e2e/AdminRoomTypesViewRoomTypeActions.cy.js @@ -292,7 +292,7 @@ describe("Admin room types view room type actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "RoomType", + model: "room_type", ids: [3], }, }).as("deleteRoomTypeRequest"); @@ -306,9 +306,7 @@ describe("Admin room types view room type actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/room_types").and("not.include", "/3"); - cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"RoomType","ids":"3"}', - ); + cy.checkToastMessage('app.flash.model_not_found.room_type_{"ids":"3"}'); // Reload view and open delete dialog again cy.visit("/admin/room_types/3"); diff --git a/tests/Frontend/e2e/AdminServerPoolsIndexServerPoolActions.cy.js b/tests/Frontend/e2e/AdminServerPoolsIndexServerPoolActions.cy.js index e0f517f52..4ee467bf0 100644 --- a/tests/Frontend/e2e/AdminServerPoolsIndexServerPoolActions.cy.js +++ b/tests/Frontend/e2e/AdminServerPoolsIndexServerPoolActions.cy.js @@ -216,7 +216,7 @@ describe("Admin server pools index server pool actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "ServerPool", + model: "server_pool", ids: [1], }, }).as("deleteServerPoolRequest"); @@ -230,9 +230,7 @@ describe("Admin server pools index server pool actions", function () { // Check that dialog is closed and error message is shown cy.get('[data-test="server-pools-delete-dialog"]').should("not.exist"); - cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"ServerPool","ids":"1"}', - ); + cy.checkToastMessage('app.flash.model_not_found.server_pool_{"ids":"1"}'); // Check that server pool is not in list anymore cy.get('[data-test="server-pool-item"]').should("have.length", 1); diff --git a/tests/Frontend/e2e/AdminServerPoolsViewServerPoolActions.cy.js b/tests/Frontend/e2e/AdminServerPoolsViewServerPoolActions.cy.js index 9cdd9956c..299e2711e 100644 --- a/tests/Frontend/e2e/AdminServerPoolsViewServerPoolActions.cy.js +++ b/tests/Frontend/e2e/AdminServerPoolsViewServerPoolActions.cy.js @@ -167,7 +167,7 @@ describe("Admin server pools view", function () { statusCode: 404, body: { message: "model_not_found", - model: "ServerPool", + model: "server_pool", ids: [1], }, }).as("deleteServerPoolRequest"); @@ -180,9 +180,7 @@ describe("Admin server pools view", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/server_pools").and("not.include", "/1"); - cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"ServerPool","ids":"1"}', - ); + cy.checkToastMessage('app.flash.model_not_found.server_pool_{"ids":"1"}'); // Reload view and open delete dialog again cy.visit("/admin/server_pools/1"); diff --git a/tests/Frontend/e2e/AdminServersIndexServerActions.cy.js b/tests/Frontend/e2e/AdminServersIndexServerActions.cy.js index c3db6e498..0df2407ec 100644 --- a/tests/Frontend/e2e/AdminServersIndexServerActions.cy.js +++ b/tests/Frontend/e2e/AdminServersIndexServerActions.cy.js @@ -168,7 +168,7 @@ describe("Admin servers index server actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Server", + model: "server", ids: [3], }, }).as("deleteServerRequest"); @@ -182,9 +182,7 @@ describe("Admin servers index server actions", function () { // Check that dialog is closed and error message is shown cy.get('[data-test="servers-delete-dialog"]').should("not.exist"); - cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Server","ids":"3"}', - ); + cy.checkToastMessage('app.flash.model_not_found.server_{"ids":"3"}'); // Check that server is not in list anymore cy.get('[data-test="server-item"]').should("have.length", 3); diff --git a/tests/Frontend/e2e/AdminServersViewServerActions.cy.js b/tests/Frontend/e2e/AdminServersViewServerActions.cy.js index 692d3798d..cbe6fe503 100644 --- a/tests/Frontend/e2e/AdminServersViewServerActions.cy.js +++ b/tests/Frontend/e2e/AdminServersViewServerActions.cy.js @@ -140,7 +140,7 @@ describe("Admin servers view server actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Server", + model: "server", ids: [1], }, }).as("deleteServerRequest"); @@ -154,9 +154,7 @@ describe("Admin servers view server actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/servers").and("not.include", "/1"); - cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Server","ids":"1"}', - ); + cy.checkToastMessage('app.flash.model_not_found.server_{"ids":"1"}'); // Reload view and open delete dialog again cy.visit("/admin/servers/1"); diff --git a/tests/Frontend/e2e/AdminUsersIndexUserActions.cy.js b/tests/Frontend/e2e/AdminUsersIndexUserActions.cy.js index e418bbf94..08931d4b4 100644 --- a/tests/Frontend/e2e/AdminUsersIndexUserActions.cy.js +++ b/tests/Frontend/e2e/AdminUsersIndexUserActions.cy.js @@ -170,7 +170,7 @@ describe("Admin users index user actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "User", + model: "user", ids: [3], }, }).as("deleteUserRequest"); @@ -184,9 +184,7 @@ describe("Admin users index user actions", function () { // Check that dialog is closed and error message is shown cy.get('[data-test="users-delete-dialog"]').should("not.exist"); - cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"User","ids":"3"}', - ); + cy.checkToastMessage('app.flash.model_not_found.user_{"ids":"3"}'); // Check that user is not in list anymore cy.get('[data-test="user-item"]').should("have.length", 3); diff --git a/tests/Frontend/e2e/AdminUsersViewUserActions.cy.js b/tests/Frontend/e2e/AdminUsersViewUserActions.cy.js index 8fa4cc32f..a48463c9e 100644 --- a/tests/Frontend/e2e/AdminUsersViewUserActions.cy.js +++ b/tests/Frontend/e2e/AdminUsersViewUserActions.cy.js @@ -132,7 +132,7 @@ describe("Admin users view user actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "User", + model: "user", ids: [2], }, }).as("deleteUserRequest"); @@ -146,9 +146,7 @@ describe("Admin users view user actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/users").and("not.include", "/2"); - cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"User","ids":"2"}', - ); + cy.checkToastMessage('app.flash.model_not_found.user_{"ids":"2"}'); // Reload view and open delete dialog again cy.visit("/admin/users/2"); @@ -259,7 +257,7 @@ describe("Admin users view user actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "User", + model: "user", ids: [2], }, }).as("resetPasswordRequest"); @@ -273,9 +271,7 @@ describe("Admin users view user actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/users").and("not.include", "/2"); - cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"User","ids":"2"}', - ); + cy.checkToastMessage('app.flash.model_not_found.user_{"ids":"2"}'); // Reload view and open reset password dialog again cy.visit("/admin/users/2"); diff --git a/tests/Frontend/e2e/RoomsViewDescription.cy.js b/tests/Frontend/e2e/RoomsViewDescription.cy.js index f5882eb45..abed2b153 100644 --- a/tests/Frontend/e2e/RoomsViewDescription.cy.js +++ b/tests/Frontend/e2e/RoomsViewDescription.cy.js @@ -472,7 +472,7 @@ describe("Rooms view description", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("saveDescriptionRequest"); @@ -488,7 +488,7 @@ describe("Rooms view description", function () { // Check that error message gets shown cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); diff --git a/tests/Frontend/e2e/RoomsViewFiles.cy.js b/tests/Frontend/e2e/RoomsViewFiles.cy.js index 0f2fd3611..06843dd57 100644 --- a/tests/Frontend/e2e/RoomsViewFiles.cy.js +++ b/tests/Frontend/e2e/RoomsViewFiles.cy.js @@ -727,7 +727,7 @@ describe("Rooms View Files", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("roomFilesRequest"); @@ -740,7 +740,7 @@ describe("Rooms View Files", function () { // Check that error message gets shown cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); diff --git a/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js b/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js index 55417004a..b9d0ca1ec 100644 --- a/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js @@ -343,7 +343,7 @@ describe("Rooms view files file actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("uploadFileRequest"); @@ -363,7 +363,7 @@ describe("Rooms view files file actions", function () { // Check that error message is shown cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -451,7 +451,7 @@ describe("Rooms view files file actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "RoomFile", + model: "room_file", ids: [3], }, }).as("deleteFileRequest"); @@ -550,7 +550,7 @@ describe("Rooms view files file actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("deleteFileRequest"); @@ -572,7 +572,7 @@ describe("Rooms view files file actions", function () { // Check that error message is shown cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -684,7 +684,7 @@ describe("Rooms view files file actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "RoomFile", + model: "room_file", ids: [3], }, }).as("editFileRequest"); @@ -807,7 +807,7 @@ describe("Rooms view files file actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("editFileRequest"); @@ -829,7 +829,7 @@ describe("Rooms view files file actions", function () { // Check that error message is shown cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); diff --git a/tests/Frontend/e2e/RoomsViewGeneral.cy.js b/tests/Frontend/e2e/RoomsViewGeneral.cy.js index 651f58c7f..bacb3d686 100644 --- a/tests/Frontend/e2e/RoomsViewGeneral.cy.js +++ b/tests/Frontend/e2e/RoomsViewGeneral.cy.js @@ -2381,7 +2381,7 @@ describe("Room View general", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("joinMembershipRequest"); @@ -2394,7 +2394,7 @@ describe("Room View general", function () { cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); // Reload room with user being a member of the room @@ -2514,7 +2514,7 @@ describe("Room View general", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("endMembershipRequest"); @@ -2528,6 +2528,11 @@ describe("Room View general", function () { // Check that redirect worked and error message is shown cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); + + // Check that error message is shown + cy.checkToastMessage( + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', + ); }); it("trigger favorites button", function () { @@ -2726,7 +2731,7 @@ describe("Room View general", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("addFavoritesRequest"); @@ -2739,7 +2744,7 @@ describe("Room View general", function () { cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); // Reload room but room is already in favorites @@ -2842,7 +2847,7 @@ describe("Room View general", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("deleteFavoritesRequest"); @@ -2857,7 +2862,7 @@ describe("Room View general", function () { cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); diff --git a/tests/Frontend/e2e/RoomsViewHistory.cy.js b/tests/Frontend/e2e/RoomsViewHistory.cy.js index d1548e679..a5f1a4cc0 100644 --- a/tests/Frontend/e2e/RoomsViewHistory.cy.js +++ b/tests/Frontend/e2e/RoomsViewHistory.cy.js @@ -508,7 +508,7 @@ describe("Rooms view history", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("roomHistoryRequest"); @@ -519,7 +519,7 @@ describe("Rooms view history", function () { // Check that redirect to 404 page works and that error message is shown cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); diff --git a/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js b/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js index 40371d111..a1d999e81 100644 --- a/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js @@ -140,7 +140,7 @@ describe("Rooms view history meeting actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Meeting", + model: "meeting", ids: ["3a3e504a-d2c4-431c-8ca1-a62598e66761"], }, }, @@ -155,7 +155,7 @@ describe("Rooms view history meeting actions", function () { // Check that error message is shown cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Meeting","ids":"3a3e504a-d2c4-431c-8ca1-a62598e66761"}', + 'app.flash.model_not_found.meeting_{"ids":"3a3e504a-d2c4-431c-8ca1-a62598e66761"}', ); // Check if dialog is closed @@ -478,7 +478,7 @@ describe("Rooms view history meeting actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Meeting", + model: "meeting", ids: ["3a3e504a-d2c4-431c-8ca1-a62598e66761"], }, }, @@ -493,7 +493,7 @@ describe("Rooms view history meeting actions", function () { // Check that error message is shown cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Meeting","ids":"3a3e504a-d2c4-431c-8ca1-a62598e66761"}', + 'app.flash.model_not_found.meeting_{"ids":"3a3e504a-d2c4-431c-8ca1-a62598e66761"}', ); // Check if dialog is closed diff --git a/tests/Frontend/e2e/RoomsViewMeetings.cy.js b/tests/Frontend/e2e/RoomsViewMeetings.cy.js index aafc2a32d..efc12ebf9 100644 --- a/tests/Frontend/e2e/RoomsViewMeetings.cy.js +++ b/tests/Frontend/e2e/RoomsViewMeetings.cy.js @@ -1366,7 +1366,7 @@ describe("Rooms view meetings", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("joinRequest"); @@ -1388,7 +1388,7 @@ describe("Rooms view meetings", function () { // Check that redirect to 404 page worked and error message is shown cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -1557,7 +1557,7 @@ describe("Rooms view meetings", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("preJoinRequest"); @@ -1569,7 +1569,7 @@ describe("Rooms view meetings", function () { // Check that redirect to 404 page worked and error message is shown cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -2953,7 +2953,7 @@ describe("Rooms view meetings", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("startRequest"); @@ -2974,7 +2974,7 @@ describe("Rooms view meetings", function () { cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -3145,7 +3145,7 @@ describe("Rooms view meetings", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("preStartRequest"); @@ -3158,7 +3158,7 @@ describe("Rooms view meetings", function () { cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); diff --git a/tests/Frontend/e2e/RoomsViewMembers.cy.js b/tests/Frontend/e2e/RoomsViewMembers.cy.js index 4d4d459e3..1f4cea804 100644 --- a/tests/Frontend/e2e/RoomsViewMembers.cy.js +++ b/tests/Frontend/e2e/RoomsViewMembers.cy.js @@ -494,7 +494,7 @@ describe("Rooms view members", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("roomMembersRequest"); @@ -507,7 +507,7 @@ describe("Rooms view members", function () { cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); diff --git a/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js b/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js index 2261a03d5..290e89427 100644 --- a/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js @@ -425,7 +425,7 @@ describe("Rooms view members bulk actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("bulkEditRequest"); @@ -443,7 +443,7 @@ describe("Rooms view members bulk actions", function () { cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -736,7 +736,7 @@ describe("Rooms view members bulk actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("bulkDeleteRequest"); @@ -756,7 +756,7 @@ describe("Rooms view members bulk actions", function () { cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -1476,7 +1476,7 @@ describe("Rooms view members bulk actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("bulkImportRequest"); @@ -1498,7 +1498,7 @@ describe("Rooms view members bulk actions", function () { cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); }); diff --git a/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js b/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js index ba9cd1949..e3adede6d 100644 --- a/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js @@ -456,7 +456,7 @@ describe("Rooms view members member actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("addUserRequest"); @@ -468,7 +468,7 @@ describe("Rooms view members member actions", function () { // Check that user is redirected to 404 page and error message is shown cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -697,7 +697,7 @@ describe("Rooms view members member actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("editUserRequest"); @@ -709,7 +709,7 @@ describe("Rooms view members member actions", function () { // Check that user is redirected to 404 page and error message is shown cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -895,7 +895,7 @@ describe("Rooms view members member actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("deleteMemberRequest"); @@ -907,7 +907,7 @@ describe("Rooms view members member actions", function () { // Check that user is redirected to 404 page and error message is shown cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); }); diff --git a/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js b/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js index 95f1d2082..fefd7960b 100644 --- a/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js +++ b/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js @@ -513,7 +513,7 @@ describe("Rooms view personalized links", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }, @@ -526,7 +526,7 @@ describe("Rooms view personalized links", function () { // Check that redirect to 404 page worked and error message is shown cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); diff --git a/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js b/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js index af6f97dda..5f4c7c9ac 100644 --- a/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js @@ -247,7 +247,7 @@ describe("Rooms view personalized links actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("addLinkRequest"); @@ -263,7 +263,7 @@ describe("Rooms view personalized links actions", function () { // Check that redirect to 404 page works and error message is shown cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -567,7 +567,7 @@ describe("Rooms view personalized links actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("editLinkRequest"); @@ -586,7 +586,7 @@ describe("Rooms view personalized links actions", function () { // Check that redirect to 404 page works and error message is shown cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -794,7 +794,7 @@ describe("Rooms view personalized links actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("deleteLinkRequest"); @@ -813,7 +813,7 @@ describe("Rooms view personalized links actions", function () { // Check that redirect to 404 page works and error message is shown cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); diff --git a/tests/Frontend/e2e/RoomsViewRecordings.cy.js b/tests/Frontend/e2e/RoomsViewRecordings.cy.js index 1de5fb405..7ec1a6800 100644 --- a/tests/Frontend/e2e/RoomsViewRecordings.cy.js +++ b/tests/Frontend/e2e/RoomsViewRecordings.cy.js @@ -766,7 +766,7 @@ describe("Rooms view recordings", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("roomRecordingsRequest"); @@ -780,7 +780,7 @@ describe("Rooms view recordings", function () { cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); diff --git a/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js b/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js index 592c7e30e..dd9b6c8be 100644 --- a/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js @@ -879,7 +879,7 @@ describe("Rooms view recordings recording actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Recording", + model: "recording", ids: ["f9569db6d5e8fb2fd2f57d367d5482b36837b9d8-1663666775"], }, }, @@ -982,7 +982,7 @@ describe("Rooms view recordings recording actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }, @@ -1003,7 +1003,7 @@ describe("Rooms view recordings recording actions", function () { // Check that redirect to 404 page worked and error message is shown cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -1376,7 +1376,7 @@ describe("Rooms view recordings recording actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }, @@ -1397,7 +1397,7 @@ describe("Rooms view recordings recording actions", function () { // Check that redirect to 404 page worked and error message is shown cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); }); diff --git a/tests/Frontend/e2e/RoomsViewSettings.cy.js b/tests/Frontend/e2e/RoomsViewSettings.cy.js index e99e27606..12c10b83c 100644 --- a/tests/Frontend/e2e/RoomsViewSettings.cy.js +++ b/tests/Frontend/e2e/RoomsViewSettings.cy.js @@ -426,7 +426,7 @@ describe("Rooms view settings", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("roomSettingsRequest"); @@ -438,7 +438,7 @@ describe("Rooms view settings", function () { // Check that redirect to 404 page worked and error message is shown cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -1744,7 +1744,7 @@ describe("Rooms view settings", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("roomDeleteRequest"); @@ -1757,7 +1757,7 @@ describe("Rooms view settings", function () { cy.wait("@roomDeleteRequest"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); // Reload room page @@ -2308,7 +2308,7 @@ describe("Rooms view settings", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("transferOwnershipRequest"); @@ -2322,7 +2322,7 @@ describe("Rooms view settings", function () { // Check that redirect to 404 page worked and error message is shown cy.url().should("include", "/404"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); }); diff --git a/tests/Frontend/e2e/RoomsViewStreaming.cy.js b/tests/Frontend/e2e/RoomsViewStreaming.cy.js index 6e10d107b..aa46a1af2 100644 --- a/tests/Frontend/e2e/RoomsViewStreaming.cy.js +++ b/tests/Frontend/e2e/RoomsViewStreaming.cy.js @@ -792,7 +792,7 @@ describe("Rooms view streaming", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("roomStreamingStatus"); @@ -804,7 +804,7 @@ describe("Rooms view streaming", function () { cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); }); diff --git a/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js b/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js index 92905de5f..9de91ac25 100644 --- a/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js @@ -283,7 +283,7 @@ describe("Rooms view streaming config actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("roomStreamingConfig"); @@ -296,7 +296,7 @@ describe("Rooms view streaming config actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); @@ -625,7 +625,7 @@ describe("Rooms view streaming config actions", function () { statusCode: 404, body: { message: "model_not_found", - model: "Room", + model: "room", ids: ["abc-def-123"], }, }).as("saveConfigRequest"); @@ -644,7 +644,7 @@ describe("Rooms view streaming config actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); cy.checkToastMessage( - 'app.flash.model_not_found_{"model":"Room","ids":"abc-def-123"}', + 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', ); }); diff --git a/tests/Frontend/fixtures/en.json b/tests/Frontend/fixtures/en.json index 4e7bcd7a7..9c7aea205 100644 --- a/tests/Frontend/fixtures/en.json +++ b/tests/Frontend/fixtures/en.json @@ -1,5 +1,19 @@ { - "data": {}, + "data": { + "app": { + "flash": { + "model_not_found": { + "meeting": "app.flash.model_not_found.meeting_{\"ids\":\":ids\"}", + "role": "app.flash.model_not_found.role_{\"ids\":\":ids\"}", + "room": "app.flash.model_not_found.room_{\"ids\":\":ids\"}", + "room_type": "app.flash.model_not_found.room_type_{\"ids\":\":ids\"}", + "server": "app.flash.model_not_found.server_{\"ids\":\":ids\"}", + "server_pool": "app.flash.model_not_found.server_pool_{\"ids\":\":ids\"}", + "user": "app.flash.model_not_found.user_{\"ids\":\":ids\"}" + } + } + } + }, "meta": { "dateTimeFormat": { "dateShort": { From 935d372363fba36b7ba2b2d6dc81d5e345860ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Sun, 22 Mar 2026 10:28:35 +0100 Subject: [PATCH 06/18] Start adjusting backend tests --- .../Backend/Feature/api/v1/RecordingTest.php | 35 +++++++++- tests/Backend/Feature/api/v1/RoleTest.php | 25 ++++++- .../Backend/Feature/api/v1/Room/FileTest.php | 57 ++++++++++++++-- .../Feature/api/v1/Room/MembershipTest.php | 7 +- .../api/v1/Room/RoomPersonalizedLinkTest.php | 68 ++++++++++++++++--- .../Backend/Feature/api/v1/Room/RoomTest.php | 53 +++++++++++++-- tests/Backend/Feature/api/v1/RoomTypeTest.php | 27 +++++++- .../Backend/Feature/api/v1/ServerPoolTest.php | 27 +++++++- tests/Backend/Feature/api/v1/ServerTest.php | 38 ++++++++++- tests/Backend/Feature/api/v1/UserTest.php | 29 ++++++-- 10 files changed, 329 insertions(+), 37 deletions(-) diff --git a/tests/Backend/Feature/api/v1/RecordingTest.php b/tests/Backend/Feature/api/v1/RecordingTest.php index 112042ed8..392582200 100644 --- a/tests/Backend/Feature/api/v1/RecordingTest.php +++ b/tests/Backend/Feature/api/v1/RecordingTest.php @@ -1093,6 +1093,17 @@ public function test_update() $this->assertTrue($podcast->disabled); $this->assertFalse($presentation->disabled); $this->assertTrue($notes->disabled); + + // Test deleted recording + $recording->delete(); + + $this->putJson(route('api.v1.rooms.recordings.update', ['room' => $room->id, 'recording' => $recording->id]), $payload) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'recording', + 'ids' => [$recording->id], + ]); } public function test_update_permissions() @@ -1190,7 +1201,12 @@ public function test_update_invalid_data() $otherRoom = Room::factory()->create(); $this->actingAs($otherRoom->owner) ->putJson(route('api.v1.rooms.recordings.update', ['room' => $otherRoom->id, 'recording' => $recording->id]), $payload) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'recording', + 'ids' => [$recording->id], + ]); } @@ -1222,6 +1238,16 @@ public function test_delete() // Check storage $this->assertDirectoryDoesNotExist(Storage::disk('recordings')->path($recording->id)); + + // Test delete again + $this->actingAs($room->owner) + ->deleteJson(route('api.v1.rooms.recordings.destroy', ['room' => $room->id, 'recording' => $recording->id])) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'recording', + 'ids' => [$recording->id], + ]); } public function test_delete_on_room_delete() @@ -1319,7 +1345,12 @@ public function test_delete_invalid_data() $otherRoom = Room::factory()->create(); $this->actingAs($otherRoom->owner) ->deleteJson(route('api.v1.rooms.recordings.destroy', ['room' => $otherRoom->id, 'recording' => $recording->id])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'recording', + 'ids' => [$recording->id], + ]); } public function test_access_recording_resource() diff --git a/tests/Backend/Feature/api/v1/RoleTest.php b/tests/Backend/Feature/api/v1/RoleTest.php index fbb05f92a..00132090b 100644 --- a/tests/Backend/Feature/api/v1/RoleTest.php +++ b/tests/Backend/Feature/api/v1/RoleTest.php @@ -239,6 +239,17 @@ public function test_update() $this->putJson(route('api.v1.roles.update', ['role' => $role]), $changes) ->assertUnprocessable() ->assertJsonValidationErrors(['permissions', 'name', 'room_limit']); + + // Test deleted + $role->delete(); + + $this->putJson(route('api.v1.roles.update', ['role' => $role]), $changes) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'role', + 'ids' => [$role->id], + ]); } public function test_update_permission_lost() @@ -324,7 +335,13 @@ public function test_show() $roleB->permissions()->attach($permission->id); $this->actingAs($user)->getJson(route('api.v1.roles.show', ['role' => self::INVALID_ID])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'role', + 'ids' => [self::INVALID_ID], + ]); + $this->getJson(route('api.v1.roles.show', ['role' => $roleA])) ->assertStatus(200) ->assertJsonFragment([ @@ -356,7 +373,11 @@ public function test_delete() $superuserRole->permissions()->attach($permission->id); $role->permissions()->attach($permission->id); - $this->deleteJson(route('api.v1.roles.destroy', ['role' => self::INVALID_ID]))->assertNotFound(); + $this->deleteJson(route('api.v1.roles.destroy', ['role' => self::INVALID_ID]))->assertNotFound()->assertJson([ + 'message' => 'model_not_found', + 'model' => 'role', + 'ids' => [self::INVALID_ID], + ]); // check if superuser role cannot be deleted $this->deleteJson(route('api.v1.roles.destroy', ['role' => $superuserRole]))->assertStatus(403); diff --git a/tests/Backend/Feature/api/v1/Room/FileTest.php b/tests/Backend/Feature/api/v1/Room/FileTest.php index 011dbe49c..69ace11a4 100644 --- a/tests/Backend/Feature/api/v1/Room/FileTest.php +++ b/tests/Backend/Feature/api/v1/Room/FileTest.php @@ -1077,7 +1077,14 @@ public function test_files_delete() // Testing delete again $this->actingAs($this->room->owner)->deleteJson(route('api.v1.rooms.files.destroy', ['room' => $this->room->id, 'file' => $room_file])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room_file', + 'ids' => [ + $room_file->id, + ], + ]); // Check if file was deleted as well Storage::disk('local')->assertMissing($this->room->id.'/'.$this->file_valid->hashName()); @@ -1128,13 +1135,27 @@ public function test_delete_file_url_manipulation() // Testing for room without permission $this->actingAs($this->room->owner)->deleteJson(route('api.v1.rooms.files.destroy', ['room' => $other_room->id, 'file' => $room_file])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room_file', + 'ids' => [ + $room_file->id, + ], + ]); // Testing for room with permission $other_room->owner()->associate($this->room->owner); $other_room->save(); $this->actingAs($this->room->owner)->deleteJson(route('api.v1.rooms.files.destroy', ['room' => $other_room->id, 'file' => $room_file])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room_file', + 'ids' => [ + $room_file->id, + ], + ]); } /** @@ -1212,13 +1233,27 @@ public function test_update_file() $other_room = Room::factory()->create(); // Testing for room without permission $this->actingAs($this->room->owner)->putJson(route('api.v1.rooms.files.update', ['room' => $other_room->id, 'file' => $room_file]), $params) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room_file', + 'ids' => [ + $room_file->id, + ], + ]); // Testing for room with permission $other_room->owner()->associate($this->room->owner); $other_room->save(); $this->actingAs($this->room->owner)->putJson(route('api.v1.rooms.files.update', ['room' => $other_room->id, 'file' => $room_file]), $params) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room_file', + 'ids' => [ + $room_file->id, + ], + ]); // Testing missing properties $params = []; @@ -1234,6 +1269,18 @@ public function test_update_file() $this->actingAs($this->room->owner)->putJson($route, $params) ->assertJsonValidationErrors(['use_in_meeting', 'download', 'default']); + + // Test deleted + $room_file->delete(); + $this->actingAs($this->room->owner)->putJson($route, $params) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room_file', + 'ids' => [ + $room_file->id, + ], + ]); } /** diff --git a/tests/Backend/Feature/api/v1/Room/MembershipTest.php b/tests/Backend/Feature/api/v1/Room/MembershipTest.php index f85ccb67d..b6f204620 100644 --- a/tests/Backend/Feature/api/v1/Room/MembershipTest.php +++ b/tests/Backend/Feature/api/v1/Room/MembershipTest.php @@ -781,7 +781,12 @@ public function test_remove_member() // Remove member with invalid user $this->actingAs($owner)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => 0])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'user', + 'ids' => [0], + ]); // Remove member as moderator $this->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => $newUser])) diff --git a/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php b/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php index 5373cff64..d9e401537 100644 --- a/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php +++ b/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php @@ -100,7 +100,12 @@ public function test_index() // Testing owner $this->actingAs($this->room->owner)->getJson(route('api.v1.rooms.personalizedLinks.get', ['room' => 1337])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [1337], + ]); $this->actingAs($this->room->owner)->getJson(route('api.v1.rooms.personalizedLinks.get', ['room' => $this->room])) ->assertSuccessful() @@ -246,7 +251,14 @@ public function test_create() // Create as moderator $this->room->members()->sync([$this->user->id => ['role' => RoomUserRole::MODERATOR]]); $this->actingAs($this->user)->postJson(route('api.v1.rooms.personalizedLinks.add', ['room' => 1337]), $payload) - ->assertNotFound(); + ->assertNotFound() + ->assertJson( + [ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [1337], + ] + ); $this->actingAs($this->user)->postJson(route('api.v1.rooms.personalizedLinks.add', ['room' => $this->room]), $payload) ->assertForbidden(); @@ -340,7 +352,14 @@ public function test_update() // Update as moderator $this->room->members()->sync([$this->user->id => ['role' => RoomUserRole::MODERATOR]]); $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => 1337, 'link' => $link]), $payload) - ->assertNotFound(); + ->assertNotFound() + ->assertJson( + [ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [1337], + ]); + $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'link' => $link]), $payload) ->assertForbidden(); @@ -401,7 +420,19 @@ public function test_update() // Check trying to update with wrong room id $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $otherRoom, 'link' => $link]), $payload) - ->assertNotFound(); + ->assertNotFound() + ->assertJsonFragment(['message' => __('app.errors.personalized_link_not_found')]); + + // Test deleted + $link->delete(); + $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'link' => $link]), $payload) + ->assertNotFound() + ->assertJson( + [ + 'message' => 'model_not_found', + 'model' => 'room_personalized_link', + 'ids' => [$link->id], + ]); } public function test_delete() @@ -452,7 +483,13 @@ public function test_delete() // Delete not existing $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson( + [ + 'message' => 'model_not_found', + 'model' => 'room_personalized_link', + 'ids' => [$link->id], + ]); // Delete as owner $link = RoomPersonalizedLink::factory()->create([ @@ -461,7 +498,13 @@ public function test_delete() $this->actingAs($this->room->owner)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) ->assertSuccessful(); $this->actingAs($this->room->owner)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson( + [ + 'message' => 'model_not_found', + 'model' => 'room_personalized_link', + 'ids' => [$link->id], + ]); // Delete with viewAllPermission $this->room->members()->sync([]); @@ -472,11 +515,20 @@ public function test_delete() // Check trying to delete with wrong room id $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $otherRoom, 'link' => $link])) - ->assertNotFound(); + ->assertNotFound() + ->assertJsonFragment(['message' => __('app.errors.personalized_link_not_found')]); $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) ->assertSuccessful(); + + // Test delete again $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson( + [ + 'message' => 'model_not_found', + 'model' => 'room_personalized_link', + 'ids' => [$link->id], + ]); } } diff --git a/tests/Backend/Feature/api/v1/Room/RoomTest.php b/tests/Backend/Feature/api/v1/Room/RoomTest.php index 3b1ad7ef9..f678d25ab 100644 --- a/tests/Backend/Feature/api/v1/Room/RoomTest.php +++ b/tests/Backend/Feature/api/v1/Room/RoomTest.php @@ -290,7 +290,12 @@ public function test_delete_room() // Try again after deleted $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.destroy', ['room' => $room])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } public function test_transfer_room() @@ -431,7 +436,12 @@ public function test_room_404_rate_limit() // Guest trying to access non-existing rooms for ($i = 0; $i < 10; $i++) { $this->getJson(route('api.v1.rooms.show', ['room' => 999999])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [999999], + ]); } // Check route is now rate limited $this->getJson(route('api.v1.rooms.show', ['room' => 999999])) @@ -446,7 +456,12 @@ public function test_room_404_rate_limit() $this->actingAs($room->owner); for ($i = 0; $i < 10; $i++) { $this->getJson(route('api.v1.rooms.show', ['room' => 999999])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [999999], + ]); } // Check route is now rate limited $this->getJson(route('api.v1.rooms.show', ['room' => 999999])) @@ -462,11 +477,21 @@ public function test_room_404_rate_limit() // Time travel 1 minute to reset rate limit $this->travel(1)->minutes(); $this->getJson(route('api.v1.rooms.show', ['room' => 999999])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [999999], + ]); $this->actingAsGuest(); $this->getJson(route('api.v1.rooms.show', ['room' => 999999])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [999999], + ]); // Time travel 1 minute to reset rate limit $this->travel(1)->minutes(); @@ -475,7 +500,12 @@ public function test_room_404_rate_limit() // due to other reasons than the room not existing are not so strictly rate limited for ($i = 0; $i < 50; $i++) { $this->actingAs($room->owner)->putJson(route('api.v1.rooms.files.update', ['room' => $room, 'file' => 999999])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room_file', + 'ids' => ['999999'], + ]); } } @@ -1637,6 +1667,17 @@ public function test_room_view() $room->save(); $this->actingAs($this->user)->getJson(route('api.v1.rooms.show', ['room' => $room])) ->assertJsonPath('data.legacy_code', false); + + // Test deleted + $room->delete(); + + $this->actingAs($this->user)->getJson(route('api.v1.rooms.show', ['room' => $room])) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } /** diff --git a/tests/Backend/Feature/api/v1/RoomTypeTest.php b/tests/Backend/Feature/api/v1/RoomTypeTest.php index 2555ba999..0e5710eb6 100644 --- a/tests/Backend/Feature/api/v1/RoomTypeTest.php +++ b/tests/Backend/Feature/api/v1/RoomTypeTest.php @@ -325,7 +325,14 @@ public function test_show() // Test deleted $roomType->delete(); $this->actingAs($this->user)->getJson(route('api.v1.roomTypes.show', ['roomType' => $roomType->id])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room_type', + 'ids' => [ + $roomType->id, + ], + ]); } /** @@ -895,7 +902,14 @@ public function test_update() // Test deleted $roomType->delete(); $this->actingAs($this->user)->putJson(route('api.v1.roomTypes.update', ['roomType' => $roomType->id]), $data) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room_type', + 'ids' => [ + $roomType->id, + ], + ]); } /** @@ -925,7 +939,14 @@ public function test_delete() // Test delete again $this->actingAs($this->user)->deleteJson(route('api.v1.roomTypes.destroy', ['roomType' => $roomType->id])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room_type', + 'ids' => [ + $roomType->id, + ], + ]); $this->assertDatabaseMissing('room_types', ['id' => $roomType->id]); diff --git a/tests/Backend/Feature/api/v1/ServerPoolTest.php b/tests/Backend/Feature/api/v1/ServerPoolTest.php index 79c321daa..dfd0c458f 100644 --- a/tests/Backend/Feature/api/v1/ServerPoolTest.php +++ b/tests/Backend/Feature/api/v1/ServerPoolTest.php @@ -169,7 +169,14 @@ public function test_show() // Test deleted $serverPool->delete(); $this->actingAs($this->user)->getJson(route('api.v1.serverPools.show', ['serverPool' => $serverPool->id])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'server_pool', + 'ids' => [ + $serverPool->id, + ], + ]); } /** @@ -335,7 +342,14 @@ public function test_update() // Test deleted $serverPool->delete(); $this->actingAs($this->user)->putJson(route('api.v1.serverPools.update', ['serverPool' => $serverPool->id]), $data) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'server_pool', + 'ids' => [ + $serverPool->id, + ], + ]); } /** @@ -374,7 +388,14 @@ public function test_delete() // Test delete again $this->actingAs($this->user)->deleteJson(route('api.v1.serverPools.destroy', ['serverPool' => $serverPool->id])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'server_pool', + 'ids' => [ + $serverPool->id, + ], + ]); $this->assertDatabaseMissing('servers', ['id' => $serverPool->id]); } diff --git a/tests/Backend/Feature/api/v1/ServerTest.php b/tests/Backend/Feature/api/v1/ServerTest.php index d1ba38888..9f8ab50ef 100644 --- a/tests/Backend/Feature/api/v1/ServerTest.php +++ b/tests/Backend/Feature/api/v1/ServerTest.php @@ -243,7 +243,12 @@ public function test_show() $server->save(); $server->delete(); $this->actingAs($this->user)->getJson(route('api.v1.servers.show', ['server' => $server->id])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'server', + 'ids' => [$server->id], + ]); } /** @@ -390,7 +395,12 @@ public function test_update() $server->save(); $server->delete(); $this->actingAs($this->user)->putJson(route('api.v1.servers.update', ['server' => $server->id]), $data) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'server', + 'ids' => [$server->id], + ]); } /** @@ -439,7 +449,12 @@ public function test_delete() // Test delete again $this->actingAs($this->user)->deleteJson(route('api.v1.servers.destroy', ['server' => $server->id])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'server', + 'ids' => [$server->id], + ]); $this->assertDatabaseMissing('servers', ['id' => $server->id]); } @@ -542,5 +557,22 @@ public function test_panic() $this->assertEquals(ServerStatus::DISABLED, $server->status); $this->assertNull($meeting->end); + + // Test deleted + $server->status = ServerStatus::DISABLED; + $server->save(); + + $meeting->end = date('Y-m-d H:i:s'); + $meeting->save(); + + $server->delete(); + + $this->actingAs($this->user)->postJson(route('api.v1.servers.panic', ['server' => $server->id])) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'server', + 'ids' => [$server->id], + ]); } } diff --git a/tests/Backend/Feature/api/v1/UserTest.php b/tests/Backend/Feature/api/v1/UserTest.php index 4fa30b758..3aedd58b6 100644 --- a/tests/Backend/Feature/api/v1/UserTest.php +++ b/tests/Backend/Feature/api/v1/UserTest.php @@ -537,7 +537,13 @@ public function test_update() // Not existing user $this->actingAs($admin)->putJson(route('api.v1.users.update', ['user' => self::INVALID_ID]), $changes) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'user', + 'ids' => [self::INVALID_ID], + ] + ); // Check as admin $changes['updated_at'] = Carbon::now(); @@ -1417,7 +1423,12 @@ public function test_show() $role->users()->attach([$externalUser->id, $user->id]); $this->actingAs($user)->getJson(route('api.v1.users.show', ['user' => self::INVALID_ID])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'user', + 'ids' => [self::INVALID_ID], + ]); // Existing user $this->actingAs($user)->getJson(route('api.v1.users.show', ['user' => $externalUser])) @@ -1481,7 +1492,12 @@ public function test_delete() ->assertForbidden(); // Not existing model - $this->actingAs($user)->deleteJson(route('api.v1.users.destroy', ['user' => self::INVALID_ID]))->assertNotFound(); + $this->actingAs($user)->deleteJson(route('api.v1.users.destroy', ['user' => self::INVALID_ID]))->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'user', + 'ids' => [self::INVALID_ID], + ]); // User own model $this->actingAs($user)->deleteJson(route('api.v1.users.destroy', ['user' => $user])) @@ -1560,7 +1576,12 @@ public function test_reset_password() $role->users()->attach([$user->id]); $this->actingAs($user)->postJson(route('api.v1.users.password.reset', ['user' => self::INVALID_ID])) - ->assertNotFound(); + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'user', + 'ids' => [self::INVALID_ID], + ]); $this->actingAs($user)->postJson(route('api.v1.users.password.reset', ['user' => $user])) ->assertForbidden(); From 7a96b9cd87384102add77b828d8b4e747e3d10c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Tue, 31 Mar 2026 13:46:40 +0200 Subject: [PATCH 07/18] Continue improving not found error handling and frontend tests --- lang/en/app.php | 17 +-- resources/js/components/RoomCard.vue | 2 + resources/js/components/RoomDeleteButton.vue | 5 +- .../js/components/RoomFavoriteButton.vue | 3 +- resources/js/components/RoomHeader.vue | 1 - resources/js/components/RoomJoinButton.vue | 4 +- .../js/components/RoomMembershipButton.vue | 10 +- .../js/components/RoomTabDescription.vue | 5 +- resources/js/components/RoomTabFiles.vue | 5 +- .../components/RoomTabFilesDeleteButton.vue | 5 +- .../js/components/RoomTabFilesEditButton.vue | 5 +- .../components/RoomTabFilesUploadButton.vue | 5 +- resources/js/components/RoomTabHistory.vue | 5 +- resources/js/components/RoomTabMembers.vue | 5 +- .../RoomTabMembersAddSingleModal.vue | 5 +- .../RoomTabMembersBulkDeleteButton.vue | 5 +- .../RoomTabMembersBulkEditButton.vue | 5 +- .../RoomTabMembersBulkImportModal.vue | 5 +- .../components/RoomTabMembersDeleteButton.vue | 5 +- .../components/RoomTabMembersEditButton.vue | 5 +- .../components/RoomTabPersonalizedLinks.vue | 5 +- .../RoomTabPersonalizedLinksAddButton.vue | 5 +- .../RoomTabPersonalizedLinksDeleteButton.vue | 5 +- .../RoomTabPersonalizedLinksEditButton.vue | 5 +- resources/js/components/RoomTabRecordings.vue | 5 +- .../RoomTabRecordingsDeleteButton.vue | 5 +- .../RoomTabRecordingsEditButton.vue | 5 +- resources/js/components/RoomTabSettings.vue | 5 +- resources/js/components/RoomTabStreaming.vue | 2 +- .../RoomTabStreamingConfigButton.vue | 4 +- .../RoomTransferOwnershipButton.vue | 5 +- resources/js/services/Api.js | 23 ++-- resources/js/views/RoomsView.vue | 23 +++- tests/Frontend/e2e/AdminRolesEdit.cy.js | 16 ++- .../e2e/AdminRolesIndexRoleActions.cy.js | 5 +- tests/Frontend/e2e/AdminRolesView.cy.js | 8 +- .../e2e/AdminRolesViewRoleActions.cy.js | 5 +- tests/Frontend/e2e/AdminRoomTypesEdit.cy.js | 16 ++- .../AdminRoomTypesIndexRoomTypeActions.cy.js | 5 +- tests/Frontend/e2e/AdminRoomTypesView.cy.js | 8 +- .../AdminRoomTypesViewRoomTypeActions.cy.js | 5 +- tests/Frontend/e2e/AdminServerPoolsEdit.cy.js | 16 ++- ...minServerPoolsIndexServerPoolActions.cy.js | 6 +- tests/Frontend/e2e/AdminServerPoolsView.cy.js | 8 +- ...dminServerPoolsViewServerPoolActions.cy.js | 5 +- tests/Frontend/e2e/AdminServersEdit.cy.js | 16 ++- .../e2e/AdminServersIndexServerActions.cy.js | 5 +- tests/Frontend/e2e/AdminServersView.cy.js | 9 +- .../e2e/AdminServersViewServerActions.cy.js | 33 +++++- tests/Frontend/e2e/AdminUsersEdit.cy.js | 8 +- tests/Frontend/e2e/AdminUsersEditBase.cy.js | 8 +- tests/Frontend/e2e/AdminUsersEditEmail.cy.js | 8 +- tests/Frontend/e2e/AdminUsersEditOthers.cy.js | 8 +- .../Frontend/e2e/AdminUsersEditSecurity.cy.js | 16 ++- .../e2e/AdminUsersIndexUserActions.cy.js | 6 +- tests/Frontend/e2e/AdminUsersView.cy.js | 8 +- .../e2e/AdminUsersViewUserActions.cy.js | 10 +- tests/Frontend/e2e/RoomsViewDescription.cy.js | 14 ++- tests/Frontend/e2e/RoomsViewFiles.cy.js | 15 ++- .../e2e/RoomsViewFilesFileActions.cy.js | 39 ++++--- tests/Frontend/e2e/RoomsViewGeneral.cy.js | 109 +++++++++++++++--- tests/Frontend/e2e/RoomsViewHistory.cy.js | 15 ++- .../e2e/RoomsViewHistoryMeetingActions.cy.js | 14 ++- tests/Frontend/e2e/RoomsViewMeetings.cy.js | 55 +++++---- tests/Frontend/e2e/RoomsViewMembers.cy.js | 14 ++- .../e2e/RoomsViewMembersBulkActions.cy.js | 44 ++++--- .../e2e/RoomsViewMembersMemberActions.cy.js | 50 +++++--- .../e2e/RoomsViewPersonalizedLinks.cy.js | 16 ++- ...omsViewPersonalizedLinksTokenActions.cy.js | 48 +++++--- tests/Frontend/e2e/RoomsViewRecordings.cy.js | 15 ++- .../RoomsViewRecordingsRecordingActions.cy.js | 32 +++-- tests/Frontend/e2e/RoomsViewSettings.cy.js | 78 ++++++++++--- tests/Frontend/e2e/RoomsViewStreaming.cy.js | 15 ++- .../e2e/RoomsViewStreamingConfigActions.cy.js | 28 +++-- tests/Frontend/fixtures/en.json | 16 +-- 75 files changed, 670 insertions(+), 389 deletions(-) diff --git a/lang/en/app.php b/lang/en/app.php index 0b9adc4ed..68b020ab1 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -65,14 +65,8 @@ 'client_error' => 'An unknown error occurred in the application!', 'guests_only' => 'The request can only be made by guests!', 'model_not_found' => [ - 'fallback' => 'The :model with the id :ids was not found!', - 'meeting' => 'The meeting with the id :ids was not found!', - 'role' => 'The role with the id :ids was not found!', - 'room' => 'The room with the id :ids was not found!', - 'room_type' => 'The room type with the id :ids was not found!', - 'server' => 'The server with the id :ids was not found!', - 'server_pool' => 'The server pool with the id :ids was not found!', - 'user' => 'The user with the id :ids was not found!', + 'title' => 'The :model was not found!', + 'details' => ' Model ids: :ids', ], 'server_error' => [ 'empty_message' => 'An error occurred on the server during request!', @@ -105,10 +99,17 @@ 'fr' => 'French', ], 'model' => [ + 'meeting' => 'meeting', + 'role' => 'Role', 'roles' => 'role', + 'room' => 'Room', + '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 @@ @@ -72,6 +73,7 @@
diff --git a/resources/js/components/RoomDeleteButton.vue b/resources/js/components/RoomDeleteButton.vue index ed0812eef..66e70631b 100644 --- a/resources/js/components/RoomDeleteButton.vue +++ b/resources/js/components/RoomDeleteButton.vue @@ -90,10 +90,7 @@ function deleteRoom() { }) .catch((error) => { isLoadingAction.value = false; - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }); } diff --git a/resources/js/components/RoomFavoriteButton.vue b/resources/js/components/RoomFavoriteButton.vue index 1cd422a2f..2cf490b75 100644 --- a/resources/js/components/RoomFavoriteButton.vue +++ b/resources/js/components/RoomFavoriteButton.vue @@ -35,7 +35,7 @@ const props = defineProps({ }, redirectOnRoomModelNotFound: { type: Boolean, - default: false, + default: true, }, }); @@ -60,6 +60,7 @@ function toggleFavorite() { .call("rooms/" + props.room.id + "/favorites", config) .catch((error) => { api.error(error, { + // ToDo emit notFound on not found error and handle it in index page (Reload room list) redirectOnUnauthenticated: props.redirectOnUnauthenticated, redirectOnRoomModelNotFound: props.redirectOnRoomModelNotFound, }); diff --git a/resources/js/components/RoomHeader.vue b/resources/js/components/RoomHeader.vue index e0a87fb68..4f1ea5735 100644 --- a/resources/js/components/RoomHeader.vue +++ b/resources/js/components/RoomHeader.vue @@ -33,7 +33,6 @@ v-if="!hideFavorites && authStore.isAuthenticated" :room="props.room" :redirect-on-unauthenticated="false" - :redirect-on-room-model-not-found="true" @favorites-changed="emit('reload')" /> { isLoadingAction.value = false; @@ -156,10 +153,7 @@ function leaveMembership() { modalVisible.value = false; }) .catch((error) => { - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabDescription.vue b/resources/js/components/RoomTabDescription.vue index 583b8e113..bb0eeef14 100644 --- a/resources/js/components/RoomTabDescription.vue +++ b/resources/js/components/RoomTabDescription.vue @@ -229,10 +229,7 @@ function save() { editorOpen.value = false; } // Handle other errors - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { // Disable saving indicator diff --git a/resources/js/components/RoomTabFiles.vue b/resources/js/components/RoomTabFiles.vue index 8fc21ff94..e00bf354a 100644 --- a/resources/js/components/RoomTabFiles.vue +++ b/resources/js/components/RoomTabFiles.vue @@ -425,10 +425,7 @@ function loadData(page = null) { return emit("invalidRoomAuthToken"); } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); paginator.revertFirst(); loadingError.value = true; }) diff --git a/resources/js/components/RoomTabFilesDeleteButton.vue b/resources/js/components/RoomTabFilesDeleteButton.vue index a05f61978..28f0aeefb 100644 --- a/resources/js/components/RoomTabFilesDeleteButton.vue +++ b/resources/js/components/RoomTabFilesDeleteButton.vue @@ -112,10 +112,7 @@ function deleteFile() { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabFilesEditButton.vue b/resources/js/components/RoomTabFilesEditButton.vue index 4f2d2f074..d7901b305 100644 --- a/resources/js/components/RoomTabFilesEditButton.vue +++ b/resources/js/components/RoomTabFilesEditButton.vue @@ -211,10 +211,7 @@ function save() { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabFilesUploadButton.vue b/resources/js/components/RoomTabFilesUploadButton.vue index 599e76fa4..c65a8018d 100644 --- a/resources/js/components/RoomTabFilesUploadButton.vue +++ b/resources/js/components/RoomTabFilesUploadButton.vue @@ -265,10 +265,7 @@ function uploadFile(file) { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }); } diff --git a/resources/js/components/RoomTabHistory.vue b/resources/js/components/RoomTabHistory.vue index c0a6424f0..c4efa78e0 100644 --- a/resources/js/components/RoomTabHistory.vue +++ b/resources/js/components/RoomTabHistory.vue @@ -298,10 +298,7 @@ function loadData(page = null) { }) .catch((error) => { paginator.revertFirst(); - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); loadingError.value = true; }) .finally(() => { diff --git a/resources/js/components/RoomTabMembers.vue b/resources/js/components/RoomTabMembers.vue index 031521eec..184c344b0 100644 --- a/resources/js/components/RoomTabMembers.vue +++ b/resources/js/components/RoomTabMembers.vue @@ -377,10 +377,7 @@ function loadData(page = null) { }) .catch((error) => { paginator.revertFirst(); - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); loadingError.value = true; }) .finally(() => { diff --git a/resources/js/components/RoomTabMembersAddSingleModal.vue b/resources/js/components/RoomTabMembersAddSingleModal.vue index 318d72781..1ef150ca7 100644 --- a/resources/js/components/RoomTabMembersAddSingleModal.vue +++ b/resources/js/components/RoomTabMembersAddSingleModal.vue @@ -239,10 +239,7 @@ function save() { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabMembersBulkDeleteButton.vue b/resources/js/components/RoomTabMembersBulkDeleteButton.vue index f3dd54e1e..077b18b1a 100644 --- a/resources/js/components/RoomTabMembersBulkDeleteButton.vue +++ b/resources/js/components/RoomTabMembersBulkDeleteButton.vue @@ -130,10 +130,7 @@ function deleteMembers() { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabMembersBulkEditButton.vue b/resources/js/components/RoomTabMembersBulkEditButton.vue index 1f13795f8..273951c3c 100644 --- a/resources/js/components/RoomTabMembersBulkEditButton.vue +++ b/resources/js/components/RoomTabMembersBulkEditButton.vue @@ -168,10 +168,7 @@ function save() { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabMembersBulkImportModal.vue b/resources/js/components/RoomTabMembersBulkImportModal.vue index 546f1a5af..aeb8a9983 100644 --- a/resources/js/components/RoomTabMembersBulkImportModal.vue +++ b/resources/js/components/RoomTabMembersBulkImportModal.vue @@ -341,10 +341,7 @@ function importUsers(firstRound = false) { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabMembersDeleteButton.vue b/resources/js/components/RoomTabMembersDeleteButton.vue index 62c86c173..cf30ba516 100644 --- a/resources/js/components/RoomTabMembersDeleteButton.vue +++ b/resources/js/components/RoomTabMembersDeleteButton.vue @@ -111,10 +111,7 @@ function deleteMember() { modalVisible.value = false; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabMembersEditButton.vue b/resources/js/components/RoomTabMembersEditButton.vue index 098b2812c..8a02bed35 100644 --- a/resources/js/components/RoomTabMembersEditButton.vue +++ b/resources/js/components/RoomTabMembersEditButton.vue @@ -178,10 +178,7 @@ function save() { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabPersonalizedLinks.vue b/resources/js/components/RoomTabPersonalizedLinks.vue index 5fac0e884..0a752d5b5 100644 --- a/resources/js/components/RoomTabPersonalizedLinks.vue +++ b/resources/js/components/RoomTabPersonalizedLinks.vue @@ -317,10 +317,7 @@ function loadData(page = null) { }) .catch((error) => { paginator.revertFirst(); - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); loadingError.value = true; }) .finally(() => { diff --git a/resources/js/components/RoomTabPersonalizedLinksAddButton.vue b/resources/js/components/RoomTabPersonalizedLinksAddButton.vue index e882dae91..2fbef8be3 100644 --- a/resources/js/components/RoomTabPersonalizedLinksAddButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksAddButton.vue @@ -171,10 +171,7 @@ function save() { ) { formErrors.set(error.response.data.errors); } else { - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); } }) .finally(() => { diff --git a/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue b/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue index 1def73a01..384cf69d1 100644 --- a/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue @@ -131,10 +131,7 @@ function deleteLink() { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabPersonalizedLinksEditButton.vue b/resources/js/components/RoomTabPersonalizedLinksEditButton.vue index 768956560..8b5b54bef 100644 --- a/resources/js/components/RoomTabPersonalizedLinksEditButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksEditButton.vue @@ -204,10 +204,7 @@ function save() { formErrors.set(error.response.data.errors); return; } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); } }) .finally(() => { diff --git a/resources/js/components/RoomTabRecordings.vue b/resources/js/components/RoomTabRecordings.vue index 12294a175..76dd9ada9 100644 --- a/resources/js/components/RoomTabRecordings.vue +++ b/resources/js/components/RoomTabRecordings.vue @@ -440,10 +440,7 @@ function loadData(page = null) { } loadingError.value = true; paginator.revertFirst(); - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isBusy.value = false; diff --git a/resources/js/components/RoomTabRecordingsDeleteButton.vue b/resources/js/components/RoomTabRecordingsDeleteButton.vue index a3c7abf0f..0a1b96d01 100644 --- a/resources/js/components/RoomTabRecordingsDeleteButton.vue +++ b/resources/js/components/RoomTabRecordingsDeleteButton.vue @@ -107,10 +107,7 @@ function deleteRecording() { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabRecordingsEditButton.vue b/resources/js/components/RoomTabRecordingsEditButton.vue index 2dfcfb140..ea677de43 100644 --- a/resources/js/components/RoomTabRecordingsEditButton.vue +++ b/resources/js/components/RoomTabRecordingsEditButton.vue @@ -252,10 +252,7 @@ function save() { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/components/RoomTabSettings.vue b/resources/js/components/RoomTabSettings.vue index 24f20c6ad..2b03e4877 100644 --- a/resources/js/components/RoomTabSettings.vue +++ b/resources/js/components/RoomTabSettings.vue @@ -429,10 +429,7 @@ function load() { loaded.value = true; }) .catch((error) => { - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); loadingError.value = true; }) .finally(() => { diff --git a/resources/js/components/RoomTabStreaming.vue b/resources/js/components/RoomTabStreaming.vue index 14f9d0f76..37d527e84 100644 --- a/resources/js/components/RoomTabStreaming.vue +++ b/resources/js/components/RoomTabStreaming.vue @@ -170,7 +170,7 @@ async function streamingCommand(command) { if (error.response.status === env.HTTP_ROOM_NOT_RUNNING) { emit("settingsChanged"); } - api.error(error, { redirectOnRoomModelNotFound: true }); + api.error(error); }) .finally(() => { autoReload(); diff --git a/resources/js/components/RoomTabStreamingConfigButton.vue b/resources/js/components/RoomTabStreamingConfigButton.vue index 36158d370..9a34fd515 100644 --- a/resources/js/components/RoomTabStreamingConfigButton.vue +++ b/resources/js/components/RoomTabStreamingConfigButton.vue @@ -228,7 +228,7 @@ function loadConfig() { response.data.data.system_default_pause_image; }) .catch((error) => { - api.error(error, { redirectOnRoomModelNotFound: true }); + api.error(error); modelLoadingError.value = true; }) .finally(() => { @@ -272,7 +272,7 @@ function save() { ) { formErrors.set(error.response.data.errors); } else { - api.error(error, { redirectOnRoomModelNotFound: true }); + api.error(error); } }) .finally(() => { diff --git a/resources/js/components/RoomTransferOwnershipButton.vue b/resources/js/components/RoomTransferOwnershipButton.vue index 9e22b4269..641abd82c 100644 --- a/resources/js/components/RoomTransferOwnershipButton.vue +++ b/resources/js/components/RoomTransferOwnershipButton.vue @@ -235,10 +235,7 @@ function transferOwnership() { return; } } - api.error(error, { - redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, - }); + api.error(error, { redirectOnUnauthenticated: false }); }) .finally(() => { isLoadingAction.value = false; diff --git a/resources/js/services/Api.js b/resources/js/services/Api.js index 8943da5f4..bea55edb2 100644 --- a/resources/js/services/Api.js +++ b/resources/js/services/Api.js @@ -17,7 +17,6 @@ export class Api { this.router = useRouter(); this.toast = useToast(); this.t = i18n.global.t; - this.te = i18n.global.te; } /** @@ -126,19 +125,21 @@ export class Api { const model = data?.model; const ids = data?.ids; - if (model === ROOM_MODEL && options.redirectOnRoomModelNotFound === true) { - this.router.push({ name: "404" }); + if (model === ROOM_MODEL && options.redirectOnRoomModelNotFound !== false) { + // Redirect to room index page if user is authenticated, otherwise show 404 page, because + // unauthenticated user is not able to visit the room index page + if (this.auth.isAuthenticated) { + this.router.push({ name: "rooms.index" }); + } else { + this.router.push({ name: "404" }); + } } this.toast.error( - this.te("app.flash.model_not_found." + model) - ? this.t("app.flash.model_not_found." + model, { - ids: ids ? `${ids.join(", ")}` : "", - }) - : this.t("app.flash.model_not_found.fallback", { - model: model, - ids: ids ? `${ids.join(", ")}` : "", - }), + this.t("app.flash.model_not_found.title", { + model: this.t("app.model." + model), + }), + this.t("app.flash.model_not_found.details", { ids: `${ids.join(", ")}` }), ); } diff --git a/resources/js/views/RoomsView.vue b/resources/js/views/RoomsView.vue index 05be64e15..0b3036066 100644 --- a/resources/js/views/RoomsView.vue +++ b/resources/js/views/RoomsView.vue @@ -441,7 +441,11 @@ function load() { if (error.response) { // Room not found (Always redirect to 404 view) if (error.response.status === env.HTTP_NOT_FOUND) { - router.push({ name: "404" }); + if (authStore.isAuthenticated) { + router.push({ name: "rooms.index" }); + } else { + router.push({ name: "404" }); + } } // Room auth token is invalid @@ -462,7 +466,10 @@ function load() { } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: false, + }); }) .finally(() => { // Disable loading indicator @@ -516,7 +523,11 @@ function reload() { if (error.response) { // Room not found (Always redirect to 404 view) if (error.response.status === env.HTTP_NOT_FOUND) { - router.push({ name: "404" }); + if (authStore.isAuthenticated) { + router.push({ name: "rooms.index" }); + } else { + router.push({ name: "404" }); + } } // Room auth token is invalid @@ -535,7 +546,10 @@ function reload() { return handleGuestsNotAllowed(); } } - api.error(error, { redirectOnUnauthenticated: false }); + api.error(error, { + redirectOnUnauthenticated: false, + redirectOnRoomModelNotFound: false, + }); }) .finally(() => { // Disable loading indicator @@ -674,7 +688,6 @@ function authenticate(type, codeOrToken) { } api.error(error, { redirectOnUnauthenticated: false, - redirectOnRoomModelNotFound: true, }); }) .finally(() => { diff --git a/tests/Frontend/e2e/AdminRolesEdit.cy.js b/tests/Frontend/e2e/AdminRolesEdit.cy.js index 6aeb1e919..0d0a53e6b 100644 --- a/tests/Frontend/e2e/AdminRolesEdit.cy.js +++ b/tests/Frontend/e2e/AdminRolesEdit.cy.js @@ -1629,7 +1629,9 @@ describe("Admin roles edit", function () { cy.intercept("PUT", "api/v1/roles/2", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "role", + ids: [2], }, }).as("saveChangesRequest"); @@ -1644,8 +1646,8 @@ describe("Admin roles edit", function () { cy.wait("@rolesRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.role"}', + 'app.flash.model_not_found.details_{"ids":"2"}', ]); // Reload @@ -1792,7 +1794,9 @@ describe("Admin roles edit", function () { cy.intercept("GET", "api/v1/roles/2", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "role", + ids: [2], }, }).as("roleRequest"); @@ -1809,8 +1813,8 @@ describe("Admin roles edit", function () { // Check that error message is shown cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.role"}', + 'app.flash.model_not_found.details_{"ids":"2"}', ]); // Reload page with 401 error diff --git a/tests/Frontend/e2e/AdminRolesIndexRoleActions.cy.js b/tests/Frontend/e2e/AdminRolesIndexRoleActions.cy.js index 50b329bc2..c149da653 100644 --- a/tests/Frontend/e2e/AdminRolesIndexRoleActions.cy.js +++ b/tests/Frontend/e2e/AdminRolesIndexRoleActions.cy.js @@ -193,7 +193,10 @@ describe("Admin roles index role actions", function () { // Check that dialog is closed and that error message is shown cy.get('[data-test="roles-delete-dialog"]').should("not.exist"); - cy.checkToastMessage('app.flash.model_not_found.role_{"ids":"3"}'); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.role"}', + 'app.flash.model_not_found.details_{"ids":"3"}', + ]); // Check that role is not in the list anymore cy.get('[data-test="role-item"]').should("have.length", 2); diff --git a/tests/Frontend/e2e/AdminRolesView.cy.js b/tests/Frontend/e2e/AdminRolesView.cy.js index 726a7a879..7b1a9a048 100644 --- a/tests/Frontend/e2e/AdminRolesView.cy.js +++ b/tests/Frontend/e2e/AdminRolesView.cy.js @@ -680,7 +680,9 @@ describe("Admin roles view", function () { cy.intercept("GET", "api/v1/roles/2", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "role", + ids: [2], }, }).as("roleRequest"); @@ -697,8 +699,8 @@ describe("Admin roles view", function () { // Check that error message is shown cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.role"}', + 'app.flash.model_not_found.details_{"ids":"2"}', ]); // Reload page with 401 error diff --git a/tests/Frontend/e2e/AdminRolesViewRoleActions.cy.js b/tests/Frontend/e2e/AdminRolesViewRoleActions.cy.js index 0f250f6e2..c5e81c696 100644 --- a/tests/Frontend/e2e/AdminRolesViewRoleActions.cy.js +++ b/tests/Frontend/e2e/AdminRolesViewRoleActions.cy.js @@ -155,7 +155,10 @@ describe("Admin roles view role actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/roles").and("not.include", "/2"); - cy.checkToastMessage('app.flash.model_not_found.role_{"ids":"2"}'); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.role"}', + 'app.flash.model_not_found.details_{"ids":"2"}', + ]); // Reload view and open delete dialog again cy.visit("/admin/roles/2"); diff --git a/tests/Frontend/e2e/AdminRoomTypesEdit.cy.js b/tests/Frontend/e2e/AdminRoomTypesEdit.cy.js index cf8d54a87..034cb4f55 100644 --- a/tests/Frontend/e2e/AdminRoomTypesEdit.cy.js +++ b/tests/Frontend/e2e/AdminRoomTypesEdit.cy.js @@ -2067,7 +2067,9 @@ describe("Admin room types edit", function () { cy.intercept("PUT", "api/v1/roomTypes/3", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "room_type", + ids: [3], }, }).as("saveChangesRequest"); @@ -2082,8 +2084,8 @@ describe("Admin room types edit", function () { cy.wait("@roomTypesRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.room_type"}', + 'app.flash.model_not_found.details_{"ids":"3"}', ]); // Reload @@ -2148,7 +2150,9 @@ describe("Admin room types edit", function () { cy.intercept("GET", "api/v1/roomTypes/3", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "room_type", + ids: [3], }, }).as("roomTypeRequest"); @@ -2163,8 +2167,8 @@ describe("Admin room types edit", function () { cy.wait("@roomTypesRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.room_type"}', + 'app.flash.model_not_found.details_{"ids":"3"}', ]); // Reload page with 401 error diff --git a/tests/Frontend/e2e/AdminRoomTypesIndexRoomTypeActions.cy.js b/tests/Frontend/e2e/AdminRoomTypesIndexRoomTypeActions.cy.js index 0a927ad0d..332e4e44a 100644 --- a/tests/Frontend/e2e/AdminRoomTypesIndexRoomTypeActions.cy.js +++ b/tests/Frontend/e2e/AdminRoomTypesIndexRoomTypeActions.cy.js @@ -357,7 +357,10 @@ describe("Admin room types index room type actions", function () { cy.get('[data-test="room-types-delete-dialog"]').should("not.exist"); // Check that error message is shown - cy.checkToastMessage('app.flash.model_not_found.room_type_{"ids":"3"}'); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room_type"}', + 'app.flash.model_not_found.details_{"ids":"3"}', + ]); // Check that room type is not there anymore cy.get('[data-test="room-type-item"]').should("have.length", 2); diff --git a/tests/Frontend/e2e/AdminRoomTypesView.cy.js b/tests/Frontend/e2e/AdminRoomTypesView.cy.js index 3ec2cd60f..fddec5bab 100644 --- a/tests/Frontend/e2e/AdminRoomTypesView.cy.js +++ b/tests/Frontend/e2e/AdminRoomTypesView.cy.js @@ -631,7 +631,9 @@ describe("Admin room types view", function () { cy.intercept("GET", "api/v1/roomTypes/3", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "room_type", + ids: [3], }, }).as("roomTypeRequest"); @@ -647,8 +649,8 @@ describe("Admin room types view", function () { // Check that error message is shown cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.room_type"}', + 'app.flash.model_not_found.details_{"ids":"3"}', ]); // Reload page with 401 error diff --git a/tests/Frontend/e2e/AdminRoomTypesViewRoomTypeActions.cy.js b/tests/Frontend/e2e/AdminRoomTypesViewRoomTypeActions.cy.js index 50405df27..1a739b263 100644 --- a/tests/Frontend/e2e/AdminRoomTypesViewRoomTypeActions.cy.js +++ b/tests/Frontend/e2e/AdminRoomTypesViewRoomTypeActions.cy.js @@ -306,7 +306,10 @@ describe("Admin room types view room type actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/room_types").and("not.include", "/3"); - cy.checkToastMessage('app.flash.model_not_found.room_type_{"ids":"3"}'); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room_type"}', + 'app.flash.model_not_found.details_{"ids":"3"}', + ]); // Reload view and open delete dialog again cy.visit("/admin/room_types/3"); diff --git a/tests/Frontend/e2e/AdminServerPoolsEdit.cy.js b/tests/Frontend/e2e/AdminServerPoolsEdit.cy.js index 377882140..edd2b4d53 100644 --- a/tests/Frontend/e2e/AdminServerPoolsEdit.cy.js +++ b/tests/Frontend/e2e/AdminServerPoolsEdit.cy.js @@ -610,7 +610,9 @@ describe("Admin server pools edit", function () { cy.intercept("PUT", "api/v1/serverPools/1", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "server_pool", + ids: [1], }, }).as("saveChangesRequest"); @@ -625,8 +627,8 @@ describe("Admin server pools edit", function () { cy.wait("@serverPoolsRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.server_pool"}', + 'app.flash.model_not_found.details_{"ids":"1"}', ]); // Reload @@ -728,7 +730,9 @@ describe("Admin server pools edit", function () { cy.intercept("GET", "api/v1/serverPools/1", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "server_pool", + ids: [1], }, }).as("serverPoolRequest"); @@ -743,8 +747,8 @@ describe("Admin server pools edit", function () { cy.wait("@serverPoolsRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.server_pool"}', + 'app.flash.model_not_found.details_{"ids":"1"}', ]); // Reload page with 401 error diff --git a/tests/Frontend/e2e/AdminServerPoolsIndexServerPoolActions.cy.js b/tests/Frontend/e2e/AdminServerPoolsIndexServerPoolActions.cy.js index 4ee467bf0..64701b0e0 100644 --- a/tests/Frontend/e2e/AdminServerPoolsIndexServerPoolActions.cy.js +++ b/tests/Frontend/e2e/AdminServerPoolsIndexServerPoolActions.cy.js @@ -230,7 +230,11 @@ describe("Admin server pools index server pool actions", function () { // Check that dialog is closed and error message is shown cy.get('[data-test="server-pools-delete-dialog"]').should("not.exist"); - cy.checkToastMessage('app.flash.model_not_found.server_pool_{"ids":"1"}'); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.server_pool"}', + 'app.flash.model_not_found.details_{"ids":"1"}', + ]); // Check that server pool is not in list anymore cy.get('[data-test="server-pool-item"]').should("have.length", 1); diff --git a/tests/Frontend/e2e/AdminServerPoolsView.cy.js b/tests/Frontend/e2e/AdminServerPoolsView.cy.js index 6fef329d9..f76b8e049 100644 --- a/tests/Frontend/e2e/AdminServerPoolsView.cy.js +++ b/tests/Frontend/e2e/AdminServerPoolsView.cy.js @@ -229,7 +229,9 @@ describe("Admin server pools view", function () { cy.intercept("GET", "api/v1/serverPools/1", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "server_pool", + ids: [1], }, }).as("serverPoolRequest"); @@ -244,8 +246,8 @@ describe("Admin server pools view", function () { cy.wait("@serverPoolsRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.server_pool"}', + 'app.flash.model_not_found.details_{"ids":"1"}', ]); // Reload page with 401 error diff --git a/tests/Frontend/e2e/AdminServerPoolsViewServerPoolActions.cy.js b/tests/Frontend/e2e/AdminServerPoolsViewServerPoolActions.cy.js index 299e2711e..e1820beaa 100644 --- a/tests/Frontend/e2e/AdminServerPoolsViewServerPoolActions.cy.js +++ b/tests/Frontend/e2e/AdminServerPoolsViewServerPoolActions.cy.js @@ -180,7 +180,10 @@ describe("Admin server pools view", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/server_pools").and("not.include", "/1"); - cy.checkToastMessage('app.flash.model_not_found.server_pool_{"ids":"1"}'); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.server_pool"}', + 'app.flash.model_not_found.details_{"ids":"1"}', + ]); // Reload view and open delete dialog again cy.visit("/admin/server_pools/1"); diff --git a/tests/Frontend/e2e/AdminServersEdit.cy.js b/tests/Frontend/e2e/AdminServersEdit.cy.js index 3b02ee5b3..6616bfb98 100644 --- a/tests/Frontend/e2e/AdminServersEdit.cy.js +++ b/tests/Frontend/e2e/AdminServersEdit.cy.js @@ -622,7 +622,9 @@ describe("Admin servers edit", function () { cy.intercept("PUT", "api/v1/servers/1", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "server", + ids: [1], }, }).as("saveChangesRequest"); @@ -637,8 +639,8 @@ describe("Admin servers edit", function () { cy.wait("@serversRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.server"}', + 'app.flash.model_not_found.details_{"ids":"1"}', ]); // Reload @@ -809,7 +811,9 @@ describe("Admin servers edit", function () { cy.intercept("GET", "api/v1/servers/1", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "server", + ids: [1], }, }).as("serverRequest"); @@ -824,8 +828,8 @@ describe("Admin servers edit", function () { cy.wait("@serversRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.server"}', + 'app.flash.model_not_found.details_{"ids":"1"}', ]); // Reload page with 401 error diff --git a/tests/Frontend/e2e/AdminServersIndexServerActions.cy.js b/tests/Frontend/e2e/AdminServersIndexServerActions.cy.js index 0df2407ec..c4f5b2d57 100644 --- a/tests/Frontend/e2e/AdminServersIndexServerActions.cy.js +++ b/tests/Frontend/e2e/AdminServersIndexServerActions.cy.js @@ -182,7 +182,10 @@ describe("Admin servers index server actions", function () { // Check that dialog is closed and error message is shown cy.get('[data-test="servers-delete-dialog"]').should("not.exist"); - cy.checkToastMessage('app.flash.model_not_found.server_{"ids":"3"}'); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.server"}', + 'app.flash.model_not_found.details_{"ids":"3"}', + ]); // Check that server is not in list anymore cy.get('[data-test="server-item"]').should("have.length", 3); diff --git a/tests/Frontend/e2e/AdminServersView.cy.js b/tests/Frontend/e2e/AdminServersView.cy.js index ffd6144e3..0d055c16f 100644 --- a/tests/Frontend/e2e/AdminServersView.cy.js +++ b/tests/Frontend/e2e/AdminServersView.cy.js @@ -577,7 +577,9 @@ describe("Admin servers view", function () { cy.intercept("GET", "api/v1/servers/1", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "server", + ids: [1], }, }).as("serverRequest"); @@ -592,10 +594,9 @@ describe("Admin servers view", function () { cy.wait("@serversRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.server"}', + 'app.flash.model_not_found.details_{"ids":"1"}', ]); - // Reload page with 401 error cy.intercept("GET", "api/v1/servers/1", { statusCode: 401, diff --git a/tests/Frontend/e2e/AdminServersViewServerActions.cy.js b/tests/Frontend/e2e/AdminServersViewServerActions.cy.js index cbe6fe503..9d3034331 100644 --- a/tests/Frontend/e2e/AdminServersViewServerActions.cy.js +++ b/tests/Frontend/e2e/AdminServersViewServerActions.cy.js @@ -154,7 +154,10 @@ describe("Admin servers view server actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/servers").and("not.include", "/1"); - cy.checkToastMessage('app.flash.model_not_found.server_{"ids":"1"}'); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.server"}', + 'app.flash.model_not_found.details_{"ids":"1"}', + ]); // Reload view and open delete dialog again cy.visit("/admin/servers/1"); @@ -450,6 +453,34 @@ describe("Admin servers view server actions", function () { cy.url().should("include", "/login?redirect=/admin/servers/1"); cy.checkToastMessage("app.flash.unauthenticated"); + + // Check with 404 error + cy.interceptAdminServersIndexRequests(); + + cy.intercept("POST", "api/v1/servers/1/panic", { + statusCode: 404, + body: { + message: "model_not_found", + model: "server", + ids: [1], + }, + }).as("panicRequest"); + + cy.visit("/admin/servers/1"); + + cy.wait("@serverRequest"); + + cy.get('[data-test="servers-panic-button"]').click(); + + cy.wait("@panicRequest"); + + // Check that redirect worked and error message is shown + cy.url().should("include", "/admin/servers").and("not.include", "/1"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.server"}', + 'app.flash.model_not_found.details_{"ids":"1"}', + ]); }); it("switch between edit and view", function () { diff --git a/tests/Frontend/e2e/AdminUsersEdit.cy.js b/tests/Frontend/e2e/AdminUsersEdit.cy.js index b49417d8c..1f6c96cbb 100644 --- a/tests/Frontend/e2e/AdminUsersEdit.cy.js +++ b/tests/Frontend/e2e/AdminUsersEdit.cy.js @@ -272,7 +272,9 @@ describe("Admin users edit", function () { cy.intercept("GET", "api/v1/users/2", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "user", + ids: [2], }, }).as("userRequest"); @@ -288,8 +290,8 @@ describe("Admin users edit", function () { // Check that error message gets shown cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.user"}', + 'app.flash.model_not_found.details_{"ids":"2"}', ]); // Reload page with 401 error diff --git a/tests/Frontend/e2e/AdminUsersEditBase.cy.js b/tests/Frontend/e2e/AdminUsersEditBase.cy.js index b18e34af1..e5729604d 100644 --- a/tests/Frontend/e2e/AdminUsersEditBase.cy.js +++ b/tests/Frontend/e2e/AdminUsersEditBase.cy.js @@ -701,7 +701,9 @@ describe("Admin users edit base", function () { cy.intercept("POST", "api/v1/users/2", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "user", + ids: [2], }, }).as("saveChangesRequest"); @@ -716,8 +718,8 @@ describe("Admin users edit base", function () { cy.wait("@usersRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.user"}', + 'app.flash.model_not_found.details_{"ids":"2"}', ]); // Visit edit page again diff --git a/tests/Frontend/e2e/AdminUsersEditEmail.cy.js b/tests/Frontend/e2e/AdminUsersEditEmail.cy.js index 927fdc84c..80c6960a8 100644 --- a/tests/Frontend/e2e/AdminUsersEditEmail.cy.js +++ b/tests/Frontend/e2e/AdminUsersEditEmail.cy.js @@ -155,7 +155,9 @@ describe("Admin users edit email", function () { cy.intercept("PUT", "api/v1/users/2/email", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "user", + ids: [2], }, }).as("saveChangesRequest"); @@ -170,8 +172,8 @@ describe("Admin users edit email", function () { cy.wait("@usersRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.user"}', + 'app.flash.model_not_found.details_{"ids":"2"}', ]); // Visit edit page again diff --git a/tests/Frontend/e2e/AdminUsersEditOthers.cy.js b/tests/Frontend/e2e/AdminUsersEditOthers.cy.js index ea55d4af6..4a312c239 100644 --- a/tests/Frontend/e2e/AdminUsersEditOthers.cy.js +++ b/tests/Frontend/e2e/AdminUsersEditOthers.cy.js @@ -187,7 +187,9 @@ describe("Admin users edit others", function () { cy.intercept("POST", "api/v1/users/2", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "user", + ids: [2], }, }).as("saveChangesRequest"); @@ -200,8 +202,8 @@ describe("Admin users edit others", function () { cy.wait("@usersRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.user"}', + 'app.flash.model_not_found.details_{"ids":"2"}', ]); // Visit edit page again diff --git a/tests/Frontend/e2e/AdminUsersEditSecurity.cy.js b/tests/Frontend/e2e/AdminUsersEditSecurity.cy.js index 3b0f2d9bf..d481139d4 100644 --- a/tests/Frontend/e2e/AdminUsersEditSecurity.cy.js +++ b/tests/Frontend/e2e/AdminUsersEditSecurity.cy.js @@ -563,7 +563,9 @@ describe("Admin users edit email", function () { cy.intercept("PUT", "api/v1/users/2 ", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "user", + ids: [2], }, }).as("saveChangesRequest"); @@ -578,8 +580,8 @@ describe("Admin users edit email", function () { cy.wait("@usersRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.user"}', + 'app.flash.model_not_found.details_{"ids":"2"}', ]); // Visit edit page again @@ -742,7 +744,9 @@ describe("Admin users edit email", function () { cy.intercept("PUT", "api/v1/users/2/password", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "user", + ids: [2], }, }).as("saveChangesRequest"); @@ -757,8 +761,8 @@ describe("Admin users edit email", function () { cy.wait("@usersRequest"); cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.user"}', + 'app.flash.model_not_found.details_{"ids":"2"}', ]); // Visit edit page again diff --git a/tests/Frontend/e2e/AdminUsersIndexUserActions.cy.js b/tests/Frontend/e2e/AdminUsersIndexUserActions.cy.js index 08931d4b4..ba1550364 100644 --- a/tests/Frontend/e2e/AdminUsersIndexUserActions.cy.js +++ b/tests/Frontend/e2e/AdminUsersIndexUserActions.cy.js @@ -184,7 +184,11 @@ describe("Admin users index user actions", function () { // Check that dialog is closed and error message is shown cy.get('[data-test="users-delete-dialog"]').should("not.exist"); - cy.checkToastMessage('app.flash.model_not_found.user_{"ids":"3"}'); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.user"}', + 'app.flash.model_not_found.details_{"ids":"3"}', + ]); // Check that user is not in list anymore cy.get('[data-test="user-item"]').should("have.length", 3); diff --git a/tests/Frontend/e2e/AdminUsersView.cy.js b/tests/Frontend/e2e/AdminUsersView.cy.js index 8c9d4f792..0bb703321 100644 --- a/tests/Frontend/e2e/AdminUsersView.cy.js +++ b/tests/Frontend/e2e/AdminUsersView.cy.js @@ -556,7 +556,9 @@ describe("Admin users view", function () { cy.intercept("GET", "api/v1/users/2", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "user", + ids: [2], }, }).as("userRequest"); @@ -572,8 +574,8 @@ describe("Admin users view", function () { // Check that error message gets shown cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"No query results for model"}', - 'app.flash.server_error.error_code_{"statusCode":404}', + 'app.flash.model_not_found.title_{"model":"app.model.user"}', + 'app.flash.model_not_found.details_{"ids":"2"}', ]); // Reload page with 401 error diff --git a/tests/Frontend/e2e/AdminUsersViewUserActions.cy.js b/tests/Frontend/e2e/AdminUsersViewUserActions.cy.js index a48463c9e..dbec5df87 100644 --- a/tests/Frontend/e2e/AdminUsersViewUserActions.cy.js +++ b/tests/Frontend/e2e/AdminUsersViewUserActions.cy.js @@ -146,7 +146,10 @@ describe("Admin users view user actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/users").and("not.include", "/2"); - cy.checkToastMessage('app.flash.model_not_found.user_{"ids":"2"}'); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.user"}', + 'app.flash.model_not_found.details_{"ids":"2"}', + ]); // Reload view and open delete dialog again cy.visit("/admin/users/2"); @@ -271,7 +274,10 @@ describe("Admin users view user actions", function () { // Check that redirect worked and error message is shown cy.url().should("include", "/admin/users").and("not.include", "/2"); - cy.checkToastMessage('app.flash.model_not_found.user_{"ids":"2"}'); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.user"}', + 'app.flash.model_not_found.details_{"ids":"2"}', + ]); // Reload view and open reset password dialog again cy.visit("/admin/users/2"); diff --git a/tests/Frontend/e2e/RoomsViewDescription.cy.js b/tests/Frontend/e2e/RoomsViewDescription.cy.js index abed2b153..0c096418c 100644 --- a/tests/Frontend/e2e/RoomsViewDescription.cy.js +++ b/tests/Frontend/e2e/RoomsViewDescription.cy.js @@ -468,6 +468,7 @@ describe("Rooms view description", function () { cy.reload(); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); cy.intercept("PUT", "api/v1/rooms/abc-def-123/description", { statusCode: 404, body: { @@ -483,13 +484,16 @@ describe("Rooms view description", function () { cy.wait("@saveDescriptionRequest"); - // Check that redirect to 404 page worked - cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + // Check that redirect to room index page worked + cy.url() + .should("include", "/rooms") + .and("not.include", "/rooms/abc-def-123"); // Check that error message gets shown - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("description changes", function () { diff --git a/tests/Frontend/e2e/RoomsViewFiles.cy.js b/tests/Frontend/e2e/RoomsViewFiles.cy.js index 06843dd57..bffa9b16e 100644 --- a/tests/Frontend/e2e/RoomsViewFiles.cy.js +++ b/tests/Frontend/e2e/RoomsViewFiles.cy.js @@ -723,6 +723,8 @@ describe("Rooms View Files", function () { .should("have.attr", "data-p-active", "true"); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("GET", "api/v1/rooms/abc-def-123/files*", { statusCode: 404, body: { @@ -735,13 +737,16 @@ describe("Rooms View Files", function () { cy.reload(); cy.wait("@roomFilesRequest"); - // Check that redirect to 404 page worked - cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + // Check that redirect to room index page worked + cy.url() + .should("include", "/rooms") + .and("not.include", "/rooms/abc-def-123"); // Check that error message gets shown - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("load files page out of range", function () { diff --git a/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js b/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js index b9d0ca1ec..81841123f 100644 --- a/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewFilesFileActions.cy.js @@ -339,6 +339,8 @@ describe("Rooms view files file actions", function () { cy.reload(); // Check 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("POST", "/api/v1/rooms/abc-def-123/files", { statusCode: 404, body: { @@ -358,13 +360,14 @@ describe("Rooms view files file actions", function () { cy.wait("@uploadFileRequest"); - // Check that redirect to 404 page worked - cy.url().should("include", "/404").and("not.include", "abc-def-123"); + // Check that redirect to room index page worked + cy.url().should("include", "/rooms").and("not.include", "abc-def-123"); // Check that error message is shown - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("delete file", function () { @@ -546,6 +549,8 @@ describe("Rooms view files file actions", function () { cy.reload(); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("DELETE", "/api/v1/rooms/abc-def-123/files/1", { statusCode: 404, body: { @@ -567,13 +572,14 @@ describe("Rooms view files file actions", function () { cy.wait("@deleteFileRequest"); - // Check that redirect to 404 page worked - cy.url().should("include", "/404").and("not.include", "abc-def-123"); + // Check that redirect to room index page worked + cy.url().should("include", "/rooms").and("not.include", "abc-def-123"); // Check that error message is shown - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("change file settings", function () { @@ -803,6 +809,8 @@ describe("Rooms view files file actions", function () { cy.reload(); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("PUT", "/api/v1/rooms/abc-def-123/files/1", { statusCode: 404, body: { @@ -824,13 +832,14 @@ describe("Rooms view files file actions", function () { cy.wait("@editFileRequest"); - // Check that redirect to 404 page worked - cy.url().should("include", "/404").and("not.include", "abc-def-123"); + // Check that redirect to room index page worked + cy.url().should("include", "/rooms").and("not.include", "abc-def-123"); // Check that error message is shown - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("download file with terms of use", function () { diff --git a/tests/Frontend/e2e/RoomsViewGeneral.cy.js b/tests/Frontend/e2e/RoomsViewGeneral.cy.js index bacb3d686..69410aa32 100644 --- a/tests/Frontend/e2e/RoomsViewGeneral.cy.js +++ b/tests/Frontend/e2e/RoomsViewGeneral.cy.js @@ -2377,6 +2377,8 @@ describe("Room View general", function () { cy.wait("@roomRequest"); // Check join membership with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("POST", "api/v1/rooms/abc-def-123/membership*", { statusCode: 404, body: { @@ -2391,11 +2393,14 @@ describe("Room View general", function () { cy.wait("@joinMembershipRequest"); // Check that redirect worked and error message is shown - cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); // Reload room with user being a member of the room cy.fixture("room.json").then((room) => { @@ -2527,12 +2532,15 @@ describe("Room View general", function () { cy.wait("@endMembershipRequest"); // Check that redirect worked and error message is shown - cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); // Check that error message is shown - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("trigger favorites button", function () { @@ -2727,6 +2735,8 @@ describe("Room View general", function () { cy.wait("@roomRequest"); // Test add to favorites with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("POST", "api/v1/rooms/abc-def-123/favorites", { statusCode: 404, body: { @@ -2741,11 +2751,14 @@ describe("Room View general", function () { cy.wait("@addFavoritesRequest"); // Check that redirect worked and error message is shown - cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); // Reload room but room is already in favorites cy.fixture("room.json").then((room) => { @@ -2843,6 +2856,8 @@ describe("Room View general", function () { cy.wait("@roomRequest"); // Test remove from favorites with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("DELETE", "api/v1/rooms/abc-def-123/favorites", { statusCode: 404, body: { @@ -2859,11 +2874,14 @@ describe("Room View general", function () { cy.wait("@deleteFavoritesRequest"); // Check that redirect worked and error message is shown - cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("visit with guest forbidden", function () { @@ -2951,6 +2969,9 @@ describe("Room View general", function () { }); it("visit with room not found", function () { + // Try with logged in user + cy.interceptRoomIndexRequests(); + cy.intercept("GET", "api/v1/rooms/abc-def-123", { statusCode: 404, body: { @@ -2960,6 +2981,22 @@ describe("Room View general", function () { cy.visit("/rooms/abc-def-123"); + // Check redirect to room index page + cy.url() + .should("include", "/rooms") + .should("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.server_error.message_{"message":"No query results for model [App\\\\Room] abc-def-123"}', + 'app.flash.server_error.error_code_{"statusCode":404}', + ]); + + // Try with guest + cy.intercept("GET", "api/v1/currentUser", {}); + + cy.visit("/rooms/abc-def-123"); + + // Check redirect to 404 page cy.url() .should("include", "/404") .should("not.include", "/rooms/abc-def-123"); @@ -3089,7 +3126,9 @@ describe("Room View general", function () { cy.wait("@roomRequest"); - // Test reload with room not found + // Test reload with room not found and guest user + cy.interceptRoomIndexRequests(); + cy.intercept("GET", "api/v1/rooms/abc-def-123", { statusCode: 404, body: { @@ -3100,6 +3139,7 @@ describe("Room View general", function () { cy.get('[data-test="reload-room-button"]').click(); cy.wait("@roomRequest"); + // Check redirect to 404 page worked cy.url() .should("include", "/404") .should("not.include", "/rooms/abc-def-123"); @@ -3108,6 +3148,41 @@ describe("Room View general", function () { 'app.flash.server_error.message_{"message":"No query results for model [App\\\\Room] abc-def-123"}', 'app.flash.server_error.error_code_{"statusCode":404}', ]); + + // Test reload with room not found and logged in user + cy.intercept("GET", "api/v1/currentUser", { fixture: "currentUser.json" }); + cy.fixture("room.json").then((room) => { + room.data.allow_membership = true; + + cy.intercept("GET", "api/v1/rooms/abc-def-123", { + statusCode: 200, + body: room, + }).as("roomRequest"); + }); + + cy.visit("/rooms/abc-def-123"); + cy.wait("@roomRequest"); + cy.contains("Meeting One").should("be.visible"); + + cy.intercept("GET", "api/v1/rooms/abc-def-123", { + statusCode: 404, + body: { + message: "No query results for model [App\\Room] abc-def-123", + }, + }).as("roomRequest"); + + cy.get('[data-test="reload-room-button"]').click(); + cy.wait("@roomRequest"); + + // Check redirect to room index page worked + cy.url() + .should("include", "/rooms") + .should("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.server_error.message_{"message":"No query results for model [App\\\\Room] abc-def-123"}', + 'app.flash.server_error.error_code_{"statusCode":404}', + ]); }); it("reload with access code errors", function () { diff --git a/tests/Frontend/e2e/RoomsViewHistory.cy.js b/tests/Frontend/e2e/RoomsViewHistory.cy.js index a5f1a4cc0..1936dd962 100644 --- a/tests/Frontend/e2e/RoomsViewHistory.cy.js +++ b/tests/Frontend/e2e/RoomsViewHistory.cy.js @@ -504,6 +504,8 @@ describe("Rooms view history", function () { cy.wait("@roomRequest"); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("GET", "api/v1/rooms/abc-def-123/meetings*", { statusCode: 404, body: { @@ -516,11 +518,14 @@ describe("Rooms view history", function () { cy.get("#tab-history").click(); cy.wait("@roomHistoryRequest"); - // Check that redirect to 404 page works and that error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that redirect to room index page works and that error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("load history page out of range", function () { diff --git a/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js b/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js index a1d999e81..6a9fb3185 100644 --- a/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewHistoryMeetingActions.cy.js @@ -154,9 +154,10 @@ describe("Rooms view history meeting actions", function () { cy.wait("@statsRequest"); // Check that error message is shown - cy.checkToastMessage( - 'app.flash.model_not_found.meeting_{"ids":"3a3e504a-d2c4-431c-8ca1-a62598e66761"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.meeting"}', + 'app.flash.model_not_found.details_{"ids":"3a3e504a-d2c4-431c-8ca1-a62598e66761"}', + ]); // Check if dialog is closed cy.get('[data-test="room-history-statistic-dialog"]').should("not.exist"); @@ -492,9 +493,10 @@ describe("Rooms view history meeting actions", function () { cy.wait("@attendanceRequest"); // Check that error message is shown - cy.checkToastMessage( - 'app.flash.model_not_found.meeting_{"ids":"3a3e504a-d2c4-431c-8ca1-a62598e66761"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.meeting"}', + 'app.flash.model_not_found.details_{"ids":"3a3e504a-d2c4-431c-8ca1-a62598e66761"}', + ]); // Check if dialog is closed cy.get('[data-test="room-history-attendance-dialog"]').should("not.exist"); diff --git a/tests/Frontend/e2e/RoomsViewMeetings.cy.js b/tests/Frontend/e2e/RoomsViewMeetings.cy.js index efc12ebf9..294d88bf8 100644 --- a/tests/Frontend/e2e/RoomsViewMeetings.cy.js +++ b/tests/Frontend/e2e/RoomsViewMeetings.cy.js @@ -1352,7 +1352,6 @@ describe("Rooms view meetings", function () { start: "2023-08-21T08:18:28.000000Z", end: null, }; - room.data.current_user = null; cy.intercept("GET", "api/v1/rooms/abc-def-123", { statusCode: 200, @@ -1362,6 +1361,8 @@ describe("Rooms view meetings", function () { cy.reload(); // Test with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("POST", "/api/v1/rooms/abc-def-123/join*", { statusCode: 404, body: { @@ -1385,11 +1386,15 @@ describe("Rooms view meetings", function () { cy.wait("@joinRequest"); - // Check that redirect to 404 page worked and error message is shown - cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that redirect to room index page worked and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("join meeting load requirements errors", function () { @@ -1568,9 +1573,11 @@ describe("Rooms view meetings", function () { // Check that redirect to 404 page worked and error message is shown cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("join running meeting with dark mode", function () { @@ -2935,20 +2942,16 @@ describe("Rooms view meetings", function () { ); // Reload room - cy.fixture("room.json").then((room) => { - room.data.current_user = null; - - cy.intercept("GET", "api/v1/rooms/abc-def-123", { - statusCode: 200, - body: room, - }).as("roomRequest"); - }); + cy.intercept("GET", "api/v1/rooms/abc-def-123", { + fixture: "room.json", + }).as("roomRequest"); cy.visit("/rooms/abc-def-123"); cy.wait("@roomRequest"); // Try with 404 error (room not found) + cy.interceptRoomIndexRequests(); cy.intercept("POST", "/api/v1/rooms/abc-def-123/start*", { statusCode: 404, body: { @@ -2971,11 +2974,14 @@ describe("Rooms view meetings", function () { cy.wait("@startRequest"); // Check if redirect worked and error message is shown - cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + cy.url() + .should("include", "/rooms") + .and("not.include", "/rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("start meeting load requirements errors", function () { @@ -3157,9 +3163,10 @@ describe("Rooms view meetings", function () { // Check if redirect worked and error message is shown cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("start meeting with dark mode", function () { diff --git a/tests/Frontend/e2e/RoomsViewMembers.cy.js b/tests/Frontend/e2e/RoomsViewMembers.cy.js index 1f4cea804..93873acd8 100644 --- a/tests/Frontend/e2e/RoomsViewMembers.cy.js +++ b/tests/Frontend/e2e/RoomsViewMembers.cy.js @@ -490,6 +490,7 @@ describe("Rooms view members", function () { cy.reload(); // Test 404 error (room not found) + cy.interceptRoomIndexRequests(); cy.intercept("GET", "api/v1/rooms/abc-def-123/member*", { statusCode: 404, body: { @@ -503,12 +504,15 @@ describe("Rooms view members", function () { cy.wait("@roomMembersRequest"); - // Check that redirect to 404 page works and error message is shown - cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + // Check that redirect to room index page works and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "/rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("load members page out of range", function () { diff --git a/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js b/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js index 290e89427..1a9dbb172 100644 --- a/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewMembersBulkActions.cy.js @@ -421,6 +421,7 @@ describe("Rooms view members bulk actions", function () { cy.get('[data-test="room-members-select-all-checkbox"]').click(); // Test bulk edit with 404 error (room not found) + cy.interceptRoomIndexRequests(); cy.intercept("PUT", "api/v1/rooms/abc-def-123/member/bulk", { statusCode: 404, body: { @@ -439,12 +440,15 @@ describe("Rooms view members bulk actions", function () { cy.wait("@bulkEditRequest"); - // Check that redirect to 404 page worked and error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + // Check that redirect to room index page worked and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("bulk delete members", function () { @@ -732,6 +736,8 @@ describe("Rooms view members bulk actions", function () { cy.get('[data-test="room-members-select-all-checkbox"] > input').click(); // Test bulk delete with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("DELETE", "api/v1/rooms/abc-def-123/member/bulk", { statusCode: 404, body: { @@ -752,12 +758,15 @@ describe("Rooms view members bulk actions", function () { cy.wait("@bulkDeleteRequest"); - // Check that redirect to 404 page worked and error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + // Check that redirect to room index page worked and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("bulk import members", function () { @@ -1472,6 +1481,8 @@ describe("Rooms view members bulk actions", function () { cy.get("#tab-members").should("be.visible").click(); // Test bulk import with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("POST", "api/v1/rooms/abc-def-123/member/bulk", { statusCode: 404, body: { @@ -1494,11 +1505,14 @@ describe("Rooms view members bulk actions", function () { cy.wait("@bulkImportRequest"); - // Check that redirect to 404 page worked and error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + // Check that redirect to room index page worked and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); }); diff --git a/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js b/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js index e3adede6d..7869c0b38 100644 --- a/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js @@ -444,6 +444,8 @@ describe("Rooms view members member actions", function () { cy.get("#tab-members").click(); // Test add new member with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.get('[data-test="room-members-add-button"]').click(); cy.get("#overlay_menu_0") @@ -465,11 +467,15 @@ describe("Rooms view members member actions", function () { cy.wait("@addUserRequest"); - // Check that user is redirected to 404 page and error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that user is redirected to room index page and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("edit member", function () { @@ -686,6 +692,8 @@ describe("Rooms view members member actions", function () { cy.wait("@roomMembersRequest"); // Test edit member with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.get('[data-test="room-member-item"]') .eq(0) .find('[data-test="room-members-edit-button"]') @@ -706,11 +714,15 @@ describe("Rooms view members member actions", function () { cy.wait("@editUserRequest"); - // Check that user is redirected to 404 page and error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that user is redirected to room index page and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("delete member", function () { @@ -883,7 +895,9 @@ describe("Rooms view members member actions", function () { cy.get("#tab-members").click(); cy.wait("@roomMembersRequest"); - // Test delete member with 404 error (room not found) + // Test delete member with room index error (room not found) + cy.interceptRoomIndexRequests(); + cy.get('[data-test="room-member-item"]') .eq(0) .find('[data-test="room-members-delete-button"]') @@ -904,10 +918,14 @@ describe("Rooms view members member actions", function () { cy.wait("@deleteMemberRequest"); - // Check that user is redirected to 404 page and error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that user is redirected to room index page and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); }); diff --git a/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js b/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js index fefd7960b..23c4c59ff 100644 --- a/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js +++ b/tests/Frontend/e2e/RoomsViewPersonalizedLinks.cy.js @@ -504,6 +504,8 @@ describe("Rooms view personalized links", function () { cy.wait("@roomRequest"); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept( { method: "GET", @@ -523,11 +525,15 @@ describe("Rooms view personalized links", function () { cy.wait("@roomPersonalizedLinksRequest"); - // Check that redirect to 404 page worked and error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that redirect to room index page worked and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("load personalized links page out of range", function () { diff --git a/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js b/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js index 5f4c7c9ac..380333e97 100644 --- a/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js @@ -243,6 +243,8 @@ describe("Rooms view personalized links actions", function () { cy.wait("@roomPersonalizedLinksRequest"); // Test add personalized link with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("POST", "/api/v1/rooms/abc-def-123/personalizedLinks/", { statusCode: 404, body: { @@ -260,11 +262,15 @@ describe("Rooms view personalized links actions", function () { cy.wait("@addLinkRequest"); - // Check that redirect to 404 page works and error message is shown - cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that redirect to room index page works and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("edit personalized link", function () { @@ -563,6 +569,8 @@ describe("Rooms view personalized links actions", function () { cy.wait("@roomPersonalizedLinksRequest"); // Test edit personalized link with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("PUT", "/api/v1/rooms/abc-def-123/personalizedLinks/1", { statusCode: 404, body: { @@ -583,11 +591,15 @@ describe("Rooms view personalized links actions", function () { cy.wait("@editLinkRequest"); - // Check that redirect to 404 page works and error message is shown - cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that redirect to room index page works and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("delete personalized link", function () { @@ -790,6 +802,8 @@ describe("Rooms view personalized links actions", function () { cy.wait("@roomPersonalizedLinksRequest"); // Test delete personalized link with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("DELETE", "/api/v1/rooms/abc-def-123/personalizedLinks/1", { statusCode: 404, body: { @@ -810,11 +824,15 @@ describe("Rooms view personalized links actions", function () { cy.wait("@deleteLinkRequest"); - // Check that redirect to 404 page works and error message is shown - cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that redirect to room index page works and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("copy personalized link", function () { diff --git a/tests/Frontend/e2e/RoomsViewRecordings.cy.js b/tests/Frontend/e2e/RoomsViewRecordings.cy.js index 7ec1a6800..71876b192 100644 --- a/tests/Frontend/e2e/RoomsViewRecordings.cy.js +++ b/tests/Frontend/e2e/RoomsViewRecordings.cy.js @@ -762,6 +762,8 @@ describe("Rooms view recordings", function () { .should("have.attr", "data-p-active", "true"); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("GET", "api/v1/rooms/abc-def-123/recordings*", { statusCode: 404, body: { @@ -776,12 +778,15 @@ describe("Rooms view recordings", function () { cy.wait("@roomRecordingsRequest"); - // Check that redirect to 404 page worked and error message is shown - cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + // Check that redirect to room index page worked and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "/rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("load recordings page out of range", function () { diff --git a/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js b/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js index dd9b6c8be..3dbe58105 100644 --- a/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js @@ -975,6 +975,8 @@ describe("Rooms view recordings recording actions", function () { cy.get("#tab-recordings").should("be.visible").click(); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept( "DELETE", "api/v1/rooms/abc-def-123/recordings/e0cfa18c5fd75a42bd7947d8549321b03abf1daf-1660728035", @@ -1000,11 +1002,15 @@ describe("Rooms view recordings recording actions", function () { cy.wait("@deleteRecordingRequest"); - // Check that redirect to 404 page worked and error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that redirect to room index page worked and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("edit recording", function () { @@ -1369,6 +1375,8 @@ describe("Rooms view recordings recording actions", function () { cy.wait("@roomRecordingsRequest"); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept( "PUT", "api/v1/rooms/abc-def-123/recordings/e0cfa18c5fd75a42bd7947d8549321b03abf1daf-1660728035", @@ -1394,10 +1402,14 @@ describe("Rooms view recordings recording actions", function () { cy.wait("@editRecordingRequest"); - // Check that redirect to 404 page worked and error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that redirect to room index page worked and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); }); diff --git a/tests/Frontend/e2e/RoomsViewSettings.cy.js b/tests/Frontend/e2e/RoomsViewSettings.cy.js index 12c10b83c..0b8ada4ab 100644 --- a/tests/Frontend/e2e/RoomsViewSettings.cy.js +++ b/tests/Frontend/e2e/RoomsViewSettings.cy.js @@ -422,6 +422,8 @@ describe("Rooms view settings", function () { cy.wait("@roomRequest"); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("GET", "api/v1/rooms/abc-def-123/settings", { statusCode: 404, body: { @@ -435,11 +437,15 @@ describe("Rooms view settings", function () { cy.wait("@roomSettingsRequest"); - // Check that redirect to 404 page worked and error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that redirect to room index page worked and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("load settings with different permissions", function () { @@ -1670,6 +1676,40 @@ describe("Rooms view settings", function () { "api/v1/rooms/abc-def-123", "settings", ); + + // Reload room page + cy.interceptRoomViewRequests(); + cy.reload(); + + cy.get("#tab-settings").click(); + + cy.wait("@roomSettingsRequest"); + + // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + + cy.intercept("PUT", "api/v1/rooms/abc-def-123", { + statusCode: 404, + body: { + message: "model_not_found", + model: "room", + ids: ["abc-def-123"], + }, + }); + + cy.get('[data-test="room-settings-save-button"]').click(); + + cy.wait("@roomSettingsSaveRequest"); + + // Check that redirect to room index page worked + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("delete room", function () { @@ -1740,6 +1780,8 @@ describe("Rooms view settings", function () { cy.get("[data-test=room-delete-dialog]").should("be.visible"); // Check with 404 error + cy.interceptRoomIndexRequests(); + cy.intercept("DELETE", "api/v1/rooms/abc-def-123", { statusCode: 404, body: { @@ -1756,9 +1798,15 @@ describe("Rooms view settings", function () { cy.wait("@roomDeleteRequest"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that redirect to room index page worked + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); // Reload room page cy.visit("/rooms/abc-def-123#tab=settings"); @@ -2304,6 +2352,8 @@ describe("Rooms view settings", function () { cy.wait("@roomSettingsRequest"); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("POST", "api/v1/rooms/abc-def-123/transfer", { statusCode: 404, body: { @@ -2319,10 +2369,12 @@ describe("Rooms view settings", function () { cy.wait("@transferOwnershipRequest"); - // Check that redirect to 404 page worked and error message is shown - cy.url().should("include", "/404"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + // Check that redirect to room index page worked and error message is shown + cy.url().should("include", "/rooms"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); }); diff --git a/tests/Frontend/e2e/RoomsViewStreaming.cy.js b/tests/Frontend/e2e/RoomsViewStreaming.cy.js index aa46a1af2..5a7a80169 100644 --- a/tests/Frontend/e2e/RoomsViewStreaming.cy.js +++ b/tests/Frontend/e2e/RoomsViewStreaming.cy.js @@ -788,6 +788,8 @@ describe("Rooms view streaming", function () { ); // Check 404 error on reload (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("GET", "api/v1/rooms/abc-def-123/streaming/status", { statusCode: 404, body: { @@ -800,11 +802,14 @@ describe("Rooms view streaming", function () { cy.get('[data-test="streaming-reload-button"]').click(); cy.wait("@roomStreamingStatus"); - // Check that redirect to 404 page worked and error message is shown - cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + // Check that redirect to room index page worked and error message is shown + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); }); diff --git a/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js b/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js index 9de91ac25..a92235a73 100644 --- a/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewStreamingConfigActions.cy.js @@ -279,6 +279,8 @@ describe("Rooms view streaming config actions", function () { }); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("GET", "api/v1/rooms/abc-def-123/streaming/config", { statusCode: 404, body: { @@ -294,10 +296,14 @@ describe("Rooms view streaming config actions", function () { cy.wait("@roomStreamingConfig"); // Check that redirect worked and error message is shown - cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("edit settings", function () { @@ -621,6 +627,8 @@ describe("Rooms view streaming config actions", function () { }); // Check with 404 error (room not found) + cy.interceptRoomIndexRequests(); + cy.intercept("POST", "api/v1/rooms/abc-def-123/streaming/config", { statusCode: 404, body: { @@ -642,10 +650,14 @@ describe("Rooms view streaming config actions", function () { cy.wait("@saveConfigRequest"); // Check that redirect worked and error message is shown - cy.url().should("include", "404").and("not.include", "rooms/abc-def-123"); - cy.checkToastMessage( - 'app.flash.model_not_found.room_{"ids":"abc-def-123"}', - ); + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("view/edit settings with different permissions", function () { diff --git a/tests/Frontend/fixtures/en.json b/tests/Frontend/fixtures/en.json index 9c7aea205..4e7bcd7a7 100644 --- a/tests/Frontend/fixtures/en.json +++ b/tests/Frontend/fixtures/en.json @@ -1,19 +1,5 @@ { - "data": { - "app": { - "flash": { - "model_not_found": { - "meeting": "app.flash.model_not_found.meeting_{\"ids\":\":ids\"}", - "role": "app.flash.model_not_found.role_{\"ids\":\":ids\"}", - "room": "app.flash.model_not_found.room_{\"ids\":\":ids\"}", - "room_type": "app.flash.model_not_found.room_type_{\"ids\":\":ids\"}", - "server": "app.flash.model_not_found.server_{\"ids\":\":ids\"}", - "server_pool": "app.flash.model_not_found.server_pool_{\"ids\":\":ids\"}", - "user": "app.flash.model_not_found.user_{\"ids\":\":ids\"}" - } - } - } - }, + "data": {}, "meta": { "dateTimeFormat": { "dateShort": { From 6ebe7aa70705b5af9ebe91dde8ad77101f0ae726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Wed, 1 Apr 2026 10:58:13 +0200 Subject: [PATCH 08/18] Improve frontend tests --- .../js/components/RoomFavoriteButton.vue | 1 - tests/Frontend/e2e/RoomsIndex.cy.js | 325 +++++++++++++++++- tests/Frontend/e2e/RoomsViewFiles.cy.js | 26 +- tests/Frontend/e2e/RoomsViewGeneral.cy.js | 92 ++++- tests/Frontend/e2e/RoomsViewRecordings.cy.js | 25 +- 5 files changed, 464 insertions(+), 5 deletions(-) diff --git a/resources/js/components/RoomFavoriteButton.vue b/resources/js/components/RoomFavoriteButton.vue index 2cf490b75..fd0439d7b 100644 --- a/resources/js/components/RoomFavoriteButton.vue +++ b/resources/js/components/RoomFavoriteButton.vue @@ -60,7 +60,6 @@ function toggleFavorite() { .call("rooms/" + props.room.id + "/favorites", config) .catch((error) => { api.error(error, { - // ToDo emit notFound on not found error and handle it in index page (Reload room list) redirectOnUnauthenticated: props.redirectOnUnauthenticated, redirectOnRoomModelNotFound: props.redirectOnRoomModelNotFound, }); diff --git a/tests/Frontend/e2e/RoomsIndex.cy.js b/tests/Frontend/e2e/RoomsIndex.cy.js index 3cd1d5504..38f049d7e 100644 --- a/tests/Frontend/e2e/RoomsIndex.cy.js +++ b/tests/Frontend/e2e/RoomsIndex.cy.js @@ -1934,7 +1934,7 @@ describe("Room Index", function () { }); }); - it("trigger favorites button errors", function () { + it("trigger favorites button errors (room card)", function () { cy.fixture("rooms.json").then((rooms) => { rooms.data = rooms.data.slice(0, 1); rooms.meta.last_page = 3; @@ -1997,6 +1997,269 @@ describe("Room Index", function () { cy.checkToastMessage("app.flash.unauthenticated"); + // Test add to favorites with 404 error + cy.visit("/rooms"); + + cy.wait("@roomRequest"); + + cy.intercept("POST", "api/v1/rooms/abc-def-123/favorites", { + statusCode: 404, + body: { + message: "model_not_found", + model: "room", + ids: ["abc-def-123"], + }, + }).as("addFavoritesRequest"); + + cy.get('[data-test="room-card"]') + .eq(0) + .within(() => { + cy.get('[data-test="room-favorites-button"]') + .should("have.attr", "aria-label", "rooms.favorites.add") + .click(); + }); + + cy.wait("@addFavoritesRequest"); + + // Check that rooms are reloaded and error message is shown + cy.wait("@roomRequest").then((interception) => { + expect(interception.request.query).to.contain({ + page: "1", + }); + }); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); + + // Visit rooms again with a room that is already a favorite + cy.fixture("rooms.json").then((rooms) => { + rooms.data = rooms.data.slice(0, 1); + rooms.data[0].is_favorite = true; + + rooms.meta.last_page = 3; + rooms.meta.per_page = 1; + rooms.meta.to = 1; + + cy.intercept("GET", "api/v1/rooms?*", { + statusCode: 200, + body: rooms, + }).as("roomRequest"); + }); + + cy.visit("/rooms"); + + cy.wait("@roomRequest"); + + // Test remove from favorites with general error + cy.intercept("DELETE", "api/v1/rooms/abc-def-123/favorites", { + statusCode: 500, + body: { + message: "Test remove favorite error", + }, + }).as("deleteFavoritesRequest"); + + cy.get('[data-test="room-card"]') + .eq(0) + .within(() => { + cy.get('[data-test="room-favorites-button"]') + .should("have.attr", "aria-label", "rooms.favorites.remove") + .click(); + + cy.wait("@deleteFavoritesRequest"); + cy.wait("@roomRequest"); + }); + + // Check that error message is shown and button stayed the same + cy.checkToastMessage([ + 'app.flash.server_error.message_{"message":"Test remove favorite error"}', + 'app.flash.server_error.error_code_{"statusCode":500}', + ]); + + // Test remove from favorites with unauthenticated error + cy.intercept("DELETE", "api/v1/rooms/abc-def-123/favorites", { + statusCode: 401, + }).as("addFavoritesRequest"); + + cy.get('[data-test="room-card"]') + .eq(0) + .within(() => { + cy.get('[data-test="room-favorites-button"]') + .should("have.attr", "aria-label", "rooms.favorites.remove") + .click(); + + cy.wait("@addFavoritesRequest"); + cy.wait("@roomRequest"); + }); + + // Check that redirect worked and error message is shown + cy.url().should("include", "/login?redirect=/rooms"); + + cy.checkToastMessage("app.flash.unauthenticated"); + + // Test remove from favorites with 404 error + cy.visit("/rooms"); + + cy.wait("@roomRequest"); + + cy.intercept("DELETE", "api/v1/rooms/abc-def-123/favorites", { + statusCode: 404, + body: { + message: "model_not_found", + model: "room", + ids: ["abc-def-123"], + }, + }).as("deleteFavoritesRequest"); + + cy.get('[data-test="room-card"]') + .eq(0) + .within(() => { + cy.get('[data-test="room-favorites-button"]') + .should("have.attr", "aria-label", "rooms.favorites.remove") + .click(); + }); + + cy.wait("@deleteFavoritesRequest"); + + // Check that rooms are reloaded and error message is shown + cy.wait("@roomRequest").then((interception) => { + expect(interception.request.query).to.contain({ + page: "1", + }); + }); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); + }); + + it("trigger favorites button errors (room info dialog)", function () { + cy.fixture("rooms.json").then((rooms) => { + rooms.data = rooms.data.slice(0, 1); + rooms.meta.last_page = 3; + rooms.meta.per_page = 1; + rooms.meta.to = 1; + + rooms.data[0].short_description = "Room short descriptions"; + + cy.intercept("GET", "api/v1/rooms?*", { + statusCode: 200, + body: rooms, + }).as("roomRequest"); + }); + + cy.visit("/rooms"); + + cy.wait("@roomRequest"); + + // Test add to favorites with general error + cy.intercept("POST", "api/v1/rooms/abc-def-123/favorites", { + statusCode: 500, + body: { + message: "Test add favorite error", + }, + }).as("addFavoritesRequest"); + + cy.get('[data-test="room-info-dialog"]').should("not.exist"); + + cy.get('[data-test="room-card"]') + .eq(0) + .within(() => { + cy.get('[data-test="room-info-button"]').click(); + }); + + cy.get('[data-test="room-info-dialog"]') + .should("be.visible") + .within(() => { + cy.get('[data-test="room-favorites-button"]') + .should("have.attr", "aria-label", "rooms.favorites.add") + .click(); + + cy.wait("@addFavoritesRequest"); + cy.wait("@roomRequest"); + }); + + // Check that error message is shown and button stayed the same + cy.checkToastMessage([ + 'app.flash.server_error.message_{"message":"Test add favorite error"}', + 'app.flash.server_error.error_code_{"statusCode":500}', + ]); + + // Test add to favorites with unauthenticated error + cy.intercept("POST", "api/v1/rooms/abc-def-123/favorites", { + statusCode: 401, + }).as("addFavoritesRequest"); + + cy.get('[data-test="room-info-dialog"]').should("not.exist"); + + cy.get('[data-test="room-card"]') + .eq(0) + .within(() => { + cy.get('[data-test="room-info-button"]').click(); + }); + + cy.get('[data-test="room-info-dialog"]') + .should("be.visible") + .within(() => { + cy.get('[data-test="room-favorites-button"]') + .should("have.attr", "aria-label", "rooms.favorites.add") + .click(); + + cy.wait("@addFavoritesRequest"); + cy.wait("@roomRequest"); + }); + + // Check that redirect worked and error message is shown + cy.url().should("include", "/login?redirect=/rooms"); + + cy.checkToastMessage("app.flash.unauthenticated"); + + // Test add to favorites with 404 error + cy.visit("/rooms"); + + cy.wait("@roomRequest"); + + cy.intercept("POST", "api/v1/rooms/abc-def-123/favorites", { + statusCode: 404, + body: { + message: "model_not_found", + model: "room", + ids: ["abc-def-123"], + }, + }).as("addFavoritesRequest"); + + cy.get('[data-test="room-info-dialog"]').should("not.exist"); + + cy.get('[data-test="room-card"]') + .eq(0) + .within(() => { + cy.get('[data-test="room-info-button"]').click(); + }); + + cy.get('[data-test="room-info-dialog"]') + .should("be.visible") + .within(() => { + cy.get('[data-test="room-favorites-button"]') + .should("have.attr", "aria-label", "rooms.favorites.add") + .click(); + }); + + cy.wait("@addFavoritesRequest"); + + // Check that rooms are reloaded and error message is shown + cy.wait("@roomRequest").then((interception) => { + expect(interception.request.query).to.contain({ + page: "1", + }); + }); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); + // Visit rooms again with a room that is already a favorite cy.fixture("rooms.json").then((rooms) => { rooms.data = rooms.data.slice(0, 1); @@ -2024,8 +2287,16 @@ describe("Room Index", function () { }, }).as("deleteFavoritesRequest"); + cy.get('[data-test="room-info-dialog"]').should("not.exist"); + cy.get('[data-test="room-card"]') .eq(0) + .within(() => { + cy.get('[data-test="room-info-button"]').click(); + }); + + cy.get('[data-test="room-info-dialog"]') + .should("be.visible") .within(() => { cy.get('[data-test="room-favorites-button"]') .should("have.attr", "aria-label", "rooms.favorites.remove") @@ -2046,8 +2317,16 @@ describe("Room Index", function () { statusCode: 401, }).as("addFavoritesRequest"); + cy.get('[data-test="room-info-dialog"]').should("not.exist"); + cy.get('[data-test="room-card"]') .eq(0) + .within(() => { + cy.get('[data-test="room-info-button"]').click(); + }); + + cy.get('[data-test="room-info-dialog"]') + .should("be.visible") .within(() => { cy.get('[data-test="room-favorites-button"]') .should("have.attr", "aria-label", "rooms.favorites.remove") @@ -2061,6 +2340,50 @@ describe("Room Index", function () { cy.url().should("include", "/login?redirect=/rooms"); cy.checkToastMessage("app.flash.unauthenticated"); + + // Test remove from favorites with 404 error + cy.visit("/rooms"); + + cy.wait("@roomRequest"); + + cy.intercept("DELETE", "api/v1/rooms/abc-def-123/favorites", { + statusCode: 404, + body: { + message: "model_not_found", + model: "room", + ids: ["abc-def-123"], + }, + }).as("deleteFavoritesRequest"); + + cy.get('[data-test="room-info-dialog"]').should("not.exist"); + + cy.get('[data-test="room-card"]') + .eq(0) + .within(() => { + cy.get('[data-test="room-info-button"]').click(); + }); + + cy.get('[data-test="room-info-dialog"]') + .should("be.visible") + .within(() => { + cy.get('[data-test="room-favorites-button"]') + .should("have.attr", "aria-label", "rooms.favorites.remove") + .click(); + }); + + cy.wait("@deleteFavoritesRequest"); + + // Check that rooms are reloaded and error message is shown + cy.wait("@roomRequest").then((interception) => { + expect(interception.request.query).to.contain({ + page: "1", + }); + }); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("error loading rooms", function () { diff --git a/tests/Frontend/e2e/RoomsViewFiles.cy.js b/tests/Frontend/e2e/RoomsViewFiles.cy.js index bffa9b16e..ec1a2d922 100644 --- a/tests/Frontend/e2e/RoomsViewFiles.cy.js +++ b/tests/Frontend/e2e/RoomsViewFiles.cy.js @@ -722,7 +722,7 @@ describe("Rooms View Files", function () { .eq(0) .should("have.attr", "data-p-active", "true"); - // Check with 404 error (room not found) + // Check with 404 error (room not found) as authenticated user cy.interceptRoomIndexRequests(); cy.intercept("GET", "api/v1/rooms/abc-def-123/files*", { @@ -747,6 +747,30 @@ describe("Rooms View Files", function () { 'app.flash.model_not_found.title_{"model":"app.model.room"}', 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', ]); + + // Check with 404 error (room not found) as guest + cy.intercept("GET", "api/v1/currentUser", { data: [] }); + cy.fixture("room.json").then((room) => { + room.data.current_user = null; + + cy.intercept("GET", "api/v1/rooms/abc-def-123*", { + statusCode: 200, + body: room, + }).as("roomRequest"); + }); + + cy.visit("/rooms/abc-def-123#tab=files"); + + cy.wait("@roomFilesRequest"); + + // Check that redirect to 404 page worked + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + + // Check that error message gets shown + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("load files page out of range", function () { diff --git a/tests/Frontend/e2e/RoomsViewGeneral.cy.js b/tests/Frontend/e2e/RoomsViewGeneral.cy.js index 69410aa32..6b608b718 100644 --- a/tests/Frontend/e2e/RoomsViewGeneral.cy.js +++ b/tests/Frontend/e2e/RoomsViewGeneral.cy.js @@ -693,6 +693,65 @@ describe("Room View general", function () { // Check that access code overlay is hidden cy.get('[data-test="room-access-code-overlay"]').should("not.exist"); + + // Check with 404 error (room not found) as authenticated user + cy.interceptRoomIndexRequests(); + cy.intercept("POST", "api/v1/rooms/abc-def-123/auth", { + statusCode: 404, + body: { + message: "model_not_found", + model: "room", + ids: ["abc-def-123"], + }, + }).as("roomAuthRequest"); + + cy.reload(); + + cy.wait("@roomRequest"); + + cy.get('[data-test="room-login-button"]').click(); + + cy.wait("@roomAuthRequest"); + + // Check that redirect to room index page worked + cy.url() + .should("include", "/rooms") + .and("not.include", "/rooms/abc-def-123"); + + // Check that error message is shown + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); + + // Check wit 404 error (room not found) as guest + cy.intercept("GET", "api/v1/currentUser", {}); + cy.fixture("room.json").then((room) => { + room.data.current_user = null; + room.data.authenticated = false; + + cy.intercept("GET", "api/v1/rooms/abc-def-123*", { + statusCode: 200, + body: room, + }).as("roomRequest"); + }); + + cy.visit("/rooms/abc-def-123"); + + cy.wait("@roomRequest"); + + cy.get('[data-test="room-login-button"]').click(); + + cy.wait("@roomAuthRequest"); + + // Check that redirect to 404 page worked + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + + // Check that error message is shown + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("room view with access code errors", function () { @@ -1589,6 +1648,37 @@ describe("Room View general", function () { cy.contains("rooms.index.room_component.never_started").should( "be.visible", ); + + // Check with 404 error + cy.intercept("POST", "api/v1/rooms/abc-def-123/auth", { + statusCode: 404, + body: { + message: "model_not_found", + model: "room", + ids: ["abc-def-123"], + }, + }).as("roomAuthRequest"); + + // Visit room with personalized link + cy.visit( + "/rooms/abc-def-123/xWDCevVTcMys1ftzt3nFPgU56Wf32fopFWgAEBtklSkFU22z1ntA4fBHsHeMygMiOa9szJbNEfBAgEWSLNWg2gcF65PwPZ2ylPQR", + ); + + cy.wait("@roomAuthRequest").then((interception) => { + expect(interception.request.body).to.eql({ + personalized_link_token: + "xWDCevVTcMys1ftzt3nFPgU56Wf32fopFWgAEBtklSkFU22z1ntA4fBHsHeMygMiOa9szJbNEfBAgEWSLNWg2gcF65PwPZ2ylPQR", + type: 1, + }); + }); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("room view with personalized link errors", function () { @@ -3149,7 +3239,7 @@ describe("Room View general", function () { 'app.flash.server_error.error_code_{"statusCode":404}', ]); - // Test reload with room not found and logged in user + // Test reload with room not found and authenticated user cy.intercept("GET", "api/v1/currentUser", { fixture: "currentUser.json" }); cy.fixture("room.json").then((room) => { room.data.allow_membership = true; diff --git a/tests/Frontend/e2e/RoomsViewRecordings.cy.js b/tests/Frontend/e2e/RoomsViewRecordings.cy.js index 71876b192..3f2260635 100644 --- a/tests/Frontend/e2e/RoomsViewRecordings.cy.js +++ b/tests/Frontend/e2e/RoomsViewRecordings.cy.js @@ -761,7 +761,7 @@ describe("Rooms view recordings", function () { .eq(0) .should("have.attr", "data-p-active", "true"); - // Check with 404 error (room not found) + // Check with 404 error (room not found) as authenticated user cy.interceptRoomIndexRequests(); cy.intercept("GET", "api/v1/rooms/abc-def-123/recordings*", { @@ -787,6 +787,29 @@ describe("Rooms view recordings", function () { 'app.flash.model_not_found.title_{"model":"app.model.room"}', 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', ]); + + // Check with 404 error (room not found) as guest + cy.intercept("GET", "api/v1/currentUser", {}); + cy.fixture("room.json").then((room) => { + room.data.current_user = null; + + cy.intercept("GET", "api/v1/rooms/abc-def-123*", { + statusCode: 200, + body: room, + }).as("roomRequest"); + + cy.visit("/rooms/abc-def-123#tab=recordings"); + + cy.wait("@roomRecordingsRequest"); + }); + + // Check that redirect to 404 page worked and error message is shown + cy.url().should("include", "/404").and("not.include", "/rooms/abc-def-123"); + + cy.checkToastMessage([ + 'app.flash.model_not_found.title_{"model":"app.model.room"}', + 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', + ]); }); it("load recordings page out of range", function () { From e79ebf2b2679b20436d63634d2e42a53ef923402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:55:21 +0200 Subject: [PATCH 09/18] Improve 404 error handling --- resources/js/components/RoomTabFilesDeleteButton.vue | 4 ++-- resources/js/components/RoomTabFilesEditButton.vue | 4 ++-- .../js/components/RoomTabPersonalizedLinksDeleteButton.vue | 4 ++-- .../js/components/RoomTabPersonalizedLinksEditButton.vue | 4 ++-- resources/js/components/RoomTabRecordingsDeleteButton.vue | 4 ++-- resources/js/components/RoomTabRecordingsEditButton.vue | 4 ++-- resources/js/constants/modelNames.js | 5 ++++- resources/js/services/Api.js | 4 ++-- tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js | 4 +++- 9 files changed, 21 insertions(+), 16 deletions(-) diff --git a/resources/js/components/RoomTabFilesDeleteButton.vue b/resources/js/components/RoomTabFilesDeleteButton.vue index 28f0aeefb..e383b1471 100644 --- a/resources/js/components/RoomTabFilesDeleteButton.vue +++ b/resources/js/components/RoomTabFilesDeleteButton.vue @@ -53,7 +53,7 @@ import { useApi } from "../composables/useApi.js"; import { ref } from "vue"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; -import { ROOM_MODEL } from "../constants/modelNames.js"; +import { ROOM_FILE } from "../constants/modelNames.js"; const props = defineProps({ roomId: { @@ -104,7 +104,7 @@ function deleteFile() { // file not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== ROOM_MODEL + error.response.data?.model === ROOM_FILE ) { toast.error(t("rooms.flash.file_gone")); emit("notFound"); diff --git a/resources/js/components/RoomTabFilesEditButton.vue b/resources/js/components/RoomTabFilesEditButton.vue index d7901b305..f602dbc31 100644 --- a/resources/js/components/RoomTabFilesEditButton.vue +++ b/resources/js/components/RoomTabFilesEditButton.vue @@ -100,7 +100,7 @@ import { ref, watch } from "vue"; import { useFormErrors } from "../composables/useFormErrors.js"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; -import { ROOM_MODEL } from "../constants/modelNames.js"; +import { ROOM_FILE } from "../constants/modelNames.js"; const props = defineProps({ roomId: { @@ -198,7 +198,7 @@ function save() { // file not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== ROOM_MODEL + error.response.data?.model === ROOM_FILE ) { toast.error(t("rooms.flash.file_gone")); emit("notFound"); diff --git a/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue b/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue index 384cf69d1..57a584477 100644 --- a/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue @@ -59,7 +59,7 @@ import { useApi } from "../composables/useApi.js"; import { ref } from "vue"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; -import { ROOM_MODEL } from "../constants/modelNames.js"; +import { ROOM } from "../constants/modelNames.js"; const props = defineProps({ roomId: { @@ -123,7 +123,7 @@ function deleteLink() { // personalized link not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== ROOM_MODEL + error.response.data?.model !== ROOM ) { toast.error(t("rooms.flash.personalized_link_gone")); modalVisible.value = false; diff --git a/resources/js/components/RoomTabPersonalizedLinksEditButton.vue b/resources/js/components/RoomTabPersonalizedLinksEditButton.vue index 8b5b54bef..91bd5a472 100644 --- a/resources/js/components/RoomTabPersonalizedLinksEditButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksEditButton.vue @@ -110,7 +110,7 @@ import { ref } from "vue"; import env from "../env.js"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; -import { ROOM_MODEL } from "../constants/modelNames.js"; +import { ROOM } from "../constants/modelNames.js"; const props = defineProps({ roomId: { @@ -192,7 +192,7 @@ function save() { // token not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== ROOM_MODEL + error.response.data?.model !== ROOM ) { toast.error(t("rooms.flash.personalized_link_gone")); modalVisible.value = false; diff --git a/resources/js/components/RoomTabRecordingsDeleteButton.vue b/resources/js/components/RoomTabRecordingsDeleteButton.vue index 0a1b96d01..553d4a80f 100644 --- a/resources/js/components/RoomTabRecordingsDeleteButton.vue +++ b/resources/js/components/RoomTabRecordingsDeleteButton.vue @@ -53,7 +53,7 @@ import { useApi } from "../composables/useApi.js"; import { ref } from "vue"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; -import { ROOM_MODEL } from "../constants/modelNames.js"; +import { RECORDING } from "../constants/modelNames.js"; const props = defineProps({ recordingId: { @@ -100,7 +100,7 @@ function deleteRecording() { // recording not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== ROOM_MODEL + error.response.data?.model === RECORDING ) { toast.error(t("rooms.flash.recording_gone")); emit("notFound"); diff --git a/resources/js/components/RoomTabRecordingsEditButton.vue b/resources/js/components/RoomTabRecordingsEditButton.vue index ea677de43..654a0d005 100644 --- a/resources/js/components/RoomTabRecordingsEditButton.vue +++ b/resources/js/components/RoomTabRecordingsEditButton.vue @@ -130,7 +130,7 @@ import * as _ from "lodash-es"; import { useSettingsStore } from "../stores/settings.js"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; -import { ROOM_MODEL } from "../constants/modelNames.js"; +import { RECORDING } from "../constants/modelNames.js"; const props = defineProps({ recordingId: { @@ -239,7 +239,7 @@ function save() { // recording not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== ROOM_MODEL + error.response.data?.model === RECORDING ) { toast.error(t("rooms.flash.recording_gone")); modalVisible.value = false; diff --git a/resources/js/constants/modelNames.js b/resources/js/constants/modelNames.js index 545d0b65c..0e304dc45 100644 --- a/resources/js/constants/modelNames.js +++ b/resources/js/constants/modelNames.js @@ -1 +1,4 @@ -export const ROOM_MODEL = "room"; +export const ROOM = "room"; +export const ROOM_FILE = "room_file"; +export const ROOM_PERSONALIZED_LINK = "room_personalized_link"; +export const RECORDING = "recording"; diff --git a/resources/js/services/Api.js b/resources/js/services/Api.js index bea55edb2..d783aeccc 100644 --- a/resources/js/services/Api.js +++ b/resources/js/services/Api.js @@ -6,7 +6,7 @@ import { useAuthStore } from "../stores/auth"; import { useRouter } from "vue-router"; import { EVENT_FORBIDDEN, EVENT_UNAUTHORIZED } from "../constants/events.js"; import EventBus from "./EventBus.js"; -import { ROOM_MODEL } from "../constants/modelNames.js"; +import { ROOM } from "../constants/modelNames.js"; axios.defaults.withCredentials = true; axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest"; @@ -125,7 +125,7 @@ export class Api { const model = data?.model; const ids = data?.ids; - if (model === ROOM_MODEL && options.redirectOnRoomModelNotFound !== false) { + if (model === ROOM && options.redirectOnRoomModelNotFound !== false) { // Redirect to room index page if user is authenticated, otherwise show 404 page, because // unauthenticated user is not able to visit the room index page if (this.auth.isAuthenticated) { diff --git a/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js b/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js index 3dbe58105..a6d1debb7 100644 --- a/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewRecordingsRecordingActions.cy.js @@ -1220,7 +1220,9 @@ describe("Rooms view recordings recording actions", function () { { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "recording", + ids: ["f9569db6d5e8fb2fd2f57d367d5482b36837b9d8-1663666775"], }, }, ).as("editRecordingRequest"); From 536080861f216a40fd0257fe83a812aa6b5a8362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Tue, 7 Apr 2026 09:55:43 +0200 Subject: [PATCH 10/18] Improve backend tests --- .../Backend/Feature/api/v1/RecordingTest.php | 23 ++++++ .../Backend/Feature/api/v1/Room/FileTest.php | 38 +++++++++ .../Feature/api/v1/Room/MembershipTest.php | 79 +++++++++++++++++++ .../api/v1/Room/RoomDescriptionTest.php | 11 +++ .../api/v1/Room/RoomPersonalizedLinkTest.php | 12 +++ .../Feature/api/v1/Room/RoomStatisticTest.php | 11 +++ 6 files changed, 174 insertions(+) diff --git a/tests/Backend/Feature/api/v1/RecordingTest.php b/tests/Backend/Feature/api/v1/RecordingTest.php index 392582200..fda7590d5 100644 --- a/tests/Backend/Feature/api/v1/RecordingTest.php +++ b/tests/Backend/Feature/api/v1/RecordingTest.php @@ -1104,6 +1104,17 @@ public function test_update() 'model' => 'recording', 'ids' => [$recording->id], ]); + + // Test deleted room + $room->delete(); + + $this->putJson(route('api.v1.rooms.recordings.update', ['room' => $room->id, 'recording' => $recording->id]), $payload) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } public function test_update_permissions() @@ -1248,6 +1259,18 @@ public function test_delete() 'model' => 'recording', 'ids' => [$recording->id], ]); + + // Test with deleted room + $room->delete(); + + $this->actingAs($room->owner) + ->deleteJson(route('api.v1.rooms.recordings.destroy', ['room' => $room->id, 'recording' => $recording->id])) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } public function test_delete_on_room_delete() diff --git a/tests/Backend/Feature/api/v1/Room/FileTest.php b/tests/Backend/Feature/api/v1/Room/FileTest.php index 69ace11a4..0813fc9d3 100644 --- a/tests/Backend/Feature/api/v1/Room/FileTest.php +++ b/tests/Backend/Feature/api/v1/Room/FileTest.php @@ -348,6 +348,18 @@ public function test_view_files() ->assertJsonCount(0, 'data') ->assertJsonPath('meta.total', 0) ->assertJsonPath('meta.total_no_filter', 3); + + // Test deleted room + $this->room->delete(); + + $this->actingAs($this->room->owner) + ->getJson(route('api.v1.rooms.files.get', ['room' => $this->room, 'query' => 'test'])) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$this->room->id], + ]); } /** @@ -1088,6 +1100,19 @@ public function test_files_delete() // Check if file was deleted as well Storage::disk('local')->assertMissing($this->room->id.'/'.$this->file_valid->hashName()); + + // Test delete with deleted room + $this->room->delete(); + + $this->actingAs($this->room->owner)->deleteJson(route('api.v1.rooms.files.destroy', ['room' => $this->room->id, 'file' => $room_file])) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [ + $this->room->id, + ], + ]); } /** @@ -1281,6 +1306,19 @@ public function test_update_file() $room_file->id, ], ]); + + // Test deleted room + $this->room->delete(); + + $this->actingAs($this->room->owner)->putJson($route, $params) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [ + $this->room->id, + ], + ]); } /** diff --git a/tests/Backend/Feature/api/v1/Room/MembershipTest.php b/tests/Backend/Feature/api/v1/Room/MembershipTest.php index b6f204620..9b617cc0e 100644 --- a/tests/Backend/Feature/api/v1/Room/MembershipTest.php +++ b/tests/Backend/Feature/api/v1/Room/MembershipTest.php @@ -630,6 +630,17 @@ public function test_member_list() $this->actingAs($room->owner)->getJson(route('api.v1.rooms.member.get', ['room' => $room, 'filter' => 'invalid_role'])) ->assertJsonCount(5, 'data') ->assertJsonPath('meta.total', 6); + + // Test deleted room + $room->delete(); + + $this->actingAs($room->owner)->getJson(route('api.v1.rooms.member.get', ['room' => $room, 'filter' => 'invalid_role'])) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } /** @@ -719,6 +730,17 @@ public function test_add_member() $this->actingAs($this->user)->postJson(route('api.v1.rooms.member.add', ['room' => $room]), ['user' => $newUser->id, 'role' => RoomUserRole::USER]) ->assertNoContent(); $this->role->permissions()->detach($this->managePermission); + + // Test with deleted room + $room->delete(); + + $this->actingAs($owner)->postJson(route('api.v1.rooms.member.add', ['room' => $room]), ['user' => $newUser->id, 'role' => RoomUserRole::USER]) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } /** @@ -803,6 +825,17 @@ public function test_remove_member() $this->actingAs($newUser)->getJson(route('api.v1.rooms.show', ['room' => $room])) ->assertStatus(200) ->assertJsonFragment(['is_member' => false]); + + // Remove member of deleted room + $room->delete(); + + $this->actingAs($newUser)->getJson(route('api.v1.rooms.show', ['room' => $room])) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } /** @@ -869,6 +902,17 @@ public function test_change_member_role() $this->actingAs($this->user)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'user' => $newUser]), ['role' => RoomUserRole::MODERATOR]) ->assertNoContent(); $this->role->permissions()->detach($this->managePermission); + + // Test with deleted room + $room->delete(); + + $this->actingAs($this->user)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'user' => $newUser]), ['role' => RoomUserRole::MODERATOR]) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } public function test_bulk_import_members() @@ -1027,6 +1071,17 @@ public function test_bulk_import_members() $this->actingAs($this->user)->postJson(route('api.v1.rooms.member.bulkImport', ['room' => $room]), ['user_emails' => [$newUser->email], 'role' => RoomUserRole::USER]) ->assertNoContent(); $this->role->permissions()->detach($this->managePermission); + + // Test with deleted room + $room->delete(); + + $this->actingAs($owner)->postJson(route('api.v1.rooms.member.bulkImport', ['room' => $room]), ['user_emails' => [$newUser->email], 'role' => RoomUserRole::USER]) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } public function test_bulk_update_members() @@ -1178,6 +1233,19 @@ public function test_bulk_update_members() route('api.v1.rooms.member.bulkUpdate', ['room' => $room]), ['users' => [$memberUser->id], 'role' => RoomUserRole::MODERATOR] )->assertForbidden(); + + // Test with deleted room + $room->delete(); + + $this->actingAs($owner)->putJson( + route('api.v1.rooms.member.bulkUpdate', ['room' => $room]), + ['users' => [$memberUser->id], 'role' => RoomUserRole::MODERATOR] + )->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } public function test_bulk_remove_members() @@ -1275,5 +1343,16 @@ public function test_bulk_remove_members() // Remove yourself as co-owner $this->actingAs($memberCoOwner)->deleteJson(route('api.v1.rooms.member.bulkDestroy', ['room' => $room]), ['users' => [$memberUser->id, $memberCoOwner->id]]) ->assertUnprocessable(); + + // Test with deleted room + $room->delete(); + + $this->actingAs($owner)->deleteJson(route('api.v1.rooms.member.bulkDestroy', ['room' => $room]), ['users' => [$memberUser->id]]) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } } diff --git a/tests/Backend/Feature/api/v1/Room/RoomDescriptionTest.php b/tests/Backend/Feature/api/v1/Room/RoomDescriptionTest.php index f8f5883f3..6c4bbff71 100644 --- a/tests/Backend/Feature/api/v1/Room/RoomDescriptionTest.php +++ b/tests/Backend/Feature/api/v1/Room/RoomDescriptionTest.php @@ -300,5 +300,16 @@ public function test_update_description_data() ->assertUnprocessable(); $room->refresh(); $this->assertNull($room->description); + + // Test deleted room + $room->delete(); + + $this->actingAs($this->user)->putJson(route('api.v1.rooms.description.update', ['room' => $room]), ['description' => $this->faker->text(100)]) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } } diff --git a/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php b/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php index d9e401537..b83abc275 100644 --- a/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php +++ b/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php @@ -530,5 +530,17 @@ public function test_delete() 'model' => 'room_personalized_link', 'ids' => [$link->id], ]); + + // Test deleted room + $this->room->delete(); + + $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) + ->assertNotFound() + ->assertJson( + [ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$this->room->id], + ]); } } diff --git a/tests/Backend/Feature/api/v1/Room/RoomStatisticTest.php b/tests/Backend/Feature/api/v1/Room/RoomStatisticTest.php index df0376b98..1977b0592 100644 --- a/tests/Backend/Feature/api/v1/Room/RoomStatisticTest.php +++ b/tests/Backend/Feature/api/v1/Room/RoomStatisticTest.php @@ -179,6 +179,17 @@ public function test_meeting_list() $this->actingAs($room->owner)->getJson(route('api.v1.rooms.meetings', ['room' => $room]).'?sort_direction=invalid') ->assertSuccessful() ->assertJsonPath('data.0.id', $meetings[0]->id); + + // Test deleted room + $room->delete(); + + $this->actingAs($room->owner)->getJson(route('api.v1.rooms.meetings', ['room' => $room]).'?sort_direction=invalid') + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$room->id], + ]); } /** From e6c6348e4b91f54d95d7041186aab45ac54ba27a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Wed, 8 Apr 2026 16:47:14 +0200 Subject: [PATCH 11/18] Use scope bindings instead of custom handling --- .../api/v1/RoomMemberController.php | 18 ++---- .../api/v1/RoomPersonalizedLinkController.php | 28 ++++------ lang/en/app.php | 6 +- .../components/RoomTabMembersDeleteButton.vue | 12 +++- .../components/RoomTabMembersEditButton.vue | 12 +++- .../RoomTabPersonalizedLinksDeleteButton.vue | 4 +- .../RoomTabPersonalizedLinksEditButton.vue | 4 +- resources/js/constants/modelNames.js | 1 + routes/api.php | 38 +++++++------ .../Feature/api/v1/Room/MembershipTest.php | 52 ++++++++++------- .../api/v1/Room/RoomPersonalizedLinkTest.php | 56 +++++++++++-------- .../e2e/RoomsViewMembersMemberActions.cy.js | 22 ++++---- ...omsViewPersonalizedLinksTokenActions.cy.js | 8 ++- 13 files changed, 148 insertions(+), 113 deletions(-) diff --git a/app/Http/Controllers/api/v1/RoomMemberController.php b/app/Http/Controllers/api/v1/RoomMemberController.php index 99841c520..4ab2d713a 100644 --- a/app/Http/Controllers/api/v1/RoomMemberController.php +++ b/app/Http/Controllers/api/v1/RoomMemberController.php @@ -120,14 +120,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(); } @@ -153,14 +150,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 cb4dd8b5a..0f28c9359 100644 --- a/app/Http/Controllers/api/v1/RoomPersonalizedLinkController.php +++ b/app/Http/Controllers/api/v1/RoomPersonalizedLinkController.php @@ -101,20 +101,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); } /** @@ -124,15 +120,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 68b020ab1..b4f8f8ad6 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -41,7 +41,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,7 +66,7 @@ 'guests_only' => 'The request can only be made by guests!', 'model_not_found' => [ 'title' => 'The :model was not found!', - 'details' => ' Model ids: :ids', + 'details' => ' Model id: :ids', ], 'server_error' => [ 'empty_message' => 'An error occurred on the server during request!', @@ -99,7 +99,7 @@ 'fr' => 'French', ], 'model' => [ - 'meeting' => 'meeting', + 'meeting' => 'Meeting', 'role' => 'Role', 'roles' => 'role', 'room' => 'Room', diff --git a/resources/js/components/RoomTabMembersDeleteButton.vue b/resources/js/components/RoomTabMembersDeleteButton.vue index cf30ba516..06c481399 100644 --- a/resources/js/components/RoomTabMembersDeleteButton.vue +++ b/resources/js/components/RoomTabMembersDeleteButton.vue @@ -56,6 +56,9 @@ import env from "../env"; import { useApi } from "../composables/useApi.js"; import { ref } from "vue"; +import { USER } from "../constants/modelNames.js"; +import { useToast } from "../composables/useToast.js"; +import { useI18n } from "vue-i18n"; const props = defineProps({ roomId: { @@ -83,6 +86,8 @@ const props = defineProps({ const emit = defineEmits(["deleted", "gone"]); const api = useApi(); +const toast = useToast(); +const { t } = useI18n(); const modalVisible = ref(false); const isLoadingAction = ref(false); @@ -106,9 +111,14 @@ function deleteMember() { // editing failed if (error.response) { // user not found - if (error.response.status === env.HTTP_GONE) { + if ( + error.response.status === env.HTTP_NOT_FOUND && + error.response.data?.model === USER + ) { + toast.error(t("app.errors.not_member_of_room")); emit("gone"); modalVisible.value = false; + return; } } api.error(error, { redirectOnUnauthenticated: false }); diff --git a/resources/js/components/RoomTabMembersEditButton.vue b/resources/js/components/RoomTabMembersEditButton.vue index 8a02bed35..518837fca 100644 --- a/resources/js/components/RoomTabMembersEditButton.vue +++ b/resources/js/components/RoomTabMembersEditButton.vue @@ -99,6 +99,9 @@ import env from "../env"; import { useApi } from "../composables/useApi.js"; import { useFormErrors } from "../composables/useFormErrors.js"; import { ref } from "vue"; +import { USER } from "../constants/modelNames.js"; +import { useToast } from "../composables/useToast.js"; +import { useI18n } from "vue-i18n"; const props = defineProps({ roomId: { @@ -131,6 +134,8 @@ const emit = defineEmits(["edited", "gone"]); const api = useApi(); const formErrors = useFormErrors(); +const toast = useToast(); +const { t } = useI18n(); const modalVisible = ref(false); const newRole = ref(null); @@ -168,9 +173,14 @@ function save() { // editing failed if (error.response) { // user not found - if (error.response.status === env.HTTP_GONE) { + if ( + error.response.status === env.HTTP_NOT_FOUND && + error.response.data?.model === USER + ) { + toast.error(t("app.errors.not_member_of_room")); emit("gone"); modalVisible.value = false; + return; } // failed due to form validation errors if (error.response.status === env.HTTP_UNPROCESSABLE_ENTITY) { diff --git a/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue b/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue index 57a584477..aa7f1ca78 100644 --- a/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksDeleteButton.vue @@ -59,7 +59,7 @@ import { useApi } from "../composables/useApi.js"; import { ref } from "vue"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; -import { ROOM } from "../constants/modelNames.js"; +import { ROOM_PERSONALIZED_LINK } from "../constants/modelNames.js"; const props = defineProps({ roomId: { @@ -123,7 +123,7 @@ function deleteLink() { // personalized link not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== ROOM + error.response.data?.model === ROOM_PERSONALIZED_LINK ) { toast.error(t("rooms.flash.personalized_link_gone")); modalVisible.value = false; diff --git a/resources/js/components/RoomTabPersonalizedLinksEditButton.vue b/resources/js/components/RoomTabPersonalizedLinksEditButton.vue index 91bd5a472..937988c60 100644 --- a/resources/js/components/RoomTabPersonalizedLinksEditButton.vue +++ b/resources/js/components/RoomTabPersonalizedLinksEditButton.vue @@ -110,7 +110,7 @@ import { ref } from "vue"; import env from "../env.js"; import { useToast } from "../composables/useToast.js"; import { useI18n } from "vue-i18n"; -import { ROOM } from "../constants/modelNames.js"; +import { ROOM_PERSONALIZED_LINK } from "../constants/modelNames.js"; const props = defineProps({ roomId: { @@ -192,7 +192,7 @@ function save() { // token not found if ( error.response.status === env.HTTP_NOT_FOUND && - error.response.data?.model !== ROOM + error.response.data?.model === ROOM_PERSONALIZED_LINK ) { toast.error(t("rooms.flash.personalized_link_gone")); modalVisible.value = false; diff --git a/resources/js/constants/modelNames.js b/resources/js/constants/modelNames.js index 0e304dc45..60d9f8a1e 100644 --- a/resources/js/constants/modelNames.js +++ b/resources/js/constants/modelNames.js @@ -2,3 +2,4 @@ export const ROOM = "room"; export const ROOM_FILE = "room_file"; export const ROOM_PERSONALIZED_LINK = "room_personalized_link"; export const RECORDING = "recording"; +export const USER = "user"; diff --git a/routes/api.php b/routes/api.php index 57eec82ee..a550ca44a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -73,7 +73,7 @@ Route::get('rooms', [RoomController::class, 'index'])->name('rooms.index'); Route::post('rooms', [RoomController::class, 'store'])->name('rooms.store'); - Route::middleware('throttle:room-enumeration')->group(function () { + Route::middleware('throttle:room-enumeration')->scopeBindings()->group(function () { Route::post('rooms/{room}/favorites', [RoomController::class, 'addToFavorites'])->name('rooms.favorites.add'); Route::delete('rooms/{room}/favorites', [RoomController::class, 'deleteFromFavorites'])->name('rooms.favorites.delete'); Route::put('rooms/{room}', [RoomController::class, 'update'])->name('rooms.update'); @@ -89,30 +89,33 @@ Route::post('rooms/{room}/membership', [RoomMemberController::class, 'join'])->name('rooms.membership.join'); Route::delete('rooms/{room}/membership', [RoomMemberController::class, 'leave'])->name('rooms.membership.leave'); - // Membership users for mass update & delete - Route::post('rooms/{room}/member/bulk', [RoomMemberController::class, 'bulkImport'])->name('rooms.member.bulkImport')->middleware('can:manageMembers,room'); - Route::put('rooms/{room}/member/bulk', [RoomMemberController::class, 'bulkUpdate'])->name('rooms.member.bulkUpdate')->middleware('can:manageMembers,room'); - Route::delete('rooms/{room}/member/bulk', [RoomMemberController::class, 'bulkDestroy'])->name('rooms.member.bulkDestroy')->middleware('can:manageMembers,room'); - // Membership operations by room owner Route::get('rooms/{room}/member', [RoomMemberController::class, 'index'])->name('rooms.member.get')->middleware('can:viewMembers,room'); - Route::post('rooms/{room}/member', [RoomMemberController::class, 'store'])->name('rooms.member.add')->middleware('can:manageMembers,room'); - Route::put('rooms/{room}/member/{user}', [RoomMemberController::class, 'update'])->name('rooms.member.update')->middleware('can:manageMembers,room'); - Route::delete('rooms/{room}/member/{user}', [RoomMemberController::class, 'destroy'])->name('rooms.member.destroy')->middleware('can:manageMembers,room'); + + Route::middleware('can:manageMembers,room')->group(function () { + // Membership users for mass update & delete + Route::post('rooms/{room}/member/bulk', [RoomMemberController::class, 'bulkImport'])->name('rooms.member.bulkImport'); + Route::put('rooms/{room}/member/bulk', [RoomMemberController::class, 'bulkUpdate'])->name('rooms.member.bulkUpdate'); + Route::delete('rooms/{room}/member/bulk', [RoomMemberController::class, 'bulkDestroy'])->name('rooms.member.bulkDestroy'); + + Route::post('rooms/{room}/member', [RoomMemberController::class, 'store'])->name('rooms.member.add'); + Route::put('rooms/{room}/member/{member}', [RoomMemberController::class, 'update'])->name('rooms.member.update'); + Route::delete('rooms/{room}/member/{member}', [RoomMemberController::class, 'destroy'])->name('rooms.member.destroy'); + }); // Recording operations - Route::middleware('can:manageRecordings,room')->scopeBindings()->group(function () { + Route::middleware('can:manageRecordings,room')->group(function () { Route::put('rooms/{room}/recordings/{recording}', [RecordingController::class, 'update'])->name('rooms.recordings.update'); Route::delete('rooms/{room}/recordings/{recording}', [RecordingController::class, 'destroy'])->name('rooms.recordings.destroy'); }); // Streaming operations - Route::middleware('can:viewStreaming,room')->scopeBindings()->group(function () { + Route::middleware('can:viewStreaming,room')->group(function () { Route::get('rooms/{room}/streaming/config', [RoomStreamingController::class, 'getConfig'])->name('rooms.streaming.config.get'); Route::get('rooms/{room}/streaming/status', [RoomStreamingController::class, 'status'])->name('rooms.streaming.status'); }); - Route::middleware('can:manageStreaming,room')->scopeBindings()->group(function () { + Route::middleware('can:manageStreaming,room')->group(function () { Route::put('rooms/{room}/streaming/config', [RoomStreamingController::class, 'updateConfig'])->name('rooms.streaming.config.update'); Route::post('rooms/{room}/streaming/start', [RoomStreamingController::class, 'start'])->name('rooms.streaming.start'); Route::post('rooms/{room}/streaming/stop', [RoomStreamingController::class, 'stop'])->name('rooms.streaming.stop'); @@ -122,12 +125,15 @@ // Personalized room links Route::get('rooms/{room}/personalizedLinks', [RoomPersonalizedLinkController::class, 'index'])->name('rooms.personalizedLinks.get')->middleware('can:viewPersonalizedLinks,room'); - Route::post('rooms/{room}/personalizedLinks', [RoomPersonalizedLinkController::class, 'store'])->name('rooms.personalizedLinks.add')->middleware('can:managePersonalizedLinks,room'); - Route::put('rooms/{room}/personalizedLinks/{link}', [RoomPersonalizedLinkController::class, 'update'])->name('rooms.personalizedLinks.update')->middleware('can:managePersonalizedLinks,room'); - Route::delete('rooms/{room}/personalizedLinks/{link}', [RoomPersonalizedLinkController::class, 'destroy'])->name('rooms.personalizedLinks.destroy')->middleware('can:managePersonalizedLinks,room'); + + Route::middleware('can:managePersonalizedLinks,room')->group(function () { + Route::post('rooms/{room}/personalizedLinks', [RoomPersonalizedLinkController::class, 'store'])->name('rooms.personalizedLinks.add'); + Route::put('rooms/{room}/personalizedLinks/{personalizedLink}', [RoomPersonalizedLinkController::class, 'update'])->name('rooms.personalizedLinks.update'); + Route::delete('rooms/{room}/personalizedLinks/{personalizedLink}', [RoomPersonalizedLinkController::class, 'destroy'])->name('rooms.personalizedLinks.destroy'); + }); // File operations - Route::middleware('can:manageFiles,room')->scopeBindings()->group(function () { + Route::middleware('can:manageFiles,room')->group(function () { Route::post('rooms/{room}/files', [RoomFileController::class, 'store'])->name('rooms.files.add'); Route::put('rooms/{room}/files/{file}', [RoomFileController::class, 'update'])->name('rooms.files.update'); Route::delete('rooms/{room}/files/{file}', [RoomFileController::class, 'destroy'])->name('rooms.files.destroy'); diff --git a/tests/Backend/Feature/api/v1/Room/MembershipTest.php b/tests/Backend/Feature/api/v1/Room/MembershipTest.php index 9b617cc0e..eb6e0eccf 100644 --- a/tests/Backend/Feature/api/v1/Room/MembershipTest.php +++ b/tests/Backend/Feature/api/v1/Room/MembershipTest.php @@ -767,42 +767,42 @@ public function test_remove_member() $room->members()->attach($memberCoOwner, ['role' => RoomUserRole::CO_OWNER]); // Remove member as guest - $this->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => $newUser])) + $this->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'member' => $newUser])) ->assertUnauthorized(); // Remove member as non owner - $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => $newUser])) + $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'member' => $newUser])) ->assertForbidden(); // Remove member as user member - $this->actingAs($memberUser)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => $newUser])) + $this->actingAs($memberUser)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'member' => $newUser])) ->assertForbidden(); // Remove member as moderator member - $this->actingAs($memberModerator)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => $newUser])) + $this->actingAs($memberModerator)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'member' => $newUser])) ->assertForbidden(); // Remove member as co-owner member - $this->actingAs($memberCoOwner)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => $newUser])) + $this->actingAs($memberCoOwner)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'member' => $newUser])) ->assertNoContent(); $room->members()->attach($newUser, ['role' => RoomUserRole::USER]); // Remove with view all rooms permission $this->user->roles()->attach($this->role); $this->role->permissions()->attach($this->viewAllPermission); - $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => $newUser])) + $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'member' => $newUser])) ->assertForbidden(); $this->role->permissions()->detach($this->viewAllPermission); // Remove with manage rooms permission $this->role->permissions()->attach($this->managePermission); - $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => $newUser])) + $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'member' => $newUser])) ->assertNoContent(); $this->role->permissions()->detach($this->managePermission); $room->members()->attach($newUser, ['role' => RoomUserRole::USER]); // Remove member with invalid user - $this->actingAs($owner)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => 0])) + $this->actingAs($owner)->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'member' => 0])) ->assertNotFound() ->assertJson([ 'message' => 'model_not_found', @@ -811,15 +811,20 @@ public function test_remove_member() ]); // Remove member as moderator - $this->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => $newUser])) + $this->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'member' => $newUser])) ->assertNoContent(); // Check member list $this->assertNull($room->members()->find($newUser)); // Try to remove user again - $this->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'user' => $newUser])) - ->assertStatus(410); + $this->deleteJson(route('api.v1.rooms.member.destroy', ['room' => $room, 'member' => $newUser])) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'user', + 'ids' => [$newUser->id], + ]); // Check if user is no member $this->actingAs($newUser)->getJson(route('api.v1.rooms.show', ['room' => $room])) @@ -863,50 +868,55 @@ public function test_change_member_role() $room->members()->attach($memberCoOwner, ['role' => RoomUserRole::CO_OWNER]); // Update with wrong role - $this->actingAs($owner)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'user' => $newUser]), ['role' => 10]) + $this->actingAs($owner)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'member' => $newUser]), ['role' => 10]) ->assertJsonValidationErrors(['role']); // Update role - $this->actingAs($owner)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'user' => $newUser]), ['role' => RoomUserRole::MODERATOR]) + $this->actingAs($owner)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'member' => $newUser]), ['role' => RoomUserRole::MODERATOR]) ->assertNoContent(); // Update role for wrong user - $this->actingAs($owner)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'user' => $otherUser]), ['role' => RoomUserRole::MODERATOR]) - ->assertStatus(410); + $this->actingAs($owner)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'member' => $otherUser]), ['role' => RoomUserRole::MODERATOR]) + ->assertNotFound() + ->assertJson([ + 'message' => 'model_not_found', + 'model' => 'user', + 'ids' => [$otherUser->id], + ]); // Check if member role is changed $foundNewUser = $room->members()->find($newUser); $this->assertEquals(RoomUserRole::MODERATOR, $foundNewUser->pivot->role); // Update role as member user - $this->actingAs($memberUser)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'user' => $newUser]), ['role' => RoomUserRole::MODERATOR]) + $this->actingAs($memberUser)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'member' => $newUser]), ['role' => RoomUserRole::MODERATOR]) ->assertForbidden(); // Update role as member moderator - $this->actingAs($memberModerator)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'user' => $newUser]), ['role' => RoomUserRole::MODERATOR]) + $this->actingAs($memberModerator)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'member' => $newUser]), ['role' => RoomUserRole::MODERATOR]) ->assertForbidden(); // Update role as member co-owner - $this->actingAs($memberCoOwner)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'user' => $newUser]), ['role' => RoomUserRole::MODERATOR]) + $this->actingAs($memberCoOwner)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'member' => $newUser]), ['role' => RoomUserRole::MODERATOR]) ->assertNoContent(); // Update role with view all rooms permission $this->user->roles()->attach($this->role); $this->role->permissions()->attach($this->viewAllPermission); - $this->actingAs($this->user)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'user' => $newUser]), ['role' => RoomUserRole::MODERATOR]) + $this->actingAs($this->user)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'member' => $newUser]), ['role' => RoomUserRole::MODERATOR]) ->assertForbidden(); $this->role->permissions()->detach($this->viewAllPermission); // Update role with manage rooms permission $this->role->permissions()->attach($this->managePermission); - $this->actingAs($this->user)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'user' => $newUser]), ['role' => RoomUserRole::MODERATOR]) + $this->actingAs($this->user)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'member' => $newUser]), ['role' => RoomUserRole::MODERATOR]) ->assertNoContent(); $this->role->permissions()->detach($this->managePermission); // Test with deleted room $room->delete(); - $this->actingAs($this->user)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'user' => $newUser]), ['role' => RoomUserRole::MODERATOR]) + $this->actingAs($this->user)->putJson(route('api.v1.rooms.member.update', ['room' => $room, 'member' => $newUser]), ['role' => RoomUserRole::MODERATOR]) ->assertNotFound() ->assertJson([ 'message' => 'model_not_found', diff --git a/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php b/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php index b83abc275..1b3519985 100644 --- a/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php +++ b/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php @@ -326,7 +326,7 @@ public function test_update() ]; // Update as guest - $this->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'link' => $link]), $payload) + $this->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'personalizedLink' => $link]), $payload) ->assertUnauthorized() ->assertJsonFragment(['message' => 'Unauthenticated.']); @@ -342,7 +342,7 @@ public function test_update() $this->putJson(route('api.v1.rooms.personalizedLinks.update', [ 'room' => $this->room, - 'link' => $link, + 'personalizedLink' => $link, 'room_auth_token' => $roomAuthToken->id, 'room_auth_token_type' => RoomAuthTokenType::PERSONALIZED_LINK->value, ]), $payload) @@ -351,7 +351,7 @@ public function test_update() // Update as moderator $this->room->members()->sync([$this->user->id => ['role' => RoomUserRole::MODERATOR]]); - $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => 1337, 'link' => $link]), $payload) + $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => 1337, 'personalizedLink' => $link]), $payload) ->assertNotFound() ->assertJson( [ @@ -360,12 +360,12 @@ public function test_update() 'ids' => [1337], ]); - $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'link' => $link]), $payload) + $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'personalizedLink' => $link]), $payload) ->assertForbidden(); // Update as co-owner invalid data $this->room->members()->sync([$this->user->id => ['role' => RoomUserRole::CO_OWNER]]); - $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'link' => $link]), $payload) + $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'personalizedLink' => $link]), $payload) ->assertJsonValidationErrors([ 'firstname', 'lastname', @@ -378,7 +378,7 @@ public function test_update() 'lastname' => $this->faker->lastName, 'role' => RoomUserRole::USER, ]; - $response = $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'link' => $link]), $payload) + $response = $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'personalizedLink' => $link]), $payload) ->assertSuccessful() ->assertJsonMissingValidationErrors([ 'firstname', @@ -393,7 +393,7 @@ public function test_update() 'lastname' => $this->faker->lastName, 'role' => RoomUserRole::USER, ]; - $response = $this->actingAs($this->room->owner)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'link' => $link]), $payload) + $response = $this->actingAs($this->room->owner)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'personalizedLink' => $link]), $payload) ->assertSuccessful() ->assertJsonMissingValidationErrors([ 'firstname', @@ -410,7 +410,7 @@ public function test_update() ]; $this->room->members()->sync([]); $this->user->roles()->attach(Role::where(['superuser' => true])->first()); - $response = $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'link' => $link]), $payload) + $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'personalizedLink' => $link]), $payload) ->assertSuccessful() ->assertJsonMissingValidationErrors([ 'firstname', @@ -419,13 +419,18 @@ public function test_update() ]); // Check trying to update with wrong room id - $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $otherRoom, 'link' => $link]), $payload) + $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $otherRoom, 'personalizedLink' => $link]), $payload) ->assertNotFound() - ->assertJsonFragment(['message' => __('app.errors.personalized_link_not_found')]); + ->assertJson( + [ + 'message' => 'model_not_found', + 'model' => 'room_personalized_link', + 'ids' => [$link->id], + ]); // Test deleted $link->delete(); - $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'link' => $link]), $payload) + $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'personalizedLink' => $link]), $payload) ->assertNotFound() ->assertJson( [ @@ -448,7 +453,7 @@ public function test_delete() ]); // Delete as guest - $this->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) + $this->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'personalizedLink' => $link])) ->assertUnauthorized() ->assertJsonFragment(['message' => 'Unauthenticated.']); @@ -464,7 +469,7 @@ public function test_delete() $this->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', [ 'room' => $this->room, - 'link' => $link, + 'personalizedLink' => $link, 'room_auth_token' => $roomAuthToken->id, 'room_auth_token_type' => RoomAuthTokenType::PERSONALIZED_LINK->value, ])) @@ -473,16 +478,16 @@ public function test_delete() // Delete as moderator $this->room->members()->sync([$this->user->id => ['role' => RoomUserRole::MODERATOR]]); - $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) + $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'personalizedLink' => $link])) ->assertForbidden(); // Delete as co-owner $this->room->members()->sync([$this->user->id => ['role' => RoomUserRole::CO_OWNER]]); - $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) + $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'personalizedLink' => $link])) ->assertSuccessful(); // Delete not existing - $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) + $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'personalizedLink' => $link])) ->assertNotFound() ->assertJson( [ @@ -495,9 +500,9 @@ public function test_delete() $link = RoomPersonalizedLink::factory()->create([ 'room_id' => $this->room, ]); - $this->actingAs($this->room->owner)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) + $this->actingAs($this->room->owner)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'personalizedLink' => $link])) ->assertSuccessful(); - $this->actingAs($this->room->owner)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) + $this->actingAs($this->room->owner)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'personalizedLink' => $link])) ->assertNotFound() ->assertJson( [ @@ -514,15 +519,20 @@ public function test_delete() ]); // Check trying to delete with wrong room id - $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $otherRoom, 'link' => $link])) + $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $otherRoom, 'personalizedLink' => $link])) ->assertNotFound() - ->assertJsonFragment(['message' => __('app.errors.personalized_link_not_found')]); + ->assertJson( + [ + 'message' => 'model_not_found', + 'model' => 'room_personalized_link', + 'ids' => [$link->id], + ]); - $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) + $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'personalizedLink' => $link])) ->assertSuccessful(); // Test delete again - $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) + $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'personalizedLink' => $link])) ->assertNotFound() ->assertJson( [ @@ -534,7 +544,7 @@ public function test_delete() // Test deleted room $this->room->delete(); - $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'link' => $link])) + $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'personalizedLink' => $link])) ->assertNotFound() ->assertJson( [ diff --git a/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js b/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js index 7869c0b38..0947f2ca6 100644 --- a/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewMembersMemberActions.cy.js @@ -580,9 +580,11 @@ describe("Rooms view members member actions", function () { // Check with member gone cy.intercept("PUT", "/api/v1/rooms/abc-def-123/member/5", { - statusCode: 410, + statusCode: 404, body: { - message: "The person is not a member of this room (anymore).", + message: "model_not_found", + model: "user", + ids: [5], }, }).as("editUserRequest"); @@ -610,10 +612,7 @@ describe("Rooms view members member actions", function () { cy.get('[data-test="room-member-item"]').should("have.length", 2); // Check that error message is shown - cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"The person is not a member of this room (anymore)."}', - 'app.flash.server_error.error_code_{"statusCode":410}', - ]); + cy.checkToastMessage("app.errors.not_member_of_room"); // Check with 422 error cy.get('[data-test="room-member-item"]') @@ -808,9 +807,11 @@ describe("Rooms view members member actions", function () { // Check delete with member gone cy.intercept("DELETE", "/api/v1/rooms/abc-def-123/member/5", { - statusCode: 410, + statusCode: 404, body: { - message: "The person is not a member of this room (anymore).", + message: "model_not_found", + model: "user", + ids: [5], }, }).as("deleteMemberRequest"); @@ -836,10 +837,7 @@ describe("Rooms view members member actions", function () { cy.get('[data-test="room-member-item"]').should("have.length", 2); // Check that error message is shown - cy.checkToastMessage([ - 'app.flash.server_error.message_{"message":"The person is not a member of this room (anymore)."}', - 'app.flash.server_error.error_code_{"statusCode":410}', - ]); + cy.checkToastMessage("app.errors.not_member_of_room"); // Check with 500 error cy.get('[data-test="room-member-item"]') diff --git a/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js b/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js index 380333e97..8cdf74b72 100644 --- a/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js +++ b/tests/Frontend/e2e/RoomsViewPersonalizedLinksTokenActions.cy.js @@ -432,7 +432,9 @@ describe("Rooms view personalized links actions", function () { cy.intercept("PUT", "/api/v1/rooms/abc-def-123/personalizedLinks/3", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "room_personalized_link", + ids: [3], }, }).as("editLinkRequest"); @@ -706,7 +708,9 @@ describe("Rooms view personalized links actions", function () { cy.intercept("DELETE", "/api/v1/rooms/abc-def-123/personalizedLinks/3", { statusCode: 404, body: { - message: "No query results for model", + message: "model_not_found", + model: "room_personalized_link", + ids: [3], }, }).as("deleteLinkRequest"); From f31f2c4672b447a68d1bc93da5d228f6bbeec37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:38:55 +0200 Subject: [PATCH 12/18] Add missing model translations --- lang/en/app.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lang/en/app.php b/lang/en/app.php index c3bc93621..eee5aaf70 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -101,18 +101,36 @@ 'fr' => 'French', ], 'model' => [ + 'included_permission_permission' => 'Included permission', 'meeting' => 'Meeting', + 'meeting_attendee' => 'Meeting attendee', + 'meeting_stat' => 'Meeting stat', + 'permission' => 'Permission', + 'permission_role' => 'Permission role', + 'recording' => 'Recording', + 'recording_format' => 'Recording format', 'role' => 'Role', + 'role_user' => 'Role user', 'roles' => 'role', 'room' => 'Room', + 'room_auth_token' => 'Room auth token', + 'room_file' => 'Room file', + 'room_personalized_link' => 'Room personalized link', + 'room_streaming' => 'Room streaming', 'room_type' => 'Room type', 'room_types' => 'room type', + 'room_type_streaming_settings' => 'Room type streaming settings', + 'room_user' => 'Room user', 'server' => 'Server', 'server_pool' => 'Server pool', 'server_pools' => 'server pool', + 'server_stat' => 'Server stat', + 'session' => 'Session', + 'session_data' => 'Session data', 'servers' => 'server', 'user' => 'User', 'users' => 'user', + 'verify_email' => 'Verify Email', ], 'model_name' => 'Name', 'next' => 'Next', From fa24bdc2684bf0d20304f67b1a50f90591ca5ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:43:39 +0200 Subject: [PATCH 13/18] Remove custom 404 handling for server connection check --- resources/js/views/AdminServersView.vue | 4 ---- 1 file changed, 4 deletions(-) diff --git a/resources/js/views/AdminServersView.vue b/resources/js/views/AdminServersView.vue index 4a0b85848..1a57f8abb 100644 --- a/resources/js/views/AdminServersView.vue +++ b/resources/js/views/AdminServersView.vue @@ -521,10 +521,6 @@ function testConnection() { health.value = null; offlineReason.value = null; - if (error.response && error.response.status === env.HTTP_NOT_FOUND) { - router.push({ name: "admin.servers" }); - } - api.error(error); }) .finally(() => { From fb9b10a123cdc2af9784361060cd7235e896829a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:55:17 +0200 Subject: [PATCH 14/18] Cleanup backend tests --- .../Backend/Feature/api/v1/RecordingTest.php | 12 ---- .../Backend/Feature/api/v1/Room/FileTest.php | 25 ------- .../Feature/api/v1/Room/MembershipTest.php | 68 ------------------- .../api/v1/Room/RoomPersonalizedLinkTest.php | 24 +++---- .../Feature/api/v1/Room/RoomStatisticTest.php | 11 --- 5 files changed, 12 insertions(+), 128 deletions(-) diff --git a/tests/Backend/Feature/api/v1/RecordingTest.php b/tests/Backend/Feature/api/v1/RecordingTest.php index da80e5a66..525729b5d 100644 --- a/tests/Backend/Feature/api/v1/RecordingTest.php +++ b/tests/Backend/Feature/api/v1/RecordingTest.php @@ -1261,18 +1261,6 @@ public function test_delete() 'model' => 'recording', 'ids' => [$recording->id], ]); - - // Test with deleted room - $room->delete(); - - $this->actingAs($room->owner) - ->deleteJson(route('api.v1.rooms.recordings.destroy', ['room' => $room->id, 'recording' => $recording->id])) - ->assertNotFound() - ->assertJson([ - 'message' => 'model_not_found', - 'model' => 'room', - 'ids' => [$room->id], - ]); } public function test_delete_on_room_delete() diff --git a/tests/Backend/Feature/api/v1/Room/FileTest.php b/tests/Backend/Feature/api/v1/Room/FileTest.php index 68538c75d..5eb509afb 100644 --- a/tests/Backend/Feature/api/v1/Room/FileTest.php +++ b/tests/Backend/Feature/api/v1/Room/FileTest.php @@ -350,18 +350,6 @@ public function test_view_files() ->assertJsonCount(0, 'data') ->assertJsonPath('meta.total', 0) ->assertJsonPath('meta.total_no_filter', 3); - - // Test deleted room - $this->room->delete(); - - $this->actingAs($this->room->owner) - ->getJson(route('api.v1.rooms.files.get', ['room' => $this->room, 'query' => 'test'])) - ->assertNotFound() - ->assertJson([ - 'message' => 'model_not_found', - 'model' => 'room', - 'ids' => [$this->room->id], - ]); } /** @@ -1102,19 +1090,6 @@ public function test_files_delete() // Check if file was deleted as well Storage::disk('local')->assertMissing($this->room->id.'/'.$this->file_valid->hashName()); - - // Test delete with deleted room - $this->room->delete(); - - $this->actingAs($this->room->owner)->deleteJson(route('api.v1.rooms.files.destroy', ['room' => $this->room->id, 'file' => $room_file])) - ->assertNotFound() - ->assertJson([ - 'message' => 'model_not_found', - 'model' => 'room', - 'ids' => [ - $this->room->id, - ], - ]); } /** diff --git a/tests/Backend/Feature/api/v1/Room/MembershipTest.php b/tests/Backend/Feature/api/v1/Room/MembershipTest.php index fa6d42d23..51fe6241a 100644 --- a/tests/Backend/Feature/api/v1/Room/MembershipTest.php +++ b/tests/Backend/Feature/api/v1/Room/MembershipTest.php @@ -632,17 +632,6 @@ public function test_member_list() $this->actingAs($room->owner)->getJson(route('api.v1.rooms.member.get', ['room' => $room, 'filter' => 'invalid_role'])) ->assertJsonCount(5, 'data') ->assertJsonPath('meta.total', 6); - - // Test deleted room - $room->delete(); - - $this->actingAs($room->owner)->getJson(route('api.v1.rooms.member.get', ['room' => $room, 'filter' => 'invalid_role'])) - ->assertNotFound() - ->assertJson([ - 'message' => 'model_not_found', - 'model' => 'room', - 'ids' => [$room->id], - ]); } /** @@ -732,17 +721,6 @@ public function test_add_member() $this->actingAs($this->user)->postJson(route('api.v1.rooms.member.add', ['room' => $room]), ['user' => $newUser->id, 'role' => RoomUserRole::USER]) ->assertNoContent(); $this->role->permissions()->detach($this->managePermission); - - // Test with deleted room - $room->delete(); - - $this->actingAs($owner)->postJson(route('api.v1.rooms.member.add', ['room' => $room]), ['user' => $newUser->id, 'role' => RoomUserRole::USER]) - ->assertNotFound() - ->assertJson([ - 'message' => 'model_not_found', - 'model' => 'room', - 'ids' => [$room->id], - ]); } /** @@ -832,17 +810,6 @@ public function test_remove_member() $this->actingAs($newUser)->getJson(route('api.v1.rooms.show', ['room' => $room])) ->assertStatus(200) ->assertJsonFragment(['is_member' => false]); - - // Remove member of deleted room - $room->delete(); - - $this->actingAs($newUser)->getJson(route('api.v1.rooms.show', ['room' => $room])) - ->assertNotFound() - ->assertJson([ - 'message' => 'model_not_found', - 'model' => 'room', - 'ids' => [$room->id], - ]); } /** @@ -1083,17 +1050,6 @@ public function test_bulk_import_members() $this->actingAs($this->user)->postJson(route('api.v1.rooms.member.bulkImport', ['room' => $room]), ['user_emails' => [$newUser->email], 'role' => RoomUserRole::USER]) ->assertNoContent(); $this->role->permissions()->detach($this->managePermission); - - // Test with deleted room - $room->delete(); - - $this->actingAs($owner)->postJson(route('api.v1.rooms.member.bulkImport', ['room' => $room]), ['user_emails' => [$newUser->email], 'role' => RoomUserRole::USER]) - ->assertNotFound() - ->assertJson([ - 'message' => 'model_not_found', - 'model' => 'room', - 'ids' => [$room->id], - ]); } public function test_bulk_update_members() @@ -1245,19 +1201,6 @@ public function test_bulk_update_members() route('api.v1.rooms.member.bulkUpdate', ['room' => $room]), ['users' => [$memberUser->id], 'role' => RoomUserRole::MODERATOR] )->assertForbidden(); - - // Test with deleted room - $room->delete(); - - $this->actingAs($owner)->putJson( - route('api.v1.rooms.member.bulkUpdate', ['room' => $room]), - ['users' => [$memberUser->id], 'role' => RoomUserRole::MODERATOR] - )->assertNotFound() - ->assertJson([ - 'message' => 'model_not_found', - 'model' => 'room', - 'ids' => [$room->id], - ]); } public function test_bulk_remove_members() @@ -1355,16 +1298,5 @@ public function test_bulk_remove_members() // Remove yourself as co-owner $this->actingAs($memberCoOwner)->deleteJson(route('api.v1.rooms.member.bulkDestroy', ['room' => $room]), ['users' => [$memberUser->id, $memberCoOwner->id]]) ->assertUnprocessable(); - - // Test with deleted room - $room->delete(); - - $this->actingAs($owner)->deleteJson(route('api.v1.rooms.member.bulkDestroy', ['room' => $room]), ['users' => [$memberUser->id]]) - ->assertNotFound() - ->assertJson([ - 'message' => 'model_not_found', - 'model' => 'room', - 'ids' => [$room->id], - ]); } } diff --git a/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php b/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php index 7b3d21a3b..c63cb5cde 100644 --- a/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php +++ b/tests/Backend/Feature/api/v1/Room/RoomPersonalizedLinkTest.php @@ -440,6 +440,18 @@ public function test_update() 'model' => 'room_personalized_link', 'ids' => [$link->id], ]); + + // Test deleted room + $this->room->delete(); + + $this->actingAs($this->user)->putJson(route('api.v1.rooms.personalizedLinks.update', ['room' => $this->room, 'personalizedLink' => $link]), $payload) + ->assertNotFound() + ->assertJson( + [ + 'message' => 'model_not_found', + 'model' => 'room', + 'ids' => [$this->room->id], + ]); } public function test_delete() @@ -542,17 +554,5 @@ public function test_delete() 'model' => 'room_personalized_link', 'ids' => [$link->id], ]); - - // Test deleted room - $this->room->delete(); - - $this->actingAs($this->user)->deleteJson(route('api.v1.rooms.personalizedLinks.destroy', ['room' => $this->room, 'personalizedLink' => $link])) - ->assertNotFound() - ->assertJson( - [ - 'message' => 'model_not_found', - 'model' => 'room', - 'ids' => [$this->room->id], - ]); } } diff --git a/tests/Backend/Feature/api/v1/Room/RoomStatisticTest.php b/tests/Backend/Feature/api/v1/Room/RoomStatisticTest.php index 8cf12c956..ef6788e49 100644 --- a/tests/Backend/Feature/api/v1/Room/RoomStatisticTest.php +++ b/tests/Backend/Feature/api/v1/Room/RoomStatisticTest.php @@ -181,17 +181,6 @@ public function test_meeting_list() $this->actingAs($room->owner)->getJson(route('api.v1.rooms.meetings', ['room' => $room]).'?sort_direction=invalid') ->assertSuccessful() ->assertJsonPath('data.0.id', $meetings[0]->id); - - // Test deleted room - $room->delete(); - - $this->actingAs($room->owner)->getJson(route('api.v1.rooms.meetings', ['room' => $room]).'?sort_direction=invalid') - ->assertNotFound() - ->assertJson([ - 'message' => 'model_not_found', - 'model' => 'room', - 'ids' => [$room->id], - ]); } /** From 8c048e43d7daaf0d49c67a0c29c1fb3d04550fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Fri, 10 Apr 2026 16:36:01 +0200 Subject: [PATCH 15/18] Code cleanup --- lang/en/app.php | 2 +- tests/Frontend/e2e/RoomsViewGeneral.cy.js | 2 +- tests/Frontend/e2e/RoomsViewSettings.cy.js | 8 ++++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lang/en/app.php b/lang/en/app.php index eee5aaf70..b01ede5b5 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -68,7 +68,7 @@ 'guests_only' => 'The request can only be made by guests!', 'model_not_found' => [ 'title' => 'The :model was not found!', - 'details' => ' Model id: :ids', + 'details' => 'Model id: :ids', ], 'server_error' => [ 'empty_message' => 'An error occurred on the server during request!', diff --git a/tests/Frontend/e2e/RoomsViewGeneral.cy.js b/tests/Frontend/e2e/RoomsViewGeneral.cy.js index 6b608b718..695e8e619 100644 --- a/tests/Frontend/e2e/RoomsViewGeneral.cy.js +++ b/tests/Frontend/e2e/RoomsViewGeneral.cy.js @@ -724,7 +724,7 @@ describe("Room View general", function () { 'app.flash.model_not_found.details_{"ids":"abc-def-123"}', ]); - // Check wit 404 error (room not found) as guest + // Check with 404 error (room not found) as guest cy.intercept("GET", "api/v1/currentUser", {}); cy.fixture("room.json").then((room) => { room.data.current_user = null; diff --git a/tests/Frontend/e2e/RoomsViewSettings.cy.js b/tests/Frontend/e2e/RoomsViewSettings.cy.js index 0b8ada4ab..2bb2bd1ef 100644 --- a/tests/Frontend/e2e/RoomsViewSettings.cy.js +++ b/tests/Frontend/e2e/RoomsViewSettings.cy.js @@ -1402,6 +1402,8 @@ describe("Rooms view settings", function () { cy.get('[data-test="room-settings-save-button"]').click(); + cy.wait("@roomSettingsSaveRequest"); + // Check that error messages are set cy.get('[data-test="room-setting-access_code"]').should( "include.text", @@ -1695,7 +1697,7 @@ describe("Rooms view settings", function () { model: "room", ids: ["abc-def-123"], }, - }); + }).as("roomSettingsSaveRequest"); cy.get('[data-test="room-settings-save-button"]').click(); @@ -2370,7 +2372,9 @@ describe("Rooms view settings", function () { cy.wait("@transferOwnershipRequest"); // Check that redirect to room index page worked and error message is shown - cy.url().should("include", "/rooms"); + cy.url() + .should("include", "/rooms") + .and("not.include", "rooms/abc-def-123"); cy.checkToastMessage([ 'app.flash.model_not_found.title_{"model":"app.model.room"}', From 256bf30993ebae6b8b69ccf8cc4a1487f316fd9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Mon, 13 Apr 2026 17:43:52 +0200 Subject: [PATCH 16/18] Code cleanup --- lang/en/app.php | 2 +- resources/js/views/RoomsView.vue | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lang/en/app.php b/lang/en/app.php index b01ede5b5..33a4c3e13 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -68,7 +68,7 @@ 'guests_only' => 'The request can only be made by guests!', 'model_not_found' => [ 'title' => 'The :model was not found!', - 'details' => 'Model id: :ids', + 'details' => 'Ids: :ids', ], 'server_error' => [ 'empty_message' => 'An error occurred on the server during request!', diff --git a/resources/js/views/RoomsView.vue b/resources/js/views/RoomsView.vue index 0b3036066..911886698 100644 --- a/resources/js/views/RoomsView.vue +++ b/resources/js/views/RoomsView.vue @@ -439,7 +439,7 @@ function load() { }) .catch((error) => { if (error.response) { - // Room not found (Always redirect to 404 view) + // Room not found (Always redirect to 404 view or room index page) if (error.response.status === env.HTTP_NOT_FOUND) { if (authStore.isAuthenticated) { router.push({ name: "rooms.index" }); @@ -521,7 +521,7 @@ function reload() { }) .catch((error) => { if (error.response) { - // Room not found (Always redirect to 404 view) + // Room not found (Always redirect to 404 view or room index page) if (error.response.status === env.HTTP_NOT_FOUND) { if (authStore.isAuthenticated) { router.push({ name: "rooms.index" }); From d9c60023f48e36025af578f6b9a0dd3ff8fb4010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:30:36 +0200 Subject: [PATCH 17/18] Cleanup model translations --- lang/en/app.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lang/en/app.php b/lang/en/app.php index 33a4c3e13..fe001afa4 100644 --- a/lang/en/app.php +++ b/lang/en/app.php @@ -101,36 +101,22 @@ 'fr' => 'French', ], 'model' => [ - 'included_permission_permission' => 'Included permission', 'meeting' => 'Meeting', - 'meeting_attendee' => 'Meeting attendee', - 'meeting_stat' => 'Meeting stat', - 'permission' => 'Permission', - 'permission_role' => 'Permission role', 'recording' => 'Recording', 'recording_format' => 'Recording format', 'role' => 'Role', - 'role_user' => 'Role user', 'roles' => 'role', 'room' => 'Room', - 'room_auth_token' => 'Room auth token', 'room_file' => 'Room file', 'room_personalized_link' => 'Room personalized link', - 'room_streaming' => 'Room streaming', 'room_type' => 'Room type', 'room_types' => 'room type', - 'room_type_streaming_settings' => 'Room type streaming settings', - 'room_user' => 'Room user', 'server' => 'Server', 'server_pool' => 'Server pool', 'server_pools' => 'server pool', - 'server_stat' => 'Server stat', - 'session' => 'Session', - 'session_data' => 'Session data', 'servers' => 'server', 'user' => 'User', 'users' => 'user', - 'verify_email' => 'Verify Email', ], 'model_name' => 'Name', 'next' => 'Next', From 44f93870b03224077f2b77d8587795e8f5bf3357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sabrina=20W=C3=BCst?= <119059706+Sabr1n4W@users.noreply.github.com> Date: Fri, 17 Apr 2026 16:22:49 +0200 Subject: [PATCH 18/18] Update changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdeced3b7..98b8d72ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Changed + +- 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.1] - 2026-04-09 ### Changed @@ -534,6 +540,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 @@ -630,6 +637,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 @@ -763,6 +771,7 @@ You can find the changelog for older versions there [here](https://github.com/TH [#3014]: https://github.com/THM-Health/PILOS/pull/3014 [#3028]: https://github.com/THM-Health/PILOS/issues/3028 [#3029]: https://github.com/THM-Health/PILOS/pull/3029 +[#3036]: https://github.com/THM-Health/PILOS/pull/3036 [unreleased]: https://github.com/THM-Health/PILOS/compare/v4.14.1...develop [v3.0.0]: https://github.com/THM-Health/PILOS/releases/tag/v3.0.0 [v3.0.1]: https://github.com/THM-Health/PILOS/releases/tag/v3.0.1