From bd71b1e0d44804ae05c7bf69e6ca509db057a795 Mon Sep 17 00:00:00 2001 From: willhockey20 Date: Sat, 23 Sep 2023 22:30:05 -0400 Subject: [PATCH 01/12] Expressified Server --- .gitignore | 2 + expressed_server_rewrite.js | 34 ++++ package.json | 15 ++ public/css/main.css | 44 +++++ public/index.html | 44 +++++ public/js/main.js | 341 ++++++++++++++++++++++++++++++++++++ server.js | 165 +++++++++++++++++ 7 files changed, 645 insertions(+) create mode 100644 .gitignore create mode 100644 expressed_server_rewrite.js create mode 100644 package.json create mode 100644 public/css/main.css create mode 100644 public/index.html create mode 100644 public/js/main.js create mode 100644 server.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..f51735d3d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +package-lock.json +/node_modules \ No newline at end of file diff --git a/expressed_server_rewrite.js b/expressed_server_rewrite.js new file mode 100644 index 000000000..b6cfaffa0 --- /dev/null +++ b/expressed_server_rewrite.js @@ -0,0 +1,34 @@ +const exp = require('express'); +const app = exp(); +const port = 3000; + +const totalPrice = { totalPrice: 0.0 }; +let retObject; +const groceryList = []; + +const calcTotalPrice = function () { + totalPrice.totalPrice = 0.0; + if(groceryList.length !== 0){groceryList.forEach((item) => { + if (!isNaN(parseFloat(item.price))) { + totalPrice.totalPrice += parseFloat(item.price); + } else { + totalPrice.totalPrice += 0.0; + } + })}; + }; + +app.use(exp.static('public')) +app.use(exp.json()) + +app.post("/submit", (req, res) => { + console.log(req) + groceryList.push(req.item); + calcTotalPrice(); + retObject = { groceryList, totalPrice }; + res.writeHead(200, { 'Content-Type': 'text/json' }) + res.end(JSON.stringify(retObject)); +}) + +app.listen(port, ()=> { + console.log(`Listening on ${port}`); +}); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 000000000..3d375c7fc --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "", + "version": "", + "description": "", + "author": "", + "scripts": { + "start": "node expressed_server_rewrite.js" + }, + "dependencies": { + "express": "^4.18.2", + "mime": "^2.6.0", + "mongodb": "^6.1.0", + "passport": "^0.6.0" + } +} diff --git a/public/css/main.css b/public/css/main.css new file mode 100644 index 000000000..cbe928857 --- /dev/null +++ b/public/css/main.css @@ -0,0 +1,44 @@ +body { + background: gray; + color:white; + font-family:"Oswald", sans-serif; + font-size: 14px; +} +h1{ + font-family:"Oswald", serif; + font-size: 48px; + color:aquamarine; +} +.lists{ + display: flex; + justify-content: flex-start; + padding-left:7rem +} +.groceryItem{ + font-weight: 300; +} +label{ + font-family: "Oswald", serif; +} +#groceryList{ + display: flex; + flex-direction:column; + list-style: none; +} +#groceryList #modbox-label{ + padding-left: 1.5rem; +} +#cartList{ + display: flex; + flex-direction:column; + list-style: none; +} +.errorMsg{ + visibility: hidden; + display: none; + color:red; + font-size: 18px; +} +.priceCounts{ + +} \ No newline at end of file diff --git a/public/index.html b/public/index.html new file mode 100644 index 000000000..f6743779d --- /dev/null +++ b/public/index.html @@ -0,0 +1,44 @@ + + + + Grocery List + + + + + + + + + +

Your Grocery List

