From 803330b174a2343c00cd6ac8a4cbf9d8c2d493c0 Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Tue, 6 May 2025 15:46:09 -0700 Subject: [PATCH 01/15] update/assets page and creation forms --- src/public/scripts/selectAssetForm.js | 31 +++++ src/router/user.js | 16 ++- src/views/assets.ejs | 173 +++++++++++++++++++++++++- 3 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 src/public/scripts/selectAssetForm.js diff --git a/src/public/scripts/selectAssetForm.js b/src/public/scripts/selectAssetForm.js new file mode 100644 index 0000000..6908766 --- /dev/null +++ b/src/public/scripts/selectAssetForm.js @@ -0,0 +1,31 @@ +const assetForms = [ + "create-other-asset-form", + "create-saving-asset-form", + "create-stock-asset-form" +]; + +/** + * selectAssetForm changes which form is displayed + * to create specified assets. + * @param {string} assetId + */ +function selectAssetForm(assetFormId) { + for (let i = 0; i < assetForms.length; i++) { + if (assetForms[i] == assetFormId) { + document.getElementById(assetFormId).style.display = "block"; + } else { + document.getElementById(assetForms[i]).style.display = "none"; + } + } +} + +/** + * resetRadio to default to other asset type. + */ +function resetRadio() { + document.getElementById("asset-other").checked = true; + document.getElementById("asset-saving").checked = false; + document.getElementById("asset-stock").checked = false; +} + +resetRadio(); diff --git a/src/router/user.js b/src/router/user.js index 407aca9..d534590 100644 --- a/src/router/user.js +++ b/src/router/user.js @@ -14,7 +14,21 @@ module.exports = (middleware, users) => { }); router.get('/assets', (req, res) => { - res.render('assets', { user: req.user }); + let assets = [ + { + name: "hello my name is braeden! abc!", + value: 1123.50, + }, + { + name: "asset 2", + value: 321.05, + }, + { + name: "asset 3", + value: 666, + }, + ]; + res.render('assets', { user: req.user, assets: assets }); return res.status(status.Ok); }); diff --git a/src/views/assets.ejs b/src/views/assets.ejs index a926f36..10ae035 100644 --- a/src/views/assets.ejs +++ b/src/views/assets.ejs @@ -2,8 +2,179 @@ <%- include("./partials/header") %>
- The Assets Page + + + +
+

Create New Asset

+
+ +
+
+ +
+ +
+ + + +
+
+ + +
+ + + + + + + + + + + + + + + +
+ + +
+
+ + + + + + +
+ +
+
+
+

Assets:

+

<%= assets.length %>

+
+
+

Total Value:

+

+ + $<%= assets.reduce((total, e) => total + e.value, 0).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}) %> +

+
+
+ +
+ + Back to Dashboard + + +
+
+ +
+ +
+ <% if (assets.length == 0) { %> + +
+ You have no assets, create a new asset above. +
+
+ <% } %> + <% assets.forEach((asset) => { %> + +
+
+
Icon
+

<%= asset.name %>

+
+
+

+ $<%= asset.value.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}) %> +

