From e072e3c042c600e3f1986d2f91e3d957a1934105 Mon Sep 17 00:00:00 2001
From: Hangzhi Yu <hangzhi@protonmail.com>
Date: Fri, 27 Jan 2023 14:59:24 +0100
Subject: [PATCH] Improve error page when a user attempts to access a route
 without the needed permissions

---
 CHANGELOG.rst                                  |  1 +
 aleksis/core/frontend/components/app/App.vue   | 15 ++++++++++-----
 .../core/frontend/components/app/ErrorPage.vue | 18 +++++++++++++++---
 aleksis/core/frontend/messages/en.json         |  4 +++-
 aleksis/core/frontend/routes.js                |  3 +++
 5 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index a31cc8000..dab1fa280 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -45,6 +45,7 @@ Changed
 * [Dev] The undocumented field `check` on `DataCheckResult` was renamed to `data_check`
 * Frontend bundling migrated from Webpack to Vite
 * Get dashboard widgets and data checks from apps with new registration mechanism.
+* Better error page with redirect option to login page when user has no permission to access a route.
 
 Fixed
 ~~~~~
diff --git a/aleksis/core/frontend/components/app/App.vue b/aleksis/core/frontend/components/app/App.vue
index c86e5910a..2820496dc 100644
--- a/aleksis/core/frontend/components/app/App.vue
+++ b/aleksis/core/frontend/components/app/App.vue
@@ -86,19 +86,22 @@
 
           <router-view
             v-if="
-              !$route.meta.permission || checkPermission($route.meta.permission)
+              !$route.meta.permission || checkPermission($route.meta.permission) || $route.name === 'dashboard'
             "
           />
-          <message-box
-            type="error"
+          <error-page
             v-else-if="
               whoAmI &&
               !$apollo.queries.whoAmI.loading &&
               !checkPermission($route.meta.permission)
             "
+            short-error-message-key="base.no_permission_message_short"
+            long-error-message-key="base.no_permission_message_long"
+            redirect-button-text-key="base.no_permission_redirect_text"
+            redirect-route-name="core.account.login"
+            redirect-button-icon="mdi-login-variant"
           >
-            {{ $t("base.no_permission") }}
-          </message-box>
+          </error-page>
         </v-container>
       </v-main>
 
@@ -205,6 +208,7 @@ import CeleryProgressBottom from "../celery_progress/CeleryProgressBottom.vue";
 import Splash from "./Splash.vue";
 import SideNav from "./SideNav.vue";
 import SnackbarItem from "./SnackbarItem.vue";
+import ErrorPage from "./ErrorPage.vue";
 
 import gqlWhoAmI from "./whoAmI.graphql";
 import gqlMessages from "./messages.graphql";
@@ -263,6 +267,7 @@ export default {
   components: {
     AccountMenu,
     BroadcastChannelNotification,
+    ErrorPage,
     NotificationList,
     CeleryProgressBottom,
     Splash,
diff --git a/aleksis/core/frontend/components/app/ErrorPage.vue b/aleksis/core/frontend/components/app/ErrorPage.vue
index abbf6a6cd..abfb51fd0 100644
--- a/aleksis/core/frontend/components/app/ErrorPage.vue
+++ b/aleksis/core/frontend/components/app/ErrorPage.vue
@@ -5,9 +5,9 @@
   >
     <h1 class="text-h2">{{ $t(shortErrorMessageKey) }}</h1>
     <div>{{ $t(longErrorMessageKey) }}</div>
-    <v-btn color="secondary" :to="{ name: 'dashboard' }">
-      <v-icon left>mdi-home-outline</v-icon>
-      {{ $t("network_errors.back_to_start") }}
+    <v-btn color="secondary" :to="{ name: redirectRouteName }">
+      <v-icon left>{{ redirectButtonIcon }}</v-icon>
+      {{ $t(redirectButtonTextKey) }}
     </v-btn>
   </div>
 </template>
@@ -24,6 +24,18 @@ export default {
       type: String,
       required: true,
     },
+    redirectButtonTextKey: {
+      type: String,
+      required: true,
+    },
+    redirectRouteName: {
+      type: String,
+      required: true,
+    },
+    redirectButtonIcon: {
+      type: String,
+      required: true,
+    },
   },
 };
 </script>
diff --git a/aleksis/core/frontend/messages/en.json b/aleksis/core/frontend/messages/en.json
index 07c1c5a15..1ae46aa91 100644
--- a/aleksis/core/frontend/messages/en.json
+++ b/aleksis/core/frontend/messages/en.json
@@ -77,7 +77,9 @@
     "person_is_dummy": "Your administrator account is not linked to any person. Therefore, a dummy person has been linked to your account.",
     "privacy_policy": "Privacy Policy",
     "user_not_linked_to_person": "Your user account is not linked to a person. This means you cannot access any school-related information. Please contact the managers of AlekSIS at your school.",
-    "no_permission": "You have no permission to view this page. Please login with an other account.",
+    "no_permission_message_long": "You have no permission to view this page. Please login with an other account.",
+    "no_permission_message_short": "No permission",
+    "no_permission_redirect_text": "Go to login",
     "logo": "Logo"
   },
   "celery_progress": {
diff --git a/aleksis/core/frontend/routes.js b/aleksis/core/frontend/routes.js
index 567f770b3..225bbef90 100644
--- a/aleksis/core/frontend/routes.js
+++ b/aleksis/core/frontend/routes.js
@@ -1072,6 +1072,9 @@ routes.push({
   props: {
     shortErrorMessageKey: "network_errors.error_404",
     longErrorMessageKey: "network_errors.page_not_found",
+    redirectButtonTextKey: "network_errors.back_to_start",
+    redirectRouteName: "dashboard",
+    redirectButtonIcon: "mdi-home-outline",
   },
 });
 
-- 
GitLab