Last active
August 29, 2015 14:09
-
-
Save ir-g/c58a2fe9eedc72f79d9f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Require all libraries in use | |
var mustache = require('mustache'); | |
var harp = require("harp"); | |
var express = require("express"); | |
var http = require("http"); | |
var fs = require("fs"); | |
var cookieparse= require("cookie-parser"); | |
var bodyParser = require('body-parser'); | |
var app = express(); | |
// Add body parsing stuff | |
app.use(bodyParser()); | |
// Set Up Databases | |
// Setup Product Database | |
var db = require('node-persist'); | |
db.initSync({dir:'db/product'}); | |
// Setup Order Database | |
var odb = require('node-persist-o'); | |
odb.initSync({dir:'db/orders'}); | |
// Setup User database | |
var udb = require('node-persist-u'); | |
udb.initSync({dir:'db/users'}); | |
// Set Main App Variables | |
app.set('port', process.env.PORT || 3000); | |
app.set('pass', process.env.PASS || 'word') | |
app.use(harp.mount(__dirname + "/public")); | |
app.use(express.static(__dirname + "/public")); | |
app.use(cookieparse()); | |
// Start Number Formatter Code | |
// Make Number human friendly, and resolving any Integer/Float Conversion issues. | |
function formatNum(n) { | |
return n.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,"); | |
} | |
// End Number Formatter | |
// Start String Hasher | |
// Take a string, and then generate a non-reversible hash, for safer cookie storage. | |
String.prototype.hashCode = function() { | |
var hash = 0, i, chr, len; | |
if (this.length == 0) return hash; | |
for (i = 0, len = this.length; i < len; i++) { | |
chr = this.charCodeAt(i); | |
hash = ((hash << 5) - hash) + chr; | |
hash |= 0; // Convert to 32bit integer | |
} | |
return hash; | |
}; | |
// End String Hasher | |
// Start User cookie generator/tester | |
function placeCookie(res,user,pass){ | |
// Place a session cookie which holds basic user data, include name, and a hash of the user's password. | |
res.cookie("user",JSON.encode({user: user, pass: pass.hashCode()})); | |
} | |
function testLogin(req){ | |
// Check for existence of user session cookie. | |
if(req.cookies['user']){ | |
var x = req.cookies['user'].split(" "); | |
var y = udb.getItem(x[0]); | |
console.log(x[0]); | |
console.log(y); | |
var z = y.pass; | |
if(z.hashCode()==x[1]){ | |
// User is allowed in, as session data matches the database. | |
console.log('true'); | |
return true; | |
}else{ | |
// User is rejected, as user session data and user data in the databse, do not match. | |
console.log('false'); | |
return false; | |
} | |
}else{ | |
// User is rejected, on grounds of not having a user session, yet. | |
console.log('false2'); | |
return false; | |
} | |
} | |
// End User cookie generator/tester | |
// Start Home Page/Product Listings | |
app.get('/',function(req,res){ | |
var s, u, user; | |
// Log to console whether or not there is user session data, and if so, what it is. | |
console.log(req.cookies['user']); | |
// Invert the boolean response of "testLogin", so that the "if" expression recieves "true" if the user is not logged in, and false, if the user is logged in. | |
// Note: The "!" is the symbol which inverts the response of the "testLogin" function. | |
if(!testLogin(req)){ | |
// User is not logged in, therefore variable "s" is set to "false", so that the template engine knows there is no user logged in. | |
s = false; | |
}else{ | |
// User is logged in, therefore variable "s" is set to "true", so that the template engine knows there is a user logged in. | |
s = true; | |
// Variable "u" is set as the usernme of the logged in user. This is later given to the template. | |
u = req.cookies['user'].split(" ")[0]; | |
// Variable "user" set as an object containing data on the user, from the database. | |
// This variable is passed to the template engine, though isn't yet used by the template engine. | |
// This is because later versions might make more use of supplied database data. | |
user = udb.getItem(u); | |
// The active username is logged to the console. | |
console.log(u); | |
} | |
// The "db.values" function is called, so that the list of products can be collected. | |
db.values(function(vals){ | |
// Note variable "vals" is an array which contains holds each and every product record, as an object. | |
// Then, the server responds with the page, after it has been passed to the template engine. | |
// The Template engine uses the file: "list.html", in directory "template/", which has been converted to a string, and is then evaluated, processing in the given data, and then returns a string response. | |
res.send(mustache.render(fs.readFileSync("template/list.html").toString(),{ | |
vals: vals, l: s, user: u, udata: user | |
})); | |
} | |
)}); | |
// End Home Page/Product Listings | |
// Start product page | |
app.get('/product/:id', function(req, res){ | |
// Set variable "id" as the url path, after "/product/". | |
// E.G. if path is "/product/donut", then "id" is set to "donut". | |
var id = req.params.id; | |
// Set variable "data" to be an object containg the record data within the product database for that product. | |
var data = db.getItem(id); | |
// Then respond with the generated page. | |
res.send( | |
// Generate page, using the file "product.html" in the directory "template/", alongside the data variable. | |
// The data variable contains the title, description, image url, and any other vital data. | |
mustache.render(fs.readFileSync("template/product.html").toString(),data) | |
); | |
}); | |
// End Product Page | |
// Start "add to cart" system | |
app.get('/cart/add', function(req,res){ | |
// Set a cookie, named after the product, which has the data for the number of products in use. | |
// The "Math.max" function sets a minimum of 1 of these products in the cart. | |
// You don't want 0 lots of a product in the cart! | |
// The req.param fetches supplied HTTP GET request data for "id" and "q", from the browser. | |
res.cookie(req.param('id'), Math.max(req.param('q'),1)); | |
// Once the Cookie is added, redirect the user to the "ordered" message page. | |
res.redirect('/m/ordered'); | |
}); | |
// End "add to cart" system | |
// Start "remove from cart" system | |
app.get('/cart/clear/', function(req,res){ | |
// Find out the supplied id from the HTTP GET request data. | |
// E.G. HTTP Path is "/cart/clear/?id=donut" therefore "req.param('id')" is "donut" | |
// Remove the cookie, with "res.clearCookie". Without the cookie, the server no longer thinks the item is in the cart. | |
res.clearCookie(req.param('id')); | |
// Once the Cookie is removed, redirect the user to the "item-removed" message page. | |
res.redirect('/m/item-removed'); | |
}); | |
// End "remove from cart" system | |
// Start "list the cart" system | |
app.get('/cart/list', function(req,res) { | |
// Log to the console that we got the request. | |
console.log("we got the request"); | |
// Try getting the list of products. | |
db.values(function(vals){ | |
// Log to the console that we got the list of product records. | |
console.log("we got the db values"); | |
// Start the total cost at 0. | |
var totalCost = 0; | |
// Start variable "x", our list of products in the cart, with no products. | |
var x = []; | |
// Start variable "count", our number of how many products are in use. | |
var count = 0; | |
// Start looping through all products. | |
for(var i=0; i < vals.length; i++) { | |
// Set variable "current" to contain all of the data of the current product. | |
var current = { | |
id: vals[i].id, | |
name: vals[i].name, | |
cost: vals[i].cost, | |
imgurl: vals[i].imgurl, | |
q: req.cookies[vals[i].id] | |
}; | |
// Check if the current product does have a cookie(and thus, is in the cart). | |
if(req.cookies[current.id] !== undefined){ | |
// The Product is in the cart! | |
// Log to console that the product is in the cart. | |
console.log("Adding "+ current.id); | |
// Log to console all of the record data of that object. | |
console.log("Its db entry is " + current); | |
// Add the current product, to the cart, array "x". | |
x.push(current); | |
// Do funny maths. | |
// Set the total cost to equal the cost of all products in the cart. | |
// This funny addition setup is due to Javasript handling numbers weirdly. | |
// 1. Multiply the quantity and cost both by 100, then by each other. | |
// 2. Then Divide that number by 10000, then add it to the total cost. | |
// 3. Huzzah! Problem solved. Next time use a language which allows explicitly declaring integers and floats! | |
totalCost += ((vals[i].cost * 100)*(req.cookies[current.id]*100))/10000; | |
// Log to the console the current product record. | |
console.log(vals[i]); | |
// Increment the count of the number of different products in the cart by 1. | |
count++; | |
} | |
// Oh yeah, use this to force JavaScript to treat this number as number, and then give it pretty decimals. | |
totalCost = formatNum(totalCost.toNumber()); | |
} | |
// If someone fancied ordering this stuff, then do this. | |
if(req.param('order')=="x"){ | |
// Add the order as a cookie. | |
res.cookie('order', x); | |
// Redirect the user to the make order page. | |
res.redirect("/user/makeorder"); | |
// Else if the cart is empty... | |
}else if(count==0){ | |
// Then redirect the user to the "Empty Cart" message page. | |
res.redirect("/m/empty"); | |
}else{ | |
// If the user has products, but aren't ordering yet... | |
// Respond with the rendered page. | |
res.send( | |
// Render the page, using the file "cart.html", in the "template" directory, alongside the the supplied product and cost data. | |
mustache.render(fs.readFileSync("template/cart.html").toString(),{list: x, cost: totalCost}) | |
); | |
} | |
}); | |
}); | |
// End "list the cart" system | |
// Start Make order system | |
app.get('/user/makeorder', function(req,res){ | |
// If the user isn't logged in, make them login. | |
if(!testLogin(req)){res.redirect("/user/login?r=/user/makeorder")}else{ | |
// Else, add the most most recent order to the db. | |
odb.setItem("recent",{order:req.cookies.order}); | |
// Set the response data to thank you for your order. | |
// Also displays raw JSON data for order. | |
// No billing, obvious reaons. | |
var data = "Thanks for your order, " + req.cookies['user'].split(" ")[0] + " .<br />\n<pre>" + JSON.stringify(req.cookies.order) + "</pre><br /><a href='/user/logout'>Logout</a>"; | |
// Append this order, to txt file. | |
var message = fs.appendFileSync('orders.txt', '\n'+data); | |
// Respond with the data. | |
res.send(data); | |
} | |
}); | |
// End Make order system | |
// Start user logout system | |
app.get('/user/logout', function(req,res){ | |
// Remove user session cookie. | |
res.clearCookie("user"); | |
// Remove user order cookie. | |
res.clearCookie("order"); | |
// Send the user back to the home page. | |
res.redirect("/"); | |
}); | |
// End user logout system | |
// Start user signup system. | |
app.get('/user/signup', function(req, res){ | |
// Return rendered template, after supplying it with the template file, as well as the data required for customising the form to work. | |
res.send(mustache.render(fs.readFileSync("template/user.html").toString(),{ | |
message: "Enter your details, to signup.", | |
formto: "/user/signup", | |
sendto: req.param('r') || "/" | |
})); | |
}); | |
app.post('/user/signup', function(req, res){ | |
// On posting a form... | |
// Add some regex, a for password/user rules verifyer. | |
var re = /^[a-z0-9]+$/i; | |
// Set variable "uname" as the HTTP POST REQUEST "u" variable. | |
var uname = req.param('u'); | |
// Set variable "pword" as the HTTP POST REQUEST "p" variable. | |
var pword = req.param('p'); | |
// Set the "r" variable to homepage, or a place of their choice... | |
var r = req.param('r') || "/"; | |
// Log to console the username and password. | |
console.log(uname + " : " + pword); | |
// If the username and password pass the regex code... | |
if(re.test(uname)&&re.test(pword)){ | |
// Add the user to the database, as so... | |
udb.setItem(uname.toString(),{ | |
name: uname.toString(), | |
pass: pword.toString() | |
}); | |
// Add user session cookie... | |
res.cookie("user",uname + " " + pword.hashCode()); | |
// Send the user to where the r variable says they should go... | |
res.redirect(r); | |
// Else, the user is unsuccessful, try again. | |
}else{res.redirect("/user/signup?r="+r);} | |
}); | |
// End user signup system. | |
// Start user login system | |
app.get('/user/login', function(req, res){ | |
// Return rendered template, after supplying it with the template file, as well as the data required for customising the form to work. | |
res.send(mustache.render(fs.readFileSync("template/user.html").toString(),{ | |
message: "Enter your details, to login.", | |
formto: "/user/login", | |
sendto: req.param('r') || "/" | |
})); | |
}); | |
app.post('/user/login', function(req, res){ | |
// On posting a form... | |
// Set variable "uname" as the HTTP POST REQUEST "u" variable. | |
var uname = req.param('u'); | |
// Set variable "pword" as the HTTP POST REQUEST "p" variable. | |
var pword = req.param('p'); | |
// Set the "r" variable to homepage, or a place of their choice... | |
var r = req.param('r') || "/"; | |
// Log to console the username and password. | |
console.log(uname + " : " + pword); | |
// Double check if the supplied username exists. | |
// If it doesn't, let the user know. | |
if(!udb.getItem(uname)){res.send("User doesn't exist");} | |
// If the username exists, load data to the "u" variable. | |
var u = udb.getItem(uname); | |
// If passwords match, then... | |
if(u.pass == pword){ | |
// Add user session cookie, with username, space, and then a hash of the pass code. | |
res.cookie("user",uname + " " + pword.hashCode()); | |
// Send the user to where the r variable says they should go... | |
res.redirect(r); | |
}else{ | |
// If the credentials don't match, send the user back to the login page. | |
res.redirect("/user/login?r="+r); | |
} | |
}); | |
// End user login system | |
// Launch | |
http.createServer(app).listen(app.get('port'), function(){ | |
// Log to the console some info. | |
console.log('Express server listening on port ' + app.get('port')); | |
}); | |
// DONE!; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment