Merge branch 'dev' into feat/assignment-page
This commit is contained in:
commit
9dcc1091cc
20 changed files with 148 additions and 53 deletions
|
@ -10,10 +10,6 @@
|
|||
}
|
||||
|
||||
const showMenuBar = computed(() => (route.meta as RouteMeta).requiresAuth && auth.authState.user);
|
||||
|
||||
auth.loadUser().catch((_error) => {
|
||||
// TODO Could not load user!
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
import auth from "@/services/auth/auth-service.ts";
|
||||
|
||||
|
@ -10,6 +11,7 @@
|
|||
const { t, locale } = useI18n();
|
||||
|
||||
const role = auth.authState.activeRole;
|
||||
const router = useRouter();
|
||||
|
||||
const name = ref(auth.authState.user!.profile.name!);
|
||||
const initials: string = name.value
|
||||
|
|
|
@ -88,6 +88,9 @@
|
|||
"sent": "sent",
|
||||
"failed": "fehlgeschlagen",
|
||||
"wrong": "etwas ist schief gelaufen",
|
||||
"created": "erstellt",
|
||||
"callbackLoading": "Sie werden angemeldet...",
|
||||
"loginUnexpectedError": "Anmeldung fehlgeschlagen",
|
||||
"submitSolution": "Lösung einreichen",
|
||||
"submitNewSolution": "Neue Lösung einreichen",
|
||||
"markAsDone": "Als fertig markieren",
|
||||
|
@ -107,8 +110,8 @@
|
|||
"created": "erstellt",
|
||||
"remove": "entfernen",
|
||||
"students": "Studenten",
|
||||
"classJoinRequests": "Anfragen verbinden",
|
||||
"reject": "zurückweisen",
|
||||
"classJoinRequests": "Beitrittsanfragen",
|
||||
"reject": "ablehnen",
|
||||
"areusure": "Sind Sie sicher?",
|
||||
"yes": "ja",
|
||||
"teachers": "Lehrer",
|
||||
|
@ -117,4 +120,3 @@
|
|||
"enterUsername": "Geben Sie den Benutzernamen der Lehrkraft ein, die Sie einladen möchten",
|
||||
"username": "Nutzername",
|
||||
"invite": "einladen"
|
||||
}
|
||||
|
|
|
@ -88,6 +88,9 @@
|
|||
"sent": "sent",
|
||||
"failed": "failed",
|
||||
"wrong": "something went wrong",
|
||||
"created": "created",
|
||||
"callbackLoading": "You are being logged in...",
|
||||
"loginUnexpectedError": "Login failed",
|
||||
"submitSolution": "Submit solution",
|
||||
"submitNewSolution": "Submit new solution",
|
||||
"markAsDone": "Mark as completed",
|
||||
|
|
|
@ -89,6 +89,8 @@
|
|||
"failed": "échoué",
|
||||
"wrong": "quelque chose n'a pas fonctionné",
|
||||
"created": "créé",
|
||||
"callbackLoading": "Vous serez connecté...",
|
||||
"loginUnexpectedError": "La connexion a échoué",
|
||||
"submitSolution": "Soumettre la solution",
|
||||
"submitNewSolution": "Soumettre une nouvelle solution",
|
||||
"markAsDone": "Marquer comme terminé",
|
||||
|
|
|
@ -89,6 +89,8 @@
|
|||
"failed": "mislukt",
|
||||
"wrong": "er ging iets verkeerd",
|
||||
"created": "gecreëerd",
|
||||
"callbackLoading": "Je wordt ingelogd...",
|
||||
"loginUnexpectedError": "Inloggen mislukt",
|
||||
"submitSolution": "Oplossing indienen",
|
||||
"submitNewSolution": "Nieuwe oplossing indienen",
|
||||
"markAsDone": "Markeren als afgewerkt",
|
||||
|
|
|
@ -12,9 +12,11 @@ import App from "./App.vue";
|
|||
import router from "./router";
|
||||
import { aliases, mdi } from "vuetify/iconsets/mdi";
|
||||
import { VueQueryPlugin, QueryClient } from "@tanstack/vue-query";
|
||||
import authService from "./services/auth/auth-service.ts";
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
await authService.loadUser();
|
||||
app.use(router);
|
||||
|
||||
const link = document.createElement("link");
|
||||
|
|
|
@ -142,9 +142,8 @@ const router = createRouter({
|
|||
router.beforeEach(async (to, _from, next) => {
|
||||
// Verify if user is logged in before accessing certain routes
|
||||
if (to.meta.requiresAuth) {
|
||||
if (!authState.isLoggedIn.value) {
|
||||
//Next("/login");
|
||||
next();
|
||||
if (!authService.isLoggedIn.value) {
|
||||
next("/login");
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ async function getUserManagers(): Promise<UserManagersForRoles> {
|
|||
const authState = reactive<AuthState>({
|
||||
user: null,
|
||||
accessToken: null,
|
||||
activeRole: authStorage.getActiveRole() || null,
|
||||
activeRole: authStorage.getActiveRole() ?? null,
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -38,18 +38,38 @@ async function loadUser(): Promise<User | null> {
|
|||
return null;
|
||||
}
|
||||
const user = await (await getUserManagers())[activeRole].getUser();
|
||||
authState.user = user;
|
||||
authState.accessToken = user?.access_token || null;
|
||||
authState.activeRole = activeRole || null;
|
||||
setUserAuthInfo(user);
|
||||
authState.activeRole = activeRole ?? null;
|
||||
return user;
|
||||
}
|
||||
|
||||
const isLoggedIn = computed(() => authState.user !== null);
|
||||
|
||||
/**
|
||||
* Clears all the cached information about the current authentication.
|
||||
*/
|
||||
function clearAuthState(): void {
|
||||
authStorage.deleteActiveRole();
|
||||
authState.accessToken = null;
|
||||
authState.user = null;
|
||||
authState.activeRole = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the information about the currently logged-in user in the cache.
|
||||
*/
|
||||
function setUserAuthInfo(newUser: User | null): void {
|
||||
authState.user = newUser;
|
||||
authState.accessToken = newUser?.access_token ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect the user to the login page where he/she can choose whether to log in as a student or teacher.
|
||||
*/
|
||||
async function initiateLogin(): Promise<void> {
|
||||
if (isLoggedIn.value) {
|
||||
clearAuthState();
|
||||
}
|
||||
await router.push(loginRoute);
|
||||
}
|
||||
|
||||
|
@ -72,6 +92,7 @@ async function handleLoginCallback(): Promise<void> {
|
|||
throw new Error("Login callback received, but the user is not logging in!");
|
||||
}
|
||||
authState.user = (await (await getUserManagers())[activeRole].signinCallback()) || null;
|
||||
await apiClient.post("/auth/hello");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,14 +101,14 @@ async function handleLoginCallback(): Promise<void> {
|
|||
async function renewToken(): Promise<User | null> {
|
||||
const activeRole = authStorage.getActiveRole();
|
||||
if (!activeRole) {
|
||||
// FIXME console.log("Can't renew the token: Not logged in!");
|
||||
await initiateLogin();
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return await (await getUserManagers())[activeRole].signinSilent();
|
||||
} catch (_error) {
|
||||
// FIXME console.log("Can't renew the token: " + error);
|
||||
const userManagerForRole = (await getUserManagers())[activeRole];
|
||||
const user = await userManagerForRole.signinSilent();
|
||||
setUserAuthInfo(user);
|
||||
} catch (_error: unknown) {
|
||||
await initiateLogin();
|
||||
}
|
||||
return null;
|
||||
|
@ -101,6 +122,7 @@ async function logout(): Promise<void> {
|
|||
if (activeRole) {
|
||||
await (await getUserManagers())[activeRole].signoutRedirect();
|
||||
authStorage.deleteActiveRole();
|
||||
clearAuthState();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,13 +141,15 @@ apiClient.interceptors.request.use(
|
|||
// Registering interceptor to refresh the token when a request failed because it was expired.
|
||||
apiClient.interceptors.response.use(
|
||||
(response) => response,
|
||||
async (error: AxiosError<{ message?: string }>) => {
|
||||
async (error: AxiosError<{ message?: string; inner?: { message?: string } }>) => {
|
||||
if (error.response?.status === 401) {
|
||||
if (error.response.data.message === "token_expired") {
|
||||
// FIXME console.log("Access token expired, trying to refresh...");
|
||||
// If the user should already be logged in, his token is probably just expired.
|
||||
if (isLoggedIn.value) {
|
||||
await renewToken();
|
||||
return apiClient(error.config!); // Retry the request
|
||||
} // Apparently, the user got a 401 because he was not logged in yet at all. Redirect him to login.
|
||||
}
|
||||
|
||||
// Apparently, the user got a 401 because he was not logged in yet at all. Redirect him to login.
|
||||
await initiateLogin();
|
||||
}
|
||||
return Promise.reject(error);
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import { useRouter } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { onMounted, ref, type Ref } from "vue";
|
||||
import auth from "../services/auth/auth-service.ts";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const errorMessage: Ref<string | null> = ref(null);
|
||||
|
@ -12,14 +15,34 @@
|
|||
await auth.handleLoginCallback();
|
||||
await router.replace("/user"); // Redirect to theme page
|
||||
} catch (error) {
|
||||
errorMessage.value = `OIDC callback error: ${error}`;
|
||||
errorMessage.value = `${t("loginUnexpectedError")}: ${error}`;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p v-if="!errorMessage">Logging you in...</p>
|
||||
<p v-else>{{ errorMessage }}</p>
|
||||
<div class="callback">
|
||||
<div
|
||||
class="callback-loading"
|
||||
v-if="!errorMessage"
|
||||
>
|
||||
<v-progress-circular indeterminate></v-progress-circular>
|
||||
<p>{{ t("callbackLoading") }}</p>
|
||||
</div>
|
||||
<v-alert
|
||||
icon="mdi-alert-circle"
|
||||
type="error"
|
||||
variant="elevated"
|
||||
v-if="errorMessage"
|
||||
>
|
||||
{{ errorMessage }}
|
||||
</v-alert>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.callback {
|
||||
text-align: center;
|
||||
margin: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue