Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added submodules as folders

  • Loading branch information...
commit ac85bc64f1457c365aa24b2f1a216c691b59d6d7 1 parent 03dd70f
@pgte authored
Showing with 1,095 additions and 0 deletions.
  1. +124 −0 episode_012/app.js
  2. +14 −0 episode_012/photos.js
  3. +50 −0 episode_012/products.js
  4. +10 −0 episode_012/static/stylesheets/styles.css
  5. BIN  episode_012/static/uploads/photos/.DS_Store
  6. BIN  episode_012/static/uploads/photos/28-ipad.png
  7. BIN  episode_012/static/uploads/photos/apple-macbook-pro-17-inch-unibody-4g8-460.jpg
  8. +8 −0 episode_012/views/layout.jade
  9. +4 −0 episode_012/views/partials/photo_form.jade
  10. +5 −0 episode_012/views/partials/product.jade
  11. +20 −0 episode_012/views/partials/product_form.jade
  12. +7 −0 episode_012/views/photos/index.jade
  13. +4 −0 episode_012/views/photos/new.jade
  14. +4 −0 episode_012/views/products/edit.jade
  15. +4 −0 episode_012/views/products/index.jade
  16. +2 −0  episode_012/views/products/new.jade
  17. +10 −0 episode_012/views/products/show.jade
  18. +2 −0  episode_012/views/root.jade
  19. +3 −0  episode_013/README
  20. +177 −0 episode_013/app.js
  21. +14 −0 episode_013/photos.js
  22. +50 −0 episode_013/products.js
  23. +30 −0 episode_013/static/stylesheets/styles.css
  24. BIN  episode_013/static/uploads/photos/.DS_Store
  25. BIN  episode_013/static/uploads/photos/28-ipad.png
  26. BIN  episode_013/static/uploads/photos/apple-macbook-pro-17-inch-unibody-4g8-460.jpg
  27. +17 −0 episode_013/users.js
  28. +15 −0 episode_013/views/layout.jade
  29. +4 −0 episode_013/views/partials/photo_form.jade
  30. +5 −0 episode_013/views/partials/product.jade
  31. +20 −0 episode_013/views/partials/product_form.jade
  32. +7 −0 episode_013/views/photos/index.jade
  33. +4 −0 episode_013/views/photos/new.jade
  34. +4 −0 episode_013/views/products/edit.jade
  35. +4 −0 episode_013/views/products/index.jade
  36. +2 −0  episode_013/views/products/new.jade
  37. +10 −0 episode_013/views/products/show.jade
  38. +2 −0  episode_013/views/root.jade
  39. +12 −0 episode_013/views/sessions/new.jade
  40. +3 −0  episode_018/README
  41. +209 −0 episode_018/app.js
  42. BIN  episode_018/data/db.0
  43. BIN  episode_018/data/db.1
  44. BIN  episode_018/data/db.ns
  45. 0  episode_018/data/mongod.lock
  46. +3 −0  episode_018/nodemon-ignore
  47. +14 −0 episode_018/photos.js
  48. +9 −0 episode_018/products.js
  49. +30 −0 episode_018/static/stylesheets/styles.css
  50. BIN  episode_018/static/uploads/photos/.DS_Store
  51. BIN  episode_018/static/uploads/photos/28-ipad.png
  52. BIN  episode_018/static/uploads/photos/apple-macbook-pro-17-inch-unibody-4g8-460.jpg
  53. +10 −0 episode_018/users.js
  54. +15 −0 episode_018/views/layout.jade
  55. +4 −0 episode_018/views/partials/photo_form.jade
  56. +5 −0 episode_018/views/partials/product.jade
  57. +20 −0 episode_018/views/partials/product_form.jade
  58. +7 −0 episode_018/views/photos/index.jade
  59. +4 −0 episode_018/views/photos/new.jade
  60. +4 −0 episode_018/views/products/edit.jade
  61. +4 −0 episode_018/views/products/index.jade
  62. +2 −0  episode_018/views/products/new.jade
  63. +10 −0 episode_018/views/products/show.jade
  64. +2 −0  episode_018/views/root.jade
  65. +12 −0 episode_018/views/sessions/new.jade
  66. +34 −0 episode_26/app.js
  67. +40 −0 episode_26/lib/users.js
  68. +4 −0 episode_26/views/home.jade
  69. +2 −0  episode_26/views/layout.jade
