mirror of
https://github.com/sstent/expressmongotest.git
synced 2026-01-25 16:42:00 +00:00
almost rebased
This commit is contained in:
10
chapter25/01_package.json
Normal file
10
chapter25/01_package.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "application-name"
|
||||
, "version": "0.0.1"
|
||||
, "private": true
|
||||
, "dependencies": {
|
||||
"express": "2.5.11"
|
||||
, "jade": ">= 0.0.1"
|
||||
, "mongoose": ">=2.7.0"
|
||||
}
|
||||
}
|
||||
9
chapter25/02_user_schema.js
Normal file
9
chapter25/02_user_schema.js
Normal file
@@ -0,0 +1,9 @@
|
||||
var mongoose = require('mongoose');
|
||||
|
||||
var UserSchema = new mongoose.Schema({
|
||||
username: String,
|
||||
name: String,
|
||||
password: String
|
||||
});
|
||||
|
||||
module.exports = UserSchema;
|
||||
6
chapter25/03_user_model.js
Normal file
6
chapter25/03_user_model.js
Normal file
@@ -0,0 +1,6 @@
|
||||
var mongoose = require('mongoose');
|
||||
var UserSchema = require('../schemas/user');
|
||||
|
||||
var User = mongoose.model('User', UserSchema);
|
||||
|
||||
module.exports = User;
|
||||
16
chapter25/04_load_user_route_middleware_new_version.js
Normal file
16
chapter25/04_load_user_route_middleware_new_version.js
Normal file
@@ -0,0 +1,16 @@
|
||||
var User = require('../../data/models/user');
|
||||
|
||||
function loadUser(req, res, next) {
|
||||
User.findOne({username: req.params.name}, function(err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (! user) {
|
||||
return res.send('Not found', 404);
|
||||
}
|
||||
req.user = user;
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = loadUser;
|
||||
56
chapter25/05_user_routes_new_version.js
Normal file
56
chapter25/05_user_routes_new_version.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* User Routes
|
||||
*/
|
||||
|
||||
var User = require('../data/models/user');
|
||||
var notLoggedIn = require('./middleware/not_logged_in');
|
||||
var loadUser = require('./middleware/load_user');
|
||||
var restrictUserToSelf = require('./middleware/restrict_user_to_self');
|
||||
|
||||
|
||||
module.exports = function(app) {
|
||||
|
||||
app.get('/users', function(req, res,next){
|
||||
User.find({}, function(err, users) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
res.render('users/index', {title: 'Users', users: users});
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/users/new', notLoggedIn, function(req, res) {
|
||||
res.render('users/new', {title: "New User"});
|
||||
});
|
||||
|
||||
app.get('/users/:name', loadUser, function(req, res, next){
|
||||
res.render('users/profile', {title: 'User profile', user: req.user});
|
||||
});
|
||||
|
||||
app.post('/users', notLoggedIn, function(req, res, next) {
|
||||
User.findOne({username: req.body.username}, function(err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (user) {
|
||||
return res.send('Conflict', 409);
|
||||
}
|
||||
User.create(req.body, function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
res.redirect('/users');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.del('/users/:name', loadUser, restrictUserToSelf,
|
||||
function(req, res, next) {
|
||||
req.user.remove(function(err) {
|
||||
if (err) { return next(err); }
|
||||
res.redirect('/users');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
21
chapter25/06_user_list_with_paging.jade
Normal file
21
chapter25/06_user_list_with_paging.jade
Normal file
@@ -0,0 +1,21 @@
|
||||
h1 Users
|
||||
|
||||
p
|
||||
a(href="/users/new") Create new profile
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ul
|
||||
- for(var username in users) {
|
||||
li
|
||||
a(href="/users/" + encodeURIComponent(username))= users[username].name
|
||||
- };
|
||||
|
||||
- if (page > 0) {
|
||||
a(href="?page=" + (page - 1)) Previous
|
||||
|
||||
- }
|
||||
|
||||
a(href="?page=" + (page + 1)) Next
|
||||
19
chapter25/07_user_list_with_paging_new_version.js
Normal file
19
chapter25/07_user_list_with_paging_new_version.js
Normal file
@@ -0,0 +1,19 @@
|
||||
h1 Users
|
||||
|
||||
p
|
||||
a(href="/users/new") Create new profile
|
||||
|
||||
ul
|
||||
- users.forEach(function(user) {
|
||||
li
|
||||
a(href="/users/" + encodeURIComponent(user.username))= user.name
|
||||
- });
|
||||
|
||||
- if (page > 0) {
|
||||
a(href="?page=" + (page - 1)) Previous
|
||||
|
||||
- }
|
||||
|
||||
- if (! lastPage) {
|
||||
a(href="?page=" + (page + 1)) Next
|
||||
- }
|
||||
11
chapter25/08_package_new_version.json
Normal file
11
chapter25/08_package_new_version.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "application-name"
|
||||
, "version": "0.0.1"
|
||||
, "private": true
|
||||
, "dependencies": {
|
||||
"express": "2.5.11"
|
||||
, "jade": ">= 0.0.1"
|
||||
, "mongoose": ">=2.7.0"
|
||||
, "async": "0.1.22"
|
||||
}
|
||||
}
|
||||
9
chapter25/09_user_schema_unique_index.js
Normal file
9
chapter25/09_user_schema_unique_index.js
Normal file
@@ -0,0 +1,9 @@
|
||||
var mongoose = require('mongoose');
|
||||
|
||||
var UserSchema = new mongoose.Schema({
|
||||
username: {type: String, unique: true},
|
||||
name: String,
|
||||
password: String
|
||||
});
|
||||
|
||||
module.exports = UserSchema;
|
||||
18
chapter25/10_user_schema_with_validated_email.js
Normal file
18
chapter25/10_user_schema_with_validated_email.js
Normal file
@@ -0,0 +1,18 @@
|
||||
var mongoose = require('mongoose');
|
||||
|
||||
// simple but incomplete email regexp:
|
||||
var emailRegexp = /.+\@.+\..+/;
|
||||
|
||||
var UserSchema = new mongoose.Schema({
|
||||
username: {type: String, unique: true},
|
||||
name: String,
|
||||
password: String,
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
match: emailRegexp
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = UserSchema;
|
||||
22
chapter25/11_user_schema_with_enumerated_field.js
Normal file
22
chapter25/11_user_schema_with_enumerated_field.js
Normal file
@@ -0,0 +1,22 @@
|
||||
var mongoose = require('mongoose');
|
||||
|
||||
var emailRegexp = /.+\@.+\..+/;
|
||||
|
||||
var UserSchema = new mongoose.Schema({
|
||||
username: {type: String, unique: true},
|
||||
name: String,
|
||||
password: String,
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
match: emailRegexp
|
||||
},
|
||||
gender: {
|
||||
type: String,
|
||||
required: true,
|
||||
uppercase: true,
|
||||
'enum': ['M', 'F']
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = UserSchema;
|
||||
23
chapter25/12_user_form_with_gender_field.jade
Normal file
23
chapter25/12_user_form_with_gender_field.jade
Normal file
@@ -0,0 +1,23 @@
|
||||
h1 New User
|
||||
|
||||
form(method="POST", action="/users")
|
||||
p
|
||||
label(for="username") Username<br />
|
||||
input#username(name="username")
|
||||
p
|
||||
label(for="name") Name<br />
|
||||
input#name(name="name")
|
||||
p
|
||||
label(for="email") Email<br />
|
||||
input#email(name="email")
|
||||
p
|
||||
label(for="password") Password<br />
|
||||
input#password(type="password", name="password")
|
||||
p
|
||||
label(for="gender") Gender<br />
|
||||
input#gender(name="gender")
|
||||
p
|
||||
label(for="bio") Bio<br />
|
||||
textarea#bio(name="bio")
|
||||
p
|
||||
input(type="submit", value="Create")
|
||||
26
chapter25/13_user_form_with_birthday.jade
Normal file
26
chapter25/13_user_form_with_birthday.jade
Normal file
@@ -0,0 +1,26 @@
|
||||
h1 New User
|
||||
|
||||
form(method="POST", action="/users")
|
||||
p
|
||||
label(for="username") Username<br />
|
||||
input#username(name="username")
|
||||
p
|
||||
label(for="name") Name<br />
|
||||
input#name(name="name")
|
||||
p
|
||||
label(for="email") Email<br />
|
||||
input#email(name="email")
|
||||
p
|
||||
label(for="password") Password<br />
|
||||
input#password(type="password", name="password")
|
||||
p
|
||||
label(for="gender") Gender<br />
|
||||
input#gender(name="gender")
|
||||
p
|
||||
label(for="birthday") Birthday<br />
|
||||
input#birthday(name="birthday")
|
||||
p
|
||||
label(for="bio") Bio<br />
|
||||
textarea#bio(name="bio")
|
||||
p
|
||||
input(type="submit", value="Create")
|
||||
12
chapter25/14_package_with_request.json
Normal file
12
chapter25/14_package_with_request.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "application-name"
|
||||
, "version": "0.0.1"
|
||||
, "private": true
|
||||
, "dependencies": {
|
||||
"express": "2.5.11"
|
||||
, "jade": ">= 0.0.1"
|
||||
, "mongoose": ">=2.7.0"
|
||||
, "async": "0.1.22"
|
||||
, "request": "2.10.0"
|
||||
}
|
||||
}
|
||||
24
chapter25/15_user_profile_with_virtual_attribute.jade
Normal file
24
chapter25/15_user_profile_with_virtual_attribute.jade
Normal file
@@ -0,0 +1,24 @@
|
||||
h1= user.name
|
||||
|
||||
h2 Bio
|
||||
p= user.bio
|
||||
|
||||
h2 Email
|
||||
p= user.email
|
||||
|
||||
h2 Gender
|
||||
p= user.gender
|
||||
|
||||
h2 Birthday
|
||||
p= user.birthday
|
||||
|
||||
- if (user.twitter) {
|
||||
h2 Twitter
|
||||
p
|
||||
a(href= user.twitter_url)="@" + user.twitter
|
||||
- }
|
||||
|
||||
|
||||
form(action="/users/" + encodeURIComponent(user.username), method="POST")
|
||||
input(name="_method", type="hidden", value="DELETE")
|
||||
input(type="submit", value="Delete")
|
||||
29
chapter25/16_user_form_with_virtual_attribute.jade
Normal file
29
chapter25/16_user_form_with_virtual_attribute.jade
Normal file
@@ -0,0 +1,29 @@
|
||||
h1 New User
|
||||
|
||||
form(method="POST", action="/users")
|
||||
p
|
||||
label(for="username") Username<br />
|
||||
input#username(name="username")
|
||||
p
|
||||
label(for="full_name") Full name (first and last)<br />
|
||||
input#full_name(name="full_name")
|
||||
p
|
||||
label(for="email") Email<br />
|
||||
input#email(name="email")
|
||||
p
|
||||
label(for="password") Password<br />
|
||||
input#password(type="password", name="password")
|
||||
p
|
||||
label(for="gender") Gender<br />
|
||||
input#gender(name="gender")
|
||||
p
|
||||
label(for="birthday") Birthday<br />
|
||||
input#birthday(name="birthday")
|
||||
p
|
||||
label(for="twitter") Twitter Handle<br />
|
||||
input#twitter(name="twitter")
|
||||
p
|
||||
label(for="bio") Bio<br />
|
||||
textarea#bio(name="bio")
|
||||
p
|
||||
input(type="submit", value="Create")
|
||||
24
chapter25/17_user_profile_with_virtual_attribute.jade
Normal file
24
chapter25/17_user_profile_with_virtual_attribute.jade
Normal file
@@ -0,0 +1,24 @@
|
||||
h1= user.full_name
|
||||
|
||||
h2 Bio
|
||||
p= user.bio
|
||||
|
||||
h2 Email
|
||||
p= user.email
|
||||
|
||||
h2 Gender
|
||||
p= user.gender
|
||||
|
||||
h2 Birthday
|
||||
p= user.birthday
|
||||
|
||||
- if (user.twitter) {
|
||||
h2 Twitter
|
||||
p
|
||||
a(href= user.twitter_url)="@" + user.twitter
|
||||
- }
|
||||
|
||||
|
||||
form(action="/users/" + encodeURIComponent(user.username), method="POST")
|
||||
input(name="_method", type="hidden", value="DELETE")
|
||||
input(type="submit", value="Delete")
|
||||
19
chapter25/18_user_list_with_virtual_attribute.jade
Normal file
19
chapter25/18_user_list_with_virtual_attribute.jade
Normal file
@@ -0,0 +1,19 @@
|
||||
h1 Users
|
||||
|
||||
p
|
||||
a(href="/users/new") Create new profile
|
||||
|
||||
ul
|
||||
- users.forEach(function(user) {
|
||||
li
|
||||
a(href="/users/" + encodeURIComponent(user.username))= user.full_name
|
||||
- });
|
||||
|
||||
- if (page > 0) {
|
||||
a(href="?page=" + (page - 1)) Previous
|
||||
|
||||
- }
|
||||
|
||||
- if (! lastPage) {
|
||||
a(href="?page=" + (page + 1)) Next
|
||||
- }
|
||||
20
chapter25/19_article_schema.js
Normal file
20
chapter25/19_article_schema.js
Normal file
@@ -0,0 +1,20 @@
|
||||
var Schema = require('mongoose').Schema;
|
||||
|
||||
var ArticleSchema = new Schema({
|
||||
title: {
|
||||
type: String,
|
||||
unique: true
|
||||
},
|
||||
body: String,
|
||||
author: {
|
||||
type: Schema.ObjectId,
|
||||
ref: 'User',
|
||||
required: true
|
||||
},
|
||||
created_at: {
|
||||
type: Date,
|
||||
'default': Date.now
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = ArticleSchema;
|
||||
6
chapter25/20_article_model.js
Normal file
6
chapter25/20_article_model.js
Normal file
@@ -0,0 +1,6 @@
|
||||
var mongoose = require('mongoose');
|
||||
var ArticleSchema = require('../schemas/article');
|
||||
|
||||
var Article = mongoose.model('Article', ArticleSchema);
|
||||
|
||||
module.exports = Article;
|
||||
96
chapter25/21_article_routes.js
Normal file
96
chapter25/21_article_routes.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Article Routes
|
||||
*/
|
||||
|
||||
var async = require('async');
|
||||
|
||||
var Article = require('../data/models/article');
|
||||
var notLoggedIn = require('./middleware/not_logged_in');
|
||||
var loadArticle = require('./middleware/load_article');
|
||||
var loggedIn = require('./middleware/logged_in');
|
||||
|
||||
var maxArticlesPerPage = 5;
|
||||
|
||||
module.exports = function(app) {
|
||||
|
||||
app.get('/articles', function(req, res, next){
|
||||
var page = req.query.page && parseInt(req.query.page, 10) || 0;
|
||||
async.parallel([
|
||||
|
||||
function(next) {
|
||||
Article.count(next);
|
||||
},
|
||||
|
||||
function(next) {
|
||||
Article.find({})
|
||||
.sort('title', 1)
|
||||
.skip(page * maxArticlesPerPage)
|
||||
.limit(maxArticlesPerPage)
|
||||
.exec(next);
|
||||
}
|
||||
],
|
||||
|
||||
// final callback
|
||||
function(err, results) {
|
||||
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
var count = results[0];
|
||||
var articles = results[1];
|
||||
|
||||
var lastPage = (page + 1) * maxArticlesPerPage >= count;
|
||||
|
||||
res.render('articles/index', {
|
||||
title: 'Articles',
|
||||
articles: articles,
|
||||
page: page,
|
||||
lastPage: lastPage
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
app.get('/articles/new', loggedIn, function(req, res) {
|
||||
res.render('Articles/new', {title: "New Article"});
|
||||
});
|
||||
|
||||
app.get('/articles/:title', loadArticle, function(req, res, next){
|
||||
res.render('articles/article', {title: req.article.title,
|
||||
article: req.article});
|
||||
});
|
||||
|
||||
app.post('/articles', loggedIn, function(req, res, next) {
|
||||
var article = req.body;
|
||||
article.author = req.session.user._id;
|
||||
Article.create(article, function(err) {
|
||||
if (err) {
|
||||
if (err.code === 11000) {
|
||||
res.send('Conflict', 409);
|
||||
} else {
|
||||
if (err.name === 'ValidationError') {
|
||||
return res.send(Object.keys(err.errors).map(function(errField) {
|
||||
return err.errors[errField].message;
|
||||
}).join('. '), 406);
|
||||
} else {
|
||||
next(err);
|
||||
}
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
res.redirect('/articles');
|
||||
});
|
||||
});
|
||||
|
||||
app.del('/articles/:title', loggedIn, loadArticle, function(req, res, next) {
|
||||
req.article.remove(function(err) {
|
||||
if (err) { return next(err); }
|
||||
res.redirect('/articles');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
18
chapter25/22_load_article_middleware.js
Normal file
18
chapter25/22_load_article_middleware.js
Normal file
@@ -0,0 +1,18 @@
|
||||
var Article = require('../../data/models/article');
|
||||
|
||||
function loadArticle(req, res, next) {
|
||||
Article.findOne({title: req.params.title})
|
||||
.populate('author')
|
||||
.exec(function(err, article) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (! article) {
|
||||
return res.send('Not found', 404);
|
||||
}
|
||||
req.article = article;
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = loadArticle;
|
||||
13
chapter25/23_article_detail.jade
Normal file
13
chapter25/23_article_detail.jade
Normal file
@@ -0,0 +1,13 @@
|
||||
h1= article.title
|
||||
|
||||
div!= article.body
|
||||
|
||||
hr
|
||||
|
||||
p
|
||||
span Author:
|
||||
|
||||
a(href="/users/" + encodeURIComponent(article.author.username))= article.author.full_name
|
||||
|
||||
p
|
||||
a(href="/articles") Back to all articles
|
||||
9
chapter25/24_logged_in_middleware.js
Normal file
9
chapter25/24_logged_in_middleware.js
Normal file
@@ -0,0 +1,9 @@
|
||||
function loggedIn(req, res, next) {
|
||||
if (! req.session.user) {
|
||||
res.send('Forbidden. Please log in first.', 403);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = loggedIn;
|
||||
19
chapter25/25_article_list.jade
Normal file
19
chapter25/25_article_list.jade
Normal file
@@ -0,0 +1,19 @@
|
||||
h1 Articles
|
||||
|
||||
p
|
||||
a(href="/articles/new") Create new article
|
||||
|
||||
ul
|
||||
- articles.forEach(function(article) {
|
||||
li
|
||||
a(href="/articles/" + encodeURIComponent(article.title))= article.title
|
||||
- });
|
||||
|
||||
- if (page > 0) {
|
||||
a(href="?page=" + (page - 1)) Previous
|
||||
|
||||
- }
|
||||
|
||||
- if (! lastPage) {
|
||||
a(href="?page=" + (page + 1)) Next
|
||||
- }
|
||||
11
chapter25/26_article_creation_form.jade
Normal file
11
chapter25/26_article_creation_form.jade
Normal file
@@ -0,0 +1,11 @@
|
||||
h1 New Article
|
||||
|
||||
form(method="POST", action="/articles")
|
||||
p
|
||||
label(for="title") Title<br />
|
||||
input#title(name="title")
|
||||
p
|
||||
label(for="body") Body<br />
|
||||
textarea#body(name="body")
|
||||
p
|
||||
input(type="submit", value="Create")
|
||||
5
chapter25/27_article_list_partial.jade
Normal file
5
chapter25/27_article_list_partial.jade
Normal file
@@ -0,0 +1,5 @@
|
||||
ul
|
||||
- articles.forEach(function(article) {
|
||||
li
|
||||
a(href="/articles/" + encodeURIComponent(article.title))= article.title
|
||||
- });
|
||||
15
chapter25/28_article_list_new_version.jade
Normal file
15
chapter25/28_article_list_new_version.jade
Normal file
@@ -0,0 +1,15 @@
|
||||
h1 Articles
|
||||
|
||||
p
|
||||
a(href="/articles/new") Create new article
|
||||
|
||||
p!= partial('articles/list', {articles: articles})
|
||||
|
||||
- if (page > 0) {
|
||||
a(href="?page=" + (page - 1)) Previous
|
||||
|
||||
- }
|
||||
|
||||
- if (! lastPage) {
|
||||
a(href="?page=" + (page + 1)) Next
|
||||
- }
|
||||
Reference in New Issue
Block a user