From d63f69645ed25e25b36e5e9cba7f3270f59d6119 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adam=20Roso=C5=82owski?=
<87621210+rr-adam@users.noreply.github.com>
Date: Mon, 9 Sep 2024 11:47:57 +0200
Subject: [PATCH 1/2] GitHub login flow
---
general/components/Header/AuthLoginModal.vue | 37 ++++++
general/pages/connect/github.vue | 128 +++++++++++++++++++
2 files changed, 165 insertions(+)
create mode 100644 general/pages/connect/github.vue
diff --git a/general/components/Header/AuthLoginModal.vue b/general/components/Header/AuthLoginModal.vue
index 0fb89758..9e95da1e 100644
--- a/general/components/Header/AuthLoginModal.vue
+++ b/general/components/Header/AuthLoginModal.vue
@@ -64,6 +64,21 @@
Create an account
+
@@ -142,5 +157,27 @@ const handleSubmit = async () => {
}
};
+const connectGithub = () => {
+ const githubConnectUrl = `${baseURL()}/api/connect/github`;
+
+ window.location.href = githubConnectUrl;
+};
+
const modalOpen = computed(() => authModalStore.authModal === 'login');
+
+
diff --git a/general/pages/connect/github.vue b/general/pages/connect/github.vue
new file mode 100644
index 00000000..11eb0717
--- /dev/null
+++ b/general/pages/connect/github.vue
@@ -0,0 +1,128 @@
+
+
+
+
+
+ Connecting
+ {{ statusMessage }}
+
+
+
+
+
+
+
+
From d7de9115ba459cd07f0a70973c626fed357e3b9e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adam=20Roso=C5=82owski?=
<87621210+rr-adam@users.noreply.github.com>
Date: Fri, 13 Sep 2024 15:12:19 +0200
Subject: [PATCH 2/2] Store route and fetch user role
---
general/components/Header/AuthLoginModal.vue | 7 ++-
general/pages/connect/github.vue | 15 ++++--
general/stores/auth.ts | 56 ++++++++++++++++++--
3 files changed, 69 insertions(+), 9 deletions(-)
diff --git a/general/components/Header/AuthLoginModal.vue b/general/components/Header/AuthLoginModal.vue
index 9e95da1e..ba50869c 100644
--- a/general/components/Header/AuthLoginModal.vue
+++ b/general/components/Header/AuthLoginModal.vue
@@ -95,6 +95,8 @@ const toastStore = useToastStore();
const authStore = useAuthStore();
const authModalStore = useAuthModalStore();
+const route = useRoute();
+
const identifier = ref('');
const password = ref('');
const error = ref(null);
@@ -132,8 +134,7 @@ const handleSubmit = async () => {
});
if (response.jwt && response.user) {
- authStore.setJwt(response.jwt);
- authStore.setUserData(response.user);
+ await authStore.loginAndFetchProfile(response.jwt, response.user);
toastStore.addToast('You are logged in.');
hideModal();
} else {
@@ -160,6 +161,8 @@ const handleSubmit = async () => {
const connectGithub = () => {
const githubConnectUrl = `${baseURL()}/api/connect/github`;
+ authStore.setRedirectLink(route.fullPath);
+
window.location.href = githubConnectUrl;
};
diff --git a/general/pages/connect/github.vue b/general/pages/connect/github.vue
index 11eb0717..69f9a366 100644
--- a/general/pages/connect/github.vue
+++ b/general/pages/connect/github.vue
@@ -68,11 +68,14 @@ onMounted(async () => {
);
if (response.jwt && response.user) {
- authStore.setJwt(response.jwt);
- authStore.setUserData(response.user);
+ await authStore.loginAndFetchProfile(response.jwt, response.user);
toastStore.addToast('Successfully logged in with GitHub.');
statusMessage.value = 'Authentication successful. Redirecting...';
- setTimeout(() => router.push('/ontology'), 2000);
+
+ const redirectUrl = authStore.redirectLink || '/ontology';
+ authStore.clearRedirectLink();
+
+ setTimeout(() => router.push(redirectUrl), 2000);
} else {
throw new Error('Invalid response from server');
}
@@ -86,7 +89,11 @@ const handleError = (message: string) => {
statusMessage.value = 'Authentication failed. Redirecting...';
toastStore.addToast(`GitHub authentication failed!`, 'error');
authStore.clear();
- setTimeout(() => router.push('/'), 2000);
+
+ const redirectUrl = authStore.redirectLink || '/';
+ authStore.clearRedirectLink();
+
+ setTimeout(() => router.push(redirectUrl), 2000);
};
diff --git a/general/stores/auth.ts b/general/stores/auth.ts
index 97660a97..51daaf52 100644
--- a/general/stores/auth.ts
+++ b/general/stores/auth.ts
@@ -1,4 +1,5 @@
import { defineStore } from 'pinia';
+import { useRuntimeConfig } from '#app';
export interface UserData {
id: number;
@@ -22,6 +23,7 @@ export interface UserData {
interface AuthState {
jwt: string | null;
user: UserData | null;
+ redirectLink: string | null;
}
export const useAuthStore = defineStore({
@@ -29,7 +31,8 @@ export const useAuthStore = defineStore({
state: (): AuthState => {
return {
jwt: null,
- user: null
+ user: null,
+ redirectLink: null
};
},
actions: {
@@ -39,9 +42,56 @@ export const useAuthStore = defineStore({
setUserData(user: UserData) {
this.user = user;
},
+ setRedirectLink(link: string) {
+ this.redirectLink = link;
+ },
+ clearRedirectLink() {
+ this.redirectLink = null;
+ },
+ async fetchFullProfile() {
+ if (!this.jwt) {
+ throw new Error('No JWT token available');
+ }
+
+ const runtimeConfig = useRuntimeConfig();
+ const baseURL =
+ typeof window !== 'undefined'
+ ? window.location.origin + `${runtimeConfig.public.strapiBasePath}`
+ : `${runtimeConfig.public.strapiBaseUrl}`;
+
+ try {
+ const response = await $fetch(
+ `${baseURL}/api/users/me?populate=role`,
+ {
+ method: 'GET',
+ headers: {
+ Authorization: `Bearer ${this.jwt}`
+ }
+ }
+ );
+
+ if (response) {
+ this.setUserData(response);
+ } else {
+ throw new Error('Invalid response from server');
+ }
+ } catch (error) {
+ console.error('Error fetching full profile:', error);
+ throw error;
+ }
+ },
+ async loginAndFetchProfile(
+ jwt: string,
+ initialUserData: Partial
+ ) {
+ this.setJwt(jwt);
+ this.setUserData({ ...initialUserData } as UserData);
+ await this.fetchFullProfile();
+ },
clear() {
this.jwt = null;
this.user = null;
+ this.redirectLink = null;
}
},
persist: {
@@ -49,7 +99,7 @@ export const useAuthStore = defineStore({
const runtimeConfig = useRuntimeConfig();
return `ontoviewer-auth-${runtimeConfig.public.ontologyName}`;
},
- storage: process.client ? localStorage : undefined,
- paths: ['jwt', 'user']
+ storage: import.meta.client ? localStorage : undefined,
+ paths: ['jwt', 'user', 'redirectLink']
}
});