diff --git a/src/auth/middleware.js b/src/auth/middleware.js index b641877..05f5d5e 100644 --- a/src/auth/middleware.js +++ b/src/auth/middleware.js @@ -24,10 +24,9 @@ const createMiddleware = (users) => { res.redirect("/login"); return res.status(status.Unauthorized); } - + if (!req.session.user) { let user = await users.findOne({ _id: new ObjectId(req.session.userId) }).then((user) => user); - if (!user) { return req.session.destroy((err) => { if (err) { @@ -49,7 +48,7 @@ const createMiddleware = (users) => { console.error("Failed to save session: ", err); return req.session.destroy((err) => { - req.session.errMessage = "An error occured, please login again."; + req.session.errMessage = "Failed to save session, please login again."; if (err) { console.error("Failed to destroy session: ", err); diff --git a/src/public/scripts/profile.js b/src/public/scripts/profile.js index d803378..79f4db0 100644 --- a/src/public/scripts/profile.js +++ b/src/public/scripts/profile.js @@ -11,6 +11,7 @@ function lockAccount() { document.getElementById("password").disabled = true; document.getElementById("repassword").disabled = true; document.getElementById("save-account").classList.add("cursor-not-allowed"); + document.getElementById("save-account").classList.remove("cursor-pointer"); document.getElementById("edit-account").innerHTML = "Edit"; document.getElementById("edit-account").onclick = unlockAccount; @@ -30,7 +31,12 @@ function lockPersonal() { document.getElementById("ms-married").disabled = true; document.getElementById("ms-divorced").disabled = true; document.getElementById("ms-widowed").disabled = true; + document.getElementById("income").disabled = true; + document.getElementById("expenses").disabled = true; + document.getElementById("assets").disabled = true; + document.getElementById("liabilities").disabled = true; document.getElementById("save-personal").classList.add("cursor-not-allowed"); + document.getElementById("save-personal").classList.remove("cursor-pointer"); document.getElementById("edit-personal").innerHTML = "Edit"; document.getElementById("edit-personal").onclick = unlockPersonal; @@ -42,11 +48,12 @@ function lockPersonal() { */ function unlockAccount() { document.getElementById("save-account").disabled = false; - // document.getElementById("email").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("save-account").classList.add("cursor-pointer"); document.getElementById("edit-account").innerHTML = "Cancel changes"; document.getElementById("edit-account").onclick = lockAccount; @@ -64,7 +71,12 @@ function unlockPersonal() { document.getElementById("ms-married").disabled = false; document.getElementById("ms-divorced").disabled = false; document.getElementById("ms-widowed").disabled = false; + document.getElementById("income").disabled = false; + document.getElementById("expenses").disabled = false; + document.getElementById("assets").disabled = false; + document.getElementById("liabilities").disabled = false; document.getElementById("save-personal").classList.remove("cursor-not-allowed"); + document.getElementById("save-personal").classList.add("cursor-pointer"); document.getElementById("edit-personal").innerHTML = "Cancel changes"; document.getElementById("edit-personal").onclick = lockPersonal; @@ -72,4 +84,4 @@ function unlockPersonal() { // On page load, ensure forms are locked and reset lockAccount(); -// lockPersonal(); +lockPersonal(); diff --git a/src/router/user.js b/src/router/user.js index d8fd3d3..420eb55 100644 --- a/src/router/user.js +++ b/src/router/user.js @@ -264,10 +264,12 @@ module.exports = (middleware, users, plans, assets) => { const validationOptions = { convert: true, abortEarly: false }; const { error, value } = questionnaireSchema.validate(req.body, validationOptions); + let referrer = req.get('Referrer') || "/home"; if (error) { console.error("Questionnaire validation error:", error.details); req.session.errMessage = "Invalid input: " + error.details.map(d => d.message.replace(/"/g, '')).join(', '); - res.status(status.BadRequest).redirect("/questionnaire"); + let redirect = referrer.includes("?profile") ? "/questionnaire?profile" : "/questionnaire"; + res.status(status.BadRequest).redirect(redirect); return; } @@ -296,20 +298,34 @@ module.exports = (middleware, users, plans, assets) => { console.log(`User questionnaire data unchanged (already up-to-date): ${req.session.userId}`); } - req.session.user.financialData = true; req.session.errMessage = ""; - - req.session.save(err => { + req.session.user = null; // set user to null so middleware updates user + req.session.save((err) => { if (err) { - res.status(status.InternalServerError).redirect("/plans"); + console.error("Failed to save session: ", err); + + return req.session.destroy((err) => { + req.session.errMessage = "Failed to save session, please login again."; + + if (err) { + console.error("Failed to destroy session: ", err); + } + + res.status(status.InternalServerError); + return res.redirect("/login"); + }); } - res.status(status.Ok).redirect("/plans"); + + let redirect = referrer.includes("?profile") ? "/profile" : + referrer != "/home" ? "/plans" : referrer; + return res.status(status.Ok).redirect(redirect); }); }).catch(err => { console.error("Error updating questionnaire in database:", err); req.session.errMessage = "An error occurred while saving your information. Please try again."; - res.status(status.InternalServerError).redirect("/questionnaire"); + let redirect = referrer.includes("?profile") ? "/questionnaire?profile" : "/questionnaire"; + res.status(status.InternalServerError).redirect(redirect); }); }); @@ -330,6 +346,7 @@ module.exports = (middleware, users, plans, assets) => { } let update = { + email: req.body.email, name: req.body.name, }; @@ -357,7 +374,25 @@ module.exports = (middleware, users, plans, assets) => { } req.session.errMessage = ""; - return res.status(status.Ok).redirect("/profile"); + req.session.user = null; // set user to null so middleware updates user + req.session.save((err) => { + if (err) { + console.error("Failed to save session: ", err); + + return req.session.destroy((err) => { + req.session.errMessage = "Failed to save session, please login again."; + + if (err) { + console.error("Failed to destroy session: ", err); + } + + res.status(status.InternalServerError); + return res.redirect("/login"); + }); + } + + 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."; @@ -365,7 +400,81 @@ module.exports = (middleware, users, plans, assets) => { }); }); - router.post("/createAsset", async (req, res) => { + router.post("/updatePersonal", (req, res) => { + const questionnaireSchema = joi.object({ + dob: joi.date().required(), + education: joi.string().valid('primary', 'secondary', 'tertiary', 'postgraduate').required(), + maritalStatus: joi.string().valid('single', 'married', 'divorced', 'widowed').required(), + income: joi.number().min(0).required(), + expenses: joi.number().min(0).required(), + assets: joi.number().min(0).required(), + liabilities: joi.number().min(0).required(), + }); + + const validationOptions = { convert: true, abortEarly: false }; + const { error, value } = questionnaireSchema.validate(req.body, validationOptions); + + if (error) { + console.error("Personal info validation error:", error.details); + req.session.errMessage = "Invalid input: " + error.details.map(d => d.message.replace(/"/g, '')).join(', '); + res.status(status.BadRequest).redirect("/profile"); + return; + } + + users.updateOne( + { _id: new ObjectId(req.session.userId) }, + { + $set: { + financialData: true, + dob: value.dob, + education: value.education, + maritalStatus: value.maritalStatus, + income: value.income, + expenses: value.expenses, + assets: value.assets, + liabilities: value.liabilities, + } + } + ).then((result) => { + if (result.matchedCount === 0) { + console.log(`User not found during personal info update: ${req.session.userId}`); + 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 personal info unchanged (already up-to-date): ${req.session.userId}`); + } + + req.session.errMessage = ""; + req.session.user = null; // set user to null so middleware updates user + req.session.save((err) => { + if (err) { + console.error("Failed to save session: ", err); + + return req.session.destroy((err) => { + req.session.errMessage = "Failed to save session, please login again."; + + if (err) { + console.error("Failed to destroy session: ", err); + } + + res.status(status.InternalServerError); + return res.redirect("/login"); + }); + } + + return res.status(status.Ok).redirect("/profile"); + }); + + }).catch(err => { + console.error("Error updating personal info in database:", err); + req.session.errMessage = "An error occurred while saving your information. Please try again."; + res.status(status.InternalServerError).redirect("/profile"); + }); + }); + + router.post("/createAsset", (req, res) => { // Create asset, each asset has different data structure based on type const type = req.body.type; const assetSchema = getAssetSchema(type); @@ -380,7 +489,7 @@ module.exports = (middleware, users, plans, assets) => { if (valid.err) { req.session.errMessage = "Invalid input", - res.status(status.BadRequest); + res.status(status.BadRequest); return res.redirect("/assets"); } @@ -411,7 +520,7 @@ module.exports = (middleware, users, plans, assets) => { return res.status(status.Ok).redirect("/assets"); }); - router.post("/updateAsset", async (req, res) => { + router.post("/updateAsset", (req, res) => { const type = req.body.type; const assetSchema = getAssetSchema(type); diff --git a/src/views/profile.ejs b/src/views/profile.ejs index 8d6e3b5..3ce06c9 100644 --- a/src/views/profile.ejs +++ b/src/views/profile.ejs @@ -73,6 +73,96 @@ + +
+
+

Personal information

+ <% if (user.financialData) { %> + + <% } %> +
+ + <% if (user.financialData) { %> +
+
+ + + <% let month = typeof(user.dob) == "object" ? user.dob.getMonth() : user.dob.split('-')[1] - 1; %> + <% let day = typeof(user.dob) == "object" ? user.dob.getDate() + 1 : user.dob.split('-')[2].split('T')[0];%> + <% let d = new Date(parseInt(year), parseInt(month), parseInt(day)); %> + value="<%= d.getFullYear() + "-" + ("0"+(d.getMonth()+1)).slice(-2) + "-" + ("0" + d.getDate()).slice(-2); %>" + > +
+
+ + +
+
+ +
+ + + + +
+
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+ <% } else { %> +
+ Answer Questionnare +
+ <% } %> + +
+ +
- -