Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Node Tutorial part 4 post

  • Loading branch information...
commit 56b46eb3e52a4a261ae88e2ddb1ae05b7c79b7f2 1 parent 32b277b
Mike Valstar authored April 16, 2012
4  app.js
@@ -16,10 +16,10 @@ app.configure(function(){
16 16
 	
17 17
 	var mongooseSessionStore = new mongoStore({
18 18
 	    url: "mongodb://localhost/mv",
19  
-	    interval: 120000 
  19
+	    interval: 1200000
20 20
 	});
21 21
 	
22  
-	app.use(express.session( {cookie: {maxAge: 120000}, store: mongooseSessionStore, secret: "mv secret" }));
  22
+	app.use(express.session( {cookie: {maxAge: 1200000}, store: mongooseSessionStore, secret: "mv secret" }));
23 23
 	app.use(app.router);
24 24
 	app.use(express.static(__dirname + '/htdocs'));
25 25
 });
5  htdocs/css/css.css
@@ -134,6 +134,11 @@ div.error span{ padding: 0.3em 1em; }
134 134
 #disqus_identity{ display: none; }
135 135
 #disqus_permalink{ display: none; }
136 136
 
  137
+/* Content: Admin */
  138
+.aPostList{ width: 100%; border-collapse: collapse; margin: 15px 0; }
  139
+.aPostList th{}
  140
