diff --git a/app.js b/app.js
index 9bd6875..4a37b8e 100644
--- a/app.js
+++ b/app.js
@@ -50,6 +50,8 @@ app.get('/', (req, res) => {
});
app.get('/signup', (req, res) => {
+ const ignore = ["User not found", "Incorrect password"];
+ if (ignore.includes(req.session.errMessage)) req.session.errMessage = "";
res.render('signup', { errMessage: req.session.errMessage });
return res.status(status.Ok);
});
diff --git a/src/auth/authentication.js b/src/auth/authentication.js
index db53450..261b5a4 100644
--- a/src/auth/authentication.js
+++ b/src/auth/authentication.js
@@ -39,8 +39,6 @@ module.exports = (users) => {
return res.redirect("/login");
}
- console.log("User logged in successfully");
- console.log("User email: " + req.body.email);
req.session.authenticated = true;
req.session.userId = user._id;
req.session.email = req.body.email;
@@ -53,7 +51,7 @@ module.exports = (users) => {
router.post("/signup", async (req, res) => {
const userSchema = joi.object({
email: joi.string().email().required(),
- // name: joi.string().alphanum().max(20).required(),
+ name: joi.string().alphanum().max(20).required(),
password: joi.string().max(20).min(8).required(),
repassword: joi.string().max(20).min(8).required(),
});
@@ -76,13 +74,13 @@ module.exports = (users) => {
users.insertOne({
email: req.body.email,
- // name: req.body.name,
+ name: req.body.name,
password: hashedPassword,
}).then((results, err) => {
if (err) {
- res.status(status.InternalServerError);
console.error(err);
- return res.send("Internal server error");
+ res.session.errMessage = "Internal server error";
+ return res.status(status.InternalServerError).redirect("/signup");
}
req.session.authenticated = true;
@@ -90,8 +88,7 @@ module.exports = (users) => {
req.session.userId = results.insertedId;
req.session.errMessage = "";
- res.status(status.Ok);
- return res.redirect("/home");
+ return res.status(status.Ok).redirect("/home");
});
});
diff --git a/src/public/scripts/profile.js b/src/public/scripts/profile.js
new file mode 100644
index 0000000..d803378
--- /dev/null
+++ b/src/public/scripts/profile.js
@@ -0,0 +1,75 @@
+/**
+ * lockAccount resets inputs and disabled inputs
+ */
+function lockAccount() {
+ // Clear unsaved inputs on page load (refresh doesnt clear them)
+ document.getElementById("account-form").reset();
+
+ document.getElementById("save-account").disabled = true;
+ document.getElementById("email").disabled = true;
+ document.getElementById("name").disabled = true;
+ document.getElementById("password").disabled = true;
+ document.getElementById("repassword").disabled = true;
+ document.getElementById("save-account").classList.add("cursor-not-allowed");
+
+ document.getElementById("edit-account").innerHTML = "Edit";
+ document.getElementById("edit-account").onclick = unlockAccount;
+}
+
+/**
+ * lockPersonal resets inputs and disabled inputs
+ */
+function lockPersonal() {
+ // Clear unsaved inputs on page load (refresh doesnt clear them)
+ document.getElementById("personal-form").reset();
+
+ document.getElementById("save-personal").disabled = true;
+ document.getElementById("dob").disabled = true;
+ document.getElementById("education").disabled = true;
+ document.getElementById("ms-single").disabled = true;
+ document.getElementById("ms-married").disabled = true;
+ document.getElementById("ms-divorced").disabled = true;
+ document.getElementById("ms-widowed").disabled = true;
+ document.getElementById("save-personal").classList.add("cursor-not-allowed");
+
+ document.getElementById("edit-personal").innerHTML = "Edit";
+ document.getElementById("edit-personal").onclick = unlockPersonal;
+}
+
+/**
+ * unlockAccount removes disabled from inputs and
+ * allows users to edit their profile.
+ */
+function unlockAccount() {
+ document.getElementById("save-account").disabled = false;
+ // document.getElementById("email").disabled = false;
+ document.getElementById("name").disabled = false;
+ document.getElementById("password").disabled = false;
+ document.getElementById("repassword").disabled = false;
+ document.getElementById("save-account").classList.remove("cursor-not-allowed");
+
+ document.getElementById("edit-account").innerHTML = "Cancel changes";
+ document.getElementById("edit-account").onclick = lockAccount;
+}
+
+/**
+ * unlocPersonal removes disabled from inputs and
+ * allows users to edit their personal information.
+ */
+function unlockPersonal() {
+ document.getElementById("save-personal").disabled = false;
+ document.getElementById("dob").disabled = false;
+ document.getElementById("education").disabled = false;
+ document.getElementById("ms-single").disabled = false;
+ document.getElementById("ms-married").disabled = false;
+ document.getElementById("ms-divorced").disabled = false;
+ document.getElementById("ms-widowed").disabled = false;
+ document.getElementById("save-personal").classList.remove("cursor-not-allowed");
+
+ document.getElementById("edit-personal").innerHTML = "Cancel changes";
+ document.getElementById("edit-personal").onclick = lockPersonal;
+}
+
+// On page load, ensure forms are locked and reset
+lockAccount();
+// lockPersonal();
diff --git a/src/router/user.js b/src/router/user.js
index d592f37..9daa7cb 100644
--- a/src/router/user.js
+++ b/src/router/user.js
@@ -1,5 +1,7 @@
const status = require("../util/statuses");
+const bcrypt = require('bcrypt');
const joi = require("joi");
+const salt = 12;
module.exports = (middleware, users, plans) => {
const router = require("express").Router();
@@ -94,7 +96,7 @@ module.exports = (middleware, users, plans) => {
});
router.get('/profile', (req, res) => {
- res.render('profiles', { user: req.user });
+ res.render('profile', { user: req.user, errMessage: req.session.errMessage });
return res.status(status.Ok);
});
@@ -111,7 +113,7 @@ module.exports = (middleware, users, plans) => {
router.post('/questionnaire', (req, res) => {
// console.log("Questionnaire POST body:", req.body);
-
+
const questionnaireSchema = joi.object({
dob: joi.date().required(),
education: joi.string().valid('primary', 'secondary', 'tertiary', 'postgraduate').required(),
@@ -167,5 +169,58 @@ module.exports = (middleware, users, plans) => {
});
});
+ router.post("/updateAccount", async (req, res) => {
+ const accountSchema = joi.object({
+ email: joi.string().email(),
+ name: joi.string().alphanum().max(20),
+ password: joi.string().max(20).min(8),
+ repassword: joi.string().max(20).min(8),
+ });
+
+ const valid = accountSchema.validate(req.body);
+
+ if (valid.err) {
+ req.session.errMessage = "Invalid input",
+ res.status(status.BadRequest);
+ return res.redirect("/profile");
+ }
+
+ let update = {
+ // email: req.body.email,
+ name: req.body.name,
+ };
+
+ if ((req.body.password != "") && (req.body.password != req.body.repassword)) {
+ req.session.errMessage = "New passwords must match";
+ res.status(status.BadRequest);
+ return res.redirect("/profile");
+ } else if (req.body.password != "") {
+ let hashedPassword = await bcrypt.hashSync(req.body.password, salt);
+ update.password = hashedPassword;
+ }
+
+ users.updateOne(
+ { email: req.session.email },
+ { $set: update }
+ ).then((result) => {
+ if (result.matchedCount === 0) {
+ console.log(`User not found during account update: ${req.session.email}`);
+ req.session.errMessage = "User session invalid. Please log in again.";
+ res.status(status.NotFound).redirect("/login");
+ return;
+ }
+ if (result.modifiedCount === 0 && result.matchedCount === 1) {
+ console.log(`User account data unchanged (already up-to-date): ${req.session.email}`);
+ }
+
+ req.session.errMessage = "";
+ return res.status(status.Ok).redirect("/profile");
+ }).catch(err => {
+ console.error("Error updating account in database:", err);
+ req.session.errMessage = "An error occurred while saving your information. Please try again.";
+ return res.status(status.InternalServerError).redirect("/profile");
+ });
+ });
+
return router;
};
diff --git a/src/views/profile.ejs b/src/views/profile.ejs
new file mode 100644
index 0000000..34f0bc2
--- /dev/null
+++ b/src/views/profile.ejs
@@ -0,0 +1,90 @@
+<%- include("./partials/fileHeader") %>
+<%- include("./partials/header") %>
+
+Welcome <%= user.name %>
+
+ <% if (errMessage != "") { %>
+ Account settings
+
+