Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented: support to reset the password for the user(#63) #64

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
19 changes: 17 additions & 2 deletions src/locales/en.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,34 @@
{
"Failed to fetch user-profile, please try again": "Failed to fetch user-profile, please try again",
"Already active session": "Already active session",
"Confirm Password": "Confirm Password",
"Email": "Email",
"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.",
"Forgot Password?": "Forgot Password?",
"Launch Pad": "Launch Pad",
"Login": "Login",
"Logout": "Logout",
"New Password": "New Password",
"Failed to fetch user-profile, please try again": "Failed to fetch user-profile, please try again",
"Logging out...": "Logging out...",
"Next": "Next",
"Not configured": "Not configured",
"OMS": "OMS",
"Password": "Password",
"Passwords do not match. Please try again": "Passwords do not match. Please try again",
"Please fill in the OMS": "Please fill in the OMS",
"Please fill in the user details": "Please fill in the user details",
"Processing": "Processing",
"Reset Password": "Reset Password",
"Resume": "Resume",
"Send Reset Link": "Send Reset Link",
"Something went wrong while login. Please contact administrator.": "Something went wrong while login. Please contact administrator.",
"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",
"There is an already active session on for. Do you want to resume it, or would you prefer to log in again?": "There is an already active session on {oms} for {partyName}. Do you want to resume it, or would you prefer to log in again?",
"Username": "Username",
"Username or Email cannot be empty.": "Username or Email cannot be empty.",
"Your password should be at least 5 characters long, it should contain at least one number, one alphabet and one special character.": "Your password should be at least 5 characters long, it should contain at least one number, one alphabet and one special character.",
"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 {email}, for further instructions.",
"This application is not enabled for your account": "This application is not enabled for your account",
"View profile": "View profile"
}
43 changes: 43 additions & 0 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ 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';
import ForgotPassword from '@/views/ForgotPassword.vue';

const loginGuard = (to: any, from: any, next: any) => {
const authStore = useAuthStore()
Expand All @@ -12,6 +14,34 @@ 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 forgotPassword = async (to: any, from: any, next: any) => {
const authStore = useAuthStore()

if (from.path !== '/login' && authStore.isAuthenticated) {
next('/')
return;
}
next()
return;
};

const routes: Array<RouteRecordRaw> = [
{
path: '/',
Expand All @@ -21,12 +51,25 @@ const routes: Array<RouteRecordRaw> = [
path: '/home',
name: 'Home',
component: Home,
beforeEnter: resetGuard
},
{
path: '/login',
name: 'Login',
component: Login,
beforeEnter: loginGuard
},
{
path: '/resetPassword',
name: 'ResetPassword',
component: ResetPassword,
beforeEnter: authGuard
},
{
path: '/forgotPassword',
name: 'ForgotPassword',
component: ForgotPassword,
beforeEnter: forgotPassword
}
];

Expand Down
20 changes: 19 additions & 1 deletion src/services/UserService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,26 @@ const checkLoginOptions = async (): Promise<any> => {
});
}

const resetPassword = async(params: any) : Promise<any> => {
return api({
url: "service/resetPassword",
method: "POST",
data: params
})
}

const forgotPassword = async(params: any) : Promise<any> => {
return api({
url: "/sendResetPasswordMail",
method: "post",
data: params
})
}

export const UserService = {
getUserProfile,
checkLoginOptions,
login
forgotPassword,
login,
resetPassword
}
4 changes: 3 additions & 1 deletion src/store/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
expiration: undefined
},
redirectUrl: '',
requirePasswordChange: false, // denotes if password change is required for the user
maargOms: ''
}),
getters: {
Expand Down Expand Up @@ -47,8 +48,7 @@
try {
const resp = await UserService.login(username, password);
if (hasError(resp)) {
showToast(translate('Sorry, your username or password is incorrect. Please try again.'));
console.error("error", resp.data._ERROR_MESSAGE_);

Check warning on line 51 in src/store/auth.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

Unexpected console statement

Check warning on line 51 in src/store/auth.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

Unexpected console statement
return Promise.reject(new Error(resp.data._ERROR_MESSAGE_));
}

Expand All @@ -57,6 +57,8 @@
expiration: resp.data.expirationTime
}

this.requirePasswordChange = resp.data.requirePasswordChange

this.current = await UserService.getUserProfile(this.token.value);
updateToken(this.token.value)
// Handling case for warnings like password may expire in few days
Expand All @@ -68,7 +70,7 @@
// If any of the API call in try block has status code other than 2xx it will be handled in common catch block.
// TODO Check if handling of specific status codes is required.
showToast(translate('Something went wrong while login. Please contact administrator.'));
console.error("error: ", error);

Check warning on line 73 in src/store/auth.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

Unexpected console statement

Check warning on line 73 in src/store/auth.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

Unexpected console statement
return Promise.reject(new Error(error))
}
},
Expand All @@ -85,7 +87,7 @@
// If any of the API call in try block has status code other than 2xx it will be handled in common catch block.
// TODO Check if handling of specific status codes is required.
showToast(translate('Something went wrong while login. Please contact administrator.'));
console.error("error: ", error);

