WebFund 2014W Midterm Review
The video from the lecture given on Feb. 12, 2014 is available:
The midterm will be based on small-adventure, a version of adventure-demo that has been simplified by removing the use of cryptography (https and bcrypt) along with a few other minor tweaks to reduce the size of the source code.
No new tutorial this week; however, two TAs/instructors will be in the lab on Thursday 4-5:30 and Friday 8:30-10 to answer last minute questions.
Source for small-adventure
app.js
var express = require('express'); //requires the express module
var routes = require('./routes'); //same as ('/routes/index.js'). The require() method returns the exports object
var path = require('path'); //imports the path module, or path.join will not be defined
var http = require('http'); //requires the http module
var MongoStore = require('connect-mongo')(express);
var app = express(); //creates an express object instance and assigns the app variable to it.
app.set('port', process.env.PORT || 3000); //listens on PORT environment variable OR port 3000 if not defined
app.set('views', path.join(__dirname, 'views')); //sets the location for application views
app.set('view engine', 'jade'); //sets the view engine, Jade
app.use(express.favicon()); //can specify where you want favicon to be found in the parameters. e.g (_dirname + 'public/favicon.ico')
app.use(express.logger('dev')); //logging requests using predefined log format 'dev'. This will generate a detail log.
app.use(express.urlencoded()); //The body of HTTP post requests. Parses the incoming request body, converting it into request object properties
app.use(express.cookieParser());
app.use(express.session({
cookie: {maxAge: 60000 * 20} // 20 minutes
, secret: "Shh... I'm a secret" //This is the secret that prevents attackers from creating their own fake session identifiers
, store: new MongoStore({db: "adventure-demo"})
}));
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.get('/', routes.redirectLoggedIn, routes.index);
app.post("/register", routes.register);
app.post("/start", routes.start);
app.post("/quit", routes.quit);
var createRooms = function() {
var i, theRoom;
routes.getRooms().toArray(
function(err, docs) {
if (err) {
throw "Couldn't find active room list";
}
var activeRooms = docs[0].activeRooms;
activeRooms.forEach(function(roomName) {
console.log('Creating room: ' + roomName);
app.get('/' + roomName,
routes.makeRoomHandler(roomName));
});
}
);
}
routes.connectToDBs(createRooms);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port') +
' in ' + app.get('env') + ' mode.');
});
//1) createServer(): a method of http that creates and returns a server object
//2) listen(): a method at the returned server object that starts the web server listening on a given port
//3) app.get(): returns the port to listen on
routes/index.js
var mc = require('mongodb').MongoClient;
var playersCollection, roomsCollection;
exports.connectToDBs = function(callback) {
mc.connect('mongodb://localhost/adventure-demo', function(err, db) {
if (err) {
throw err;
}
playersCollection = db.collection('players');
roomsCollection = db.collection('rooms');
callback();
});
}
exports.index = function(req, res){
res.render('index', { title: 'COMP 2406 Small Adventure Demo',
error: req.query.error });
}
exports.redirectLoggedIn = function(req, res, next) {
if (req.session.player) {
res.redirect("/" + req.session.player.room);
} else {
next();
}
}
exports.redirectNotLoggedIn = function(req, res, next) {
if (req.session.player) {
next();
} else {
res.redirect("/");
}
}
exports.register = function(req, res) {
var playername = req.body.playername;
var password = req.body.password;
var addPlayer = function(err, players) {
if(players.length!=0){
res.redirect("/?error=player already exists");
return;
}
var newPlayer = {
playername: playername,
password: password,
room: "bridge"
};
playersCollection.insert(newPlayer, function(err, newPlayers){
if (err) {
throw err;
} else {
res.send('Successfully registered ' + newPlayers[0].playername);
}
});
}
playersCollection.find({playername: playername}).toArray(addPlayer);
}
exports.start = function(req, res){
var playername = req.body.playername;
var password = req.body.password;
playersCollection.findOne({playername: playername}, function(err, player) {
if (err || !player){
req.session.destroy(function(err) {
res.redirect("/?error=invalid playername or password");
});
return;
}
if (password === player.password) {
req.session.player = player;
delete req.session.player._id;
res.redirect("/" + player.room);
} else {
req.session.destroy(function(err) {
res.redirect("/?error=invalid playername or password");
});
}
});
}
exports.quit = function(req, res){
req.session.destroy(function(err){
if(err){
console.log("Error: %s", err);
}
res.redirect("/");
});
}
exports.makeRoomHandler = function(roomName) {
var handler = function(req, res) {
if (req.session.player) {
var player = req.session.player;
player.room = roomName;
playersCollection.update({"playername": player.playername},
player, function(err, count) {
if (err) {
console.log(
"Couldn't save player state");
}
});
roomsCollection.findOne(
{name: roomName},
function(err, room) {
if (err || !room) {
throw "Couldn't find room " + roomName;
}
res.render("room.jade", room);
}
);
} else {
res.redirect("/");
}
}
return handler;
}
exports.getRooms = function() {
return roomsCollection.find({name: "roomList"});
}
public/javascripts/home.js
$(function(){
$("#register").on("click",function(){
var $form = $("form");
$form.attr("action","/register");
$form.submit();
});
});
views/layout.jade
doctype html
html
head
title= title
script(src='/vendor/jquery/jquery.js')
script('vendor/bootstrap/dist/js/bootstrap.js')
link(rel='stylesheet', href='/vendor/bootstrap/dist/css/bootstrap.css')
link(rel='stylesheet', href='/stylesheets/style.css')
block header
body
block content
views/index.jade
extends layout
block header
script(src='/javascripts/home.js')
block content
h1= title
- if(error)
div.alert-error #{error}
p Please log in
div
form(action="/start", method="post")
div.control-group.input-append
input(type="text", name="playername")
label.add-on(for="playername") Player Name
div.control-group.input-append
input(type="password", name="password")
label.add-on(for="password") Password
button(type="submit") Start
button#register(type="button") Register
views/room.jade
extends layout
block content
h1= title
p #{description}
p Go to:
ul
each theExit in roomExits
li
a(href= theExit) #{theExit}
form(action="/quit", method="post")
button(type="submit") Quit