Skip to content

Instantly share code, notes, and snippets.

@werelax
Last active January 3, 2016 00:48
Show Gist options
  • Select an option

  • Save werelax/8384696 to your computer and use it in GitHub Desktop.

Select an option

Save werelax/8384696 to your computer and use it in GitHub Desktop.
Base Node.js structure for small projects (missing auth routes/controllers)
/* jshint node: true, laxcomma: true */
/* global __dirname */
/* Dependencies */
var express = require("express")
, Q = require("q")
, check = require("validator").check
, auth = require("./simpleauth")
, MongoClient = require("mongodb").MongoClient
, ObjectID = require("mongodb").ObjectID
;
/* Config */
var client = Q.ninvoke(MongoClient,
"connect",
"mongodb://127.0.0.1:27017/cf");
client.fail(function(e) {
"use strict";
console.log("ERROR conectando a Mongo: ", e);
});
Q.longStackSupport = true;
var app = express();
app.configure(function() {
"use strict";
app.use(express.favicon());
app.use(express.logger("short"));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser("your secret here"));
app.use(express.session());
app.use(app.router);
app.use(express.static(__dirname + "/public"));
});
/* Utils */
function extend() {
"use strict";
var args = [].slice.call(arguments);
return args.reduce(function(acc, el) {
for (var k in el) {
if (el.hasOwnProperty(k)) { acc[k] = el[k]; }
}
return acc;
});
}
function Model(collection, klass) {
"use strict";
klass = klass || {};
klass._collectionName = collection;
klass._collection = client.then(function(db) {
return db.collection(klass._collectionName);
});
return extend(klass, {
op: function() {
var args = [].slice.call(arguments);
return klass._collection.then(function(col) {
return Q.ninvoke.apply(Q, [col].concat(args));
});
},
makeOp: function() {
var args = [].slice.call(arguments);
return function() {
this.op.apply(this, args);
}.bind(this);
},
create: function(data) {
return klass.op("insert",
extend(data, this.defaults || {}, {date: Date.now()}));
}
});
}
// Remotron approach (simpler, more elegant in my opinion)
function op(colname) {
"use strict";
var args = [].slice.call(arguments, 1),
collections = {};
return client.then(function(db) {
if (!(colname in collections)) { collections[colname] = db.collection(colname); }
return Q.ninvoke.apply(Q, [collections[colname]].concat(args));
})
.fail(function(err) {
console.log("[MongoDB]", err);
throw err;
});
}
function makeOp(col) {
"use strict";
var args = [].slice.call(arguments, 1);
return function () { return col.apply({}, args); };
}
/* Models */
var User = Model("users", {
});
var Customer = Model("customers", {
});
var Publication = Model("publications", {
});
// Remotron approach
var users = extend(op.bind({}, "users"), {
});
var customers = extend(op.bind({}, "customers"), {
});
var publications = extend(op.bind({}, "publications"), {
});
/* Auth */
auth.setStrategy({
serializeUser: function(user) {
"use strict";
return user._id;
},
deserializeUser: function(userId, cb) {
"use strict";
users("findOne", { _id: new ObjectID(userId) })
.then(function(user) {
return user;
})
.then(cb)
.done();
},
checkCredentials: function(username, pass, cb) {
"use strict";
users("findOne", { email: username })
.then(function(user) {
cb(null, (user && user.password === pass) ? user : null);
});
}
});
/* Controllers */
var usersController = {
index: function () {
},
new: function() {
},
create: function() {
},
show: function() {
},
edit: function() {
},
update: function() {
},
delete: function () {
},
param: function() {
}
};
/* Routing */
function resources(app, name, controller) {
"use strict";
if (controller.index) { app.get("/"+name, controller.index); }
if (controller["new"]) { app.get("/"+name+"/new", controller["new"]); }
if (controller.create) { app.post("/"+name, controller.create); }
if (controller.show) { app.get("/"+name+"/:"+name+"id", controller.show); }
if (controller.edit) { app.get("/"+name+"/:"+name+"id/edit", controller.edit); }
if (controller.update) { app.put("/"+name+"/:"+name+"id", controller.update); }
if (controller["delete"]) { app["delete"]("/"+name+"/:"+name+"id", controller["delete"]); }
if (controller.param) { app.param(name + "id", controller.param); }
}
/* Routes example:
app.get("/login", sessionsController.new);
app.post("/session", auth.createSession({redirect: "/home"}));
app.get("/logout", auth.destroySession, function(req, res) {
res.redirect("/login");
});
app.get("/register", usersController.new);
app.post("/users", usersController.create);
auth.withToken(app, function(app) {
resources(app, "jobs", jobsController);
});
auth.withSession(app, function(app) {
app.get("/home", usersController.show);
});
*/
/* Populate */
// users("ensureIndex", {token: 1});
/* Exports */
exports.app = app;
if (process.argv[2] === "run") app.listen(process.env.PORT || "8080", "0.0.0.0");
function extend() {
"use strict";
var args = [].slice.call(arguments);
return args.reduce(function(acc, el) {
for (var k in el) {
if (el.hasOwnProperty(k)) { acc[k] = el[k]; }
}
return acc;
});
}
var strategy = {
serializeUser: function() {
// (user)
},
deserializeUser: function() {
// (userId, cb)
},
checkCredentials: function() {
// (username, pass, done)
},
loginRoute: "/login"
};
exports.setStrategy = function(customStrategy) {
"use strict";
strategy = extend({}, strategy, customStrategy);
};
exports.isLogged = function(req) {
"use strict";
return req.session.user !== undefined;
};
exports.login = function(req, user) {
"use strict";
req.session.user = strategy.serializeUser(user);
};
exports.createSession = function(options) {
"use strict";
var config = {
username: "username",
password: "password",
redirect: "/me",
failRedirect: strategy.loginRoute
};
config = extend({}, config, options);
return function(req, res) {
var username = req.body[config.username],
pass = req.body[config.password];
strategy.checkCredentials(username, pass, function(err, user) {
if (!err && user) {
console.log("Usuario logueado:",username);
exports.login(req, user);
res.redirect(config.redirect);
} else {
console.log("Credenciales incorrectas");
res.redirect(config.failRedirect);
}
});
};
};
exports.requiresSession = function(req, res, next) {
"use strict";
if (req.session.user) {
strategy.deserializeUser(req.session.user, function(user) {
if (!user) {
console.log("El usuario no existe!");
delete req.session.user;
res.redirect(strategy.loginRoute);
} else {
req.user = user;
next();
}
});
} else {
console.log("No existe la sesión...");
res.redirect(strategy.loginRoute);
}
};
exports.requiresToken = function(req, res, next) {
"use strict";
var token = req.param("token");
if (token !== undefined) {
strategy.deserializeUserToken(token, function(user) {
if (!user) {
console.log("El usuario no existe!");
res.send(401, {error: "No autorizado"});
} else {
req.user = user;
next();
}
});
} else {
console.log("No existe token...");
res.send(401, {error: "No autorizado"});
}
};
exports.destroySession = function(req, res, next) {
"use strict";
delete req.session.user;
next();
};
function withAuth(authMethod) {
"use strict";
return function(app, cb) {
function createAuthRouting(verb) {
return function() {
var route = arguments[0],
args = [].slice.call(arguments, 1);
return app[verb].apply(app, [route, authMethod].concat(args));
};
}
var routeVerbs = Object.create(app);
["get", "post", "put", "delete"].forEach(function(v) {
routeVerbs[v] = createAuthRouting(v);
});
cb(routeVerbs);
};
}
exports.withSession = withAuth(exports.requiresSession);
exports.withToken = withAuth(exports.requiresToken);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment