diff --git a/README.md b/README.md index 86fe11ca7..e87a84d60 100644 --- a/README.md +++ b/README.md @@ -5,13 +5,13 @@ Lilium frontend ## Install the dependencies ```bash -bun install +pnpm install ``` ### Install quasar cli ```bash -sudo bun install -g @quasar/cli +sudo npm install -g @quasar/cli ``` ### Start the app in development mode (hot-code reloading, error reporting, etc.) @@ -23,13 +23,13 @@ quasar dev ### Run unit tests ```bash -bun run test:unit +pnpm run test:unit ``` ### Run e2e tests ```bash -npm run test:e2e +pnpm run test:e2e ``` ### Build the app for production diff --git a/src/boot/axios.js b/src/boot/axios.js index c58cc2d08..e3e7289af 100644 --- a/src/boot/axios.js +++ b/src/boot/axios.js @@ -11,7 +11,7 @@ axios.defaults.baseURL = '/api/'; const onRequest = (config) => { const token = session.getToken(); - if (token.length && config.headers) { + if (token.length && !config.headers.Authorization) { config.headers.Authorization = token; } diff --git a/src/components/NavBar.vue b/src/components/NavBar.vue index 12366e174..17b8c2b7e 100644 --- a/src/components/NavBar.vue +++ b/src/components/NavBar.vue @@ -10,12 +10,12 @@ import UserPanel from 'components/UserPanel.vue'; import VnBreadcrumbs from './common/VnBreadcrumbs.vue'; const { t } = useI18n(); -const session = useSession(); const stateStore = useStateStore(); const quasar = useQuasar(); const state = useState(); const user = state.getUser(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const appName = 'Lilium'; onMounted(() => stateStore.setMounted()); diff --git a/src/components/UserPanel.vue b/src/components/UserPanel.vue index e0b6b86ed..a18dad79a 100644 --- a/src/components/UserPanel.vue +++ b/src/components/UserPanel.vue @@ -44,7 +44,7 @@ const darkMode = computed({ }); const user = state.getUser(); -const token = session.getToken(); +const token = session.getTokenMultimedia(); onMounted(async () => { updatePreferences(); diff --git a/src/components/ui/VnAvatar.vue b/src/components/ui/VnAvatar.vue index 5a5483084..287f741e0 100644 --- a/src/components/ui/VnAvatar.vue +++ b/src/components/ui/VnAvatar.vue @@ -10,8 +10,8 @@ const $props = defineProps({ size: { type: String, default: null }, title: { type: String, default: null }, }); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const { t } = useI18n(); const title = computed(() => $props.title ?? t('globals.system')); diff --git a/src/composables/downloadFile.js b/src/composables/downloadFile.js index 877d2a254..b26dec731 100644 --- a/src/composables/downloadFile.js +++ b/src/composables/downloadFile.js @@ -1,8 +1,8 @@ import { useSession } from 'src/composables/useSession'; import { getUrl } from './getUrl'; -const session = useSession(); -const token = session.getToken(); +const {getTokenMultimedia} = useSession(); +const token = getTokenMultimedia(); export async function downloadFile(dmsId) { let appUrl = await getUrl('', 'lilium'); diff --git a/src/composables/useSession.js b/src/composables/useSession.js index 008337b02..580efbdf8 100644 --- a/src/composables/useSession.js +++ b/src/composables/useSession.js @@ -1,6 +1,7 @@ import { useState } from './useState'; import { useRole } from './useRole'; import { useUserConfig } from './useUserConfig'; +import axios from 'axios'; export function useSession() { @@ -10,21 +11,54 @@ export function useSession() { return localToken || sessionToken || ''; } + function getTokenMultimedia() { + const localTokenMultimedia = localStorage.getItem('tokenMultimedia'); + const sessionTokenMultimedia = sessionStorage.getItem('tokenMultimedia'); + + return localTokenMultimedia || sessionTokenMultimedia || ''; + } function setToken(data) { if (data.keepLogin) { localStorage.setItem('token', data.token); + localStorage.setItem('tokenMultimedia', data.tokenMultimedia); } else { sessionStorage.setItem('token', data.token); + sessionStorage.setItem('tokenMultimedia', data.tokenMultimedia); } } - function destroy() { - if (localStorage.getItem('token')) - localStorage.removeItem('token') + async function destroy() { + if (localStorage.getItem('tokenMultimedia')){ + await axios.post('VnUsers/logoutMultimedia', null, { + headers: {Authorization: localStorage.getItem('tokenMultimedia') } + }); + localStorage.removeItem('tokenMultimedia') + + } + if (localStorage.getItem('token')){ + await axios.post('VnUsers/logout', null, { + headers: {Authorization: localStorage.getItem('token') } + }); + localStorage.removeItem('token') + } + + + if (sessionStorage.getItem('tokenMultimedia')){ + await axios.post('VnUsers/logoutMultimedia', null, { + headers: {Authorization: sessionStorage.getItem('tokenMultimedia') } + }); + sessionStorage.removeItem('tokenMultimedia') + + } + if (sessionStorage.getItem('token')){ + await axios.post('VnUsers/logout', null, { + headers: {Authorization: sessionStorage.getItem('token') } + }); + sessionStorage.removeItem('token') + } + - if (sessionStorage.getItem('token')) - sessionStorage.removeItem('token'); const { setUser } = useState(); @@ -37,8 +71,8 @@ export function useSession() { }); } - async function login(token, keepLogin) { - setToken({ token, keepLogin }); + async function login(token, tokenMultimedia, keepLogin) { + setToken({ token, tokenMultimedia, keepLogin }); await useRole().fetch(); await useUserConfig().fetch(); @@ -53,6 +87,7 @@ export function useSession() { return { getToken, + getTokenMultimedia, setToken, destroy, login, diff --git a/src/pages/Claim/Card/ClaimBasicData.vue b/src/pages/Claim/Card/ClaimBasicData.vue index b5bf2bb42..c7c5ab8a2 100644 --- a/src/pages/Claim/Card/ClaimBasicData.vue +++ b/src/pages/Claim/Card/ClaimBasicData.vue @@ -13,8 +13,8 @@ import { useSession } from 'src/composables/useSession'; const route = useRoute(); const { t } = useI18n(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const claimFilter = { fields: [ diff --git a/src/pages/Claim/Card/ClaimPhoto.vue b/src/pages/Claim/Card/ClaimPhoto.vue index 6ac116ce0..dd97b60df 100644 --- a/src/pages/Claim/Card/ClaimPhoto.vue +++ b/src/pages/Claim/Card/ClaimPhoto.vue @@ -11,8 +11,8 @@ import FetchData from 'components/FetchData.vue'; const router = useRouter(); const quasar = useQuasar(); const { t } = useI18n(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const claimId = computed(() => router.currentRoute.value.params.id); diff --git a/src/pages/Claim/Card/ClaimSummary.vue b/src/pages/Claim/Card/ClaimSummary.vue index e14351286..80757c57b 100644 --- a/src/pages/Claim/Card/ClaimSummary.vue +++ b/src/pages/Claim/Card/ClaimSummary.vue @@ -14,8 +14,8 @@ import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; const route = useRoute(); const { t } = useI18n(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const $props = defineProps({ id: { diff --git a/src/pages/Customer/Card/CustomerBasicData.vue b/src/pages/Customer/Card/CustomerBasicData.vue index 458d50082..d23b08f17 100644 --- a/src/pages/Customer/Card/CustomerBasicData.vue +++ b/src/pages/Customer/Card/CustomerBasicData.vue @@ -11,8 +11,8 @@ import VnInput from 'src/components/common/VnInput.vue'; const route = useRoute(); const { t } = useI18n(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const workers = ref([]); const workersCopy = ref([]); diff --git a/src/pages/Entry/EntryLatestBuys.vue b/src/pages/Entry/EntryLatestBuys.vue index 217a25870..bbc4a16cf 100644 --- a/src/pages/Entry/EntryLatestBuys.vue +++ b/src/pages/Entry/EntryLatestBuys.vue @@ -20,8 +20,8 @@ import { dashIfEmpty } from 'src/filters'; import { useArrayData } from 'composables/useArrayData'; const router = useRouter(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const stateStore = useStateStore(); const { t } = useI18n(); diff --git a/src/pages/Item/Card/ItemDescriptor.vue b/src/pages/Item/Card/ItemDescriptor.vue index 8c986e627..981de0632 100644 --- a/src/pages/Item/Card/ItemDescriptor.vue +++ b/src/pages/Item/Card/ItemDescriptor.vue @@ -41,7 +41,7 @@ const quasar = useQuasar(); const route = useRoute(); const router = useRouter(); const { t } = useI18n(); -const { getToken } = useSession(); +const { getTokenMultimedia } = useSession(); const state = useState(); const user = state.getUser(); @@ -79,7 +79,7 @@ onMounted(async () => { }); const getItemAvatar = async () => { - const token = getToken(); + const token = getTokenMultimedia(); const timeStamp = `timestamp=${Date.now()}`; image.value = `/api/Images/catalog/200x200/${entityId.value}/download?access_token=${token}&${timeStamp}`; }; diff --git a/src/pages/Login/LoginMain.vue b/src/pages/Login/LoginMain.vue index 9c469e611..f920854c6 100644 --- a/src/pages/Login/LoginMain.vue +++ b/src/pages/Login/LoginMain.vue @@ -30,8 +30,15 @@ async function onSubmit() { const { data } = await axios.post('Accounts/login', params); if (!data) return; + const { + data: { multimediaToken }, + } = await axios.get('VnUsers/ShareToken', { + headers: { Authorization: data.token }, + }); - await session.login(data.token, keepLogin.value); + if (!multimediaToken) return; + + await session.login(data.token, multimediaToken.id, keepLogin.value); quasar.notify({ message: t('login.loginSuccess'), diff --git a/src/pages/Order/Card/OrderCatalogItem.vue b/src/pages/Order/Card/OrderCatalogItem.vue index ee73bcffb..a197ceafc 100644 --- a/src/pages/Order/Card/OrderCatalogItem.vue +++ b/src/pages/Order/Card/OrderCatalogItem.vue @@ -11,8 +11,8 @@ import toCurrency from '../../../filters/toCurrency'; const DEFAULT_PRICE_KG = 0; -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const { t } = useI18n(); defineProps({ diff --git a/src/pages/Order/OrderLines.vue b/src/pages/Order/OrderLines.vue index a2ee42481..4b6c21c75 100644 --- a/src/pages/Order/OrderLines.vue +++ b/src/pages/Order/OrderLines.vue @@ -17,9 +17,9 @@ import axios from 'axios'; const route = useRoute(); const { t } = useI18n(); -const session = useSession(); +const { getTokenMultimedia } = useSession(); const quasar = useQuasar(); -const token = session.getToken(); +const token = getTokenMultimedia(); const orderSummary = ref({ total: null, vat: null, diff --git a/src/pages/Route/Cmr/CmrList.vue b/src/pages/Route/Cmr/CmrList.vue index eb1901ab8..41908ec6c 100644 --- a/src/pages/Route/Cmr/CmrList.vue +++ b/src/pages/Route/Cmr/CmrList.vue @@ -12,8 +12,8 @@ import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy const stateStore = useStateStore(); const { t } = useI18n(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const selected = ref([]); const columns = computed(() => [ diff --git a/src/pages/Route/RouteList.vue b/src/pages/Route/RouteList.vue index 6b1b0d45f..d308696e1 100644 --- a/src/pages/Route/RouteList.vue +++ b/src/pages/Route/RouteList.vue @@ -133,10 +133,10 @@ const showRouteReport = () => { let url; if (selectedRows.value.length <= 1) { - url = `api/Routes/${idString}/driver-route-pdf?access_token=${session.getToken()}`; + url = `api/Routes/${idString}/driver-route-pdf?access_token=${session.getTokenMultimedia()}`; } else { const params = new URLSearchParams({ - access_token: session.getToken(), + access_token: session.getTokenMultimedia(), id: idString, }); url = `api/Routes/downloadZip?${params.toString()}`; diff --git a/src/pages/Wagon/WagonCounter.vue b/src/pages/Wagon/WagonCounter.vue index bd5d2ca67..15a1ab7ba 100644 --- a/src/pages/Wagon/WagonCounter.vue +++ b/src/pages/Wagon/WagonCounter.vue @@ -7,8 +7,8 @@ import VnConfirm from 'components/ui/VnConfirm.vue'; const quasar = useQuasar(); const { t } = useI18n(); -const session = useSession(); -const token = session.getToken(); +const { getTokenMultimedia } = useSession(); +const token = getTokenMultimedia(); const counters = ref({ alquilerBandeja: { count: 0, id: 96001, title: 'CC Bandeja', isTray: true }, diff --git a/src/pages/Worker/Card/WorkerDescriptor.vue b/src/pages/Worker/Card/WorkerDescriptor.vue index bec56bee7..5144b3bfa 100644 --- a/src/pages/Worker/Card/WorkerDescriptor.vue +++ b/src/pages/Worker/Card/WorkerDescriptor.vue @@ -22,7 +22,7 @@ const $props = defineProps({ const route = useRoute(); const { t } = useI18n(); -const { getToken } = useSession(); +const { getTokenMultimedia } = useSession(); const entityId = computed(() => { return $props.id || route.params.id; @@ -56,7 +56,7 @@ const filter = { const sip = computed(() => worker.value?.sip && worker.value.sip.extension); function getWorkerAvatar() { - const token = getToken(); + const token = getTokenMultimedia(); return `/api/Images/user/160x160/${entityId.value}/download?access_token=${token}`; } const data = ref(useCardDescription()); diff --git a/test/vitest/__tests__/composables/useSession.spec.js b/test/vitest/__tests__/composables/useSession.spec.js index 4f900aca6..f9f3dcb80 100644 --- a/test/vitest/__tests__/composables/useSession.spec.js +++ b/test/vitest/__tests__/composables/useSession.spec.js @@ -54,7 +54,8 @@ describe('session', () => { expect(localStorage.getItem('token')).toEqual('tokenToBeGone'); expect(user.value).toEqual(previousUser); - session.destroy(); + vi.spyOn(axios, 'post').mockResolvedValue({ data: true }); + await session.destroy(); user = state.getUser(); expect(localStorage.getItem('token')).toBeNull(); @@ -92,9 +93,10 @@ describe('session', () => { }); const expectedToken = 'mySessionToken'; + const expectedTokenMultimedia = 'mySessionTokenMultimedia'; const keepLogin = false; - await session.login(expectedToken, keepLogin); + await session.login(expectedToken,expectedTokenMultimedia, keepLogin); const roles = state.getRoles(); const localToken = localStorage.getItem('token'); @@ -104,7 +106,7 @@ describe('session', () => { expect(localToken).toBeNull(); expect(sessionToken).toEqual(expectedToken); - session.destroy(); // this clears token and user for any other test + await session.destroy(); // this clears token and user for any other test }); it('should fetch the user roles and then set token in the localStorage', async () => { @@ -114,9 +116,10 @@ describe('session', () => { }); const expectedToken = 'myLocalToken'; + const expectedTokenMultimedia = 'myLocalTokenMultimedia'; const keepLogin = true; - await session.login(expectedToken, keepLogin); + await session.login(expectedToken, expectedTokenMultimedia, keepLogin); const roles = state.getRoles(); const localToken = localStorage.getItem('token'); @@ -126,7 +129,7 @@ describe('session', () => { expect(localToken).toEqual(expectedToken); expect(sessionToken).toBeNull(); - session.destroy(); // this clears token and user for any other test + await session.destroy(); // this clears token and user for any other test }); }); }); diff --git a/test/vitest/__tests__/pages/Login/Login.spec.js b/test/vitest/__tests__/pages/Login/Login.spec.js index fadfc898f..6e2de9870 100644 --- a/test/vitest/__tests__/pages/Login/Login.spec.js +++ b/test/vitest/__tests__/pages/Login/Login.spec.js @@ -22,9 +22,9 @@ describe('Login', () => { darkMode: false, }, }; - vi.spyOn(axios, 'post').mockResolvedValue({ data: { token: 'token' } }); + vi.spyOn(axios, 'post').mockResolvedValueOnce({ data: { token: 'token' } }); vi.spyOn(axios, 'get').mockResolvedValue({ - data: { roles: [], user: expectedUser }, + data: { roles: [], user: expectedUser , multimediaToken: {id:'multimediaToken' }}, }); vi.spyOn(vm.quasar, 'notify'); @@ -36,7 +36,7 @@ describe('Login', () => { expect(vm.quasar.notify).toHaveBeenCalledWith( expect.objectContaining({ type: 'positive' }) ); - vm.session.destroy(); + await vm.session.destroy(); }); it('should not set the token into session if any error occurred', async () => {