View
124 episode_012/app.js
@@ -0,0 +1,124 @@
+var express = require('express');
+var multipart = require('multipart');
+var fs = require('fs');
+
+var app = express.createServer();
+
+app.configure(function() {
+ app.use(express.logger());
+ app.use(express.bodyDecoder());
+ app.use(express.methodOverride());
+ app.use(express.staticProvider(__dirname + '/static'));
+});
+
+app.configure('development', function () {
+ app.use(express.errorHandler({
+ dumpExceptions: true,
+ showStack: true
+ }));
+});
+
+app.configure('production', function () {
+ app.use(express.errorHandler());
+});
+
+app.set('views', __dirname + '/views');
+app.set('view engine', 'jade');
+
+app.get('/', function(req, res) {
+ res.render('root');
+});
+
+var products = require('./products');
+var photos = require('./photos');
+
+app.get('/products', function(req, res) {
+ res.render('products/index', {locals: {
+ products: products.all
+ }});
+});
+
+app.get('/products/new', function(req, res) {
+ res.render('products/new', {locals: {
+ product: req.body && req.body.product || products.new()
+ }});
+});
+
+app.post('/products', function(req, res) {
+ var id = products.insert(req.body.product);
+ res.redirect('/products/' + id);
+});
+
+app.get('/products/:id', function(req, res) {
+ var product = products.find(req.params.id);
+ res.render('products/show', {locals: {
+ product: product
+ }});
+});
+
+app.get('/products/:id/edit', function(req, res) {
+ var product = products.find(req.params.id);
+ photos.list(function(err, photo_list) {
+ if (err) {
+ throw err;
+ }
+ res.render('products/edit', {locals: {
+ product: product,
+ photos: photo_list
+ }});
+
+ });
+});
+
+app.put('/products/:id', function(req, res) {
+ var id = req.params.id;
+ products.set(id, req.body.product);
+ res.redirect('/products/'+id);
+});
+
+/* Photos */
+
+app.get('/photos', function(req, res) {
+ photos.list(function(err, photo_list) {
+ res.render('photos/index', {locals: {
+ photos: photo_list
+ }})
+ });
+});
+
+app.get('/photos/new', function(req, res) {
+ res.render('photos/new');
+});
+
+app.post('/photos', function(req, res) {
+ req.setEncoding('binary');
+
+ var parser = multipart.parser();
+
+ parser.headers = req.headers;
+ var ws;
+
+ parser.onPartBegin = function(part) {
+ ws = fs.createWriteStream(__dirname + '/static/uploads/photos/' + part.filename);
+ ws.on('error', function(err) {
+ throw err;
+ });
+ };
+
+ parser.onData = function(data) {
+ ws.write(data, 'binary');
+ };
+
+ parser.onPartEnd = function() {
+ ws.end();
+ parser.close();
+ res.redirect('/photos');
+ };
+
+ req.on('data', function(data) {
+ parser.write(data);
+ });
+
+});
+
+app.listen(4000);
View
14 episode_012/photos.js
@@ -0,0 +1,14 @@
+var fs = require('fs');
+
+var src_path = __dirname + '/static/uploads/photos/'
+module.exports.list = function(callback) {
+ fs.readdir(src_path, function(err, files) {
+ var ret_files = [];
+ files.forEach(function(file) {
+ ret_files.push('/uploads/photos/' + file);
+ });
+ console.log(ret_files);
+ callback(err, ret_files);
+
+ });
+};
View
50 episode_012/products.js
@@ -0,0 +1,50 @@
+var products = [
+{
+ id: 1,
+ name : 'Mac Book Pro',
+ description: 'Apple 13 inch Mac Book Pro Notebook',
+ price: 1000
+},
+{
+ id: 2,
+ name : 'iPad',
+ description: 'Apple 64GB 3G iPad',
+ price: 899
+}
+];
+
+module.exports.all = products;
+
+module.exports.find = function(id) {
+ id = parseInt(id, 10);
+ var found = null;
+ productloop: for(product_index in products) {
+ var product = products[product_index];
+ if (product.id == id) {
+ found = product;
+ break productloop;
+ }
+ };
+ return found;
+}
+
+module.exports.set = function(id, product) {
+ id = parseInt(id, 10);
+ product.id = id;
+ products[id - 1] = product;
+};
+
+module.exports.new = function() {
+ return {
+ name: '',
+ description: '',
+ price: 0
+ };
+}
+
+module.exports.insert = function(product) {
+ var id = products.length + 1;
+ product.id = id;
+ products[id - 1] = product;
+ return id;
+}
View
10 episode_012/static/stylesheets/styles.css
@@ -0,0 +1,10 @@
+body {
+ font-family: Helvetica, Arial, Sans-Serif;
+ font-size: 16px;
+}
+#main {
+ width: 960px;
+ margin: 0 auto;
+ border: 1px solid #ddd;
+ padding: 1em;
+}
View
BIN  episode_012/static/uploads/photos/.DS_Store
Binary file not shown
View
BIN  episode_012/static/uploads/photos/28-ipad.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  episode_012/static/uploads/photos/apple-macbook-pro-17-inch-unibody-4g8-460.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
8 episode_012/views/layout.jade
@@ -0,0 +1,8 @@
+!!! 5
+html
+ head
+ link(rel='stylesheet', href='/stylesheets/styles.css')
+ title My template
+ body
+ #main
+ #container!= body
View
4 episode_012/views/partials/photo_form.jade
@@ -0,0 +1,4 @@
+p
+ label(for='photo') Photo:
+p
+ input(type='file', name='photo')
View
5 episode_012/views/partials/product.jade
@@ -0,0 +1,5 @@
+h2= product.name
+p= product.description
+p Price: #{product.price}
+p
+ a(href='/products/'+product.id) Details
View
20 episode_012/views/partials/product_form.jade
@@ -0,0 +1,20 @@
+p
+ label(for='product_name') Name:
+p
+ input(type='text', id='product_name', name='product[name]', value=product.name)
+p
+ label(for='product_description') Description:
+p
+ textarea(id='product_name', name='product[description]')= product.description
+p
+ label(for='product_price') Price:
+p
+ input(type='text', id='product_price', name='product[price]', value=product.price)
+p
+ label(for='product_photo') Photo:
+p
+ select(id='product_photo', name='product[photo]')
+ - each photo in photos
+ option(value=photo, selected=(product.photo == photo))= photo
+p
+ input(type='submit')
View
7 episode_012/views/photos/index.jade
@@ -0,0 +1,7 @@
+h1 Photos:
+p
+ a(href='/photos/new') Create
+ul
+ - each photo in photos
+ li
+ img(src=photo)
View
4 episode_012/views/photos/new.jade
@@ -0,0 +1,4 @@
+h1 New Photo
+form(action='/photos', method='POST', enctype='multipart/form-data')!= partial('photo_form')
+ p
+ input(type='submit')
View
4 episode_012/views/products/edit.jade
@@ -0,0 +1,4 @@
+h1 Editing #{product.name}
+form(action='/products/'+product.id, method='POST')
+ input(type='hidden', name='_method', value='PUT')
+ div!= partial('product_form', {locals: {product: product, photos: photos}})
View
4 episode_012/views/products/index.jade
@@ -0,0 +1,4 @@
+h1 Products:
+#products!= partial('product', {collection: products})
+p
+ a(href='/products/new') New
View
2  episode_012/views/products/new.jade
@@ -0,0 +1,2 @@
+h1 New product
+form(action='/products', method='POST')!= partial('product_form', {locals: {product: product}})
View
10 episode_012/views/products/show.jade
@@ -0,0 +1,10 @@
+h2= product.name
+p= product.description
+- if (product.photo)
+ p
+ img(src=product.photo)
+p Price: #{product.price}
+p
+ a(href='/products') Back
+a
+ a(href='/products/'+product.id+'/edit') Edit
View
2  episode_012/views/root.jade
@@ -0,0 +1,2 @@
+h2 Hello
+p World!
View
3  episode_013/README
@@ -0,0 +1,3 @@
+See Node Tuts episode 13 - Authentication in Express - Sessions and Route middleware
+
+http://nodetuts.com/tutorials/13-authentication-in-express-sessions-and-route-middleware.html
View
177 episode_013/app.js
@@ -0,0 +1,177 @@
+var express = require('express');
+var multipart = require('multipart');
+var fs = require('fs');
+
+var app = express.createServer();
+
+var MemStore = require('connect/middleware/session/memory');
+
+app.configure(function() {
+ app.use(express.logger());
+ app.use(express.bodyDecoder());
+ app.use(express.methodOverride());
+ app.use(express.staticProvider(__dirname + '/static'));
+ app.use(express.cookieDecoder());
+ app.use(express.session({store: MemStore( {
+ reapInterval: 60000 * 10
+ })}));
+});
+
+app.configure('development', function () {
+ app.use(express.errorHandler({
+ dumpExceptions: true,
+ showStack: true
+ }));
+});
+
+app.configure('production', function () {
+ app.use(express.errorHandler());
+});
+
+app.set('views', __dirname + '/views');
+app.set('view engine', 'jade');
+
+app.dynamicHelpers(
+ {
+ session: function(req, res) {
+ return req.session;
+ },
+
+ flash: function(req, res) {
+ return req.flash();
+ }
+ }
+);
+
+function requiresLogin(req, res, next) {
+ if (req.session.user) {
+ next();
+ } else {
+ res.redirect('/sessions/new?redir=' + req.url);
+ }
+};
+
+app.get('/', function(req, res) {
+ res.render('root');
+});
+
+/* Sessions */
+
+var users = require('./users');
+
+app.get('/sessions/new', function(req, res) {
+ res.render('sessions/new', {locals: {
+ redir: req.query.redir
+ }});
+});
+
+app.post('/sessions', function(req, res) {
+ users.authenticate(req.body.login, req.body.password, function(user) {
+ if (user) {
+ req.session.user = user;
+ res.redirect(req.body.redir || '/');
+ } else {
+ req.flash('warn', 'Login failed');
+ res.render('sessions/new', {locals: {redir: req.body.redir}});
+ }
+ });
+});
+
+app.get('/sessions/destroy', function(req, res) {
+ delete req.session.user;
+ res.redirect('/sessions/new');
+});
+
+var products = require('./products');
+var photos = require('./photos');
+
+app.get('/products', requiresLogin, function(req, res) {
+ res.render('products/index', {locals: {
+ products: products.all
+ }});
+});
+
+app.get('/products/new', requiresLogin, function(req, res) {
+ res.render('products/new', {locals: {
+ product: req.body && req.body.product || products.new()
+ }});
+});
+
+app.post('/products', requiresLogin, function(req, res) {
+ var id = products.insert(req.body.product);
+ res.redirect('/products/' + id);
+});
+
+app.get('/products/:id', function(req, res) {
+ var product = products.find(req.params.id);
+ res.render('products/show', {locals: {
+ product: product
+ }});
+});
+
+app.get('/products/:id/edit', requiresLogin, function(req, res) {
+ var product = products.find(req.params.id);
+ photos.list(function(err, photo_list) {
+ if (err) {
+ throw err;
+ }
+ res.render('products/edit', {locals: {
+ product: product,
+ photos: photo_list
+ }});
+
+ });
+});
+
+app.put('/products/:id', requiresLogin, function(req, res) {
+ var id = req.params.id;
+ products.set(id, req.body.product);
+ res.redirect('/products/'+id);
+});
+
+/* Photos */
+
+app.get('/photos', function(req, res) {
+ photos.list(function(err, photo_list) {
+ res.render('photos/index', {locals: {
+ photos: photo_list
+ }})
+ });
+});
+
+app.get('/photos/new', function(req, res) {
+ res.render('photos/new');
+});
+
+app.post('/photos', function(req, res) {
+ req.setEncoding('binary');
+
+ var parser = multipart.parser();
+
+ parser.headers = req.headers;
+ var ws;
+
+ parser.onPartBegin = function(part) {
+ ws = fs.createWriteStream(__dirname + '/static/uploads/photos/' + part.filename);
+ ws.on('error', function(err) {
+ throw err;
+ });
+ };
+
+ parser.onData = function(data) {
+ ws.write(data, 'binary');
+ };
+
+ parser.onPartEnd = function() {
+ ws.end();
+ parser.close();
+ res.redirect('/photos');
+ };
+
+ req.on('data', function(data) {
+ parser.write(data);
+ });
+
+});
+
+app.listen(4000);
View
14 episode_013/photos.js
@@ -0,0 +1,14 @@
+var fs = require('fs');
+
+var src_path = __dirname + '/static/uploads/photos/'
+module.exports.list = function(callback) {
+ fs.readdir(src_path, function(err, files) {
+ var ret_files = [];
+ files.forEach(function(file) {
+ ret_files.push('/uploads/photos/' + file);
+ });
+ console.log(ret_files);
+ callback(err, ret_files);
+
+ });
+};
View
50 episode_013/products.js
@@ -0,0 +1,50 @@
+var products = [
+{
+ id: 1,
+ name : 'Mac Book Pro',
+ description: 'Apple 13 inch Mac Book Pro Notebook',
+ price: 1000
+},
+{
+ id: 2,
+ name : 'iPad',
+ description: 'Apple 64GB 3G iPad',
+ price: 899
+}
+];
+
+module.exports.all = products;
+
+module.exports.find = function(id) {
+ id = parseInt(id, 10);
+ var found = null;
+ productloop: for(product_index in products) {
+ var product = products[product_index];
+ if (product.id == id) {
+ found = product;
+ break productloop;
+ }
+ };
+ return found;
+}
+
+module.exports.set = function(id, product) {
+ id = parseInt(id, 10);
+ product.id = id;
+ products[id - 1] = product;
+};
+
+module.exports.new = function() {
+ return {
+ name: '',
+ description: '',
+ price: 0
+ };
+}
+
+module.exports.insert = function(product) {
+ var id = products.length + 1;
+ product.id = id;
+ products[id - 1] = product;
+ return id;
+}
View
30 episode_013/static/stylesheets/styles.css
@@ -0,0 +1,30 @@
+body {
+ font-family: Helvetica, Arial, Sans-Serif;
+ font-size: 16px;
+}
+#main {
+ width: 960px;
+ margin: 0 auto;
+ border: 1px solid #ddd;
+ padding: 1em;
+}
+#header {
+ float: right;
+ clear: both;
+}
+#user {
+ float: left;
+ margin-right: 1em;
+}
+#logout {
+ float: left;
+}
+#warn {
+ background-color: #fdd;
+ padding: 1em;
+ border: 1px solid red;
+ width: 50%;
+}
+#container {
+ clear: both;
+}
View
BIN  episode_013/static/uploads/photos/.DS_Store
Binary file not shown
View
BIN  episode_013/static/uploads/photos/28-ipad.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  episode_013/static/uploads/photos/apple-macbook-pro-17-inch-unibody-4g8-460.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
17 episode_013/users.js
@@ -0,0 +1,17 @@
+var users = {
+ 'pedro' : {login: 'pedro', password: 'test1', role: 'admin'},
+ 'john' : {login: 'john', password: 'test2', role: 'user'}
+};
+module.exports.authenticate = function(login, password, callback) {
+ var user = users[login];
+ if (!user) {
+ callback(null);
+ return;
+ }
+ if (user.password == password) {
+ callback(user);
+ return;
+ }
+ callback(null);
+};
+
View
15 episode_013/views/layout.jade
@@ -0,0 +1,15 @@
+!!! 5
+html
+ head
+ link(rel='stylesheet', href='/stylesheets/styles.css')
+ title My template
+ body
+ #main
+ #header
+ - if (session.user)
+ #user= 'logged in as ' + session.user.login
+ #logout
+ a(href='/sessions/destroy') logout
+ - if (flash.warn)
+ p#warn= flash.warn
+ #container!= body
View
4 episode_013/views/partials/photo_form.jade
@@ -0,0 +1,4 @@
+p
+ label(for='photo') Photo:
+p
+ input(type='file', name='photo')
View
5 episode_013/views/partials/product.jade
@@ -0,0 +1,5 @@
+h2= product.name
+p= product.description
+p Price: #{product.price}
+p
+ a(href='/products/'+product.id) Details
View
20 episode_013/views/partials/product_form.jade
@@ -0,0 +1,20 @@
+p
+ label(for='product_name') Name:
+p
+ input(type='text', id='product_name', name='product[name]', value=product.name)
+p
+ label(for='product_description') Description:
+p
+ textarea(id='product_name', name='product[description]')= product.description
+p
+ label(for='product_price') Price:
+p
+ input(type='text', id='product_price', name='product[price]', value=product.price)
+p
+ label(for='product_photo') Photo:
+p
+ select(id='product_photo', name='product[photo]')
+ - each photo in photos
+ option(value=photo, selected=(product.photo == photo))= photo
+p
+ input(type='submit')
View
7 episode_013/views/photos/index.jade
@@ -0,0 +1,7 @@
+h1 Photos:
+p
+ a(href='/photos/new') Create
+ul
+ - each photo in photos
+ li
+ img(src=photo)
View
4 episode_013/views/photos/new.jade
@@ -0,0 +1,4 @@
+h1 New Photo
+form(action='/photos', method='POST', enctype='multipart/form-data')!= partial('photo_form')
+ p
+ input(type='submit')
View
4 episode_013/views/products/edit.jade
@@ -0,0 +1,4 @@
+h1 Editing #{product.name}
+form(action='/products/'+product.id, method='POST')
+ input(type='hidden', name='_method', value='PUT')
+ div!= partial('product_form', {locals: {product: product, photos: photos}})
View
4 episode_013/views/products/index.jade
@@ -0,0 +1,4 @@
+h1 Products:
+#products!= partial('product', {collection: products})
+p
+ a(href='/products/new') New
View
2  episode_013/views/products/new.jade
@@ -0,0 +1,2 @@
+h1 New product
+form(action='/products', method='POST')!= partial('product_form', {locals: {product: product}})
View
10 episode_013/views/products/show.jade
@@ -0,0 +1,10 @@
+h2= product.name
+p= product.description
+- if (product.photo)
+ p
+ img(src=product.photo)
+p Price: #{product.price}
+p
+ a(href='/products') Back
+a
+ a(href='/products/'+product.id+'/edit') Edit
View
2  episode_013/views/root.jade
@@ -0,0 +1,2 @@
+h2 Hello
+p World!
View
12 episode_013/views/sessions/new.jade
@@ -0,0 +1,12 @@
+h1 Login
+form(action='/sessions', method='POST')
+ input(type='hidden', name='redir', value=redir)
+ p
+ label(for='login') Login:
+ input(type='text', name='login', id='login')
+ p
+ label(for='password') Password:
+ input(type='password', name='password', id='password')
+ p
+ input(type='submit')
+
View
3  episode_018/README
@@ -0,0 +1,3 @@
+See Node Tuts episode 13 - Authentication in Express - Sessions and Route middleware
+
+http://nodetuts.com/tutorials/13-authentication-in-express-sessions-and-route-middleware.html
View
209 episode_018/app.js
@@ -0,0 +1,209 @@
+var express = require('express');
+var multipart = require('multipart');
+var fs = require('fs');
+
+var mongoose = require('mongoose');
+
+var db = mongoose.connect('mongodb://localhost/db');
+
+var app = express.createServer();
+
+var MemStore = require('connect').session.MemoryStore;
+
+app.configure(function() {
+ app.use(express.logger());
+ app.use(express.bodyDecoder());
+ app.use(express.methodOverride());
+ app.use(express.staticProvider(__dirname + '/static'));
+ app.use(express.cookieDecoder());
+ app.use(express.session({store: MemStore( {
+ reapInterval: 60000 * 10
+ }),
+ secret: "320ºrifsdçlfksdçfksf'ewfsdfkl"}));
+});
+
+app.configure('development', function () {
+ app.use(express.errorHandler({
+ dumpExceptions: true,
+ showStack: true
+ }));
+});
+
+app.configure('production', function () {
+ app.use(express.errorHandler());
+});
+
+app.set('views', __dirname + '/views');
+app.set('view engine', 'jade');
+
+app.dynamicHelpers(
+ {
+ session: function(req, res) {
+ return req.session;
+ },
+
+ flash: function(req, res) {
+ return req.flash();
+ }
+ }
+);
+
+function requiresLogin(req, res, next) {
+ if (req.session.user) {
+ next();
+ } else {
+ res.redirect('/sessions/new?redir=' + req.url);
+ }
+};
+
+app.get('/', function(req, res) {
+ res.render('root');
+});
+
+/* Sessions */
+
+require('./users');
+
+var User = db.model('User');
+
+app.get('/sessions/new', function(req, res) {
+ res.render('sessions/new', {locals: {
+ redir: req.query.redir
+ }});
+});
+
+
+app.post('/sessions', function(req, res, next) {
+ User.findOne({login: req.body.login, password: req.body.password}, function(err, user) {
+ if (err) { next(err); return; }
+ if (user) {
+ req.session.user = user;
+ res.redirect(req.body.redir || '/');
+ } else {
+ req.flash('warn', 'Login failed');
+ res.render('sessions/new', {locals: {redir: req.body.redir}});
+ }
+ });
+});
+
+app.get('/sessions/destroy', function(req, res) {
+ delete req.session.user;
+ res.redirect('/sessions/new');
+});
+
+require('./products');
+var Product = db.model('Product');
+var photos = require('./photos');
+
+app.get('/products', requiresLogin, function(req, res, next) {
+ Product.find({}, function(err, products) {
+ if (err) { next(err); return;}
+ res.render('products/index', {locals: {
+ products: products
+ }});
+ });
+});
+
+app.get('/products/new', requiresLogin, function(req, res) {
+ photos.list(function(err, photo_list) {
+ if (err) {
+ throw err;
+ }
+ res.render('products/new', {locals: {
+ photos: photo_list,
+ product: req.body && req.body.product || new Product()
+ }});
+
+ });
+});
+
+app.post('/products', requiresLogin, function(req, res) {
+ var product = new Product(req.body.product);
+ product.save(function() {
+ res.redirect('/products/' + product._id.toHexString());
+ });
+});
+
+app.get('/products/:id', function(req, res, next) {
+ Product.findById(req.params.id, function(err, product) {
+ if (err) { next(err); return;}
+ res.render('products/show', {locals: {
+ product: product
+ }});
+ });
+});
+
+app.get('/products/:id/edit', requiresLogin, function(req, res, next) {
+ Product.findById(req.params.id, function(err, product) {
+ if (err) { next(err); return; }
+ photos.list(function(err, photo_list) {
+ if (err) { next(err); return; }
+ res.render('products/edit', {locals: {
+ product: product,
+ photos: photo_list
+ }});
+ });
+ });
+});
+
+app.put('/products/:id', requiresLogin, function(req, res, next) {
+ var id = req.params.id;
+ console.log(req.body.product);
+ Product.findById(id, function(err, product) {
+ if (err) { next(err); return; }
+ product.name = req.body.product.name;
+ product.description = req.body.product.description;
+ product.price = req.body.product.price;
+ product.photo = req.body.product.photo;
+ product.save(function() {
+ res.redirect('/products/'+product._id.toHexString());
+ });
+ });
+});
+
+/* Photos */
+
+app.get('/photos', function(req, res) {
+ photos.list(function(err, photo_list) {
+ res.render('photos/index', {locals: {
+ photos: photo_list
+ }})
+ });
+});
+
+app.get('/photos/new', function(req, res) {
+ res.render('photos/new');
+});
+
+app.post('/photos', function(req, res) {
+ req.setEncoding('binary');
+
+ var parser = multipart.parser();
+
+ parser.headers = req.headers;
+ var ws;
+
+ parser.onPartBegin = function(part) {
+ ws = fs.createWriteStream(__dirname + '/static/uploads/photos/' + part.filename);
+ ws.on('error', function(err) {
+ throw err;
+ });
+ };
+
+ parser.onData = function(data) {
+ ws.write(data, 'binary');
+ };
+
+ parser.onPartEnd = function() {
+ ws.end();
+ parser.close();
+ res.redirect('/photos');
+ };
+
+ req.on('data', function(data) {
+ parser.write(data);
+ });
+
+});
+
+app.listen(4000);
View
BIN  episode_018/data/db.0
Binary file not shown
View
BIN  episode_018/data/db.1
Binary file not shown
View
BIN  episode_018/data/db.ns
Binary file not shown
View
0  episode_018/data/mongod.lock
No changes.
View
3  episode_018/nodemon-ignore
@@ -0,0 +1,3 @@
+data
+*.jpg
+*.png
View
14 episode_018/photos.js
@@ -0,0 +1,14 @@
+var fs = require('fs');
+
+var src_path = __dirname + '/static/uploads/photos/'
+module.exports.list = function(callback) {
+ fs.readdir(src_path, function(err, files) {
+ var ret_files = [];
+ files.forEach(function(file) {
+ ret_files.push('/uploads/photos/' + file);
+ });
+ console.log(ret_files);
+ callback(err, ret_files);
+
+ });
+};
View
9 episode_018/products.js
@@ -0,0 +1,9 @@
+var Mongoose = require('mongoose'),
+ Schema = Mongoose.Schema;
+
+Mongoose.model('Product', new Schema({
+ name: String,
+ description: String,
+ price: Number,
+ photo: String
+}));
View
30 episode_018/static/stylesheets/styles.css
@@ -0,0 +1,30 @@
+body {
+ font-family: Helvetica, Arial, Sans-Serif;
+ font-size: 16px;
+}
+#main {
+ width: 960px;
+ margin: 0 auto;
+ border: 1px solid #ddd;
+ padding: 1em;
+}
+#header {
+ float: right;
+ clear: both;
+}
+#user {
+ float: left;
+ margin-right: 1em;
+}
+#logout {
+ float: left;
+}
+#warn {
+ background-color: #fdd;
+ padding: 1em;
+ border: 1px solid red;
+ width: 50%;
+}
+#container {
+ clear: both;
+}
View
BIN  episode_018/static/uploads/photos/.DS_Store
Binary file not shown
View
BIN  episode_018/static/uploads/photos/28-ipad.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  episode_018/static/uploads/photos/apple-macbook-pro-17-inch-unibody-4g8-460.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
10 episode_018/users.js
@@ -0,0 +1,10 @@
+var Mongoose = require('mongoose'),
+ Schema = Mongoose.Schema;
+
+var User = new Schema({
+ login: String,
+ password: String,
+ role: String,
+});
+
+Mongoose.model('User', User);
View
15 episode_018/views/layout.jade
@@ -0,0 +1,15 @@
+!!! 5
+html
+ head
+ link(rel='stylesheet', href='/stylesheets/styles.css')
+ title My template
+ body
+ #main
+ #header
+ - if (session.user)
+ #user= 'logged in as ' + session.user.login
+ #logout
+ a(href='/sessions/destroy') logout
+ - if (flash.warn)
+ p#warn= flash.warn
+ #container!= body
View
4 episode_018/views/partials/photo_form.jade
@@ -0,0 +1,4 @@
+p
+ label(for='photo') Photo:
+p
+ input(type='file', name='photo')
View
5 episode_018/views/partials/product.jade
@@ -0,0 +1,5 @@
+h2= product.name
+p= product.description
+p Price: #{product.price}
+p
+ a(href='/products/'+product._id.toHexString()) Details
View
20 episode_018/views/partials/product_form.jade
@@ -0,0 +1,20 @@
+p
+ label(for='product_name') Name:
+p
+ input(type='text', id='product_name', name='product[name]', value=product.name)
+p
+ label(for='product_description') Description:
+p
+ textarea(id='product_name', name='product[description]')= product.description
+p
+ label(for='product_price') Price:
+p
+ input(type='text', id='product_price', name='product[price]', value=product.price)
+p
+ label(for='product_photo') Photo:
+p
+ select(id='product_photo', name='product[photo]')
+ - each photo in photos
+ option(value=photo, selected=(product.photo == photo))= photo
+p
+ input(type='submit')
View
7 episode_018/views/photos/index.jade
@@ -0,0 +1,7 @@
+h1 Photos:
+p
+ a(href='/photos/new') Create
+ul
+ - each photo in photos
+ li
+ img(src=photo)
View
4 episode_018/views/photos/new.jade
@@ -0,0 +1,4 @@
+h1 New Photo
+form(action='/photos', method='POST', enctype='multipart/form-data')!= partial('photo_form')
+ p
+ input(type='submit')
View
4 episode_018/views/products/edit.jade
@@ -0,0 +1,4 @@
+h1 Editing #{product.name}
+form(action='/products/'+product._id.toHexString(), method='POST')
+ input(type='hidden', name='_method', value='PUT')
+ div!= partial('product_form', {locals: {product: product, photos: photos}})
View
4 episode_018/views/products/index.jade
@@ -0,0 +1,4 @@
+h1 Products:
+#products!= partial('product', {collection: products})
+p
+ a(href='/products/new') New
View
2  episode_018/views/products/new.jade
@@ -0,0 +1,2 @@
+h1 New product
+form(action='/products', method='POST')!= partial('product_form', {locals: {product: product}})
View
10 episode_018/views/products/show.jade
@@ -0,0 +1,10 @@
+h2= product.name
+p= product.description
+- if (product.photo)
+ p
+ img(src=product.photo)
+p Price: #{product.price}
+p
+ a(href='/products') Back
+a
+ a(href='/products/'+product._id.toHexString()+'/edit') Edit
View
2  episode_018/views/root.jade
@@ -0,0 +1,2 @@
+h2 Hello
+p World!
View
12 episode_018/views/sessions/new.jade
@@ -0,0 +1,12 @@
+h1 Login
+form(action='/sessions', method='POST')
+ input(type='hidden', name='redir', value=redir)
+ p
+ label(for='login') Login:
+ input(type='text', name='login', id='login')
+ p
+ label(for='password') Password:
+ input(type='password', name='password', id='password')
+ p
+ input(type='submit')
+
View
34 episode_26/app.js
@@ -0,0 +1,34 @@
+var express = require('express'),
+ everyauth = require('everyauth'),
+ util = require('util'),
+ users = require('./lib/users');
+
+everyauth.twitter
+ .consumerKey('OExJ9lyDkQlaedNVB6QQ')
+ .consumerSecret('qDOXx67ArhbiA6fYeGOuxgbMYyph0hiJmMfEDtosc')
+ .findOrCreateUser(function(session, accessToken, accessTokenSecret, twitterUserData) {
+ var promise = this.Promise();
+ users.findOrCreateByTwitterData(twitterUserData, accessToken, accessTokenSecret, promise);
+ return promise;
+ })
+ .redirectPath('/');
+
+var app = express.createServer();
+app.configure(function() {
+ app.use(express.bodyParser());
+ app.use(express.cookieParser());
+ app.use(express.session({secret: "90ndsj9dfdsf"}));
+ app.use(everyauth.middleware());
+ app.use(app.router);
+ app.set('view engine', 'jade');
+ app.use(express.static(__dirname + '/public'));
+ app.use(express.errorHandler());
+ everyauth.helpExpress(app);
+});
+
+
+app.get('/', function(req, res) {
+ res.render('home');
+});
+
+app.listen(4000);
View
40 episode_26/lib/users.js
@@ -0,0 +1,40 @@
+var cradle = require('cradle'),
+ util = require('util');
+
+var c = new cradle.Connection('nodetuts26.iriscouch.com', 80, {
+ auth: { username: 'node', password: 'tuts'}
+});
+var users = c.database('users');
+
+exports.findOrCreateByTwitterData = function(twitterUserData, accessToken, accessTokenSecret, promise) {
+ users.view('docs/twitterId', {key: twitterUserData.id_str}, function(err, docs) {
+ if (err) {
+ console.log("Error using users/_design/docs/_view/twitterId:");
+ console.log(err);
+ promise.fail(err);
+ return;
+ }
+ if (docs.length > 0) {
+ var user = docs[0].value;
+ console.log('user exists: ' + util.inspect(user));
+ promise.fulfill(user);
+ } else {
+ var doc = {
+ accessToken: accessToken,
+ accessTokenSecret: accessTokenSecret,
+ name: twitterUserData.name,
+ twitterId: twitterUserData.id
+ };
+ c.database('users').save(doc, function(err, res) {
+ if (err) {
+ console.log("Error using users:");
+ console.log(err);
+ promise.fail(err);
+ return;
+ }
+ console.log('user created: ' + util.inspect(doc));
+ promise.fulfill(doc);
+ })
+ }
+ });
+}
View
4 episode_26/views/home.jade
@@ -0,0 +1,4 @@
+- if (everyauth.loggedIn)
+ p Hello #{everyauth.twitter.user.name}
+- else
+ a(href:"/auth/twitter") log in with twitter
View
2  episode_26/views/layout.jade
@@ -0,0 +1,2 @@
+!!! 5
+body!= body
Please sign in to comment.
Something went wrong with that request. Please try again.