diff --git a/mvc/controllers/main/index.js b/mvc/controllers/main/index.js new file mode 100644 index 0000000..87922b5 --- /dev/null +++ b/mvc/controllers/main/index.js @@ -0,0 +1,6 @@ +'use strict' + +exports.index = function(req, res){ + res.redirect('/users'); +}; +console.log(2); diff --git a/mvc/controllers/pet/index.js b/mvc/controllers/pet/index.js new file mode 100644 index 0000000..214160f --- /dev/null +++ b/mvc/controllers/pet/index.js @@ -0,0 +1,31 @@ +'use strict' + +/** + * Module dependencies. + */ + +var db = require('../../db'); + +exports.engine = 'ejs'; + +exports.before = function(req, res, next){ + var pet = db.pets[req.params.pet_id]; + if (!pet) return next('route'); + req.pet = pet; + next(); +}; + +exports.show = function(req, res, next){ + res.render('show', { pet: req.pet }); +}; + +exports.edit = function(req, res, next){ + res.render('edit', { pet: req.pet }); +}; + +exports.update = function(req, res, next){ + var body = req.body; + req.pet.name = body.pet.name; + res.message('Information updated!'); + res.redirect('/pet/' + req.pet.id); +}; diff --git a/mvc/controllers/pet/views/edit.ejs b/mvc/controllers/pet/views/edit.ejs new file mode 100644 index 0000000..655666e --- /dev/null +++ b/mvc/controllers/pet/views/edit.ejs @@ -0,0 +1,17 @@ + + +
+ + + +You are viewing <%= pet.name %>
+ + diff --git a/mvc/controllers/user-pet/index.js b/mvc/controllers/user-pet/index.js new file mode 100644 index 0000000..42a29ad --- /dev/null +++ b/mvc/controllers/user-pet/index.js @@ -0,0 +1,22 @@ +'use strict' + +/** + * Module dependencies. + */ + +var db = require('../../db'); + +exports.name = 'pet'; +exports.prefix = '/user/:user_id'; + +exports.create = function(req, res, next){ + var id = req.params.user_id; + var user = db.users[id]; + var body = req.body; + if (!user) return next('route'); + var pet = { name: body.pet.name }; + pet.id = db.pets.push(pet) - 1; + user.pets.push(pet); + res.message('Added pet ' + body.pet.name); + res.redirect('/user/' + id); +}; diff --git a/mvc/controllers/user/index.js b/mvc/controllers/user/index.js new file mode 100644 index 0000000..ec3ae4c --- /dev/null +++ b/mvc/controllers/user/index.js @@ -0,0 +1,41 @@ +'use strict' + +/** + * Module dependencies. + */ + +var db = require('../../db'); + +exports.engine = 'hbs'; + +exports.before = function(req, res, next){ + var id = req.params.user_id; + if (!id) return next(); + // pretend to query a database... + process.nextTick(function(){ + req.user = db.users[id]; + // cant find that user + if (!req.user) return next('route'); + // found it, move on to the routes + next(); + }); +}; + +exports.list = function(req, res, next){ + res.render('list', { users: db.users }); +}; + +exports.edit = function(req, res, next){ + res.render('edit', { user: req.user }); +}; + +exports.show = function(req, res, next){ + res.render('show', { user: req.user }); +}; + +exports.update = function(req, res, next){ + var body = req.body; + req.user.name = body.user.name; + res.message('Information updated!'); + res.redirect('/user/' + req.user.id); +}; diff --git a/mvc/controllers/user/views/edit.hbs b/mvc/controllers/user/views/edit.hbs new file mode 100644 index 0000000..2be7ddc --- /dev/null +++ b/mvc/controllers/user/views/edit.hbs @@ -0,0 +1,27 @@ + + + + + + +Click a user below to view their pets.
+View {{user.name}}'s pets:
+No pets!
+{{/if}} + + diff --git a/mvc/db.js b/mvc/db.js new file mode 100644 index 0000000..94d1480 --- /dev/null +++ b/mvc/db.js @@ -0,0 +1,16 @@ +'use strict' + +// faux database + +var pets = exports.pets = []; + +pets.push({ name: 'Tobi', id: 0 }); +pets.push({ name: 'Loki', id: 1 }); +pets.push({ name: 'Jane', id: 2 }); +pets.push({ name: 'Raul', id: 3 }); + +var users = exports.users = []; + +users.push({ name: 'TJ', pets: [pets[0], pets[1], pets[2]], id: 0 }); +users.push({ name: 'Guillermo', pets: [pets[3]], id: 1 }); +users.push({ name: 'Nathan', pets: [], id: 2 }); diff --git a/mvc/index.js b/mvc/index.js new file mode 100644 index 0000000..1d8aa0e --- /dev/null +++ b/mvc/index.js @@ -0,0 +1,95 @@ +'use strict' + +/** + * Module dependencies. + */ + +var express = require('../..'); +var logger = require('morgan'); +var path = require('node:path'); +var session = require('express-session'); +var methodOverride = require('method-override'); + +var app = module.exports = express(); + +// set our default template engine to "ejs" +// which prevents the need for using file extensions +app.set('view engine', 'ejs'); + +// set views for error and 404 pages +app.set('views', path.join(__dirname, 'views')); + +// define a custom res.message() method +// which stores messages in the session +app.response.message = function(msg){ + // reference `req.session` via the `this.req` reference + var sess = this.req.session; + // simply add the msg to an array for later + sess.messages = sess.messages || []; + sess.messages.push(msg); + return this; +}; + +// log +if (!module.parent) app.use(logger('dev')); + +// serve static files +app.use(express.static(path.join(__dirname, 'public'))); + +// session support +app.use(session({ + resave: false, // don't save session if unmodified + saveUninitialized: false, // don't create session until something stored + secret: 'some secret here' +})); + +// parse request bodies (req.body) +app.use(express.urlencoded({ extended: true })) + +// allow overriding methods in query (?_method=put) +app.use(methodOverride('_method')); + +// expose the "messages" local variable when views are rendered +app.use(function(req, res, next){ + var msgs = req.session.messages || []; + + // expose "messages" local variable + res.locals.messages = msgs; + + // expose "hasMessages" + res.locals.hasMessages = !! msgs.length; + + /* This is equivalent: + res.locals({ + messages: msgs, + hasMessages: !! msgs.length + }); + */ + + next(); + // empty or "flush" the messages so they + // don't build up + req.session.messages = []; +}); + +// load controllers +require('./lib/boot')(app, { verbose: !module.parent }); + +app.use(function(err, req, res, next){ + // log it + if (!module.parent) console.error(err.stack); + + // error page + res.status(500).render('5xx'); +}); + +// assume 404 since no middleware responded +app.use(function(req, res, next){ + res.status(404).render('404', { url: req.originalUrl }); +}); + +/* istanbul ignore next */ +if (!module.parent) { + app.listen(3000); + console.log('Express started on port 3000'); +} diff --git a/mvc/lib/boot.js b/mvc/lib/boot.js new file mode 100644 index 0000000..fc2ab0f --- /dev/null +++ b/mvc/lib/boot.js @@ -0,0 +1,83 @@ +'use strict' + +/** + * Module dependencies. + */ + +var express = require('../../..'); +var fs = require('node:fs'); +var path = require('node:path'); + +module.exports = function(parent, options){ + var dir = path.join(__dirname, '..', 'controllers'); + var verbose = options.verbose; + fs.readdirSync(dir).forEach(function(name){ + var file = path.join(dir, name) + if (!fs.statSync(file).isDirectory()) return; + verbose && console.log('\n %s:', name); + var obj = require(file); + var name = obj.name || name; + var prefix = obj.prefix || ''; + var app = express(); + var handler; + var method; + var url; + + // allow specifying the view engine + if (obj.engine) app.set('view engine', obj.engine); + app.set('views', path.join(__dirname, '..', 'controllers', name, 'views')); + + // generate routes based + // on the exported methods + for (var key in obj) { + // "reserved" exports + if (~['name', 'prefix', 'engine', 'before'].indexOf(key)) continue; + // route exports + switch (key) { + case 'show': + method = 'get'; + url = '/' + name + '/:' + name + '_id'; + break; + case 'list': + method = 'get'; + url = '/' + name + 's'; + break; + case 'edit': + method = 'get'; + url = '/' + name + '/:' + name + '_id/edit'; + break; + case 'update': + method = 'put'; + url = '/' + name + '/:' + name + '_id'; + break; + case 'create': + method = 'post'; + url = '/' + name; + break; + case 'index': + method = 'get'; + url = '/'; + break; + default: + /* istanbul ignore next */ + throw new Error('unrecognized route: ' + name + '.' + key); + } + + // setup + handler = obj[key]; + url = prefix + url; + + // before middleware support + if (obj.before) { + app[method](url, obj.before, handler); + verbose && console.log(' %s %s -> before -> %s', method.toUpperCase(), url, key); + } else { + app[method](url, handler); + verbose && console.log(' %s %s -> %s', method.toUpperCase(), url, key); + } + } + + // mount the app + parent.use(app); + }); +}; diff --git a/mvc/public/style.css b/mvc/public/style.css new file mode 100644 index 0000000..8a23f9d --- /dev/null +++ b/mvc/public/style.css @@ -0,0 +1,14 @@ +body { + padding: 50px; + font: 16px "Helvetica Neue", Helvetica, Arial, sans-serif; +} +a { + color: #107aff; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +h1 a { + font-size: 16px; +} diff --git a/mvc/views/404.ejs b/mvc/views/404.ejs new file mode 100644 index 0000000..21a86f8 --- /dev/null +++ b/mvc/views/404.ejs @@ -0,0 +1,13 @@ + + + + + +Sorry we can't find <%= url %>
+ + diff --git a/mvc/views/5xx.ejs b/mvc/views/5xx.ejs new file mode 100644 index 0000000..190f580 --- /dev/null +++ b/mvc/views/5xx.ejs @@ -0,0 +1,13 @@ + + + + + +Looks like something blew up!
+ +