diff --git a/src/components/ForgotPasswordModal.vue b/src/components/ForgotPasswordModal.vue
new file mode 100644
index 0000000..c29b3aa
--- /dev/null
+++ b/src/components/ForgotPasswordModal.vue
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+
+
+ {{$t("Reset password")}}
+
+
+
+
+
+
+
+ {{ errorMessage }}
+
+
+ {{ successMessage }}
+
+
+
+
+ {{ $t("Your username must have an email already associated with it in HotWax to receive a reset password email. If you do not have an email linked to your account already, please contact your administrator to manually reset your password.") }}
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/locales/en.json b/src/locales/en.json
index 851679e..f8e926f 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -1,13 +1,19 @@
{
+ "Confirm Password": "Confirm Password",
"Failed to fetch user-profile, please try again": "Failed to fetch user-profile, please try again",
+ "Failed to reset password, please try again and follow the instructions for creating a new password.": "Failed to reset password, please try again and follow the instructions for creating a new password.",
+ "Failed to send password reset link, please try again or contact administrator.": "Failed to send password reset link, please try again or contact administrator.",
+ "Finish resetting your password": "Finish resetting your password",
"Launch Pad": "Launch Pad",
"Login": "Login",
"Logout": "Logout",
"Logging out...": "Logging out...",
+ "New Password": "New Password",
"Next": "Next",
"Not configured": "Not configured",
"OMS": "OMS",
"Password": "Password",
+ "Reset Password":"Reset Password",
"Please fill in the OMS": "Please fill in the OMS",
"Please fill in the user details": "Please fill in the user details",
"Processing": "Processing",
@@ -15,5 +21,9 @@
"Sorry, your username or password is incorrect. Please try again.": "Sorry, your username or password is incorrect. Please try again.",
"This application is not enabled for your account": "This application is not enabled for your account",
"Username": "Username",
- "View profile": "View profile"
+ "Username cannot be empty.": "Username cannot be empty.",
+ "View profile": "View profile",
+ "Your password has been successfully reset.": "Your password has been successfully reset.",
+ "Your request for reset password has been processed. Please check your email, for further instructions.":"Your request for reset password has been processed. Please check your email, for further instructions.",
+ "Your username must have an email already associated with it in HotWax to receive a reset password email. If you do not have an email linked to your account already, please contact your administrator to manually reset your password.":"Your username must have an email already associated with it in HotWax to receive a reset password email. If you do not have an email linked to your account already, please contact your administrator to manually reset your password."
}
\ No newline at end of file
diff --git a/src/router/index.ts b/src/router/index.ts
index 2a5fe6c..0d59fc0 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -3,6 +3,7 @@ import { RouteRecordRaw } from 'vue-router';
import Home from '@/views/Home.vue';
import Login from '@/views/Login.vue';
import { useAuthStore } from "@/store/auth";
+import ResetPassword from '@/views/ResetPassword.vue';
const loginGuard = (to: any, from: any, next: any) => {
const authStore = useAuthStore()
@@ -12,6 +13,23 @@ const loginGuard = (to: any, from: any, next: any) => {
next();
};
+const authGuard = async (to: any, from: any, next: any) => {
+ const authStore = useAuthStore()
+ if (!authStore.isAuthenticated) {
+ next('/login')
+ }
+ next()
+};
+
+const resetGuard = async (to: any, from: any, next: any) => {
+ const authStore = useAuthStore()
+ if (authStore.requirePasswordChange) {
+ next('/resetPassword')
+ return;
+ }
+ next()
+};
+
const routes: Array = [
{
path: '/',
@@ -21,13 +39,20 @@ const routes: Array = [
path: '/home',
name: 'Home',
component: Home,
+ beforeEnter: resetGuard
},
{
path: '/login',
name: 'Login',
component: Login,
beforeEnter: loginGuard
- }
+ },
+ {
+ path: '/resetPassword',
+ name: 'ResetPassword',
+ component: ResetPassword,
+ beforeEnter: authGuard
+ },
];
const router = createRouter({
diff --git a/src/services/UserService.ts b/src/services/UserService.ts
index 837cf9d..f16eef1 100644
--- a/src/services/UserService.ts
+++ b/src/services/UserService.ts
@@ -130,9 +130,27 @@ const getUserPermissions = async (payload: any, token: any): Promise => {
}
}
+const resetPassword = async(params: any) : Promise => {
+ return api({
+ url: "service/resetPassword",
+ method: "POST",
+ data: params
+ })
+}
+
+const forgotPassword = async(params: any) : Promise => {
+ return api({
+ url: "sendResetPasswordEmail",
+ method: "post",
+ data: params
+ })
+}
+
export const UserService = {
getUserProfile,
checkLoginOptions,
login,
- getUserPermissions
+ getUserPermissions,
+ resetPassword,
+ forgotPassword
}
\ No newline at end of file
diff --git a/src/store/auth.ts b/src/store/auth.ts
index 58a34fe..051619e 100644
--- a/src/store/auth.ts
+++ b/src/store/auth.ts
@@ -21,6 +21,7 @@ export const useAuthStore = defineStore('authStore', {
expiration: undefined
},
redirectUrl: '',
+ requirePasswordChange: false, // denotes if password change is required for the user
maargOms: '',
permissions: [] as any
}),
@@ -64,6 +65,8 @@ export const useAuthStore = defineStore('authStore', {
expiration: resp.data.expirationTime
}
+ this.requirePasswordChange = resp.data.requirePasswordChange
+
this.current = await UserService.getUserProfile(this.token.value);
updateToken(this.token.value)
diff --git a/src/views/Login.vue b/src/views/Login.vue
index f34cd45..1e8fb97 100644
--- a/src/views/Login.vue
+++ b/src/views/Login.vue
@@ -41,6 +41,13 @@
+
+
+
+ {{ $t('The username or password you entered is incorrect. Please try again.') }}
+ {{ $t('forgot password') }}
+
+
@@ -67,18 +74,20 @@ import {
IonItem,
IonPage,
IonSpinner,
- loadingController
+ loadingController,
+ modalController
} from "@ionic/vue";
import { defineComponent } from "vue";
import { useRouter } from "vue-router";
import { useAuthStore } from "@/store/auth";
import Logo from '@/components/Logo.vue';
-import { arrowForwardOutline, gridOutline } from 'ionicons/icons'
+import { arrowForwardOutline, gridOutline,warningOutline } from 'ionicons/icons'
import { UserService } from "@/services/UserService";
import { translate } from "@/i18n";
import { appInfo, isMaargLogin, isOmsWithMaarg, showToast } from "@/util";
import { hasError } from "@hotwax/oms-api";
import { Actions, hasPermission } from "@/authorization";
+import ForgotPasswordModal from "@/components/ForgotPasswordModal.vue";
export default defineComponent({
name: "Login",
@@ -109,12 +118,16 @@ export default defineComponent({
loader: null as any,
loginOption: {} as any,
isCheckingOms: false,
- isLoggingIn: false
+ isLoggingIn: false,
+ errorMessage: '',
};
},
ionViewWillEnter() {
this.initialise()
},
+ ionViewWillLeave() {
+ this.errorMessage = ''
+ },
methods: {
async initialise() {
this.hideBackground = true
@@ -256,6 +269,14 @@ export default defineComponent({
this.isLoggingIn = true;
try {
await this.authStore.login(username.trim(), password)
+ // when password needs to be changed, redirecting the user to reset page
+ if(this.authStore.requirePasswordChange) {
+ this.username = ''
+ this.password = ''
+ this.router.push('/resetPassword');
+ this.isLoggingIn = false
+ return
+ }
if (this.authStore.getRedirectUrl) {
this.generateRedirectionLink()
} else {
@@ -264,7 +285,8 @@ export default defineComponent({
this.password = ''
this.router.push('/')
}
- } catch (error) {
+ } catch (error:any) {
+ this.errorMessage = error
console.error(error)
}
this.isLoggingIn = false;
@@ -339,6 +361,16 @@ export default defineComponent({
omsUrl = omsUrl ? omsUrl : this.authStore.oms.startsWith('http') ? this.authStore.oms.includes('/api') ? this.authStore.oms : `${this.authStore.oms}/api/` : this.authStore.oms
window.location.replace(`${url}?oms=${omsUrl}&token=${this.authStore.token.value}&expirationTime=${this.authStore.token.expiration}${omsRedirectionUrl ? '&omsRedirectionUrl=' + omsRedirectionUrl : ''}`)
+ },
+ async openForgotPasswordModal(){
+ const forgotPasswordModal = await modalController.create({
+ component:ForgotPasswordModal,
+ })
+ forgotPasswordModal.onDidDismiss()
+ this.errorMessage = ''
+ this.username = ''
+ this.password = ''
+ return forgotPasswordModal.present()
}
},
setup () {
@@ -348,7 +380,8 @@ export default defineComponent({
arrowForwardOutline,
authStore,
gridOutline,
- router
+ router,
+ warningOutline
};
}
});
@@ -364,5 +397,12 @@ export default defineComponent({
align-items: center;
height: 100%;
}
-
+.ion-item-banner {
+ --background:#ED576B1A;
+ --border-radius: 8px;
+}
+.ion-item-banner a {
+ display: block;
+ color: var(--ion-color-danger) ;
+}
diff --git a/src/views/ResetPassword.vue b/src/views/ResetPassword.vue
new file mode 100644
index 0000000..d15d625
--- /dev/null
+++ b/src/views/ResetPassword.vue
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+ {{ $t('Your password has been successfully reset') }}
+
+
+ {{ $t('Login') }}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file