+.aPostList td{border: 1px solid #CCC; padding: 3px 7px;}
  141
+
137 142
 /* Footer */
138 143
 #F{ margin-top: 3em; font-weight: bold; padding-left: 5em; font-size: 0.9em; text-transform: uppercase; color: #B4B4B4; }
139 144
 
1  htdocs/js/mikevalstar.js
@@ -97,6 +97,7 @@ $(function(){
97 97
 			&& href.substring(href.length - 4) != '.jpg'
98 98
 			&& href.substring(href.length - 5) != '.jpeg'
99 99
 			&& href.substring(href.length - 4) != '.gif'
  100
+			&& href.substring(0,7) != '/Admin/'
100 101
 			&& !(href.indexOf('usrimg') > 0)
101 102
 			&& !(href.indexOf('usrfiles') > 0)
102 103
 				){
155  lib/AdminPages.js
@@ -18,10 +18,18 @@ AdminPages.prototype = {
18 18
 		this.db = db;
19 19
 		var self = this;
20 20
 		
  21
+		// login related
21 22
 		app.get ('/Admin/Login', function(req, res) { self.pageLogin(req, res); } );
22 23
 		app.post('/Admin/Login', function(req, res) { self.pageLoginPost(req, res); }  );
23 24
 		app.get ('/Admin/Logout', function(req, res) { self.pageLogout(req, res); }  );
24 25
 		
  26
+		// post related
  27
+		app.get ('/Admin/PostList', function(req, res) { self.pagePostList(req, res); }  );
  28
+		app.get ('/Admin/NewPost', function(req, res) { self.pagePost(req, res); }  );
  29
+		app.post('/Admin/Post', function(req, res) { self.pagePostPost(req, res); }  );
  30
+		app.get ('/Admin/Post/:id', function(req, res) { self.pagePost(req, res); }  );
  31
+		
  32
+		// misc.
25 33
 		app.get ('/Admin', function(req, res) { self.pageIndex(req, res); } );
26 34
 	}
27 35
 	
@@ -40,6 +48,11 @@ AdminPages.prototype = {
40 48
 		});
41 49
 	} 
42 50
 	
  51
+	, pageLogout: function(req, res){
  52
+		delete req.session.loggedIn;
  53
+		res.redirect('/Admin/Login');
  54
+	}
  55
+	
43 56
 	, pageLoginPost: function(req, res){
44 57
 		if(req.body && req.body.password && req.body.email){
45 58
 			var adminuser = this.db.model('adminUser');
@@ -57,7 +70,7 @@ AdminPages.prototype = {
57 70
 				}else{
58 71
 					if(row){
59 72
 						req.session.loggedIn = true; // register user is logged in
60  
-						res.redirect('/Admin')
  73
+						res.redirect('/Admin');
61 74
 					}else{
62 75
 						res.render('admin/login', {
63 76
 							title: 'Login',
@@ -86,9 +99,143 @@ AdminPages.prototype = {
86 99
 		});
87 100
 	}
88 101
 	
89  
-	, pageLogout: function(req, res){
90  
-		delete req.session.loggedIn;
91  
-		res.redirect('/Admin/Login');
  102
+	/* Blog post related */
  103
+	, pagePostList: function(req, res){ // List of blog posts
  104
+		if( !this._checkLogin(req, res) ) return;
  105
+		
  106
+		var blogpost = this.db.model('blogPost');
  107
+		
  108
+		var query = blogpost.find().sort("posted", -1).limit(1000).exec(function(err, docs){
  109
+			res.render('admin/postlist', {
  110
+				title: 'Post Listing',
  111
+				posts: docs,
  112
+				showFullNav: false
  113
+			});
  114
+		});
  115
+	}
  116
+	
  117
+	, pagePost: function(req, res){ // Edit/New Page
  118
+		if( !this._checkLogin(req, res) ) return;
  119
+		
  120
+		if(req.params.id){ // Old Post
  121
+		
  122
+			var blogpost = this.db.model('blogPost');
  123
+			blogpost.findOne({sid: req.params.id}, function(err, row){
  124
+				if(!row){
  125
+					res.redirect('/Admin/NewPost');
  126
+					return;
  127
+				}
  128
+				
  129
+				res.render('admin/post', {
  130
+					title: req.params.id + ' - ' + row.title,
  131
+					post: row,
  132
+					showFullNav: false
  133
+				});
  134
+			});
  135
+		
  136
+		}else{ // New Post
  137
+			var newid = 1;
  138
+			var blogpost = this.db.model('blogPost');
  139
+			blogpost.find().sort("sid", -1).limit(1).exec(function(err, doc){
  140
+				if(err)
  141
+					console.info(err);
  142
+					
  143
+				if(!doc || doc.length == 0){
  144
+					newid = 1;
  145
+				}else{
  146
+					newid = doc[0].sid + 1;
  147
+				}
  148
+		
  149
+				res.render('admin/post', {
  150
+					title: 'New Blog Post',
  151
+					post: {	id		: "",
  152
+							sid		: newid,
  153
+							author	: "mikevalstar@gmail.com",
  154
+							title	: "",
  155
+							img_lg	: "",
  156
+							img_sm	: "",
  157
+							content	: "",
  158
+							short	: "",
  159
+							ext_link: "",
  160
+							posted	: "",
  161
+							edited	: "",
  162
+						},
  163
+					showFullNav: false
  164
+				});
  165
+			});
  166
+		}
  167
+	}
  168
+	
  169
+	, pagePostPost: function(req, res){
  170
+		if( !this._checkLogin(req, res) ) return;
  171
+		
  172
+		if(req.body.id && req.body.id != ""){
  173
+			// old page
  174
+			var blogpost = this.db.model('blogPost');
  175
+			
  176
+			blogpost.update(
  177
+				{_id: req.body.id},
  178
+				{
  179
+					sid		: req.body.sid,
  180
+					title	: req.body.title,
  181
+					img_lg	: req.body.img_lg,
  182
+					img_sm	: req.body.img_sm,
  183
+					content	: req.body.content,
  184
+					short	: req.body.short,
  185
+					ext_link: req.body.ext_link,
  186
+				},
  187
+				{ multi: false },
  188
+				function(err, numrows){
  189
+					if(err){
  190
+						console.log(err);
  191
+					}else{
  192
+						console.log("Updated ("+numrows+") blog post(s) at internal id: " + req.body.id);
  193
+					}
  194
+					
  195
+					res.redirect('/Admin/Post/' + req.body.sid);
  196
+				});
  197
+			
  198
+		}else{
  199
+			// new page
  200
+			var blogpost = this.db.model('blogPost');
  201
+			
  202
+			// max id + 1
  203
+			var newid = 1;
  204
+			blogpost.find().sort("sid", -1).limit(1).exec(function(err, doc){
  205
+				if(err)
  206
+					console.info(err);
  207
+					
  208
+				if(!doc || doc.length == 0){
  209
+					newid = 1;
  210
+				}else{
  211
+					newid = doc[0].sid + 1;
  212
+				}
  213
+				
  214
+				// new blog post
  215
+				var post = new blogpost({
  216
+					sid		: req.body.sid == "" ? parseInt(newid) : req.body.sid,
  217
+					author	: "mikevalstar@gmail.com",
  218
+					title	: req.body.title,
  219
+					img_lg	: req.body.img_lg,
  220
+					img_sm	: req.body.img_sm,
  221
+					content	: req.body.content,
  222
+					short	: req.body.short,
  223
+					ext_link: req.body.ext_link,
  224
+				});
  225
+				
  226
+				post.save(function(err){
  227
+					if(err){
  228
+						console.log(err);
  229
+					}else{
  230
+						console.log("Inserted new blog post at sid: " + post.sid + " at internal id: " + post.id);
  231
+					}
  232
+					
  233
+					res.redirect('/Admin/Post/' + post.sid);
  234
+				});
  235
+				
  236
+			});
  237
+			
  238
+		}
92 239
 	}
93 240
 	
94 241
 };
19  lib/Database.js
@@ -10,7 +10,19 @@ Database.prototype = {
10 10
 	  	adminUser: {
11 11
 			  login		: String
12 12
 			, password	: String
13  
-		}
  13
+		},
  14
+		blogPost:{
  15
+			sid		: { type: Number, required: true, unique: true, index: true },
  16
+			author	: { type: String },
  17
+			title	: { type: String },
  18
+			img_lg	: { type: String },
  19
+			img_sm	: { type: String },
  20
+			content	: { type: String },
  21
+			short	: { type: String },
  22
+			ext_link: { type: String },
  23
+			posted	: { type: Date, index: true, default: Date.now },
  24
+			edited	: { type: Date, default: Date.now },
  25
+		},
14 26
 	}
15 27
 	
16 28
 	, _db: null
@@ -23,12 +35,17 @@ Database.prototype = {
23 35
 		this._schema.adminUser = new Schema(this._collections.adminUser);
24 36
 		this._model.adminUser = mongoose.model('adminUser', this._schema.adminUser);
25 37
 		
  38
+		this._schema.blogPost = new Schema(this._collections.blogPost);
  39
+		this._model.blogPost = mongoose.model('blogPost', this._schema.blogPost);
  40
+		
26 41
 	}
27 42
 	
28 43
 	, model: function(mod){	
29 44
 		switch (mod){
30 45
 			case 'adminUser':
31 46
 				return this._model.adminUser;
  47
+			case 'blogPost':
  48
+				return this._model.blogPost;
32 49
 		}
33 50
 	}
34 51
 
6  views/admin/index.jade
... ...
@@ -1,3 +1,7 @@
1 1
 h2 Admin
2 2
 
3  
-h3 You are logged in
  3
+h3 You are logged in
  4
+
  5
+ul
  6
+	li
  7
+		a(href="/Admin/PostList") Blog Posts
2  views/admin/login.jade
... ...
@@ -1,7 +1,7 @@
1 1
 h2 Admin - Login
2 2
 
3 3
 div.loginform
4  
-	form(method="post")
  4
+	form(method="post", action="/Admin/Login")
5 5
 		h3 Login
6 6
 		
7 7
 		- if(typeof(error_text) != 'undefined')
21  views/admin/post.jade
... ...
@@ -0,0 +1,21 @@
  1
+h2 Edit Post 
  2
+	span.postid= post.id
  3
+
  4
+form(method="post", action="/Admin/Post")
  5
+	input(type="hidden", name="id", value=post.id)
  6
+	h3 ID 
  7
+		input(type="text", name="sid", value=post.sid)
  8
+	h3 Title
  9
+	input(type="text", name="title", style="width: 100%;", value=post.title)
  10
+	h4 Image Large
  11
+	input(type="text", name="img_lg", style="width: 50%;", value=post.img_lg)
  12
+	h4 Image Small
  13
+	input(type="text", name="img_sm", style="width: 50%;", value=post.img_sm)
  14
+	h3 Content
  15
+	textarea(name="short", style="width: 100%; height: 5em;")= post.short
  16
+	textarea(name="content", style="width: 100%; height: 20em;")= post.content
  17
+	span.i All content is in jade format
  18
+	h4 Link to external content
  19
+	input(type="text", name="ext_link", style="width: 100%;", value=post.ext_link)
  20
+	br
  21
+	input(type="submit", value="Save")
24  views/admin/postlist.jade
... ...
@@ -0,0 +1,24 @@
  1
+h2 Admin - Post Listing
  2
+
  3
+table.aPostList
  4
+	thead
  5
+		tr
  6
+			th Post ID
  7
+			th Title
  8
+			th Int/Ext
  9
+			th Posted
  10
+	tbody
  11
+	- posts.forEach(function(item){
  12
+		tr
  13
+			td= item.sid
  14
+			td: a(href="/Admin/Post/" + item.sid)= item.title
  15
+			td
  16
+				- if(item.ext_link != ""){
  17
+				| External
  18
+				- }else{
  19
+				| Internal
  20
+				- }
  21
+			td: time= item.posted
  22
+	- })
  23
+
  24
+a(href="/Admin/NewPost") Create a new post
2  views/error.jade
@@ -48,7 +48,7 @@ body#mikevalstar
48 48
 			#CC
49 49
 				h2 500 Error
50 50
 
51  
-				- if(stack)
  51
+				- if(typeof(stack) != 'undefined')
52 52
 					pre: code.stack!=stack
53 53
 				- else
54 54
 					There was an error rendering this page. Sorry for the inconvenience.
43  views/post/bp_108.draft.md
Source Rendered
... ...
@@ -0,0 +1,43 @@
  1
+# Coding with Node.js: Part 4; Storing blog posts
  2
+
  3
+_See [Coding with Node.js: Part 1; Getting started with Express.](/Blog/103/Coding_with_Node.js_Part_1_Getting_started_with_Express) for the beginning of this tutorial series._
  4
+
  5
+With the admin login page completed we now need a list of blog entries and a way to create and edit them. So to start lets give ourselves an admin interface for blog posts that we can later integrate into the main website.
  6
+
  7
+## Structuring the posts
  8
+For the blog posts i'm going with the below structure for the posts to fit my blog.  One key column I'm adding in is the external link, this will be very useful for determining posts that are not full articles like this one but comments on something else that I would like to link to.
  9
+
  10
+So lets first add the structure to the database
  11
+#### Database.js
  12
+
  13
+## Listing your posts
  14
+Now that we have our database structure setup we'll need to setup a page to display all of the current posts and provide a link to create a new one.
  15
+
  16
+#### AdminPages.js
  17
+
  18
+#### postlist.jade
  19
+
  20
+## Editing Post
  21
+The first step we need to add is creating the post.  Because we want to keep an id for our posts that is short and numeric we're using the sid column to link to posts; and we need to find the maximum for the column before we start a page as seen below. 
  22
+
  23
+Also we need to check for when a user posts back the data in the form and apply that to the database.
  24
+
  25
+#### AdminPages.js
  26
+
  27
+#### post.jade
  28
+
  29
+Also note above that we set the post id to 1 when no maximum post id can be found.
  30
+
  31
+## Deficiencies
  32
+* No error checking - because this is a simple uxorial.. and I'll be the only one using the software I have put 0 error checking into this demo.  if you plan on making anything like this public make sure to add in some error checking.
  33
+* Post ID Collision - I do not currently detect a duplicate post id, this would be a good idea to add and i may do so later.
  34
+* Look & Feel - I have made the interface very spartan for now for this demo but once again plan on making this better in the future.
  35
+
  36
+## Final Thoughts
  37
+With the ability to add/edit blog posts we can now start translating all the posts into the database and be ready to switch over to a db driven blog listing.
  38
+
  39
+## The Code
  40
+All code created for this website is available on the [github page](https://github.com/mikevalstar/mikevalstar_com) and this tutorial specifically is available here: [https://github.com/mikevalstar/mikevalstar\_com/tree/Node\_Tutorial\_pt4](https://github.com/mikevalstar/mikevalstar_com/tree/Node_Tutorial_pt4)
  41
+
  42
+## Next Time
  43
+In the next part of this series we can show these blog posts on the front page. And later an RSS feed.

0 notes on commit 56b46eb

Please sign in to comment.
Something went wrong with that request. Please try again.