Permalink
Browse files

Node Tutorial part 4 post

  • Loading branch information...
1 parent 32b277b commit 56b46eb3e52a4a261ae88e2ddb1ae05b7c79b7f2 @mikevalstar committed Apr 16, 2012
View
4 app.js
@@ -16,10 +16,10 @@ app.configure(function(){
var mongooseSessionStore = new mongoStore({
url: "mongodb://localhost/mv",
- interval: 120000
+ interval: 1200000
});
- app.use(express.session( {cookie: {maxAge: 120000}, store: mongooseSessionStore, secret: "mv secret" }));
+ app.use(express.session( {cookie: {maxAge: 1200000}, store: mongooseSessionStore, secret: "mv secret" }));
app.use(app.router);
app.use(express.static(__dirname + '/htdocs'));
});
View
5 htdocs/css/css.css
@@ -134,6 +134,11 @@ div.error span{ padding: 0.3em 1em; }
#disqus_identity{ display: none; }
#disqus_permalink{ display: none; }
+/* Content: Admin */
+.aPostList{ width: 100%; border-collapse: collapse; margin: 15px 0; }
+.aPostList th{}
+.aPostList td{border: 1px solid #CCC; padding: 3px 7px;}
+
/* Footer */
#F{ margin-top: 3em; font-weight: bold; padding-left: 5em; font-size: 0.9em; text-transform: uppercase; color: #B4B4B4; }
View
1 htdocs/js/mikevalstar.js
@@ -97,6 +97,7 @@ $(function(){
&& href.substring(href.length - 4) != '.jpg'
&& href.substring(href.length - 5) != '.jpeg'
&& href.substring(href.length - 4) != '.gif'
+ && href.substring(0,7) != '/Admin/'
&& !(href.indexOf('usrimg') > 0)
&& !(href.indexOf('usrfiles') > 0)
){
View
155 lib/AdminPages.js
@@ -18,10 +18,18 @@ AdminPages.prototype = {
this.db = db;
var self = this;
+ // login related
app.get ('/Admin/Login', function(req, res) { self.pageLogin(req, res); } );
app.post('/Admin/Login', function(req, res) { self.pageLoginPost(req, res); } );
app.get ('/Admin/Logout', function(req, res) { self.pageLogout(req, res); } );
+ // post related
+ app.get ('/Admin/PostList', function(req, res) { self.pagePostList(req, res); } );
+ app.get ('/Admin/NewPost', function(req, res) { self.pagePost(req, res); } );
+ app.post('/Admin/Post', function(req, res) { self.pagePostPost(req, res); } );
+ app.get ('/Admin/Post/:id', function(req, res) { self.pagePost(req, res); } );
+
+ // misc.
app.get ('/Admin', function(req, res) { self.pageIndex(req, res); } );
}
@@ -40,6 +48,11 @@ AdminPages.prototype = {
});
}
+ , pageLogout: function(req, res){
+ delete req.session.loggedIn;
+ res.redirect('/Admin/Login');
+ }
+
, pageLoginPost: function(req, res){
if(req.body && req.body.password && req.body.email){
var adminuser = this.db.model('adminUser');
@@ -57,7 +70,7 @@ AdminPages.prototype = {
}else{
if(row){
req.session.loggedIn = true; // register user is logged in
- res.redirect('/Admin')
+ res.redirect('/Admin');
}else{
res.render('admin/login', {
title: 'Login',
@@ -86,9 +99,143 @@ AdminPages.prototype = {
});
}
- , pageLogout: function(req, res){
- delete req.session.loggedIn;
- res.redirect('/Admin/Login');
+ /* Blog post related */
+ , pagePostList: function(req, res){ // List of blog posts
+ if( !this._checkLogin(req, res) ) return;
+
+ var blogpost = this.db.model('blogPost');
+
+ var query = blogpost.find().sort("posted", -1).limit(1000).exec(function(err, docs){
+ res.render('admin/postlist', {
+ title: 'Post Listing',
+ posts: docs,
+ showFullNav: false
+ });
+ });
+ }
+
+ , pagePost: function(req, res){ // Edit/New Page
+ if( !this._checkLogin(req, res) ) return;
+
+ if(req.params.id){ // Old Post
+
+ var blogpost = this.db.model('blogPost');
+ blogpost.findOne({sid: req.params.id}, function(err, row){
+ if(!row){
+ res.redirect('/Admin/NewPost');
+ return;
+ }
+
+ res.render('admin/post', {
+ title: req.params.id + ' - ' + row.title,
+ post: row,
+ showFullNav: false
+ });
+ });
+
+ }else{ // New Post
+ var newid = 1;
+ var blogpost = this.db.model('blogPost');
+ blogpost.find().sort("sid", -1).limit(1).exec(function(err, doc){
+ if(err)
+ console.info(err);
+
+ if(!doc || doc.length == 0){
+ newid = 1;
+ }else{
+ newid = doc[0].sid + 1;
+ }
+
+ res.render('admin/post', {
+ title: 'New Blog Post',
+ post: { id : "",
+ sid : newid,
+ author : "mikevalstar@gmail.com",
+ title : "",
+ img_lg : "",
+ img_sm : "",
+ content : "",
+ short : "",
+ ext_link: "",
+ posted : "",
+ edited : "",
+ },
+ showFullNav: false
+ });
+ });
+ }
+ }
+
+ , pagePostPost: function(req, res){
+ if( !this._checkLogin(req, res) ) return;
+
+ if(req.body.id && req.body.id != ""){
+ // old page
+ var blogpost = this.db.model('blogPost');
+
+ blogpost.update(
+ {_id: req.body.id},
+ {
+ sid : req.body.sid,
+ title : req.body.title,
+ img_lg : req.body.img_lg,
+ img_sm : req.body.img_sm,
+ content : req.body.content,
+ short : req.body.short,
+ ext_link: req.body.ext_link,
+ },
+ { multi: false },
+ function(err, numrows){
+ if(err){
+ console.log(err);
+ }else{
+ console.log("Updated ("+numrows+") blog post(s) at internal id: " + req.body.id);
+ }
+
+ res.redirect('/Admin/Post/' + req.body.sid);
+ });
+
+ }else{
+ // new page
+ var blogpost = this.db.model('blogPost');
+
+ // max id + 1
+ var newid = 1;
+ blogpost.find().sort("sid", -1).limit(1).exec(function(err, doc){
+ if(err)
+ console.info(err);
+
+ if(!doc || doc.length == 0){
+ newid = 1;
+ }else{
+ newid = doc[0].sid + 1;
+ }
+
+ // new blog post
+ var post = new blogpost({
+ sid : req.body.sid == "" ? parseInt(newid) : req.body.sid,
+ author : "mikevalstar@gmail.com",
+ title : req.body.title,
+ img_lg : req.body.img_lg,
+ img_sm : req.body.img_sm,
+ content : req.body.content,
+ short : req.body.short,
+ ext_link: req.body.ext_link,
+ });
+
+ post.save(function(err){
+ if(err){
+ console.log(err);
+ }else{
+ console.log("Inserted new blog post at sid: " + post.sid + " at internal id: " + post.id);
+ }
+
+ res.redirect('/Admin/Post/' + post.sid);
+ });
+
+ });
+
+ }
}
};
View
19 lib/Database.js
@@ -10,7 +10,19 @@ Database.prototype = {
adminUser: {
login : String
, password : String
- }
+ },
+ blogPost:{
+ sid : { type: Number, required: true, unique: true, index: true },
+ author : { type: String },
+ title : { type: String },
+ img_lg : { type: String },
+ img_sm : { type: String },
+ content : { type: String },
+ short : { type: String },
+ ext_link: { type: String },
+ posted : { type: Date, index: true, default: Date.now },
+ edited : { type: Date, default: Date.now },
+ },
}
, _db: null
@@ -23,12 +35,17 @@ Database.prototype = {
this._schema.adminUser = new Schema(this._collections.adminUser);
this._model.adminUser = mongoose.model('adminUser', this._schema.adminUser);
+ this._schema.blogPost = new Schema(this._collections.blogPost);
+ this._model.blogPost = mongoose.model('blogPost', this._schema.blogPost);
+
}
, model: function(mod){
switch (mod){
case 'adminUser':
return this._model.adminUser;
+ case 'blogPost':
+ return this._model.blogPost;
}
}
View
6 views/admin/index.jade
@@ -1,3 +1,7 @@
h2 Admin
-h3 You are logged in
+h3 You are logged in
+
+ul
+ li
+ a(href="/Admin/PostList") Blog Posts
View
2 views/admin/login.jade
@@ -1,7 +1,7 @@
h2 Admin - Login
div.loginform
- form(method="post")
+ form(method="post", action="/Admin/Login")
h3 Login
- if(typeof(error_text) != 'undefined')
View
21 views/admin/post.jade
@@ -0,0 +1,21 @@
+h2 Edit Post
+ span.postid= post.id
+
+form(method="post", action="/Admin/Post")
+ input(type="hidden", name="id", value=post.id)
+ h3 ID
+ input(type="text", name="sid", value=post.sid)
+ h3 Title
+ input(type="text", name="title", style="width: 100%;", value=post.title)
+ h4 Image Large
+ input(type="text", name="img_lg", style="width: 50%;", value=post.img_lg)
+ h4 Image Small
+ input(type="text", name="img_sm", style="width: 50%;", value=post.img_sm)
+ h3 Content
+ textarea(name="short", style="width: 100%; height: 5em;")= post.short
+ textarea(name="content", style="width: 100%; height: 20em;")= post.content
+ span.i All content is in jade format
+ h4 Link to external content
+ input(type="text", name="ext_link", style="width: 100%;", value=post.ext_link)
+ br
+ input(type="submit", value="Save")
View
24 views/admin/postlist.jade
@@ -0,0 +1,24 @@
+h2 Admin - Post Listing
+
+table.aPostList
+ thead
+ tr
+ th Post ID
+ th Title
+ th Int/Ext
+ th Posted
+ tbody
+ - posts.forEach(function(item){
+ tr
+ td= item.sid
+ td: a(href="/Admin/Post/" + item.sid)= item.title
+ td
+ - if(item.ext_link != ""){
+ | External
+ - }else{
+ | Internal
+ - }
+ td: time= item.posted
+ - })
+
+a(href="/Admin/NewPost") Create a new post
View
2 views/error.jade
@@ -48,7 +48,7 @@ body#mikevalstar
#CC
h2 500 Error
- - if(stack)
+ - if(typeof(stack) != 'undefined')
pre: code.stack!=stack
- else
There was an error rendering this page. Sorry for the inconvenience.
View
43 views/post/bp_108.draft.md
@@ -0,0 +1,43 @@
+# Coding with Node.js: Part 4; Storing blog posts
+
+_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._
+
+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.
+
+## Structuring the posts
+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.
+
+So lets first add the structure to the database
+#### Database.js
+
+## Listing your posts
+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.
+
+#### AdminPages.js
+
+#### postlist.jade
+
+## Editing Post
+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.
+
+Also we need to check for when a user posts back the data in the form and apply that to the database.
+
+#### AdminPages.js
+
+#### post.jade
+
+Also note above that we set the post id to 1 when no maximum post id can be found.
+
+## Deficiencies
+* 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.
+* 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.
+* 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.
+
+## Final Thoughts
+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.
+
+## The Code
+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)
+
+## Next Time
+In the next part of this series we can show these blog posts on the front page. And later an RSS feed.

0 comments on commit 56b46eb

Please sign in to comment.