Skip to content

Commit

Permalink
Merge pull request #196 from ymaheshwari1/feat/single-sign-in
Browse files Browse the repository at this point in the history
Implemented: single-sign-in support using launchpad(#192)
  • Loading branch information
ymaheshwari1 authored May 20, 2024
2 parents 880be90 + 518073e commit 9a2227b
Show file tree
Hide file tree
Showing 15 changed files with 1,254 additions and 109 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ VUE_APP_RULE_FILTER_ENUMS={"FACILITY_GROUP":{"id":"IIP_FACILITY_GROUP","code":"f
VUE_APP_RULE_SORT_ENUMS={"PROXIMITY":{"id":"ISP_PROXIMITY","code":"distance"},"INV_BALANCE":{"id":"ISP_INV_BAL","code":"inventoryForAllocation"},"CUSTOMER_SEQ":{"id":"ISP_CUST_SEQ","code":"facilitySequence"}}
VUE_APP_RULE_ACTION_ENUMS={"RM_AUTO_CANCEL_DATE":{"id":"ORA_RM_CANCEL_DATE","code":"RM_AUTO_CANCEL_DATE"},"AUTO_CANCEL_DAYS":{"id":"ORA_AUTO_CANCEL_DAYS","code":"ADD_AUTO_CANCEL_DATE"},"NEXT_RULE":{"id":"ORA_NEXT_RULE","code":"NEXT_RULE"},"MOVE_TO_QUEUE":{"id":"ORA_MV_TO_QUEUE","code":"MOVE_TO_QUEUE"}}
VUE_APP_CRON_EXPRESSIONS={"Every 5 minutes":"0 */5 * ? * *","Every 15 minutes":"0 */15 * ? * *","Every 30 minutes":"0 */30 * ? * *","Hourly":"0 0 * ? * *","Every six hours":"0 0 */6 ? * *","Every day at midnight":"0 0 0 * * ?"}
VUE_APP_LOGIN_URL="https://launchpad.hotwax.io/login"
1,162 changes: 1,094 additions & 68 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"@capacitor/core": "^2.4.7",
"@hotwax/app-version-info": "^1.0.0",
"@hotwax/apps-theme": "^1.2.6",
"@hotwax/dxp-components": "^1.13.0",
"@hotwax/oms-api": "^1.14.0",
"@ionic/core": "^7.6.0",
"@ionic/vue": "^7.6.0",
"@ionic/vue-router": "^7.6.0",
Expand Down
Binary file modified public/assets/icon/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 22 additions & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,28 @@ import emitter from "@/event-bus"
import { Settings } from 'luxon'
import store from "./store";
import { translate } from "@/i18n"
import { initialise, resetConfig } from '@/adapter'
const loader = ref(null) as any
const userProfile = computed(() => store.getters["user/getUserProfile"])
const userToken = computed(() => store.getters["user/getUserToken"])
const instanceUrl = computed(() => store.getters["user/getInstanceUrl"])
const loader = ref(null) as any
const maxAge = process.env.VUE_APP_CACHE_MAX_AGE ? parseInt(process.env.VUE_APP_CACHE_MAX_AGE) : 0
initialise({
token: userToken.value,
instanceUrl: instanceUrl.value,
cacheMaxAge: maxAge,
events: {
responseError: () => {
setTimeout(() => dismissLoader(), 100);
},
queueTask: (payload: any) => {
emitter.emit("queueTask", payload);
}
}
})
async function presentLoader(options = { message: "Click the backdrop to dismiss.", backdropDismiss: true }) {
// When having a custom message remove already existing loader, if not removed it takes into account the already existing loader
Expand Down Expand Up @@ -56,5 +75,7 @@ onMounted(async () => {
onUnmounted(() => {
emitter.off("presentLoader", presentLoader);
emitter.off("dismissLoader", dismissLoader);
resetConfig()
})
</script>
15 changes: 15 additions & 0 deletions src/adapter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { api, client, getConfig, getProductIdentificationPref, getUserFacilities, initialise, logout, resetConfig, setProductIdentificationPref, updateInstanceUrl, updateToken } from '@hotwax/oms-api'

export {
api,
client,
getConfig,
getProductIdentificationPref,
getUserFacilities,
initialise,
logout,
resetConfig,
setProductIdentificationPref,
updateInstanceUrl,
updateToken
}
4 changes: 3 additions & 1 deletion src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ axios.interceptors.response.use(function (response) {
const { status } = error.response;
if (status === StatusCodes.UNAUTHORIZED) {
store.dispatch("user/logout");
router.push("/login")
const redirectUrl = window.location.origin + '/login';
// Explicitly passing isLoggedOut as in case of maarg apps we need to call the logout api in launchpad
window.location.href = `${process.env.VUE_APP_LOGIN_URL}?redirectUrl=${redirectUrl}&isLoggedOut=true`;
}
}
// Any status codes that falls outside the range of 2xx cause this function to trigger
Expand Down
15 changes: 14 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ import "@ionic/vue/css/display.css";
import "./theme/variables.css";
import "@hotwax/apps-theme";

import { dxpComponents } from "@hotwax/dxp-components"
import { login, logout, loader } from "@/user-utils";
import { getConfig, initialise } from '@/adapter';

import i18n from "./i18n"
import store from "./store"
import { DateTime } from "luxon";
Expand All @@ -39,7 +43,16 @@ const app = createApp(App)
})
.use(router)
.use(i18n)
.use(store);
.use(store)
.use(dxpComponents, {
defaultImgUrl: require("@/assets/images/defaultImage.png"),
login,
logout,
loader,
appLoginUrl: process.env.VUE_APP_LOGIN_URL as string,
getConfig,
initialise
});

// Filters are removed in Vue 3 and global filter introduced https://v3.vuejs.org/guide/migration/filters.html#global-filters
app.config.globalProperties.$filters = {
Expand Down
27 changes: 16 additions & 11 deletions src/router/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import { createRouter, createWebHistory } from "@ionic/vue-router";
import { RouteRecordRaw } from "vue-router";
import Login from "@/views/Login.vue"
import store from "@/store"
import Tabs from "@/views/Tabs.vue"
import { DxpLogin, useAuthStore } from '@hotwax/dxp-components';
import { loader } from '@/user-utils';

const authGuard = (to: any, from: any, next: any) => {
if (store.getters["user/isAuthenticated"]) {
next()
} else {
next("/login")
const authGuard = async (to: any, from: any, next: any) => {
const authStore = useAuthStore()
if (!authStore.isAuthenticated || !store.getters['user/isAuthenticated']) {
await loader.present('Authenticating')
// TODO use authenticate() when support is there
const redirectUrl = window.location.origin + '/login'
window.location.href = `${process.env.VUE_APP_LOGIN_URL}?redirectUrl=${redirectUrl}`
loader.dismiss()
}
next()
};

const loginGuard = (to: any, from: any, next: any) => {
if (!store.getters["user/isAuthenticated"]) {
next()
} else {
next("/")
const authStore = useAuthStore()
if (authStore.isAuthenticated && !to.query?.token && !to.query?.oms) {
next('/')
}
next();
};

const routes: Array<RouteRecordRaw> = [
Expand Down Expand Up @@ -57,7 +62,7 @@ const routes: Array<RouteRecordRaw> = [
{
path: "/login",
name: "Login",
component: Login,
component: DxpLogin,
beforeEnter: loginGuard
},
]
Expand Down
26 changes: 16 additions & 10 deletions src/services/UserService.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,34 @@
import api, {client} from "@/api"
import api, { client } from "@/api"
import store from "@/store";
import { hasError } from "@/utils";

const login = async (username: string, password: string): Promise <any> => {
let token = ""
const login = async (token: string): Promise <any> => {
const url = store.getters["user/getBaseUrl"]
const baseURL = url.startsWith('http') ? url.includes('/rest/s1/order-routing') ? url : `${url}/rest/s1/order-routing/` : `https://${url}.hotwax.io/rest/s1/order-routing/`;
let api_key = ""

try {
const resp = await api({
const resp = await client({
url: "login",
method: "post",
data: {
username,
password
baseURL,
params: {
token
},
headers: {
"Content-Type": "application/json"
}
}) as any;

if(!hasError(resp) && resp.data.token) {
token = resp.data.token
if(!hasError(resp) && (resp.data.api_key || resp.data.token)) {
api_key = resp.data.api_key || resp.data.token
} else {
throw "Sorry, login failed. Please try again";
}
} catch(err) {
return Promise.reject("Sorry, login failed. Please try again");
}
return Promise.resolve(token)
return Promise.resolve(api_key)
}

const getUserProfile = async (token: any): Promise<any> => {
Expand Down
33 changes: 22 additions & 11 deletions src/store/modules/user/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,37 @@ import { translate } from "@/i18n"
import logger from "@/logger"
import emitter from "@/event-bus"
import { Settings } from "luxon"
import { useAuthStore } from '@hotwax/dxp-components'
import { resetConfig } from '@/adapter'

const actions: ActionTree<UserState, RootState> = {

/**
* Login user and return token
*/
async login({ commit }, { username, password }) {
async login({ commit, dispatch }, payload) {
try {
if(!username.length || !password.length) {
return Promise.reject('')
}

emitter.emit("presentLoader", { message: "Logging in...", backdropDismiss: false })
// TODO: implement support for permission check
const token = await UserService.login(username, password)

const userProfile = await UserService.getUserProfile(token);
// TODO: oms here is of ofbiz we need to check how to get the maarg url from here as we need to hit all apis on maarg
const { token, oms } = payload;
dispatch("setUserInstanceUrl", oms);

emitter.emit("presentLoader", { message: "Logging in...", backdropDismiss: false })
const api_key = await UserService.login(token)
const userProfile = await UserService.getUserProfile(api_key);

// TODO: fetch only associated product stores for user, currently api does not support this
userProfile.stores = await UserService.getEComStores(token);
userProfile.stores = await UserService.getEComStores(api_key);

if (userProfile.timeZone) {
Settings.defaultZone = userProfile.timeZone;
}

commit(types.USER_TOKEN_CHANGED, { newToken: token })
commit(types.USER_TOKEN_CHANGED, { newToken: api_key })
commit(types.USER_INFO_UPDATED, userProfile);
commit(types.USER_CURRENT_ECOM_STORE_UPDATED, userProfile.stores.length ? userProfile.stores[0] : {});
emitter.emit("dismissLoader")
return Promise.resolve({ token })
} catch (err: any) {
emitter.emit("dismissLoader")
showToast(translate(err));
Expand All @@ -50,10 +51,20 @@ const actions: ActionTree<UserState, RootState> = {
* Logout user
*/
async logout({ commit }) {
emitter.emit('presentLoader', { message: 'Logging out', backdropDismiss: false })

const authStore = useAuthStore()

// TODO add any other tasks if need
commit(types.USER_END_SESSION)
this.dispatch("orderRouting/clearRouting")
this.dispatch("util/clearUtilState")
resetConfig();

// reset plugin state on logout
authStore.$reset()

emitter.emit('dismissLoader')
},

/**
Expand Down
6 changes: 2 additions & 4 deletions src/store/modules/user/getters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ const getters: GetterTree <UserState, RootState> = {
return state.current
},
getInstanceUrl(state) {
const baseUrl = process.env.VUE_APP_BASE_URL;
return baseUrl ? baseUrl : state.instanceUrl;
return state.instanceUrl;
},
getCurrentEComStore(state) {
return state.currentEComStore
},
getBaseUrl(state) {
let baseURL = process.env.VUE_APP_BASE_URL;
if (!baseURL) baseURL = state.instanceUrl;
const baseURL = state.instanceUrl;
return baseURL.startsWith("http") ? baseURL : `https://${baseURL}.hotwax.io/rest/s1/order-routing/`;
}
}
Expand Down
34 changes: 34 additions & 0 deletions src/user-utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { translate } from '@/i18n'
import store from '@/store'
import { loadingController } from '@ionic/vue'

const login = async (payload: any) => store.dispatch('user/login', payload);

const logout = async (payload: any) => store.dispatch('user/logout', payload);

const loader = {
value: null as any,
present: async (message: string) => {
if (!loader.value) {
loader.value = await loadingController
.create({
message: translate(message),
translucent: false,
backdropDismiss: false
});
}
loader.value.present();
},
dismiss: () => {
if (loader.value) {
loader.value.dismiss();
loader.value = null as any;
}
}
}

export {
login,
loader,
logout
}
3 changes: 2 additions & 1 deletion src/views/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,8 @@ async function changeTimeZone() {
function logout() {
store.dispatch("user/logout").then(() => {
router.push("/login");
const redirectUrl = window.location.origin + '/login'
window.location.href = `${process.env.VUE_APP_LOGIN_URL}?isLoggedOut=true&redirectUrl=${redirectUrl}`
})
}
Expand Down
12 changes: 11 additions & 1 deletion vue.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const path = require('path')
require("@hotwax/app-version-info")

module.exports = {
Expand All @@ -12,5 +13,14 @@ module.exports = {
fullInstall: true,
enableInSFC: true
}
}
},
configureWebpack: {
resolve: {
alias: {
vue: path.resolve('./node_modules/vue')
}
}
},
runtimeCompiler: true,
transpileDependencies: ['@hotwax/dxp-components']
}

0 comments on commit 9a2227b

Please sign in to comment.