Last active
January 3, 2016 00:48
-
-
Save werelax/8384696 to your computer and use it in GitHub Desktop.
Base Node.js structure for small projects (missing auth routes/controllers)
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
| /* 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"); |
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
| 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