Implement CRUD operations on user accounts

This commit is contained in:
Conor McNamara
2023-03-12 13:39:35 +00:00
parent 26822d0be9
commit 71865159e3
7 changed files with 194 additions and 55 deletions

View File

@ -42,6 +42,7 @@ exports.postStationData = functions.https.onRequest((request, response) => {
// helper function to write to the database // helper function to write to the database
function batchWriteDB(request, response, db, jsonData, dartCodes, stationTypeCode) { function batchWriteDB(request, response, db, jsonData, dartCodes, stationTypeCode) {
if (!jsonData) return
response.set('Access-Control-Allow-Origin', '*'); response.set('Access-Control-Allow-Origin', '*');
response.set('Access-Control-Allow-Credentials', 'true'); response.set('Access-Control-Allow-Credentials', 'true');
@ -136,6 +137,7 @@ exports.postLiveTrainData = functions.https.onRequest((request, response) => {
// helper function to write to the database // helper function to write to the database
function batchWriteDB(request, response, db, jsonData, trainTypeCode) { function batchWriteDB(request, response, db, jsonData, trainTypeCode) {
if (!jsonData) return
response.set('Access-Control-Allow-Origin', '*'); response.set('Access-Control-Allow-Origin', '*');
response.set('Access-Control-Allow-Credentials', 'true'); response.set('Access-Control-Allow-Credentials', 'true');

View File

@ -17,12 +17,12 @@
<a class="nav-link"><router-link to="/insights">Insights</router-link></a> <a class="nav-link"><router-link to="/insights">Insights</router-link></a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a v-if="!isLoggedIn" class="nav-link"><router-link to="/signup">Sign Up</router-link></a> <a v-if="!isLoggedIn" class="nav-link"><router-link to="/login">Login</router-link></a>
<a v-if="isLoggedIn" class="nav-link"><router-link to="/secure">Secure</router-link></a> <a v-if="isLoggedIn" class="nav-link"><router-link to="/account">Account Settings</router-link></a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a v-if="isLoggedIn" class="nav-link"><router-link style="text-decoration: none; color: black; font-weight: 100;" @click="logout" to="/" class="navlink">Logout</router-link></a> <a v-if="isLoggedIn" class="nav-link"><router-link style="text-decoration: none; color: black; font-weight: 100;" @click="logout" to="/" class="navlink">Logout</router-link></a>
<a v-if="!isLoggedIn" class="nav-link"><router-link to="/login">Login</router-link></a> <a v-if="!isLoggedIn" class="nav-link"><router-link to="/signup">Sign Up</router-link></a>
</li> </li>
</ul> </ul>

165
src/pages/AccountPage.vue Normal file
View File

@ -0,0 +1,165 @@
<template>
<Navbar />
<h1>Account Settings</h1>
<p>Your Email: {{ displayEmail }}</p>
<div>
<p>Enter your current password to edit account settings</p>
<input type="password" v-model="currentPassword" placeholder="Enter existing password">
<h1>Change email</h1>
<input type="email" v-model="newEmail" aria-describedby="emailHelp" placeholder="Enter new email">
<input @click="updateUserEmail" type="submit" name="" value="Update Email">
<h1>Change password</h1>
<input type="password" v-model="newPassword" placeholder="Enter new password">
<input @click="updateUserPassword" type="submit" name="" value="Update Password">
<h1>Delete account</h1>
<input @click="deleteUserAccount" type="submit" name="" value="Delete Account">
</div>
<p v-if="missingCredentials">Missing credentials to complete this action</p>
<p v-if="displayFirebaseSuccessMsg">{{ FirebaseSuccessMsg }}</p>
<p v-if="displayFirebaseError">{{ FirebaseError }}</p>
</template>
<script>
import Navbar from '../components/Navbar.vue'
import app from '../api/firebase'
import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions"
import { getAuth, updateEmail, updatePassword, deleteUser, reauthenticateWithCredential, EmailAuthProvider } from "firebase/auth";
const auth = getAuth();
const user = auth.currentUser;
export default {
name: "AccountPage",
components: {
Navbar,
},
data() {
return {
displayEmail: "",
newEmail: "",
newPassword: "",
currentPassword: "",
displayFirebaseSuccessMsg: false,
FirebaseSuccessMsg: "",
displayFirebaseError: false,
FirebaseError: "",
reAuthSuccessful: false,
missingCredentials: false
}
},
created() {
const user = auth.currentUser
this.displayEmail = user.email
const functions = getFunctions(app)
let host = window.location.hostname
if (host === '127.0.0.1' || host === 'localhost') {
connectFunctionsEmulator(functions, host, 5001);
}
const secureFunction = httpsCallable(functions, 'securefunction')
secureFunction().then((response) => {
console.log(response);
})
},
methods: {
async authenticateUser(password) {
var credential = await EmailAuthProvider.credential(user.email, password)
await reauthenticateWithCredential(user, credential).then(() => {
this.reAuthSuccessful = true
})
.catch((error) => {
this.reAuthSuccessful = false
this.FirebaseError = error.message
this.displayFirebaseError = true
})
},
resetMessages() {
this.missingCredentials = false
this.displayFirebaseError = false
this.displayFirebaseSuccessMsg = false
},
resetCredentials() {
this.newEmail = ""
this.newPassword = ""
this.currentPassword = ""
this.reAuthSuccessful = false
},
updateUserEmail() {
this.resetMessages()
if (!this.newEmail || !this.currentPassword) {
this.missingCredentials = true
return
}
this.authenticateUser(this.currentPassword).then(() => {
if (!this.reAuthSuccessful) return
updateEmail(user, this.newEmail).then(() => {
this.displayEmail = this.newEmail
this.resetCredentials()
this.FirebaseSuccessMsg = "Email updated"
this.displayFirebaseSuccessMsg = true
})
.catch((error) => {
this.FirebaseError = error.message
this.displayFirebaseError = true
})
})
},
updateUserPassword() {
this.resetMessages()
if (!this.newPassword || !this.currentPassword) {
this.missingCredentials = true
return
}
this.authenticateUser(this.currentPassword).then(() => {
if (!this.reAuthSuccessful) return
updatePassword(user, this.newPassword).then(() => {
this.resetCredentials()
this.FirebaseSuccessMsg = "Password updated"
this.displayFirebaseSuccessMsg = true
})
.catch((error) => {
this.FirebaseError = error.message
this.displayFirebaseError = true
})
})
},
deleteUserAccount() {
this.resetMessages()
if (!this.currentPassword) {
this.missingCredentials = true
return
}
this.authenticateUser(this.currentPassword).then(() => {
if (!this.reAuthSuccessful) return
deleteUser(user).then(() => {
this.resetCredentials()
this.FirebaseSuccessMsg = "Account deleted"
this.displayFirebaseSuccessMsg = true
this.$router.push({path:'/'})
})
.catch((error) => {
this.FirebaseError = error.message
this.displayFirebaseError = true
})
})
}
}
}
</script>
<style scoped>
</style>

View File

@ -11,6 +11,7 @@
<input @click="login" type="submit" name="" value="Login"> <input @click="login" type="submit" name="" value="Login">
<a><router-link to="/signup">Don't have an account?</router-link></a> <a><router-link to="/signup">Don't have an account?</router-link></a>
</div> </div>
<p v-if="displayFirebaseError">{{ FirebaseError }}</p>
</div> </div>
</template> </template>
@ -25,7 +26,9 @@ export default {
data() { data() {
return { return {
email: "", email: "",
password: "" password: "",
displayFirebaseError: false,
FirebaseError: ""
} }
}, },
@ -35,17 +38,16 @@ export default {
methods: { methods: {
login() { login() {
this.displayFirebaseError = false
const auth = getAuth(app) const auth = getAuth(app)
signInWithEmailAndPassword(auth, this.email, this.password) signInWithEmailAndPassword(auth, this.email, this.password)
.then((userCredential) => { .then((userCredential) => {
const user = userCredential.user const user = userCredential.user
this.$router.push({path:'/secure'}) this.$router.push({path:'/account'})
}) })
.catch((error) => { .catch((error) => {
const errorCode = error.code this.FirebaseError = error.message
const errorMessage = error.message this.displayFirebaseError = true
console.log(errorCode)
console.log(errorMessage)
}) })
} }
} }

View File

@ -1,32 +0,0 @@
<template>
<Navbar />
<h1>Secure</h1>
</template>
<script>
import Navbar from '../components/Navbar.vue'
import app from '../api/firebase'
import {getFunctions, httpsCallable, connectFunctionsEmulator} from "firebase/functions"
export default {
name: "SecurePage",
components: {
Navbar,
},
created() {
const functions = getFunctions(app)
let host = window.location.hostname
if (host === '127.0.0.1' || host === 'localhost') {
connectFunctionsEmulator(functions, host, 5001);
}
const secureFunction = httpsCallable(functions, 'securefunction')
secureFunction().then((response) => {
console.log(response);
})
}
}
</script>
<style scoped>
</style>

View File

@ -11,6 +11,7 @@
<input @click="signup" type="submit" name="" value="Sign Up"> <input @click="signup" type="submit" name="" value="Sign Up">
<a><router-link to="/login">Already have an account?</router-link></a> <a><router-link to="/login">Already have an account?</router-link></a>
</div> </div>
<p v-if="displayFirebaseError">{{ FirebaseError }}</p>
</div> </div>
</template> </template>
@ -25,7 +26,9 @@ export default {
data() { data() {
return { return {
email: "", email: "",
password: "" password: "",
displayFirebaseError: false,
FirebaseError: ""
} }
}, },
@ -35,17 +38,16 @@ export default {
methods: { methods: {
signup() { signup() {
this.displayFirebaseError = false;
const auth = getAuth(app) const auth = getAuth(app)
createUserWithEmailAndPassword(auth, this.email, this.password) createUserWithEmailAndPassword(auth, this.email, this.password)
.then((userCredential) => { .then((userCredential) => {
const user = userCredential.user const user = userCredential.user
this.$router.push({path:'/secure'}) this.$router.push({path:'/account'})
}) })
.catch((error) => { .catch((error) => {
const errorCode = error.code this.FirebaseError = error.message
const errorMessage = error.message this.displayFirebaseError = true
console.log(errorCode)
console.log(errorMessage)
}) })
} }
} }

View File

@ -23,7 +23,7 @@ function loadPage(component) {
export default [ export default [
{path: "/", component:loadPage("MapPage")}, {path: "/", component:loadPage("MapPage")},
{path: "/insights", component:loadPage("InsightsPage")}, {path: "/insights", component:loadPage("InsightsPage")},
{path: "/secure", component:loadPage('SecurePage'), beforeEnter: isAuth}, {path: "/account", component:loadPage('AccountPage'), beforeEnter: isAuth},
{path: "/signup", component:loadPage('SignUpPage')}, {path: "/signup", component:loadPage('SignUpPage')},
{path: "/login", component:loadPage('LoginPage')}, {path: "/login", component:loadPage('LoginPage')},
] ]