Check warning on line 90 in src/store/auth.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

Unexpected console statement

Check warning on line 90 in src/store/auth.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

Unexpected console statement
return Promise.reject(new Error(error))
}
},
Expand All @@ -99,7 +101,7 @@
try {
await logout();
} catch(err) {
console.error('Error parsing data', err)

Check warning on line 104 in src/store/auth.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

Unexpected console statement

Check warning on line 104 in src/store/auth.ts

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

Unexpected console statement
}
}

Expand Down
150 changes: 150 additions & 0 deletions src/views/ForgotPassword.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<template>
<ion-page>
<ion-content>
<div class="flex">
<form id="forgotPasswordForm" class="login-container" @keyup.enter="forgotPassword()" @submit.prevent>
<Logo />
<section>
<ion-item lines="full">
<ion-label position="fixed">{{ $t("Username") }}</ion-label>
<ion-input @ionFocus="clearMessages" name="username" v-model="username" id="username" type="text" />
</ion-item>
<ion-item lines="none">
<ion-label position="fixed">{{ $t("Email") }}</ion-label>
<ion-input @ionFocus="clearMessages" name="email" v-model="email" id="email" type="email"/>
</ion-item>

<div class="ion-padding">
<ion-button name="forgotPasswordForm" color="primary" expand="block" @click.prevent="forgotPassword()" @keyup.enter.stop>
{{ $t("Send Reset Link") }}
</ion-button>
</div>

<ion-item lines="none" v-show="errorMessage">
<ion-icon color="danger" slot="start" :icon="closeCircleOutline" />
<ion-label class="ion-text-wrap">{{ errorMessage }}</ion-label>
</ion-item>

<ion-item lines="none" v-show="successMessage">
<ion-icon color="success" slot="start" :icon="checkmarkCircleOutline" />
<ion-label class="ion-text-wrap">{{ successMessage }}</ion-label>
</ion-item>
</section>
<ion-button name="loginButton" fill="clear" class="ion-text-center" @click.stop="router.push('/login')">{{ $t('Login') }}</ion-button>
</form>
</div>

<ion-fab vertical="bottom" horizontal="end" slot="fixed">
<ion-fab-button color="medium" @click="router.push('/')">
<ion-icon :icon="gridOutline" />
</ion-fab-button>
</ion-fab>
</ion-content>
</ion-page>
</template>


<script lang="ts">
import {
IonButton,
IonContent,
IonFab,
IonFabButton,
IonIcon,
IonInput,
IonItem,
IonLabel,
IonPage
} from "@ionic/vue";
import { defineComponent } from "vue";
import { useRouter } from "vue-router";
import { useAuthStore } from "@/store/auth";
import Logo from '@/components/Logo.vue';
import { checkmarkCircleOutline, closeCircleOutline, gridOutline } from 'ionicons/icons'
import { hasError } from "@/adapter";
import { UserService } from "@/services/UserService"

export default defineComponent({
name: "ForgotPassword",
components: {
IonButton,
IonContent,
IonFab,
IonFabButton,
IonIcon,
IonInput,
IonItem,
IonLabel,
IonPage,
Logo
},
data () {
return {
username: '',
email: '',
errorMessage: '',
successMessage: ''
};
},
ionViewWillLeave() {
// clearning the data on page leave
this.username = ''
this.email = ''
this.clearMessages();
},
methods: {
async forgotPassword() {
if(!this.username.trim() || !this.email.trim()) {
this.errorMessage = this.$t('Username or Email cannot be empty.')
return;
}

const params = {
userName: this.username,
emailAddress: this.email
}

try {
const resp = await UserService.forgotPassword(params);

if(!hasError(resp)) {
this.successMessage = this.$t('Your request for reset password has been processed. Please check your email, for further instructions.', { email: this.email })
} else {
throw resp.data._ERROR_MESSAGE_
}
} catch(err) {
this.errorMessage = this.$t('Failed to send password reset link, please try again or contact administrator.')
console.error(err)

Check warning on line 117 in src/views/ForgotPassword.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

Unexpected console statement

Check warning on line 117 in src/views/ForgotPassword.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

Unexpected console statement
}
},
clearMessages() {
this.errorMessage = ''
this.successMessage = ''
}
},
setup () {
const router = useRouter();
const authStore = useAuthStore();
return {
authStore,
checkmarkCircleOutline,
closeCircleOutline,
gridOutline,
router
};
}
});
</script>
<style scoped>
.login-container {
width: 375px;
}

.flex {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}

</style>
25 changes: 24 additions & 1 deletion src/views/Login.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
<ion-icon v-else slot="end" :icon="arrowForwardOutline" />
</ion-button>
</div>

<p class="ion-text-center" v-show="errorMessage">{{ errorMessage }}</p>

<ion-button fill="clear" @click="forgotPassword">
<p class="ion-text-center">{{ $t('Forgot Password?') }}</p>
</ion-button>
</section>
</form>
</div>
Expand Down Expand Up @@ -107,13 +113,17 @@
isConfirmingForActiveSession: false,
loader: null as any,
loginOption: {} as any,
errorMessage: '',
isCheckingOms: false,
isLoggingIn: false
};
},
ionViewWillEnter() {
this.initialise()
},
ionViewWillLeave() {
this.errorMessage = ''
},
methods: {
async initialise() {
this.hideBackground = true
Expand Down Expand Up @@ -241,7 +251,7 @@
await this.authStore.setMaargInstance(resp.data.maargInstanceUrl)
}
} catch (error) {
console.error(error)

Check warning on line 254 in src/views/Login.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

Unexpected console statement

Check warning on line 254 in src/views/Login.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

Unexpected console statement
}
},
async login() {
Expand All @@ -254,6 +264,15 @@
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');
return
}

if (this.authStore.getRedirectUrl) {
this.generateRedirectionLink()
} else {
Expand All @@ -262,8 +281,9 @@
this.password = ''
this.router.push('/')
}
} catch (error) {
} catch (error: any) {
this.errorMessage = error
console.error(error)

Check warning on line 286 in src/views/Login.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (18.x)

Unexpected console statement

Check warning on line 286 in src/views/Login.vue

View workflow job for this annotation

GitHub Actions / call-workflow-in-another-repo / reusable_workflow_job (20.x)

Unexpected console statement
}
this.isLoggingIn = false;
},
Expand All @@ -281,6 +301,9 @@
console.error(error)
}
},
forgotPassword() {
this.router.push('/forgotPassword')
},
async basicLogin() {
try {
const { oms, token, expirationTime } = this.$route.query as any
Expand Down
Loading
Loading