diff --git a/packages/nc-gui-v2/composables/user.ts b/packages/nc-gui-v2/composables/user.ts index 9eb4c7b024..e77e2429bb 100644 --- a/packages/nc-gui-v2/composables/user.ts +++ b/packages/nc-gui-v2/composables/user.ts @@ -1,18 +1,16 @@ import { store } from 'nuxt3-store' import { useNuxtApp } from '#app' -export const useUser = () => { - const user = store({ - name: 'user', - type: 'localstorage', - value: { token: null, user: null }, - reactiveType: 'reactive', - version: '1.0.0', - }) +const user = store({ + name: 'user', + type: 'localstorage', + value: { token: null, user: null }, + reactiveType: 'reactive', + version: '1.0.0', +}) +export const useUser = () => { const { $api } = useNuxtApp() - const route = useRoute() - const router = useRouter() const getUser = async (args = {}) => { const userInfo = await $api.auth.me(args, { @@ -28,88 +26,5 @@ export const useUser = () => { user.token = token } - $api?.instance?.interceptors.request.use((config) => { - config.headers['xc-gui'] = 'true' - - if (user?.token) - config.headers['xc-auth'] = user?.token - - if (!config.url.endsWith('/user/me') && !config.url.endsWith('/admin/roles')) { - // config.headers['xc-preview'] = store.state.users.previewAs - } - - if (!config.url.endsWith('/user/me') && !config.url.endsWith('/admin/roles')) { - if (route && route.params && route.params.shared_base_id) - config.headers['xc-shared-base-id'] = route.params.shared_base_id - } - - return config - }) - - // $axios.setBaseURL('http://localhost:8080') - - $api?.instance?.interceptors.response.use((response) => { - // Return a successful response back to the calling service - return response - }, (error) => { - if (error.response && error.response.data && error.response.data.msg === 'Database config not found') { - router.replace('/project/0') - return - } - - // Return any error which is not due to authentication back to the calling service - if (!error.response || error.response.status !== 401) { - return new Promise((resolve, reject) => { - reject(error) - }) - } - - // Logout user if token refresh didn't work or user is disabled - if (error.config.url === '/auth/refresh-token') { - // todo: clear token - // store.dispatch('users/ActSignOut') - setToken(null) - - return new Promise((resolve, reject) => { - reject(error) - }) - } - - // Try request again with new token - return $api.instance.post('/auth/refresh-token', null, { - withCredentials: true, - }) - .then((token) => { - // New request with new token - const config = error.config - config.headers['xc-auth'] = token.data.token - user.token = token.data.token - - return new Promise((resolve, reject) => { - $api.instance.request(config).then((response) => { - resolve(response) - }).catch((error) => { - reject(error) - }) - }) - }) - .catch(async (error) => { - // todo: clear token - // await store.dispatch('users/ActSignOut') - setToken(null) - if (store.state.project.appInfo.firstUser) { - router.replace('/') - } - else { - // $toast.clear() - // $toast.info('Token Expired. Please login again.', { - // position: 'bottom-center' - // }).goAway(5000) - router.replace('/user/authentication/signin') - } - return Promise.reject(error) - }) - }) - return { user, setToken, getUser } } diff --git a/packages/nc-gui-v2/package-lock.json b/packages/nc-gui-v2/package-lock.json index dd9e9c1a15..eda89315c5 100644 --- a/packages/nc-gui-v2/package-lock.json +++ b/packages/nc-gui-v2/package-lock.json @@ -10,7 +10,7 @@ "primeflex": "3.2.0", "primeicons": "5.0.0", "primevue": "3.10.0", - "vuetify": "^3.0.0-alpha.12" + "vuetify": "^3.0.0-alpha.13" }, "devDependencies": { "@antfu/eslint-config": "^0.25.2", @@ -22,7 +22,7 @@ } }, "../nocodb-sdk": { - "version": "0.92.0", + "version": "0.92.3", "license": "MIT", "dependencies": { "axios": "^0.21.1", @@ -11556,15 +11556,36 @@ "integrity": "sha512-UBc1Pg1T3yZ97vsA2ueER0F6GbJebLHYlEi4ou1H5YL4KWvMOOWwpYo9/QpWq93wxKG6Wo13IY74Hcn/f7c7Bg==" }, "node_modules/vuetify": { - "version": "3.0.0-alpha.12", - "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.0.0-alpha.12.tgz", - "integrity": "sha512-F9TwV3Xk6J/bSH422kATrKeIiumGRkzGJPsvM0/8vPwYF0HWh7dHRhhYsIKkfhl5UJl/LYdeGNm1L8+jtldA0w==", + "version": "3.0.0-beta.5", + "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.0.0-beta.5.tgz", + "integrity": "sha512-mU+pO5ZAZOR2Z7eVBoPwZw6nePxT5Sdqpsa4++Q99TwVxXQ7jl76Cy97v72MkDYWfxjDjj8XvW6IqNPGrJpU8w==", + "engines": { + "node": "^12.20 || >=14.13" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/johnleider" }, "peerDependencies": { - "vue": "^3.2.19" + "@formatjs/intl": "^1.0.0 || ^2.0.0", + "vite-plugin-vuetify": "1.0.0-alpha.12", + "vue": "^3.2.0", + "vue-i18n": "^9.0.0", + "webpack-plugin-vuetify": "2.0.0-alpha.11" + }, + "peerDependenciesMeta": { + "@formatjs/intl": { + "optional": true + }, + "vite-plugin-vuetify": { + "optional": true + }, + "vue-i18n": { + "optional": true + }, + "webpack-plugin-vuetify": { + "optional": true + } } }, "node_modules/watchpack": { @@ -20369,9 +20390,9 @@ } }, "vuetify": { - "version": "3.0.0-alpha.12", - "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.0.0-alpha.12.tgz", - "integrity": "sha512-F9TwV3Xk6J/bSH422kATrKeIiumGRkzGJPsvM0/8vPwYF0HWh7dHRhhYsIKkfhl5UJl/LYdeGNm1L8+jtldA0w==", + "version": "3.0.0-beta.5", + "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.0.0-beta.5.tgz", + "integrity": "sha512-mU+pO5ZAZOR2Z7eVBoPwZw6nePxT5Sdqpsa4++Q99TwVxXQ7jl76Cy97v72MkDYWfxjDjj8XvW6IqNPGrJpU8w==", "requires": {} }, "watchpack": { diff --git a/packages/nc-gui-v2/plugins/api.ts b/packages/nc-gui-v2/plugins/api.ts index affc903fdc..ab44efba56 100644 --- a/packages/nc-gui-v2/plugins/api.ts +++ b/packages/nc-gui-v2/plugins/api.ts @@ -1,9 +1,108 @@ import { Api } from 'nocodb-sdk' import { defineNuxtPlugin } from 'nuxt3/app' +const addAxiosInterceptors = ($api: Api) => { + const router = useRouter() + const route = useRoute() + + const { user, setToken } = useUser() + + $api?.instance?.interceptors.request.use((config) => { + config.headers['xc-gui'] = 'true' + + if (user?.token) + config.headers['xc-auth'] = user?.token + + if (!config.url.endsWith('/user/me') && !config.url.endsWith('/admin/roles')) { + // config.headers['xc-preview'] = store.state.users.previewAs + } + + if (!config.url.endsWith('/user/me') && !config.url.endsWith('/admin/roles')) { + if (route && route.params && route.params.shared_base_id) + config.headers['xc-shared-base-id'] = route.params.shared_base_id + } + + return config + }) + + // $axios.setBaseURL('http://localhost:8080') + + $api?.instance?.interceptors.response.use((response) => { + // Return a successful response back to the calling service + return response + }, (error) => { + if (error.response && error.response.data && error.response.data.msg === 'Database config not found') { + router.replace('/project/0') + return + } + + // Return any error which is not due to authentication back to the calling service + if (!error.response || error.response.status !== 401) { + return new Promise((resolve, reject) => { + reject(error) + }) + } + + // Logout user if token refresh didn't work or user is disabled + if (error.config.url === '/auth/refresh-token') { + // todo: clear token + // store.dispatch('users/ActSignOut') + setToken(null) + + return new Promise((resolve, reject) => { + reject(error) + }) + } + + // Try request again with new token + return $api.instance.post('/auth/refresh-token', null, { + withCredentials: true, + }) + .then((token) => { + // New request with new token + const config = error.config + config.headers['xc-auth'] = token.data.token + user.token = token.data.token + + return new Promise((resolve, reject) => { + $api.instance.request(config).then((response) => { + resolve(response) + }).catch((error) => { + reject(error) + }) + }) + }) + .catch(async (error) => { + // todo: clear token + // await store.dispatch('users/ActSignOut') + setToken(null) + // todo: handle new user + // if (store.state.project.appInfo.firstUser) { + // router.replace('/') + // } + // else { + // $toast.clear() + // $toast.info('Token Expired. Please login again.', { + // position: 'bottom-center' + // }).goAway(5000) + router.replace('/user/authentication/signin') + // } + return Promise.reject(error) + }) + }) +} + export default defineNuxtPlugin((nuxtApp) => { + const { user } = useUser() const api = getApi(null, null) + watch(() => user.token, (newToken, oldToken) => { + if (newToken !== oldToken) + addAxiosInterceptors(api) + }) + + addAxiosInterceptors(api) + nuxtApp.provide('api', api) })