+
+ + + + + + + +
+ +
+ + + +
+
+ + + +
+ + + diff --git a/public/js/main.js b/public/js/main.js new file mode 100644 index 000000000..128467310 --- /dev/null +++ b/public/js/main.js @@ -0,0 +1,341 @@ +let total = 0.00 +const submit = async function( event ) { + event.preventDefault() + + let err = document.getElementsByClassName("errorMsg")[0]; + const itemin = document.querySelector( "#item" ), + pricein = document.querySelector("#price"), + json = { item: {itemName: itemin.value, price: pricein.value} }, + body = JSON.stringify( json ) + if(isNaN(parseFloat(json.item.price))) + { + err.style.display = "flex" + err.style.visibility = "visible" + return false; + } + else{ + err.style.display = "none" + err.style.visibility = "hidden" + } + + const response = await fetch( '/submit', { + method:'POST', + headers: {'Content-Type': 'application/json'}, + body: body + }) + + const data = await response.json() + + addList(data); + +} + +const modify = async function (event){ + event.preventDefault() + let idxs = []; + let idx = 0; + let list = [].slice.call(document.getElementById("groceryList").children) + list = list.splice(1) + list.forEach(element => { + if(element.getElementsByClassName("modbox").length === 1) + { + if(element.getElementsByClassName("modbox")[0].checked){ + idxs.push(idx); + } + } + idx+= 1; + }); + + let err = document.getElementsByClassName("errorMsg")[0]; + const pricein = document.querySelector("#price"), + json = { items: idxs, price: pricein.value}, + body = JSON.stringify( json ) + if(isNaN(parseFloat(json.price))) + { + err.style.display = "flex" + err.style.visibility = "visible" + return false; + } + else{ + err.style.display = "none" + err.style.visibility = "hidden" + } + + const response = await fetch( '/modify', { + method:'POST', + body + }) + + const data = await response.json() + + updateList(data); +} + +const reset = async function( event ) +{ + event.preventDefault(); + workingTotal = 0.0 + let body = JSON.stringify({id: "reset"}) + + const resetResponse = await fetch( "/reset", { + method:'DELETE', + body + }) + + let list; + if(document.getElementById("groceryList") === null) + { + list = document.createElement('ul') + list.setAttribute("id", "groceryList") + list.appendChild(listLabel) + list.appendChild(defaultListItem); + document.getElementById("lists-container").appendChild(list) + } + else{ + list = document.getElementById("groceryList") + list.innerHTML = "" + } + list.appendChild(listLabel) + list.appendChild(defaultListItem); + + let tp = document.getElementById("tpNum"); + tp.innerText = `$0.00` + tp = document.getElementById("icNum") + tp.innerText = `$0.00` + tp = document.getElementById("difNum") + tp.innerText = `$0.00` + + document.getElementById("cartList").innerHTML = "" + document.getElementById("cartList").appendChild(cartLabel) +} +const addList = function(data){ + let list; + let tmp; + if(document.getElementById("groceryList") === null) + { + list = document.createElement('ul') + list.setAttribute("id", "groceryList") + } + else{ + list = document.getElementById("groceryList") + tmp = [].slice.call(list.children); + } + //console.log(tmp) + if(tmp[1].innerText == "Item Name: Price($)") + { + console.log(tmp[1]) + list.removeChild(tmp[1]) + const li = document.createElement('li') + const myIn = document.createElement('input') + const inTwo = document.createElement('input') + const checkLabel = document.createElement("label") + checkLabel.appendChild(document.createTextNode(data.groceryList[0].itemName[0].toUpperCase() + data.groceryList[0].itemName.slice(1) + `: $${data.groceryList[0].price}`)) + myIn.setAttribute("type", "checkbox") + myIn.className = "giBox" + inTwo.setAttribute("type", "checkbox") + inTwo.className = "modbox" + li.className = "groceryItem" + li.appendChild(myIn); + li.appendChild(checkLabel); + li.appendChild(inTwo) + li.id = "item-0" + list.appendChild( li ) + } + for(let i = 0; i < data.groceryList.length; i++) + { + console.log(i, tmp.length) + if(i >= (tmp.length - 1)) + { + const li = document.createElement('li') + const myIn = document.createElement('input') + const inTwo = document.createElement('input') + const checkLabel = document.createElement("label") + checkLabel.appendChild(document.createTextNode(data.groceryList[i].itemName[0].toUpperCase() + data.groceryList[i].itemName.slice(1) + `: $${data.groceryList[i].price}`)) + myIn.setAttribute("type", "checkbox") + myIn.className = "giBox" + inTwo.setAttribute("type", "checkbox") + inTwo.className = "modbox" + li.className = "groceryItem" + li.id = `item-${i}` + li.appendChild(myIn); + li.appendChild(checkLabel); + li.appendChild(inTwo) + list.appendChild( li ) + } + } + let tp = document.getElementById("tpNum"); + tp.innerText = `$${data.totalPrice.totalPrice.toFixed(2)}` + total = parseFloat(data.totalPrice.totalPrice.toFixed(2)) +} + +const delItems = async function ( event ){ + event.preventDefault() + + let idxs = []; + let idx = 0; + let list = [].slice.call(document.getElementById("groceryList").children) + list = list.splice(1) + list.forEach(element => { + if(element.getElementsByClassName("modbox").length === 1) + { + if(element.getElementsByClassName("modbox")[0].checked){ + idxs.push(idx); + } + } + idx+= 1; + }); + + const json = {items: idxs}, + body = JSON.stringify( json ) + const response = await fetch( '/delete', { + method:'DELETE', + body + }) + + const data = await response.json() + + updateList(data); +} + +const updateList = function(data){ + let list; + let tmp; + if(document.getElementById("groceryList") === null) + { + list = document.createElement('ul') + list.setAttribute("id", "groceryList") + } + else{ + list = document.getElementById("groceryList") + tmp = [].slice.call(list.children); + } + //console.log(tmp) + if(tmp[1].innerText == "Item Name: Price($) ") + { + console.log(tmp[1]) + list.removeChild(tmp[1]) + const li = document.createElement('li') + const myIn = document.createElement('input') + const inTwo = document.createElement('input') + const checkLabel = document.createElement("label") + checkLabel.appendChild(document.createTextNode(data.groceryList[0].itemName[0].toUpperCase() + data.groceryList[0].itemName.slice(1) + `: $${data.groceryList[0].price}`)) + myIn.setAttribute("type", "checkbox") + myIn.className = "giBox" + inTwo.setAttribute("type", "checkbox") + inTwo.className = "modbox" + li.className = "groceryItem" + li.appendChild(myIn); + li.appendChild(checkLabel); + li.appendChild(inTwo) + li.id = "item-0" + list.appendChild( li ) + } + for(let i = 0; i < data.groceryList.length; i++) + { + const li = document.createElement('li') + const myIn = document.createElement('input') + const inTwo = document.createElement('input') + const checkLabel = document.createElement("label") + checkLabel.appendChild(document.createTextNode(data.groceryList[i].itemName[0].toUpperCase() + data.groceryList[i].itemName.slice(1) + `: $${data.groceryList[i].price}`)) + myIn.setAttribute("type", "checkbox") + myIn.className = "giBox" + console.log(tmp[i + 1].getElementsByClassName("giBox")[0].checked) + myIn.checked = tmp[i + 1].getElementsByClassName("giBox")[0].checked + inTwo.setAttribute("type", "checkbox") + inTwo.className = "modbox" + li.className = "groceryItem" + li.id = `item-${i}` + li.appendChild(myIn); + li.appendChild(checkLabel); + li.appendChild(inTwo) + list.removeChild(tmp[i+1]) + list.appendChild( li ) + + } + let tp = document.getElementById("tpNum"); + tp.innerText = `$${data.totalPrice.totalPrice.toFixed(2)}` + total = parseFloat(data.totalPrice.totalPrice.toFixed(2)) +} + +const defaultListItem = document.createElement("li"); +const defaultIn = document.createElement('input') +const defaultLabel = document.createElement("label") +const cartLabel = document.createElement("label") +const listLabel = document.createElement("label") + +let workingTotal = 0.00; +let glist; +window.onload = function() { + + defaultLabel.appendChild(document.createTextNode("Item Name: Price($)")) + defaultIn.setAttribute("type", "checkbox") + defaultListItem.className = "groceryItem" + defaultListItem.appendChild(defaultIn); + defaultListItem.appendChild(defaultLabel); + listLabel.appendChild(document.createTextNode("Check items In Cart")) + listLabel.id = "glist-lab" + cartLabel.appendChild(document.createTextNode("In Your Cart")) + cartLabel.id = "cart-lab" + + const button = document.getElementById("submit"); + const resetBut = document.getElementById("reset"); + const modBut = document.getElementById("modify"); + const delBut = document.getElementById("delete") + modBut.onclick = modify; + button.onclick = submit; + resetBut.onclick = reset; + delBut.onclick = delItems; + + gList = document.getElementById("groceryList"); + + gList.addEventListener('change', function(e){ + + if(e.target.classList.contains("giBox")){ + let myLi = e.target.parentElement; + let cartList = document.getElementById("cartList"); + if(e.target.checked){ + let temp = myLi.cloneNode(); + let txt = myLi.innerText; + let num = txt.slice(txt.indexOf("$") + 1) + if(isNaN(parseFloat(num))) + { + //workingTotal+= parseFloat(num.slice(num.indexOf("$"))) + console.log(parseFloat(num.slice(num.indexOf(" ")))) + console.log(num.slice(num.indexOf("$") + 1), "NaN") + console.log(workingTotal) + } + else{ + workingTotal+= parseFloat(num); + console.log(parseFloat(num), "Num") + console.log(workingTotal) + } + document.getElementById("icNum").innerText= `$${workingTotal.toFixed(2)}`; + document.getElementById("difNum").innerText= `$${(total - workingTotal).toFixed(2)}`; + temp.innerHTML = "" + temp.innerText = txt + cartList.appendChild(temp) + } + else{ + let arr = [].slice.call(cartList.children) + arr.every(i => { + if(i.innerText === myLi.innerText) + { + let tnum = i.innerText.slice(i.innerText.indexOf("$") + 1) + if(isNaN(parseFloat(tnum))) + { + workingTotal-= parseFloat(tnum.slice(tnum.indexOf(" ") + 1)) + } + else{ + workingTotal-= parseFloat(tnum); + } + document.getElementById("icNum").innerText= `$${workingTotal.toFixed(2)}`; + document.getElementById("difNum").innerText= `$${Math.abs((total - workingTotal).toFixed(2))}`; + i.remove() + return false; + } + return true; + }) + } + } +}) +} diff --git a/server.js b/server.js new file mode 100644 index 000000000..685b2ae44 --- /dev/null +++ b/server.js @@ -0,0 +1,165 @@ +const http = require("http"), + fs = require("fs"), + // IMPORTANT: you must run `npm install` in the directory for this assignment + // to install the mime library if you're testing this on your local machine. + // However, Glitch will install it automatically by looking in your package.json + // file. + mime = require("mime"), + dir = "public/", + port = 3000; + +const appdata = [ + { model: "toyota", year: 1999, mpg: 23 }, + { model: "honda", year: 2004, mpg: 30 }, + { model: "ford", year: 1987, mpg: 14 }, +]; + +const totalPrice = { totalPrice: 0.0 }; +let retObject; + +const groceryList = []; + +const server = http.createServer(function (request, response) { + + if (request.method === "GET") { + handleGet(request, response); + } else if (request.method === "POST") { + handlePost(request, response); + }else if (request.method === "DELETE") { + handleDelete(request, response); + } + +}); + +const handleGet = function (request, response) { + const filename = dir + request.url.slice(1); + + if (request.url === "/") { + sendFile(response, "public/index.html"); + } else { + sendFile(response, filename); + } +}; + +const calcTotalPrice = function () { + totalPrice.totalPrice = 0.0; + if(groceryList.length !== 0){groceryList.forEach((item) => { + if (!isNaN(parseFloat(item.price))) { + totalPrice.totalPrice += parseFloat(item.price); + } else { + totalPrice.totalPrice += 0.0; + } + })}; +}; + +const modifyPrice = function (data){ + data.items.forEach(idx => { + console.log(groceryList[idx]) + groceryList[idx].price = data.price; + }) +} +const handlePost = function (request, response) { + let dataString = ""; + + request.on("data", function (data) { + dataString += data; + }); + + if(request.url ==="/submit") + { + request.on("end", function () { + const newItem = JSON.parse(dataString).item; + groceryList.push(newItem); + calcTotalPrice(); + //console.log(totalPrice); + retObject = { groceryList, totalPrice }; + console.log(retObject) + response.writeHead(200, "OK", { "Content-Type": "text/json" }); + response.end(JSON.stringify(retObject)); + }); + } + else{ + request.on("end", function () { + modifyPrice(JSON.parse(dataString)) + calcTotalPrice(); + retObject = { groceryList, totalPrice }; + console.log(retObject) + response.writeHead(200, "OK", { "Content-Type": "text/json" }); + response.end(JSON.stringify(retObject)); + }); + } + + +}; +const deleteItems = function(data){ + let temp = [] + outerLoop: data.items.forEach(idx =>{ + if(idx < groceryList.length){ + innerLoop: for(let i = 0; i < groceryList.length; i++) + { + if(i !== idx){ + temp.push(groceryList[i]) + } + else{ + groceryList.splice(idx, 1) + } + }} + else{ + groceryList.splice(idx, 1) + } + }); + + console.log(temp) + groceryList.splice(0, groceryList.length); + temp.forEach(item =>{ + groceryList.push(item) + }); + +} +const handleDelete = function (request, response) { + + let dataString = ""; + + request.on("data", function (data) { + dataString += data; + }); + + if(request.url === "/reset"){ + request.on("end", function () { + groceryList.splice(0, groceryList.length); + console.log(groceryList) + calcTotalPrice(); + response.writeHead(200, "OK", { "Content-Type": "text/json" }); + response.end(JSON.stringify(groceryList)); + });} + else{ + request.on("end", function () { + deleteItems(JSON.parse(dataString)) + calcTotalPrice(); + retObject = { groceryList, totalPrice }; + console.log(retObject) + response.writeHead(200, "OK", { "Content-Type": "text/json" }); + response.end(JSON.stringify(retObject)); + }); + } + +}; + +const sendFile = function (response, filename) { + const type = mime.getType(filename); + + fs.readFile(filename, function (err, content) { + // if the error = null, then we've loaded the file successfully + if (err === null) { + // status code: https://httpstatuses.com + response.writeHeader(200, { "Content-Type": type }); + response.end(content); + } else { + // file not found, error code 404 + response.writeHeader(404); + response.end("404 Error: File Not Found"); + } + }); +}; + +server.listen(process.env.PORT || port); From 2470cca37d11fef278f37af9cc0e7c1ee4ab12ec Mon Sep 17 00:00:00 2001 From: willhockey20 Date: Mon, 25 Sep 2023 20:03:25 -0400 Subject: [PATCH 02/12] Mongo and express done, working on auth and a css framework --- .gitignore | 3 +- README.md | 2 + expressed_server_rewrite.js | 95 +++++++++++++++++++++++++++++---- public/index.html => index.html | 2 +- item_entry.json | 6 +++ login_page.html | 18 +++++++ package.json | 5 ++ public/js/auth.js | 15 ++++++ 8 files changed, 133 insertions(+), 13 deletions(-) rename public/index.html => index.html (97%) create mode 100644 item_entry.json create mode 100644 login_page.html create mode 100644 public/js/auth.js diff --git a/.gitignore b/.gitignore index f51735d3d..8461401c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ package-lock.json -/node_modules \ No newline at end of file +/node_modules +.env \ No newline at end of file diff --git a/README.md b/README.md index 8a31308ca..da3a8645a 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,8 @@ Sample Readme (delete the above when you're ready to submit, and modify the belo your glitch (or alternative server) link e.g. http://a3-charlie-roberts.glitch.me +Professor Roberts gave me an extension on this assignment + Include a very brief summary of your project here. Images are encouraged, along with concise, high-level text. Be sure to include: - the goal of the application diff --git a/expressed_server_rewrite.js b/expressed_server_rewrite.js index b6cfaffa0..2f7e9a790 100644 --- a/expressed_server_rewrite.js +++ b/expressed_server_rewrite.js @@ -1,11 +1,73 @@ const exp = require('express'); +const denv = require('dotenv').config() +const {MongoClient, ObjectId} = require('mongodb'); +const auth = require('passport'); const app = exp(); -const port = 3000; +const port = process.env.PORT; +const connect_uri = process.env.connectionStr +console.log(`Here: ${connect_uri}`) +const client = new MongoClient(connect_uri) +let collection = null; const totalPrice = { totalPrice: 0.0 }; let retObject; const groceryList = []; +async function run() { + await client.connect() + collection = await client.db("GroceryList").collection("Grocery_Items") + if(collection !== null){ + const docs = await collection.find({}).toArray() + console.log(docs) + } + app.get("/docs", async (req, res) => { + if(collection !== null){ + const docs = await collection.find({}).toArray() + res.json(docs) + } + }) + +app.use(exp.static('public')) +app.use(exp.json()) + +app.post("/submit", async (req, res) => { + groceryList.push(req.body.item); + const rst = await collection.insertOne(req.body.item) + console.log(rst) + calcTotalPrice(); + retObject = { groceryList, totalPrice }; + res.writeHead(200, { 'Content-Type': 'application/json' }) + res.end(JSON.stringify(retObject)); +}) + +app.post("/modify", (req, res) => { + modifyPrice(req.body) + calcTotalPrice(); + retObject = { groceryList, totalPrice }; + res.writeHead(200, { 'Content-Type': 'application/json' }) + res.end(JSON.stringify(retObject)); +}) + +app.delete("/reset", (req, res) => { + console.log(req) + groceryList.splice(0, groceryList.length); + calcTotalPrice(); + retObject = { groceryList, totalPrice }; + res.writeHead(200, { 'Content-Type': 'application/json' }) + res.end(JSON.stringify(retObject)); +}) + +app.delete("/del", (req, res) => { + console.log(req) + deleteItems(req.body) + calcTotalPrice(); + retObject = { groceryList, totalPrice }; + res.writeHead(200, { 'Content-Type': 'application/json' }) + res.end(JSON.stringify(retObject)); +}) + +} + const calcTotalPrice = function () { totalPrice.totalPrice = 0.0; if(groceryList.length !== 0){groceryList.forEach((item) => { @@ -17,17 +79,28 @@ const calcTotalPrice = function () { })}; }; -app.use(exp.static('public')) -app.use(exp.json()) +const modifyPrice = function (data){ + data.items.forEach(idx => { + console.log(groceryList[idx]) + groceryList[idx].price = data.price; + }) + } -app.post("/submit", (req, res) => { - console.log(req) - groceryList.push(req.item); - calcTotalPrice(); - retObject = { groceryList, totalPrice }; - res.writeHead(200, { 'Content-Type': 'text/json' }) - res.end(JSON.stringify(retObject)); -}) +const deleteItems = function (data){ + for(let i = groceryList.length - 1; i >= 0; i--) + { + data.every(idx => { + if(idx === i) + { + groceryList.splice(i, 1); + return false; + } + return true; + }) + } +} + +run() app.listen(port, ()=> { console.log(`Listening on ${port}`); diff --git a/public/index.html b/index.html similarity index 97% rename from public/index.html rename to index.html index f6743779d..eadf2f565 100644 --- a/public/index.html +++ b/index.html @@ -1,7 +1,7 @@ - Grocery List + Grocery List Tracker + + + Grocery List Tracker + + + + + + + \ No newline at end of file diff --git a/package.json b/package.json index 3d375c7fc..7e11c3f44 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,14 @@ "start": "node expressed_server_rewrite.js" }, "dependencies": { + "cookie-session": "^2.0.0", + "dotenv": "^16.3.1", "express": "^4.18.2", "mime": "^2.6.0", "mongodb": "^6.1.0", "passport": "^0.6.0" + }, + "devDependencies": { + "tailwindcss": "^3.3.3" } } diff --git a/public/js/auth.js b/public/js/auth.js new file mode 100644 index 000000000..8d50c0096 --- /dev/null +++ b/public/js/auth.js @@ -0,0 +1,15 @@ +console.log("Hey have this be the client side log in code") + +const auth = async function (e) { + e.preventDefault(); + + let uname = document.getElementById("username").value; + let pw = document.getElementById("password").value; + let body = JSON.stringify({uname, pw}); + + const response = await fetch("/auth", { + method: 'GET', + headers: {'Content-Type': 'application/json'}, + body: body + }) +} \ No newline at end of file From f96dc27206f20a329ebdce3829597b29138f338b Mon Sep 17 00:00:00 2001 From: willhockey20 Date: Tue, 26 Sep 2023 18:52:48 -0400 Subject: [PATCH 03/12] Basic log in setup, moving locations though --- expressed_server_rewrite.js | 47 ++- package.json | 3 +- public/js/auth.js | 23 +- public/js/main.js | 518 ++++++++++++++-------------- login_page.html => views/index.html | 4 + index.html => views/main.html | 0 6 files changed, 334 insertions(+), 261 deletions(-) rename login_page.html => views/index.html (61%) rename index.html => views/main.html (100%) diff --git a/expressed_server_rewrite.js b/expressed_server_rewrite.js index 2f7e9a790..ba28723d6 100644 --- a/expressed_server_rewrite.js +++ b/expressed_server_rewrite.js @@ -2,6 +2,8 @@ const exp = require('express'); const denv = require('dotenv').config() const {MongoClient, ObjectId} = require('mongodb'); const auth = require('passport'); +const ghauth = require('passport-github').Strategy; +const cookie = require('cookie-session') const app = exp(); const port = process.env.PORT; const connect_uri = process.env.connectionStr @@ -13,6 +15,15 @@ const totalPrice = { totalPrice: 0.0 }; let retObject; const groceryList = []; +app.use(exp.static('public')) +app.use(exp.static('views')) +app.use(exp.json()) +app.use(exp.urlencoded({extended: true})) +app.use(cookie({ + name: 'session', + keys: ['key1', 'key2'] +})) + async function run() { await client.connect() collection = await client.db("GroceryList").collection("Grocery_Items") @@ -27,8 +38,40 @@ async function run() { } }) -app.use(exp.static('public')) -app.use(exp.json()) + app.post("/auth", async (req, res)=>{ + let usr = await client.db("GroceryList").collection("Users").findOne({uname: req.body.uname}); + + if(usr.pw === req.body.pw) + { + req.session.login = true; + + res.redirect('main.html') + }else{ + res.redirect('index.html') + } + + }) + + app.post("/newAc", async (req, res)=> { + let usr = await client.db("GroceryList").collection("Users").findOne({uname: req.body.uname}); + /** + * duplicate account creation logic + */ + if(usr !== null) + { + let newusr = await client.db("GroceryList").collection("Users").insertOne({ + uname: req.body.uname, + pw: req.body.pw + }); + req.session.login = true; + + res.redirect('main.html') + } + else{ + res.sendFile(__dirname + "/views/index.html") + } + + }) app.post("/submit", async (req, res) => { groceryList.push(req.body.item); diff --git a/package.json b/package.json index 7e11c3f44..887d2e83f 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "express": "^4.18.2", "mime": "^2.6.0", "mongodb": "^6.1.0", - "passport": "^0.6.0" + "passport": "^0.6.0", + "passport-github": "^1.1.0" }, "devDependencies": { "tailwindcss": "^3.3.3" diff --git a/public/js/auth.js b/public/js/auth.js index 8d50c0096..0d7a69358 100644 --- a/public/js/auth.js +++ b/public/js/auth.js @@ -8,8 +8,29 @@ const auth = async function (e) { let body = JSON.stringify({uname, pw}); const response = await fetch("/auth", { - method: 'GET', + method: 'POST', headers: {'Content-Type': 'application/json'}, body: body }) +} + +const accountCreation = async function (e) { + e.preventDefault(); + + let uname = document.getElementById("username").value; + let pw = document.getElementById("password").value; + let body = JSON.stringify({uname, pw}); + + const response = await fetch("/newAc", { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: body + }) +} + +window.onload = function(){ + const login = document.getElementById('login') + const reg = document.getElementById('register') + login.onclick = auth; + reg.onclick = accountCreation; } \ No newline at end of file diff --git a/public/js/main.js b/public/js/main.js index 128467310..5a5dd0212 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,286 +1,289 @@ -let total = 0.00 -const submit = async function( event ) { - event.preventDefault() +let total = 0.0; +const submit = async function (event) { + event.preventDefault(); let err = document.getElementsByClassName("errorMsg")[0]; - const itemin = document.querySelector( "#item" ), - pricein = document.querySelector("#price"), - json = { item: {itemName: itemin.value, price: pricein.value} }, - body = JSON.stringify( json ) - if(isNaN(parseFloat(json.item.price))) - { - err.style.display = "flex" - err.style.visibility = "visible" + const itemin = document.querySelector("#item"), + pricein = document.querySelector("#price"), + json = { item: { itemName: itemin.value, price: pricein.value } }, + body = JSON.stringify(json); + if (isNaN(parseFloat(json.item.price))) { + err.style.display = "flex"; + err.style.visibility = "visible"; return false; - } - else{ - err.style.display = "none" - err.style.visibility = "hidden" + } else { + err.style.display = "none"; + err.style.visibility = "hidden"; } - const response = await fetch( '/submit', { - method:'POST', - headers: {'Content-Type': 'application/json'}, - body: body - }) + const response = await fetch("/submit", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: body, + }); - const data = await response.json() + const data = await response.json(); addList(data); +}; -} - -const modify = async function (event){ - event.preventDefault() +const modify = async function (event) { + event.preventDefault(); let idxs = []; let idx = 0; - let list = [].slice.call(document.getElementById("groceryList").children) - list = list.splice(1) - list.forEach(element => { - if(element.getElementsByClassName("modbox").length === 1) - { - if(element.getElementsByClassName("modbox")[0].checked){ + let list = [].slice.call(document.getElementById("groceryList").children); + list = list.splice(1); + list.forEach((element) => { + if (element.getElementsByClassName("modbox").length === 1) { + if (element.getElementsByClassName("modbox")[0].checked) { idxs.push(idx); } } - idx+= 1; + idx += 1; }); let err = document.getElementsByClassName("errorMsg")[0]; const pricein = document.querySelector("#price"), - json = { items: idxs, price: pricein.value}, - body = JSON.stringify( json ) - if(isNaN(parseFloat(json.price))) - { - err.style.display = "flex" - err.style.visibility = "visible" + json = { items: idxs, price: pricein.value }, + body = JSON.stringify(json); + if (isNaN(parseFloat(json.price))) { + err.style.display = "flex"; + err.style.visibility = "visible"; return false; - } - else{ - err.style.display = "none" - err.style.visibility = "hidden" + } else { + err.style.display = "none"; + err.style.visibility = "hidden"; } - const response = await fetch( '/modify', { - method:'POST', - body - }) + const response = await fetch("/modify", { + method: "POST", + body, + }); - const data = await response.json() + const data = await response.json(); updateList(data); -} +}; -const reset = async function( event ) -{ +const reset = async function (event) { event.preventDefault(); - workingTotal = 0.0 - let body = JSON.stringify({id: "reset"}) + workingTotal = 0.0; + let body = JSON.stringify({ id: "reset" }); - const resetResponse = await fetch( "/reset", { - method:'DELETE', - body - }) + const resetResponse = await fetch("/reset", { + method: "DELETE", + body, + }); let list; - if(document.getElementById("groceryList") === null) - { - list = document.createElement('ul') - list.setAttribute("id", "groceryList") - list.appendChild(listLabel) + if (document.getElementById("groceryList") === null) { + list = document.createElement("ul"); + list.setAttribute("id", "groceryList"); + list.appendChild(listLabel); list.appendChild(defaultListItem); - document.getElementById("lists-container").appendChild(list) - } - else{ - list = document.getElementById("groceryList") - list.innerHTML = "" + document.getElementById("lists-container").appendChild(list); + } else { + list = document.getElementById("groceryList"); + list.innerHTML = ""; } - list.appendChild(listLabel) + list.appendChild(listLabel); list.appendChild(defaultListItem); let tp = document.getElementById("tpNum"); - tp.innerText = `$0.00` - tp = document.getElementById("icNum") - tp.innerText = `$0.00` - tp = document.getElementById("difNum") - tp.innerText = `$0.00` + tp.innerText = `$0.00`; + tp = document.getElementById("icNum"); + tp.innerText = `$0.00`; + tp = document.getElementById("difNum"); + tp.innerText = `$0.00`; - document.getElementById("cartList").innerHTML = "" - document.getElementById("cartList").appendChild(cartLabel) -} -const addList = function(data){ + document.getElementById("cartList").innerHTML = ""; + document.getElementById("cartList").appendChild(cartLabel); +}; +const addList = function (data) { let list; let tmp; - if(document.getElementById("groceryList") === null) - { - list = document.createElement('ul') - list.setAttribute("id", "groceryList") - } - else{ - list = document.getElementById("groceryList") + if (document.getElementById("groceryList") === null) { + list = document.createElement("ul"); + list.setAttribute("id", "groceryList"); + } else { + list = document.getElementById("groceryList"); tmp = [].slice.call(list.children); } //console.log(tmp) - if(tmp[1].innerText == "Item Name: Price($)") - { - console.log(tmp[1]) - list.removeChild(tmp[1]) - const li = document.createElement('li') - const myIn = document.createElement('input') - const inTwo = document.createElement('input') - const checkLabel = document.createElement("label") - checkLabel.appendChild(document.createTextNode(data.groceryList[0].itemName[0].toUpperCase() + data.groceryList[0].itemName.slice(1) + `: $${data.groceryList[0].price}`)) - myIn.setAttribute("type", "checkbox") - myIn.className = "giBox" - inTwo.setAttribute("type", "checkbox") - inTwo.className = "modbox" - li.className = "groceryItem" + if (tmp[1].innerText == "Item Name: Price($)") { + console.log(tmp[1]); + list.removeChild(tmp[1]); + const li = document.createElement("li"); + const myIn = document.createElement("input"); + const inTwo = document.createElement("input"); + const checkLabel = document.createElement("label"); + checkLabel.appendChild( + document.createTextNode( + data.groceryList[0].itemName[0].toUpperCase() + + data.groceryList[0].itemName.slice(1) + + `: $${data.groceryList[0].price}` + ) + ); + myIn.setAttribute("type", "checkbox"); + myIn.className = "giBox"; + inTwo.setAttribute("type", "checkbox"); + inTwo.className = "modbox"; + li.className = "groceryItem"; li.appendChild(myIn); li.appendChild(checkLabel); - li.appendChild(inTwo) - li.id = "item-0" - list.appendChild( li ) + li.appendChild(inTwo); + li.id = "item-0"; + list.appendChild(li); } - for(let i = 0; i < data.groceryList.length; i++) - { - console.log(i, tmp.length) - if(i >= (tmp.length - 1)) - { - const li = document.createElement('li') - const myIn = document.createElement('input') - const inTwo = document.createElement('input') - const checkLabel = document.createElement("label") - checkLabel.appendChild(document.createTextNode(data.groceryList[i].itemName[0].toUpperCase() + data.groceryList[i].itemName.slice(1) + `: $${data.groceryList[i].price}`)) - myIn.setAttribute("type", "checkbox") - myIn.className = "giBox" - inTwo.setAttribute("type", "checkbox") - inTwo.className = "modbox" - li.className = "groceryItem" - li.id = `item-${i}` - li.appendChild(myIn); - li.appendChild(checkLabel); - li.appendChild(inTwo) - list.appendChild( li ) - } + for (let i = 0; i < data.groceryList.length; i++) { + console.log(i, tmp.length); + if (i >= tmp.length - 1) { + const li = document.createElement("li"); + const myIn = document.createElement("input"); + const inTwo = document.createElement("input"); + const checkLabel = document.createElement("label"); + checkLabel.appendChild( + document.createTextNode( + data.groceryList[i].itemName[0].toUpperCase() + + data.groceryList[i].itemName.slice(1) + + `: $${data.groceryList[i].price}` + ) + ); + myIn.setAttribute("type", "checkbox"); + myIn.className = "giBox"; + inTwo.setAttribute("type", "checkbox"); + inTwo.className = "modbox"; + li.className = "groceryItem"; + li.id = `item-${i}`; + li.appendChild(myIn); + li.appendChild(checkLabel); + li.appendChild(inTwo); + list.appendChild(li); } - let tp = document.getElementById("tpNum"); - tp.innerText = `$${data.totalPrice.totalPrice.toFixed(2)}` - total = parseFloat(data.totalPrice.totalPrice.toFixed(2)) -} + } + let tp = document.getElementById("tpNum"); + tp.innerText = `$${data.totalPrice.totalPrice.toFixed(2)}`; + total = parseFloat(data.totalPrice.totalPrice.toFixed(2)); +}; -const delItems = async function ( event ){ - event.preventDefault() +const delItems = async function (event) { + event.preventDefault(); let idxs = []; let idx = 0; - let list = [].slice.call(document.getElementById("groceryList").children) - list = list.splice(1) - list.forEach(element => { - if(element.getElementsByClassName("modbox").length === 1) - { - if(element.getElementsByClassName("modbox")[0].checked){ + let list = [].slice.call(document.getElementById("groceryList").children); + list = list.splice(1); + list.forEach((element) => { + if (element.getElementsByClassName("modbox").length === 1) { + if (element.getElementsByClassName("modbox")[0].checked) { idxs.push(idx); } } - idx+= 1; + idx += 1; }); - const json = {items: idxs}, - body = JSON.stringify( json ) - const response = await fetch( '/delete', { - method:'DELETE', - body - }) + const json = { items: idxs }, + body = JSON.stringify(json); + const response = await fetch("/delete", { + method: "DELETE", + body, + }); - const data = await response.json() + const data = await response.json(); updateList(data); -} +}; -const updateList = function(data){ +const updateList = function (data) { let list; let tmp; - if(document.getElementById("groceryList") === null) - { - list = document.createElement('ul') - list.setAttribute("id", "groceryList") - } - else{ - list = document.getElementById("groceryList") + if (document.getElementById("groceryList") === null) { + list = document.createElement("ul"); + list.setAttribute("id", "groceryList"); + } else { + list = document.getElementById("groceryList"); tmp = [].slice.call(list.children); } //console.log(tmp) - if(tmp[1].innerText == "Item Name: Price($) ") - { - console.log(tmp[1]) - list.removeChild(tmp[1]) - const li = document.createElement('li') - const myIn = document.createElement('input') - const inTwo = document.createElement('input') - const checkLabel = document.createElement("label") - checkLabel.appendChild(document.createTextNode(data.groceryList[0].itemName[0].toUpperCase() + data.groceryList[0].itemName.slice(1) + `: $${data.groceryList[0].price}`)) - myIn.setAttribute("type", "checkbox") - myIn.className = "giBox" - inTwo.setAttribute("type", "checkbox") - inTwo.className = "modbox" - li.className = "groceryItem" + if (tmp[1].innerText == "Item Name: Price($) ") { + console.log(tmp[1]); + list.removeChild(tmp[1]); + const li = document.createElement("li"); + const myIn = document.createElement("input"); + const inTwo = document.createElement("input"); + const checkLabel = document.createElement("label"); + checkLabel.appendChild( + document.createTextNode( + data.groceryList[0].itemName[0].toUpperCase() + + data.groceryList[0].itemName.slice(1) + + `: $${data.groceryList[0].price}` + ) + ); + myIn.setAttribute("type", "checkbox"); + myIn.className = "giBox"; + inTwo.setAttribute("type", "checkbox"); + inTwo.className = "modbox"; + li.className = "groceryItem"; li.appendChild(myIn); li.appendChild(checkLabel); - li.appendChild(inTwo) - li.id = "item-0" - list.appendChild( li ) + li.appendChild(inTwo); + li.id = "item-0"; + list.appendChild(li); } - for(let i = 0; i < data.groceryList.length; i++) - { - const li = document.createElement('li') - const myIn = document.createElement('input') - const inTwo = document.createElement('input') - const checkLabel = document.createElement("label") - checkLabel.appendChild(document.createTextNode(data.groceryList[i].itemName[0].toUpperCase() + data.groceryList[i].itemName.slice(1) + `: $${data.groceryList[i].price}`)) - myIn.setAttribute("type", "checkbox") - myIn.className = "giBox" - console.log(tmp[i + 1].getElementsByClassName("giBox")[0].checked) - myIn.checked = tmp[i + 1].getElementsByClassName("giBox")[0].checked - inTwo.setAttribute("type", "checkbox") - inTwo.className = "modbox" - li.className = "groceryItem" - li.id = `item-${i}` - li.appendChild(myIn); - li.appendChild(checkLabel); - li.appendChild(inTwo) - list.removeChild(tmp[i+1]) - list.appendChild( li ) - - } - let tp = document.getElementById("tpNum"); - tp.innerText = `$${data.totalPrice.totalPrice.toFixed(2)}` - total = parseFloat(data.totalPrice.totalPrice.toFixed(2)) -} + for (let i = 0; i < data.groceryList.length; i++) { + const li = document.createElement("li"); + const myIn = document.createElement("input"); + const inTwo = document.createElement("input"); + const checkLabel = document.createElement("label"); + checkLabel.appendChild( + document.createTextNode( + data.groceryList[i].itemName[0].toUpperCase() + + data.groceryList[i].itemName.slice(1) + + `: $${data.groceryList[i].price}` + ) + ); + myIn.setAttribute("type", "checkbox"); + myIn.className = "giBox"; + console.log(tmp[i + 1].getElementsByClassName("giBox")[0].checked); + myIn.checked = tmp[i + 1].getElementsByClassName("giBox")[0].checked; + inTwo.setAttribute("type", "checkbox"); + inTwo.className = "modbox"; + li.className = "groceryItem"; + li.id = `item-${i}`; + li.appendChild(myIn); + li.appendChild(checkLabel); + li.appendChild(inTwo); + list.removeChild(tmp[i + 1]); + list.appendChild(li); + } + let tp = document.getElementById("tpNum"); + tp.innerText = `$${data.totalPrice.totalPrice.toFixed(2)}`; + total = parseFloat(data.totalPrice.totalPrice.toFixed(2)); +}; const defaultListItem = document.createElement("li"); -const defaultIn = document.createElement('input') -const defaultLabel = document.createElement("label") -const cartLabel = document.createElement("label") -const listLabel = document.createElement("label") +const defaultIn = document.createElement("input"); +const defaultLabel = document.createElement("label"); +const cartLabel = document.createElement("label"); +const listLabel = document.createElement("label"); -let workingTotal = 0.00; +let workingTotal = 0.0; let glist; -window.onload = function() { - - defaultLabel.appendChild(document.createTextNode("Item Name: Price($)")) - defaultIn.setAttribute("type", "checkbox") - defaultListItem.className = "groceryItem" +window.onload = function () { + defaultLabel.appendChild(document.createTextNode("Item Name: Price($)")); + defaultIn.setAttribute("type", "checkbox"); + defaultListItem.className = "groceryItem"; defaultListItem.appendChild(defaultIn); defaultListItem.appendChild(defaultLabel); - listLabel.appendChild(document.createTextNode("Check items In Cart")) - listLabel.id = "glist-lab" - cartLabel.appendChild(document.createTextNode("In Your Cart")) - cartLabel.id = "cart-lab" + listLabel.appendChild(document.createTextNode("Check items In Cart")); + listLabel.id = "glist-lab"; + cartLabel.appendChild(document.createTextNode("In Your Cart")); + cartLabel.id = "cart-lab"; const button = document.getElementById("submit"); const resetBut = document.getElementById("reset"); const modBut = document.getElementById("modify"); - const delBut = document.getElementById("delete") + const delBut = document.getElementById("delete"); modBut.onclick = modify; button.onclick = submit; resetBut.onclick = reset; @@ -288,54 +291,55 @@ window.onload = function() { gList = document.getElementById("groceryList"); - gList.addEventListener('change', function(e){ - - if(e.target.classList.contains("giBox")){ - let myLi = e.target.parentElement; - let cartList = document.getElementById("cartList"); - if(e.target.checked){ - let temp = myLi.cloneNode(); - let txt = myLi.innerText; - let num = txt.slice(txt.indexOf("$") + 1) - if(isNaN(parseFloat(num))) - { - //workingTotal+= parseFloat(num.slice(num.indexOf("$"))) - console.log(parseFloat(num.slice(num.indexOf(" ")))) - console.log(num.slice(num.indexOf("$") + 1), "NaN") - console.log(workingTotal) - } - else{ - workingTotal+= parseFloat(num); - console.log(parseFloat(num), "Num") - console.log(workingTotal) - } - document.getElementById("icNum").innerText= `$${workingTotal.toFixed(2)}`; - document.getElementById("difNum").innerText= `$${(total - workingTotal).toFixed(2)}`; - temp.innerHTML = "" - temp.innerText = txt - cartList.appendChild(temp) - } - else{ - let arr = [].slice.call(cartList.children) - arr.every(i => { - if(i.innerText === myLi.innerText) - { - let tnum = i.innerText.slice(i.innerText.indexOf("$") + 1) - if(isNaN(parseFloat(tnum))) - { - workingTotal-= parseFloat(tnum.slice(tnum.indexOf(" ") + 1)) - } - else{ - workingTotal-= parseFloat(tnum); - } - document.getElementById("icNum").innerText= `$${workingTotal.toFixed(2)}`; - document.getElementById("difNum").innerText= `$${Math.abs((total - workingTotal).toFixed(2))}`; - i.remove() - return false; + gList.addEventListener("change", function (e) { + if (e.target.classList.contains("giBox")) { + let myLi = e.target.parentElement; + let cartList = document.getElementById("cartList"); + if (e.target.checked) { + let temp = myLi.cloneNode(); + let txt = myLi.innerText; + let num = txt.slice(txt.indexOf("$") + 1); + if (isNaN(parseFloat(num))) { + //workingTotal+= parseFloat(num.slice(num.indexOf("$"))) + console.log(parseFloat(num.slice(num.indexOf(" ")))); + console.log(num.slice(num.indexOf("$") + 1), "NaN"); + console.log(workingTotal); + } else { + workingTotal += parseFloat(num); + console.log(parseFloat(num), "Num"); + console.log(workingTotal); } - return true; - }) + document.getElementById("icNum").innerText = `$${workingTotal.toFixed( + 2 + )}`; + document.getElementById("difNum").innerText = `$${( + total - workingTotal + ).toFixed(2)}`; + temp.innerHTML = ""; + temp.innerText = txt; + cartList.appendChild(temp); + } else { + let arr = [].slice.call(cartList.children); + arr.every((i) => { + if (i.innerText === myLi.innerText) { + let tnum = i.innerText.slice(i.innerText.indexOf("$") + 1); + if (isNaN(parseFloat(tnum))) { + workingTotal -= parseFloat(tnum.slice(tnum.indexOf(" ") + 1)); + } else { + workingTotal -= parseFloat(tnum); + } + document.getElementById( + "icNum" + ).innerText = `$${workingTotal.toFixed(2)}`; + document.getElementById("difNum").innerText = `$${Math.abs( + (total - workingTotal).toFixed(2) + )}`; + i.remove(); + return false; + } + return true; + }); + } } - } -}) -} + }); +}; diff --git a/login_page.html b/views/index.html similarity index 61% rename from login_page.html rename to views/index.html index d3f353f1c..85073e53b 100644 --- a/login_page.html +++ b/views/index.html @@ -3,6 +3,7 @@ Grocery List Tracker + @@ -12,6 +13,9 @@ + + + diff --git a/index.html b/views/main.html similarity index 100% rename from index.html rename to views/main.html From b4312bf9c74e4371fe1ba4552eac43e9a3fe1aee Mon Sep 17 00:00:00 2001 From: willhockey20 Date: Wed, 27 Sep 2023 18:38:05 -0400 Subject: [PATCH 04/12] Oauth be oauthing --- expressed_server_rewrite.js | 90 ++++++++++++++++++++++++++++--------- package.json | 4 +- public/js/auth.js | 8 ++++ views/index.html | 4 +- 4 files changed, 83 insertions(+), 23 deletions(-) diff --git a/expressed_server_rewrite.js b/expressed_server_rewrite.js index ba28723d6..138a34ae2 100644 --- a/expressed_server_rewrite.js +++ b/expressed_server_rewrite.js @@ -3,11 +3,13 @@ const denv = require('dotenv').config() const {MongoClient, ObjectId} = require('mongodb'); const auth = require('passport'); const ghauth = require('passport-github').Strategy; -const cookie = require('cookie-session') +const cookie = require('express-session') const app = exp(); const port = process.env.PORT; const connect_uri = process.env.connectionStr -console.log(`Here: ${connect_uri}`) +const sec = process.env.ghAuthClientSecret; +const cID = process.env.ghAuthClientId; + const client = new MongoClient(connect_uri) let collection = null; @@ -15,27 +17,68 @@ const totalPrice = { totalPrice: 0.0 }; let retObject; const groceryList = []; -app.use(exp.static('public')) app.use(exp.static('views')) +app.use(exp.static('public')) app.use(exp.json()) -app.use(exp.urlencoded({extended: true})) -app.use(cookie({ - name: 'session', - keys: ['key1', 'key2'] -})) async function run() { await client.connect() collection = await client.db("GroceryList").collection("Grocery_Items") - if(collection !== null){ - const docs = await collection.find({}).toArray() - console.log(docs) - } - app.get("/docs", async (req, res) => { - if(collection !== null){ - const docs = await collection.find({}).toArray() - res.json(docs) + +app.use(cookie({ secret: 'areyoureadytorumbleelelelelelele', resave: false, saveUninitialized: true })); +app.use(auth.initialize()) + + auth.use(new ghauth({ + clientID: cID, + clientSecret: sec, + callbackURL: "http://localhost:3000/auth/github/callback" + }, async (accessToken, refreshToken, gituser, done) => { + await client.db("GroceryList").collection("Users").findOne({githubId: gituser.id}, async (err, user) => { + if(err) return done(err); + if(!user){ + const newUsr = { + githubId: gituser.id, + username: gituser.username, + displayName: gituser.displayName, + }; + + let dummy = await client.db("GroceryList").collection("Users").insertOne(newUsr) + if(!dummy) return done(new Error("Could not insert")); + return done(null, newUsr); + + } + else{ + return done(null, user) + } + }) + })) + + auth.serializeUser((user, done) => { + done(null, user); + }) + + auth.deserializeUser(async (user, done) => { + let testusr = await client.db("GroceryList").collection("Users").findOne({user: user}) + if(!testusr){ + return done(new Error('user not found')); } + done(null, testusr) + }) + + app.get('/auth/github', auth.authenticate('github', {scope: ['user: email']})); + app.get('/auth/github/callback', auth.authenticate('github', { failureRedirect: '/' }), (req, res) => { + console.log(req) + console.log(req.isAuthenticated()) + res.redirect('/index'); + }); + + app.get("/", async (req, res) => { + res.sendFile(__dirname + "/views/index.html") + }) + + app.get("/index", async (req, res) => { + res.sendFile(__dirname + "/views/main.html") + }) app.post("/auth", async (req, res)=>{ @@ -45,19 +88,26 @@ async function run() { { req.session.login = true; - res.redirect('main.html') + res.redirect('/index') }else{ - res.redirect('index.html') + res.redirect('/') } }) + app.use( function( req,res,next) { + if( req.session.login === true ) + next() + else + res.sendFile( __dirname + '/views/index.html' ) + }) + app.post("/newAc", async (req, res)=> { let usr = await client.db("GroceryList").collection("Users").findOne({uname: req.body.uname}); /** * duplicate account creation logic */ - if(usr !== null) + if(usr === null) { let newusr = await client.db("GroceryList").collection("Users").insertOne({ uname: req.body.uname, @@ -65,7 +115,7 @@ async function run() { }); req.session.login = true; - res.redirect('main.html') + res.redirect('/views/main.html') } else{ res.sendFile(__dirname + "/views/index.html") diff --git a/package.json b/package.json index 887d2e83f..23c959d88 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,12 @@ "cookie-session": "^2.0.0", "dotenv": "^16.3.1", "express": "^4.18.2", + "express-session": "^1.17.3", "mime": "^2.6.0", "mongodb": "^6.1.0", "passport": "^0.6.0", - "passport-github": "^1.1.0" + "passport-github": "^1.1.0", + "passport-github2": "^0.1.12" }, "devDependencies": { "tailwindcss": "^3.3.3" diff --git a/public/js/auth.js b/public/js/auth.js index 0d7a69358..f4a94afc4 100644 --- a/public/js/auth.js +++ b/public/js/auth.js @@ -28,9 +28,17 @@ const accountCreation = async function (e) { }) } +const ghlogin = async function(e) { + e.preventDefault(); + + window.location.href = "/auth/github" +} + window.onload = function(){ const login = document.getElementById('login') const reg = document.getElementById('register') + const gbut = document.getElementById('ghlog') login.onclick = auth; reg.onclick = accountCreation; + gbut.onclick = ghlogin; } \ No newline at end of file diff --git a/views/index.html b/views/index.html index 85073e53b..5c021fc7f 100644 --- a/views/index.html +++ b/views/index.html @@ -12,10 +12,10 @@ - + - + From 51724862334fc923e114264e905d91d7762b8499 Mon Sep 17 00:00:00 2001 From: willhockey20 Date: Wed, 27 Sep 2023 18:44:14 -0400 Subject: [PATCH 05/12] oauth still oauthing --- expressed_server_rewrite.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/expressed_server_rewrite.js b/expressed_server_rewrite.js index 138a34ae2..6e994290f 100644 --- a/expressed_server_rewrite.js +++ b/expressed_server_rewrite.js @@ -34,7 +34,8 @@ app.use(auth.initialize()) callbackURL: "http://localhost:3000/auth/github/callback" }, async (accessToken, refreshToken, gituser, done) => { await client.db("GroceryList").collection("Users").findOne({githubId: gituser.id}, async (err, user) => { - if(err) return done(err); + console.log("In here") + if(err) {console.log(err);return done(err);} if(!user){ const newUsr = { githubId: gituser.id, @@ -54,10 +55,12 @@ app.use(auth.initialize()) })) auth.serializeUser((user, done) => { + console.log("In here2") done(null, user); }) auth.deserializeUser(async (user, done) => { + console.log("In here3") let testusr = await client.db("GroceryList").collection("Users").findOne({user: user}) if(!testusr){ return done(new Error('user not found')); From abc34430a974f61dbfdf4eb72ba47011374e70f0 Mon Sep 17 00:00:00 2001 From: willhockey20 Date: Thu, 28 Sep 2023 16:17:53 -0400 Subject: [PATCH 06/12] Oauth is working finally, session management now --- expressed_server_rewrite.js | 312 +++++++++++++++++++----------------- public/js/main.js | 2 + views/index.html | 1 + views/main.html | 6 +- 4 files changed, 175 insertions(+), 146 deletions(-) diff --git a/expressed_server_rewrite.js b/expressed_server_rewrite.js index 6e994290f..1b0c7d09e 100644 --- a/expressed_server_rewrite.js +++ b/expressed_server_rewrite.js @@ -1,203 +1,227 @@ -const exp = require('express'); -const denv = require('dotenv').config() -const {MongoClient, ObjectId} = require('mongodb'); -const auth = require('passport'); -const ghauth = require('passport-github').Strategy; -const cookie = require('express-session') +const exp = require("express"); +const denv = require("dotenv").config(); +const { MongoClient, ObjectId } = require("mongodb"); +const auth = require("passport"); +const ghauth = require("passport-github").Strategy; +const cookie = require("express-session"); const app = exp(); const port = process.env.PORT; -const connect_uri = process.env.connectionStr +const connect_uri = process.env.connectionStr; const sec = process.env.ghAuthClientSecret; const cID = process.env.ghAuthClientId; -const client = new MongoClient(connect_uri) +const client = new MongoClient(connect_uri); let collection = null; const totalPrice = { totalPrice: 0.0 }; let retObject; const groceryList = []; -app.use(exp.static('views')) -app.use(exp.static('public')) -app.use(exp.json()) +app.use(exp.static("views")); +app.use(exp.static("public")); +app.use(exp.json()); async function run() { - await client.connect() - collection = await client.db("GroceryList").collection("Grocery_Items") - -app.use(cookie({ secret: 'areyoureadytorumbleelelelelelele', resave: false, saveUninitialized: true })); -app.use(auth.initialize()) - - auth.use(new ghauth({ - clientID: cID, - clientSecret: sec, - callbackURL: "http://localhost:3000/auth/github/callback" - }, async (accessToken, refreshToken, gituser, done) => { - await client.db("GroceryList").collection("Users").findOne({githubId: gituser.id}, async (err, user) => { - console.log("In here") - if(err) {console.log(err);return done(err);} - if(!user){ - const newUsr = { - githubId: gituser.id, - username: gituser.username, - displayName: gituser.displayName, - }; - - let dummy = await client.db("GroceryList").collection("Users").insertOne(newUsr) - if(!dummy) return done(new Error("Could not insert")); - return done(null, newUsr); + await client.connect(); + collection = await client.db("GroceryList").collection("Grocery_Items"); + + app.use( + cookie({ + secret: "areyoureadytorumbleelelelelelele", + resave: true, + saveUninitialized: true, + }) + ); + app.use(auth.initialize()); + auth.use( + new ghauth( + { + clientID: cID, + clientSecret: sec, + callbackURL: "http://localhost:3000/auth/github/callback", + }, + async (accessToken, refreshToken, gituser, done) => { + let user = await client + .db("GroceryList") + .collection("Users") + .findOne({ githubId: gituser.id }); + //console.log("In here"); + if (!user) { + const newUsr = { + githubId: gituser.id, + username: gituser.username, + displayName: gituser.displayName, + }; + + let dummy = await client + .db("GroceryList") + .collection("Users") + .insertOne(newUsr); + if (!dummy) return done(new Error("Could not insert")); + return done(null, newUsr); + } else { + return done(null, user); + } } - else{ - return done(null, user) - } - }) - })) + ) + ); auth.serializeUser((user, done) => { - console.log("In here2") + //console.log("In here2"); done(null, user); - }) + }); auth.deserializeUser(async (user, done) => { - console.log("In here3") - let testusr = await client.db("GroceryList").collection("Users").findOne({user: user}) - if(!testusr){ - return done(new Error('user not found')); + //console.log("In here3"); + let testusr = await client + .db("GroceryList") + .collection("Users") + .findOne({ user: user }); + if (!testusr) { + return done(new Error("user not found")); } - done(null, testusr) - }) - - app.get('/auth/github', auth.authenticate('github', {scope: ['user: email']})); - app.get('/auth/github/callback', auth.authenticate('github', { failureRedirect: '/' }), (req, res) => { - console.log(req) - console.log(req.isAuthenticated()) - res.redirect('/index'); + done(null, testusr); }); + app.get( + "/auth/github", + auth.authenticate("github", { scope: ["user: email"] }) + ); + app.get( + "/auth/github/callback", + auth.authenticate("github", { failureRedirect: "/" }), + (req, res) => { + //console.log(req); + //console.log(req.isAuthenticated()); + res.redirect("/index"); + } + ); + app.get("/", async (req, res) => { - res.sendFile(__dirname + "/views/index.html") - }) + res.sendFile(__dirname + "/views/index.html"); + }); app.get("/index", async (req, res) => { - res.sendFile(__dirname + "/views/main.html") - - }) + res.sendFile(__dirname + "/views/main.html"); + }); - app.post("/auth", async (req, res)=>{ - let usr = await client.db("GroceryList").collection("Users").findOne({uname: req.body.uname}); + app.post("/auth", async (req, res) => { + let usr = await client + .db("GroceryList") + .collection("Users") + .findOne({ uname: req.body.uname }); - if(usr.pw === req.body.pw) - { + if (usr.pw === req.body.pw) { req.session.login = true; - - res.redirect('/index') - }else{ - res.redirect('/') + res.redirect("/index"); + } else { + res.redirect("/"); } + }); - }) - - app.use( function( req,res,next) { - if( req.session.login === true ) - next() - else - res.sendFile( __dirname + '/views/index.html' ) - }) + app.use(function (req, res, next) { + if (req.session.login === true) next(); + else res.redirect("/"); + }); - app.post("/newAc", async (req, res)=> { - let usr = await client.db("GroceryList").collection("Users").findOne({uname: req.body.uname}); + app.post("/newAc", async (req, res) => { + let usr = await client + .db("GroceryList") + .collection("Users") + .findOne({ uname: req.body.uname }); /** * duplicate account creation logic */ - if(usr === null) - { - let newusr = await client.db("GroceryList").collection("Users").insertOne({ - uname: req.body.uname, - pw: req.body.pw - }); - req.session.login = true; - - res.redirect('/views/main.html') - } - else{ - res.sendFile(__dirname + "/views/index.html") - } + if (usr === null) { + let newusr = await client + .db("GroceryList") + .collection("Users") + .insertOne({ + uname: req.body.uname, + pw: req.body.pw, + }); + req.session.login = true; - }) + res.redirect("/index"); + } else { + res.sendFile(__dirname + "/views/index.html"); + } + }); -app.post("/submit", async (req, res) => { + app.post("/submit", async (req, res) => { groceryList.push(req.body.item); - const rst = await collection.insertOne(req.body.item) - console.log(rst) + console.log("Printing session: ", req.session) + //const rst = await collection.insertOne(req.body.item); + //console.log(await rst); + calcTotalPrice(); + retObject = { groceryList, totalPrice }; + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify(retObject)); + }); + + app.post("/modify", (req, res) => { + modifyPrice(req.body); + calcTotalPrice(); + retObject = { groceryList, totalPrice }; + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify(retObject)); + }); + + app.delete("/reset", (req, res) => { + console.log(req); + groceryList.splice(0, groceryList.length); calcTotalPrice(); retObject = { groceryList, totalPrice }; - res.writeHead(200, { 'Content-Type': 'application/json' }) + res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(retObject)); -}) - -app.post("/modify", (req, res) => { - modifyPrice(req.body) - calcTotalPrice(); - retObject = { groceryList, totalPrice }; - res.writeHead(200, { 'Content-Type': 'application/json' }) - res.end(JSON.stringify(retObject)); -}) - -app.delete("/reset", (req, res) => { - console.log(req) - groceryList.splice(0, groceryList.length); - calcTotalPrice(); - retObject = { groceryList, totalPrice }; - res.writeHead(200, { 'Content-Type': 'application/json' }) - res.end(JSON.stringify(retObject)); -}) - -app.delete("/del", (req, res) => { - console.log(req) - deleteItems(req.body) - calcTotalPrice(); - retObject = { groceryList, totalPrice }; - res.writeHead(200, { 'Content-Type': 'application/json' }) - res.end(JSON.stringify(retObject)); -}) + }); + + app.delete("/del", (req, res) => { + console.log(req); + deleteItems(req.body); + calcTotalPrice(); + retObject = { groceryList, totalPrice }; + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify(retObject)); + }); } const calcTotalPrice = function () { - totalPrice.totalPrice = 0.0; - if(groceryList.length !== 0){groceryList.forEach((item) => { + totalPrice.totalPrice = 0.0; + if (groceryList.length !== 0) { + groceryList.forEach((item) => { if (!isNaN(parseFloat(item.price))) { totalPrice.totalPrice += parseFloat(item.price); } else { totalPrice.totalPrice += 0.0; } - })}; - }; - -const modifyPrice = function (data){ - data.items.forEach(idx => { - console.log(groceryList[idx]) - groceryList[idx].price = data.price; - }) + }); } +}; -const deleteItems = function (data){ - for(let i = groceryList.length - 1; i >= 0; i--) - { - data.every(idx => { - if(idx === i) - { +const modifyPrice = function (data) { + data.items.forEach((idx) => { + console.log(groceryList[idx]); + groceryList[idx].price = data.price; + }); +}; + +const deleteItems = function (data) { + for (let i = groceryList.length - 1; i >= 0; i--) { + data.every((idx) => { + if (idx === i) { groceryList.splice(i, 1); return false; } return true; - }) + }); } -} +}; -run() +run(); -app.listen(port, ()=> { - console.log(`Listening on ${port}`); -}); \ No newline at end of file +app.listen(port, () => { + console.log(`Listening on ${port}`); +}); diff --git a/public/js/main.js b/public/js/main.js index 5a5dd0212..2d43fb341 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,4 +1,5 @@ let total = 0.0; +let localItems = []; const submit = async function (event) { event.preventDefault(); @@ -22,6 +23,7 @@ const submit = async function (event) { body: body, }); + console.log(response) const data = await response.json(); addList(data); diff --git a/views/index.html b/views/index.html index 5c021fc7f..90fec7a5d 100644 --- a/views/index.html +++ b/views/index.html @@ -3,6 +3,7 @@ Grocery List Tracker + diff --git a/views/main.html b/views/main.html index eadf2f565..adc5d5593 100644 --- a/views/main.html +++ b/views/main.html @@ -3,11 +3,13 @@ Grocery List Tracker + + - + @@ -32,7 +34,7 @@
    - +
  • Item Name: Price($)
    From 62c3b12fb092358951e854336cdac2f8e371ac94 Mon Sep 17 00:00:00 2001 From: willhockey20 Date: Fri, 29 Sep 2023 17:44:22 -0400 Subject: [PATCH 07/12] Full migration to session and persistent storage done, as well as updated css framework and log out button. Should be able to finish tonight --- expressed_server_rewrite.js | 110 +++++++++++++++++++++++++----------- package.json | 3 - public/css/main.css | 7 +++ public/js/main.js | 42 +++++++++++--- views/main.html | 5 +- 5 files changed, 122 insertions(+), 45 deletions(-) diff --git a/expressed_server_rewrite.js b/expressed_server_rewrite.js index 1b0c7d09e..5b6fbd00a 100644 --- a/expressed_server_rewrite.js +++ b/expressed_server_rewrite.js @@ -15,7 +15,7 @@ let collection = null; const totalPrice = { totalPrice: 0.0 }; let retObject; -const groceryList = []; +let groceryList = []; app.use(exp.static("views")); app.use(exp.static("public")); @@ -94,6 +94,7 @@ async function run() { (req, res) => { //console.log(req); //console.log(req.isAuthenticated()); + req.session.login = true; res.redirect("/index"); } ); @@ -114,6 +115,7 @@ async function run() { if (usr.pw === req.body.pw) { req.session.login = true; + req.session.user = usr res.redirect("/index"); } else { res.redirect("/"); @@ -130,9 +132,6 @@ async function run() { .db("GroceryList") .collection("Users") .findOne({ uname: req.body.uname }); - /** - * duplicate account creation logic - */ if (usr === null) { let newusr = await client .db("GroceryList") @@ -142,53 +141,83 @@ async function run() { pw: req.body.pw, }); req.session.login = true; + req.session.user = await client.db("GroceryList").collection("Users").findOne(newusr.insertedId); res.redirect("/index"); } else { - res.sendFile(__dirname + "/views/index.html"); + res.redirect("/"); } }); app.post("/submit", async (req, res) => { - groceryList.push(req.body.item); - console.log("Printing session: ", req.session) - //const rst = await collection.insertOne(req.body.item); - //console.log(await rst); - calcTotalPrice(); - retObject = { groceryList, totalPrice }; + //groceryList.push(req.body.item); + let newItem = req.body.item; + newItem.user = (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id; + const rst = await client.db("GroceryList").collection("Grocery_Items").insertOne(newItem); + console.log(await rst); + + newItem = await client.db("GroceryList").collection("Grocery_Items").findOne(rst.insertedId) + console.log(await newItem); + groceryList = await client.db("GroceryList").collection("Grocery_Items") + .find({user: (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id}) + .toArray(); + calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); + retObject = { groceryList, totalPrice}; res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(retObject)); }); - app.post("/modify", (req, res) => { + app.post("/modify", async (req, res) => { + console.log("Here's the modify body", req.body) modifyPrice(req.body); - calcTotalPrice(); + calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); + groceryList = await client.db("GroceryList").collection("Grocery_Items") + .find({user: (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id}) + .toArray() retObject = { groceryList, totalPrice }; res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(retObject)); }); - app.delete("/reset", (req, res) => { + app.delete("/reset", async (req, res) => { console.log(req); groceryList.splice(0, groceryList.length); - calcTotalPrice(); + client.db("GroceryList").collection("Grocery_Items").deleteMany({user : (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id}) + calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); retObject = { groceryList, totalPrice }; res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(retObject)); }); - app.delete("/del", (req, res) => { + app.delete("/del", async (req, res) => { console.log(req); deleteItems(req.body); - calcTotalPrice(); + groceryList = await client.db("GroceryList") + .collection("Grocery_Items") + .find({user : (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id}) + .toArray(); + calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); retObject = { groceryList, totalPrice }; res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(retObject)); }); + app.get("/items", async (req, res) => { + let items = await client.db("GroceryList").collection("Grocery_Items").find({user : (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id}).toArray(); + console.log(items); + res.writeHead(200, {"Content-Type": "application/json"}) + res.end(JSON.stringify(items)); + }) + + app.get("/logout", async (req, res) => { + req.session.destroy(); + console.log(req.session) + res.redirect("/"); + }); + } -const calcTotalPrice = function () { +const calcTotalPrice = async function (usrSes) { totalPrice.totalPrice = 0.0; if (groceryList.length !== 0) { groceryList.forEach((item) => { @@ -199,25 +228,42 @@ const calcTotalPrice = function () { } }); } + const addPrice = { + $set :{ + totalPrice + } + } + + let usr = await client.db("GroceryList").collection("Users").updateOne({_id: new ObjectId(`${usrSes}`)}, addPrice); + if(!usr){ + return(new Error("Couldn't update user's total price")); + } }; -const modifyPrice = function (data) { - data.items.forEach((idx) => { - console.log(groceryList[idx]); - groceryList[idx].price = data.price; +const modifyPrice = async function (data) { + console.log("New price: ", data.price) + const updater = {$set: { + price: data.price + }}; + console.log(data) + data.items.forEach(async (_updateId) => { + let mod = await client.db("GroceryList").collection("Grocery_Items").updateOne({_id : new ObjectId(`${_updateId}`)}, updater) + console.log(mod); + if(!mod){ + return (new Error("Couldn't modify item pricing")) + } }); }; -const deleteItems = function (data) { - for (let i = groceryList.length - 1; i >= 0; i--) { - data.every((idx) => { - if (idx === i) { - groceryList.splice(i, 1); - return false; - } - return true; - }); - } +const deleteItems = async function (data) { + + data.items.forEach(async (_delId) => { + let del = await client.db("GroceryList").collection("Grocery_Items").deleteOne({_id : new ObjectId(`${delId}`)}) + if(!del){ + return (new Error("Couldn't delete item")) + } + }); + }; run(); diff --git a/package.json b/package.json index 23c959d88..e5c03eb79 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,5 @@ "passport": "^0.6.0", "passport-github": "^1.1.0", "passport-github2": "^0.1.12" - }, - "devDependencies": { - "tailwindcss": "^3.3.3" } } diff --git a/public/css/main.css b/public/css/main.css index cbe928857..0c76e5d2c 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -20,6 +20,13 @@ h1{ label{ font-family: "Oswald", serif; } +div#logout-box{ + position:absolute; + right: 10rem; +} +#logout{ + position:absolute; +} #groceryList{ display: flex; flex-direction:column; diff --git a/public/js/main.js b/public/js/main.js index 2d43fb341..106af7e8d 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -32,16 +32,15 @@ const submit = async function (event) { const modify = async function (event) { event.preventDefault(); let idxs = []; - let idx = 0; let list = [].slice.call(document.getElementById("groceryList").children); list = list.splice(1); list.forEach((element) => { if (element.getElementsByClassName("modbox").length === 1) { if (element.getElementsByClassName("modbox")[0].checked) { - idxs.push(idx); + idxs.push(element.getAttribute("dbid")); + console.log(element.getAttribute("dbid")); } } - idx += 1; }); let err = document.getElementsByClassName("errorMsg")[0]; @@ -59,7 +58,8 @@ const modify = async function (event) { const response = await fetch("/modify", { method: "POST", - body, + headers: { "Content-Type": "application/json" }, + body: body, }); const data = await response.json(); @@ -74,7 +74,8 @@ const reset = async function (event) { const resetResponse = await fetch("/reset", { method: "DELETE", - body, + headers: { "Content-Type": "application/json" }, + body: body, }); let list; @@ -131,6 +132,7 @@ const addList = function (data) { inTwo.setAttribute("type", "checkbox"); inTwo.className = "modbox"; li.className = "groceryItem"; + li.setAttribute("dbid", data.groceryList[0]._id) li.appendChild(myIn); li.appendChild(checkLabel); li.appendChild(inTwo); @@ -156,6 +158,7 @@ const addList = function (data) { inTwo.setAttribute("type", "checkbox"); inTwo.className = "modbox"; li.className = "groceryItem"; + li.setAttribute("dbid", data.groceryList[i]._id) li.id = `item-${i}`; li.appendChild(myIn); li.appendChild(checkLabel); @@ -172,23 +175,23 @@ const delItems = async function (event) { event.preventDefault(); let idxs = []; - let idx = 0; let list = [].slice.call(document.getElementById("groceryList").children); list = list.splice(1); list.forEach((element) => { if (element.getElementsByClassName("modbox").length === 1) { if (element.getElementsByClassName("modbox")[0].checked) { - idxs.push(idx); + idxs.push(element.getAttribute("dbid")); } } - idx += 1; + }); const json = { items: idxs }, body = JSON.stringify(json); const response = await fetch("/delete", { method: "DELETE", - body, + headers: { "Content-Type": "application/json" }, + body: body, }); const data = await response.json(); @@ -230,6 +233,7 @@ const updateList = function (data) { li.appendChild(checkLabel); li.appendChild(inTwo); li.id = "item-0"; + li.setAttribute("dbid", data.groceryList[0]._id) list.appendChild(li); } for (let i = 0; i < data.groceryList.length; i++) { @@ -251,6 +255,7 @@ const updateList = function (data) { inTwo.setAttribute("type", "checkbox"); inTwo.className = "modbox"; li.className = "groceryItem"; + li.setAttribute("dbid", data.groceryList[i]._id) li.id = `item-${i}`; li.appendChild(myIn); li.appendChild(checkLabel); @@ -263,6 +268,14 @@ const updateList = function (data) { total = parseFloat(data.totalPrice.totalPrice.toFixed(2)); }; +const getItems = async function(){ + let temp575 = await fetch("/items", { + method: "GET" + }) + + console.log(await temp575.json()); +} + const defaultListItem = document.createElement("li"); const defaultIn = document.createElement("input"); const defaultLabel = document.createElement("label"); @@ -282,10 +295,21 @@ window.onload = function () { cartLabel.appendChild(document.createTextNode("In Your Cart")); cartLabel.id = "cart-lab"; + getItems() + const button = document.getElementById("submit"); const resetBut = document.getElementById("reset"); const modBut = document.getElementById("modify"); const delBut = document.getElementById("delete"); + const lgout = document.getElementById("logout"); + lgout.onclick = async function (e) { + e.preventDefault() + let lgout = await fetch("/logout", { + method: "GET" + }); + + window.location.href = "/"; + }; modBut.onclick = modify; button.onclick = submit; resetBut.onclick = reset; diff --git a/views/main.html b/views/main.html index adc5d5593..2ca1bb12b 100644 --- a/views/main.html +++ b/views/main.html @@ -15,13 +15,16 @@

    Your Grocery List

    +
    + +
    - +
    From 8d30eea1fe41f385622003e52a40564cadde31d4 Mon Sep 17 00:00:00 2001 From: willhockey20 Date: Sat, 30 Sep 2023 16:29:39 -0400 Subject: [PATCH 08/12] Lighthouse testing and deployment time --- expressed_server_rewrite.js | 20 +++++++------- public/js/main.js | 53 ++++++++++++++++++++++++++++++++++--- views/main.html | 2 +- 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/expressed_server_rewrite.js b/expressed_server_rewrite.js index 5b6fbd00a..c3f5cecd8 100644 --- a/expressed_server_rewrite.js +++ b/expressed_server_rewrite.js @@ -161,7 +161,7 @@ async function run() { groceryList = await client.db("GroceryList").collection("Grocery_Items") .find({user: (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id}) .toArray(); - calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); + let t = await calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); retObject = { groceryList, totalPrice}; res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(retObject)); @@ -170,10 +170,11 @@ async function run() { app.post("/modify", async (req, res) => { console.log("Here's the modify body", req.body) modifyPrice(req.body); - calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); + groceryList = await client.db("GroceryList").collection("Grocery_Items") .find({user: (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id}) - .toArray() + .toArray(); + let t = await calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); retObject = { groceryList, totalPrice }; res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(retObject)); @@ -183,7 +184,7 @@ async function run() { console.log(req); groceryList.splice(0, groceryList.length); client.db("GroceryList").collection("Grocery_Items").deleteMany({user : (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id}) - calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); + let t = await calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); retObject = { groceryList, totalPrice }; res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(retObject)); @@ -196,17 +197,18 @@ async function run() { .collection("Grocery_Items") .find({user : (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id}) .toArray(); - calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); + let t = await calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); retObject = { groceryList, totalPrice }; res.writeHead(200, { "Content-Type": "application/json" }); res.end(JSON.stringify(retObject)); }); app.get("/items", async (req, res) => { - let items = await client.db("GroceryList").collection("Grocery_Items").find({user : (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id}).toArray(); - console.log(items); + groceryList = await client.db("GroceryList").collection("Grocery_Items").find({user : (!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id}).toArray(); + let t = await calcTotalPrice((!req.session.passport.user._id)?req.session.user._id:req.session.passport.user._id); + retObject = { groceryList, totalPrice }; res.writeHead(200, {"Content-Type": "application/json"}) - res.end(JSON.stringify(items)); + res.end(JSON.stringify(retObject)); }) app.get("/logout", async (req, res) => { @@ -258,7 +260,7 @@ const modifyPrice = async function (data) { const deleteItems = async function (data) { data.items.forEach(async (_delId) => { - let del = await client.db("GroceryList").collection("Grocery_Items").deleteOne({_id : new ObjectId(`${delId}`)}) + let del = await client.db("GroceryList").collection("Grocery_Items").deleteOne({_id : new ObjectId(`${_delId}`)}) if(!del){ return (new Error("Couldn't delete item")) } diff --git a/public/js/main.js b/public/js/main.js index 106af7e8d..29df8188a 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -171,6 +171,48 @@ const addList = function (data) { total = parseFloat(data.totalPrice.totalPrice.toFixed(2)); }; +const rebuild = function (data){ + let list; + //let info = [] + if (document.getElementById("groceryList") === null) { + list = document.createElement("ul"); + list.setAttribute("id", "groceryList"); + document.getElementById("lists-container").appendChild(list); + } else { + list = document.getElementById("groceryList"); + list.innerHTML = ""; + list.appendChild(listLabel); + } + + for(let i = 0; i < data.groceryList.length; i++){ + const li = document.createElement("li"); + const myIn = document.createElement("input"); + const inTwo = document.createElement("input"); + const checkLabel = document.createElement("label"); + checkLabel.appendChild( + document.createTextNode( + data.groceryList[i].itemName[0].toUpperCase() + + data.groceryList[i].itemName.slice(1) + + `: $${data.groceryList[i].price}` + ) + ); + myIn.setAttribute("type", "checkbox"); + myIn.className = "giBox"; + inTwo.setAttribute("type", "checkbox"); + inTwo.className = "modbox"; + li.className = "groceryItem"; + li.setAttribute("dbid", data.groceryList[i]._id) + li.id = `item-${i}`; + li.appendChild(myIn); + li.appendChild(checkLabel); + li.appendChild(inTwo); + list.appendChild(li); + } + let tp = document.getElementById("tpNum"); + tp.innerText = `$${data.totalPrice.totalPrice.toFixed(2)}`; + total = parseFloat(data.totalPrice.totalPrice.toFixed(2)); +} + const delItems = async function (event) { event.preventDefault(); @@ -188,7 +230,7 @@ const delItems = async function (event) { const json = { items: idxs }, body = JSON.stringify(json); - const response = await fetch("/delete", { + const response = await fetch("/del", { method: "DELETE", headers: { "Content-Type": "application/json" }, body: body, @@ -196,7 +238,7 @@ const delItems = async function (event) { const data = await response.json(); - updateList(data); + rebuild(data); }; const updateList = function (data) { @@ -273,7 +315,8 @@ const getItems = async function(){ method: "GET" }) - console.log(await temp575.json()); + let data = await temp575.json(); + if(data.groceryList.length > 0) rebuild(data); } const defaultListItem = document.createElement("li"); @@ -281,6 +324,7 @@ const defaultIn = document.createElement("input"); const defaultLabel = document.createElement("label"); const cartLabel = document.createElement("label"); const listLabel = document.createElement("label"); +const modLab = document.createElement("label"); let workingTotal = 0.0; let glist; @@ -290,7 +334,10 @@ window.onload = function () { defaultListItem.className = "groceryItem"; defaultListItem.appendChild(defaultIn); defaultListItem.appendChild(defaultLabel); + modLab.appendChild(document.createTextNode("Check to Modify/Delete")) + modLab.id = "modbox-label" listLabel.appendChild(document.createTextNode("Check items In Cart")); + listLabel.appendChild(modLab) listLabel.id = "glist-lab"; cartLabel.appendChild(document.createTextNode("In Your Cart")); cartLabel.id = "cart-lab"; diff --git a/views/main.html b/views/main.html index 2ca1bb12b..0283b0d40 100644 --- a/views/main.html +++ b/views/main.html @@ -36,7 +36,7 @@
      - +
    • Item Name: Price($)
    From 2dcc466125c3e044ceb321a12d753372fa3df5b3 Mon Sep 17 00:00:00 2001 From: willhockey20 Date: Sat, 30 Sep 2023 21:32:34 -0400 Subject: [PATCH 09/12] Deploying to digital ocean --- README.md | 105 ++--- .../Screenshot 2023-09-30 at 5.28.44 PM.png | Bin 0 -> 430826 bytes expressed_server_rewrite.js | 275 ------------- old_server.js | 165 ++++++++ package.json | 2 +- public/css/main.css | 11 +- public/js/main.js | 38 +- server.js | 368 ++++++++++++------ views/main.html | 25 +- 9 files changed, 501 insertions(+), 488 deletions(-) create mode 100644 assets/Screenshot 2023-09-30 at 5.28.44 PM.png delete mode 100644 expressed_server_rewrite.js create mode 100644 old_server.js diff --git a/README.md b/README.md index da3a8645a..1277ffc74 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Assignment 3 - Persistence: Two-tier Web Application with Database, Express serv Due: September 25nd, by 11:59 AM. -This assignnment continues where we left off, extending it to use the most popular Node.js server framework (express), +This assignnment continues where we left off, extending it to use the most popular Node.js server framework (express), a database (mongodb), and a CSS application framework / template of your choice (Boostrap, Material Design, Semantic UI, Pure etc.) Baseline Requirements @@ -13,40 +13,40 @@ Your application is required to implement the following functionalities: - a `Server`, created using Express (no alternatives will be accepted for this assignment) - a `Results` functionality which shows all data associated with a logged in user (except passwords) -- a `Form/Entry` functionality which allows users to add, modify, and delete data items (must be all three!) associated with their user name / account. -- Persistent data storage in between server sessions using [mongodb](https://www.mongodb.com/cloud/atlas) (you *must* use mongodb for this assignment). You can use either the [official mongodb node.js library](https://www.npmjs.com/package/mongodb) or use the [Mongoose library](https://www.npmjs.com/package/mongoose), which enables you to define formal schemas for your database. Please be aware that the course staff cannot provide in-depth support for use of Mongoose. -- Use of a [CSS framework or template](https://github.com/troxler/awesome-css-frameworks). -This should do the bulk of your styling/CSS for you and be appropriate to your application. +- a `Form/Entry` functionality which allows users to add, modify, and delete data items (must be all three!) associated with their user name / account. +- Persistent data storage in between server sessions using [mongodb](https://www.mongodb.com/cloud/atlas) (you *must* use mongodb for this assignment). You can use either the [official mongodb node.js library](https://www.npmjs.com/package/mongodb) or use the [Mongoose library](https://www.npmjs.com/package/mongoose), which enables you to define formal schemas for your database. Please be aware that the course staff cannot provide in-depth support for use of Mongoose. +- Use of a [CSS framework or template](https://github.com/troxler/awesome-css-frameworks). +This should do the bulk of your styling/CSS for you and be appropriate to your application. For example, don't use [NES.css](https://nostalgic-css.github.io/NES.css/) (which is awesome!) unless you're creating a game or some type of retro 80s site. -Your application is required to demonstrate the use of the following concepts: +Your application is required to demonstrate the use of the following concepts: -HTML: +HTML: - HTML input tags and form fields of various flavors (`