Skip to content

Instantly share code, notes, and snippets.

@ir-g
Last active August 29, 2015 14:09
Show Gist options
  • Save ir-g/c58a2fe9eedc72f79d9f to your computer and use it in GitHub Desktop.
Save ir-g/c58a2fe9eedc72f79d9f to your computer and use it in GitHub Desktop.
// 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