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

Password reset and password change #29

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,15 @@
<router-view></router-view>
</v-col>
</v-row>
<v-row v-if="!is_logged_in && $route.path.indexOf('/pages') !== 0" fluid>
<v-row v-if="!is_logged_in && $route.path.indexOf('/password-reset') === 0">
<v-col
class="col-12 col-md-9"
id="app_body"
>
<router-view></router-view>
</v-col>
</v-row>
<v-row v-if="!is_logged_in && $route.path.indexOf('/pages') !== 0 && !is_logged_in && $route.path.indexOf('/password-reset') !== 0" fluid>
<v-col class="col-12">
<AppLogin></AppLogin>
</v-col>
Expand Down Expand Up @@ -215,11 +223,12 @@
// import MakeModelRun from "@/components/MakeModelRun";
import vuetify from './plugins/vuetify.js' // path to vuetify export
import AppLogin from "./components/AppLogin.vue"
import PasswordReset from "./components/PasswordReset.vue"
import Vue from "vue";

export default {
name: 'stormchaser',
components: { AppLogin },
components: { AppLogin, PasswordReset },
vuetify: vuetify,
data: function() {
return {
Expand Down
8 changes: 8 additions & 0 deletions src/components/AppLogin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
</v-text-field>
<v-btn type="submit" :disabled="!form_valid" id="log_in_button">Log In</v-btn>
</v-form>
<p><router-link :to="{name: 'Reset-Password'}">Forgot Password</router-link></p>
</v-col>
</v-row>
<v-row>
Expand Down Expand Up @@ -76,7 +77,14 @@ export default {
return this.username && this.password;
},
},

methods: {
navigate: function(params){
this.$router.push(params);
},
gotoPasswordReset() {
this.$router.push('/PasswordReset');
},
do_login() {
let login_promise = this.$store.dispatch("do_login", {
username: this.username,
Expand Down
228 changes: 228 additions & 0 deletions src/components/PasswordReset.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
<template>
<v-row>
<v-container>

</v-container>
<v-col class="col-6">
<router-link :to="{name: 'AppLogin'}"><v-btn type="submit" id="home-btn">Home</v-btn></router-link>
</v-col>
<v-col id="middle_col" class="login col-10 offset-1 col-md-6 offset-md-3">
<v-row>
<v-col class="col-12">
<h1>Reset Password</h1>
</v-col>
</v-row>
<v-row v-if="!is_logged_in()" id="middle_col">
<v-col>
<notification-snackbar
v-model="login_failed_snackbar"
constant_snackbar_text="Failed to log you in"
:error_text="login_failed_text"
></notification-snackbar>
<h2>Account Info</h2>
<v-form @submit.prevent="get_reset_link">
<v-text-field
v-model="username"
id="email"
label="Email"
required
:rules="username_rules"
>
</v-text-field>

<v-btn type="submit" :disabled="!form_valid_email" id="log_in_button">Submit</v-btn>
<p id="email_sent">{{ instructionsText }}</p>
</v-form>
</v-col>
</v-row>
<v-row v-if="is_logged_in()" id="middle_col">
<v-col>
<notification-snackbar
v-model="login_failed_snackbar"
constant_snackbar_text="Failed to log you in"
:error_text="login_failed_text"
></notification-snackbar>
<h2>Enter Old Password</h2>
<v-text-field
v-model="old_password"
id="old_password"
label=" Password"
required
:rules="password_rules"
>
</v-text-field>

<h2>New Password</h2>
<v-form @submit.prevent="do_password_reset">
<v-text-field
v-model="password"
id="password"
label=" Password"
required
:rules="password_rules"
>
</v-text-field>
<v-text-field
v-model="confirm_password"
id="confirm_password"
label="Confirm Password"
required
:rules="confirm_password_rules"
>
</v-text-field>
<v-btn type="submit" :disabled="!form_valid_password" id="log_in_button">Submit</v-btn>
<p id="email_sent"> <b>{{ instructionsText }}</b> </p>
</v-form>
</v-col>
</v-row>
<v-row>
<v-col class="col-12">
<p>Copyright {{ new Date().getYear() + 1900 }}, Regents of the University of California.</p>
<p>Developed by the <a href="http://wsm.ucmerced.edu">Water Systems Management Lab</a>, <a href="https://vicelab.ucmerced.edu">ViceLab</a>,
and the <a href="https://citris.ucmerced.edu">Center for Information Technology
Research in the Interest of Society</a> (CITRIS) at UC Merced.</p>
</v-col>
</v-row>
</v-col>
</v-row>
</template>

<script>
import NotificationSnackbar from "./NotificationSnackbar.vue";
export default {
name: "PasswordReset",
components: { NotificationSnackbar },
data: function () {
return {
username: null,
password: null,
old_password: null,
encoded_pk: null,
temp_token: null,
confirm_password: null,
instructionsText: '',
login_failed_snackbar: false,
login_failed_text: "",
username_rules: [
(v) => !!v || "email is required",
(v) => v.includes('@') || "Email must contain @",
],
password_rules: [
(v) => !!v || "Password is required",
(v) => v != null,
],
confirm_password_rules: [
v => !!v || 'Confirmation password is required',
v => v === this.password || 'Passwords must match',
(v) => v != null,
],
};
},
methods: {
get_token_from_storage(){
let session_data = window.sessionStorage;
this.$store.commit("set_api_token", session_data.getItem("waterspout_token")); // set the value, then return
if (this.$store.state.user_api_token !== null && this.$store.state.user_api_token !== undefined && this.$store.state.user_api_token !== ""){ // we might not want to do this here - creates a side effect?
this.$store.dispatch("fetch_variables"); // get the application data then - currently will fill in the token *again*, but this basically triggers application setup
}
},
get_reset_link() {
let login_promise = this.$store.dispatch("get_password_reset_link", {
email: this.username,
})

login_promise
.then((response => {
if (response.message.length > 0){
this.instructionsText += "Reset link has been sent, please check your email.";
}
}))
.catch(response => {
this.login_failed_text = "Email not found"
this.login_failed_snackbar = true;
})
},
do_password_reset(){
// Check if encoded_pk and token is empty if so,
// this could mean the user is performing a password change
if( this.encoded_pk === null || this.encoded_pk === undefined &&
this.temp_token === null || this.temp_token === undefined && this.is_logged_in()){
this.do_password_change();
} else {
let login_promise = this.$store.dispatch("do_password_reset", {
password: this.password,
encoded_pk: this.encoded_pk,
token: this.temp_token
})
login_promise
.then((response) =>{
if(response.status === 200){
this.instructionsText += "Password has been changed, redirecting to login."
}
});
}
},
do_password_change(){
// Created a different endpoint for alt flow of user already signed in
const payload = {
password: this.password,
old_password: this.old_password,
token: this.$store.state.user_api_token
}
let password_change_promise = this.$store.dispatch("do_password_change", payload)
password_change_promise
.then((response) => {
if(response.status === 200){
this.instructionsText += "Password has been change";
} else {
console.log(response)
}
})
},
is_logged_in: function(){ // url parser to check if user is logged in or using reset link
let token = this.$store.state.user_api_token;

// Parse the url for params
this.encoded_pk = this.$route.query.encoded_pk;
this.temp_token = this.$route.query.token;

if (this.encoded_pk !== null && this.encoded_pk !== '' && this.encoded_pk !== undefined &&
this.temp_token !== null && this.temp_token !== '' && this.temp_token !== undefined) {
return true;
}

if (token !== null && token !== undefined && token !== ""){
return true; // return quickly if we're logged in, otherwise, check sessionStorage first, then return false
}

// now see if we have it in storage
this.get_token_from_storage();
token = this.$store.state.user_api_token; // get it again, it might have changed
this.temp_token = token
return token !== null && token !== undefined && token !== "";
},
},
computed: {
form_valid_password: function () {
return this.password === this.confirm_password && this.password != null;
},
form_valid_email: function () {
return this.username;
},
},
};
</script>

<style scoped lang="stylus">
#middle_col
div.row
margin-top: 5%;
background-color: rgba(255,255,255,0.75);
border-radius: 10px;
#home-btn
background-color: #2a76d2
#email_sent
padding-top: 5px;
text-decoration: bold;
text-emphasis: #0d0d0d;
</style>
8 changes: 7 additions & 1 deletion src/components/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
</v-col>

</v-row>

<v-row
v-if="net_revenue_available_on_a_model_area">
<!-- WARNING! Need to change this v-if if we add more settings that aren't related to net revenue below it -->
Expand Down Expand Up @@ -75,6 +74,13 @@
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
<v-row style="padding-top: 20px; padding-bottom: 20px">
<!-- WARNING! Need to change this v-if if we add more settings that aren't related to net revenue below it -->
<h3>Reset Password</h3>
</v-row>
<v-btn @click="enable_net_revenue_settings = true"
><router-link :to="{name: 'Reset-Password'}">Change Password</router-link>
</v-btn>
</v-container>
</template>

Expand Down
2 changes: 2 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ListModelRuns from "./components/ListModelRuns.vue";
import InputDataViewer from "./components/InputDataViewer.vue";
import Settings from "./components/Settings.vue";
import About from "./components/About.vue";
import PasswordReset from "./components/PasswordReset.vue";
import Help from "./components/Help.vue";
const ModelRun = () => import(/* webpackPrefetch: true */ "./components/ModelRun.vue"); // we load this this way so that it can lazy load it on demand
import 'material-design-icons-iconfont/dist/material-design-icons.css' // need this for material design icons
Expand All @@ -35,6 +36,7 @@ const routes = [
{ path: '/help/', name:'help', component: Help, meta: {title: "Help and Tutorials"} },
{ path: '/settings/', name:'settings', component: Settings, meta: {title: "Settings"} },
{ path: '/pages/about/', name:'about', component: About, meta: {title: "About OpenAg"} },
{ path: '/password-reset', name:'Reset-Password', component: PasswordReset, meta: {title: "Reset your Password"} },
]

const router = new VueRouter({
Expand Down
Loading
Loading