+
+
+
+ <% }) %> +
+ + <%- include("./partials/navBar") %> <%- include("./partials/footer") %> \ No newline at end of file From d67718733d28d4dda6ef5ddc854826885e106ff4 Mon Sep 17 00:00:00 2001 From: nicoagostini Date: Tue, 6 May 2025 15:46:57 -0700 Subject: [PATCH 02/15] fix/ Route fixed for index/dashboard --- app.js | 2 +- src/router/user.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index fa59c80..2d7af71 100644 --- a/app.js +++ b/app.js @@ -46,7 +46,7 @@ async function initDatabase() { app.get('/', (req, res) => { if (!req.session.errMessage) req.session.errMessage = ""; - res.render('dashboard'); + res.render('landing'); return res.status(status.Ok); }); diff --git a/src/router/user.js b/src/router/user.js index 9daa7cb..6061bdd 100644 --- a/src/router/user.js +++ b/src/router/user.js @@ -9,7 +9,7 @@ module.exports = (middleware, users, plans) => { router.use(middleware); router.get('/home', async (req, res) => { - res.render('home', { user: req.user }); + res.render('dashboard', { user: req.user }); return res.status(status.Ok); }); From 47fc1983f8dae66b532aca704e8cab7ae794a434 Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Tue, 6 May 2025 15:52:53 -0700 Subject: [PATCH 03/15] update/doc comments + create assets collection --- app.js | 6 ++++-- src/auth/authentication.js | 4 ++++ src/auth/middleware.js | 5 ++--- src/public/scripts/selectAssetForm.js | 2 +- src/router/user.js | 8 +++++++- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app.js b/app.js index 6321d6e..e3f7e23 100644 --- a/app.js +++ b/app.js @@ -33,11 +33,13 @@ app.use("/images", express.static("./src/public/images")); const { connectMongo, getCollection } = require("./src/database/connection"); let users; +let assets; async function initDatabase() { const db = await connectMongo(mongoURI, database); // For any collection, init here - users = await getCollection(db, "users"); + users = await getCollection(db, "users"); + assets = await getCollection(db, "assets"); } /*** ROUTINGS ***/ @@ -79,7 +81,7 @@ initDatabase().then(() => { // Import middleware & apply to user routes const middleware = require("./src/auth/middleware")(users); - app.use(require('./src/router/user')(middleware, users)); + app.use(require('./src/router/user')(middleware, users, assets)); // 404 handler app.get('/*splat', (req, res) => { diff --git a/src/auth/authentication.js b/src/auth/authentication.js index b71fa12..0a25931 100644 --- a/src/auth/authentication.js +++ b/src/auth/authentication.js @@ -3,6 +3,10 @@ const bcrypt = require('bcrypt'); const joi = require("joi"); const salt = 12; +/** + * @param {MongoClient.collection} users db collection + * @returns {express.Router} authentication router + */ module.exports = (users) => { const router = require("express").Router(); diff --git a/src/auth/middleware.js b/src/auth/middleware.js index 8eeaff2..1642da5 100644 --- a/src/auth/middleware.js +++ b/src/auth/middleware.js @@ -2,9 +2,8 @@ const status = require("../util/statuses"); const session = require("express-session"); /** - * createMiddleware returns a middleware function for express. - * @param {MongoClient.collection} users - * @return {async function} + * @param {MongoClient.collection} users db collection + * @returns {async function} middleware handler function */ const createMiddleware = (users) => { return async (req, res, next) => { diff --git a/src/public/scripts/selectAssetForm.js b/src/public/scripts/selectAssetForm.js index 6908766..b40a946 100644 --- a/src/public/scripts/selectAssetForm.js +++ b/src/public/scripts/selectAssetForm.js @@ -7,7 +7,7 @@ const assetForms = [ /** * selectAssetForm changes which form is displayed * to create specified assets. - * @param {string} assetId + * @param {string} assetFormId */ function selectAssetForm(assetFormId) { for (let i = 0; i < assetForms.length; i++) { diff --git a/src/router/user.js b/src/router/user.js index d534590..9a3897f 100644 --- a/src/router/user.js +++ b/src/router/user.js @@ -3,7 +3,13 @@ const bcrypt = require('bcrypt'); const joi = require("joi"); const salt = 12; -module.exports = (middleware, users) => { +/** + * @param {function} middleware handler + * @param {MongoClient.collection} users db collection + * @param {MongoClient.collection} assets db collection + * @returns {express.Router} user protected routes router + */ +module.exports = (middleware, users, assets) => { const router = require("express").Router(); router.use(middleware); From 1f8579a0523d6e60d8394cfe0d937acf7e6069c2 Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Tue, 6 May 2025 16:59:33 -0700 Subject: [PATCH 04/15] update/save user from middleware to session --- src/auth/middleware.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/auth/middleware.js b/src/auth/middleware.js index 1642da5..fc8c730 100644 --- a/src/auth/middleware.js +++ b/src/auth/middleware.js @@ -13,15 +13,18 @@ const createMiddleware = (users) => { return res.status(status.Unauthorized); } - let user = await users.findOne({ "email": req.session.email }).then((user) => user); - - if (!user) { - req.session.errMessage = "User not found"; - res.redirect("/login"); - return res.status(status.Unauthorized); + if (!req.session.user) { + let user = await users.findOne({ "email": req.session.email }).then((user) => user); + + if (!user) { + req.session.errMessage = "User not found"; + res.redirect("/login"); + return res.status(status.Unauthorized); + } + + req.session.user = user; } - - req.user = user; + next(); }; } From 78946bb6ca49cf0830d559fc7b43cebc330b45b5 Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Tue, 6 May 2025 16:59:49 -0700 Subject: [PATCH 05/15] update/save asset to database --- src/router/user.js | 106 +++++++++++++++++++++++++++++++++---------- src/views/assets.ejs | 17 ++++--- 2 files changed, 91 insertions(+), 32 deletions(-) diff --git a/src/router/user.js b/src/router/user.js index 9a3897f..8310630 100644 --- a/src/router/user.js +++ b/src/router/user.js @@ -15,53 +15,40 @@ module.exports = (middleware, users, assets) => { router.use(middleware); router.get('/home', async (req, res) => { - res.render('home', { user: req.user }); + res.render('home', { user: req.session.user }); return res.status(status.Ok); }); - router.get('/assets', (req, res) => { - let assets = [ - { - name: "hello my name is braeden! abc!", - value: 1123.50, - }, - { - name: "asset 2", - value: 321.05, - }, - { - name: "asset 3", - value: 666, - }, - ]; - res.render('assets', { user: req.user, assets: assets }); + router.get('/assets', async (req, res) => { + let userAssets = await assets.find({ "ownerId": req.session.user._id }).toArray(); + res.render('assets', { user: req.session.user, assets: userAssets }); return res.status(status.Ok); }); router.get('/plans', (req, res) => { - res.render('plans', { user: req.user }); + res.render('plans', { user: req.session.user }); return res.status(status.Ok); }); router.get('/more', (req, res) => { - res.render('more', { user: req.user }); + res.render('more', { user: req.session.user }); return res.status(status.Ok); }); router.get('/profile', (req, res) => { - res.render('profile', { user: req.user, errMessage: req.session.errMessage }); + res.render('profile', { user: req.session.user, errMessage: req.session.errMessage }); return res.status(status.Ok); }); router.get('/settings', (req, res) => { - res.render('settings', { user: req.user }); + res.render('settings', { user: req.session.user }); return res.status(status.Ok); }); router.get('/questionnaire', (req, res) => { const errMessage = req.session.errMessage; req.session.errMessage = ""; - res.render('questionnaire', { user: req.user, errMessage: errMessage }); + res.render('questionnaire', { user: req.session.user, errMessage: errMessage }); }); router.post('/questionnaire', (req, res) => { @@ -145,7 +132,6 @@ module.exports = (middleware, users, assets) => { } let update = { - // email: req.body.email, name: req.body.name, }; @@ -181,5 +167,79 @@ module.exports = (middleware, users, assets) => { }); }); + router.post("/createAsset", async (req, res) => { + // Create asset, each asset has different data structure based on type + const type = req.body.assetType; + let assetSchema; + + switch (type) { + case "other": + assetSchema = joi.object({ + ownerId: joi.string().alphanum().required(), + type: joi.string().valid("other", "stock", "saving").required(), + name: joi.string().alphanum().min(3).max(30).required(), + value: joi.number().min(0).required(), + purchaseDate: joi.date().required(), + description: joi.string().alphanum().max(240), + }); + break; + case "saving": + assetSchema = joi.object({ + ownerId: joi.string().alphanum().required(), + type: joi.string().valid("other", "stock", "saving").required(), + name: joi.string().alphanum().min(3).max(30).required(), + value: joi.number().min(0).required(), + }); + break; + case "stock": + assetSchema = joi.object({ + ownerId: joi.string().alphanum().required(), + type: joi.string().valid("other", "stock", "saving").required(), + ticker: joi.string().alphanum().min(3).max(5).required(), + price: joi.number().min(0).required(), + quantity: joi.number().min(1).required(), + purchaseDate: joi.date().required(), + }); + break; + default: + console.error("Modified asset type, rejected"); + req.session.errMessage = "Invalid input"; + return res.status(status.BadRequest).redirect("/assets"); + }; + + const valid = assetSchema.validate(req.body); + + if (valid.err) { + req.session.errMessage = "Invalid input", + res.status(status.BadRequest); + return res.redirect("/assets"); + } + + let newAsset = { + ...req.body, + updatedAt: new Date(), + }; + + if (type == "stock") { + newAsset.quantity = parseInt(newAsset.quantity); + newAsset.price = parseFloat(newAsset.price) + newAsset.value = newAsset.quantity * newAsset.price; + newAsset.name = `${newAsset.ticker} Stock`; + } + newAsset.value = parseFloat(newAsset.value); + newAsset.type = type; + + assets.insertOne(newAsset, (err, result) => { + if (err) { + console.error("Error creating asset: ", err); + req.session.errMessage = "Internal server error"; + return res.status(status.InternalServerError).redirect("/assets"); + } + }); + + req.session.errMessage = ""; + return res.status(status.Ok).redirect("/assets"); + }); + return router; }; diff --git a/src/views/assets.ejs b/src/views/assets.ejs index 10ae035..4d4417b 100644 --- a/src/views/assets.ejs +++ b/src/views/assets.ejs @@ -33,12 +33,12 @@ -
+ - + @@ -63,12 +63,12 @@
- -