Skip to content

Commit

Permalink
Node Tutorial part 4 post
Browse files Browse the repository at this point in the history
  • Loading branch information
mikevalstar committed Apr 16, 2012
1 parent 32b277b commit 56b46eb
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 10 deletions.
4 changes: 2 additions & 2 deletions app.js
Expand Up @@ -16,10 +16,10 @@ app.configure(function(){


var mongooseSessionStore = new mongoStore({ var mongooseSessionStore = new mongoStore({
url: "mongodb://localhost/mv", 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(app.router);
app.use(express.static(__dirname + '/htdocs')); app.use(express.static(__dirname + '/htdocs'));
}); });
Expand Down
5 changes: 5 additions & 0 deletions htdocs/css/css.css
Expand Up @@ -134,6 +134,11 @@ div.error span{ padding: 0.3em 1em; }
#disqus_identity{ display: none; } #disqus_identity{ display: none; }
#disqus_permalink{ 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 */ /* Footer */
#F{ margin-top: 3em; font-weight: bold; padding-left: 5em; font-size: 0.9em; text-transform: uppercase; color: #B4B4B4; } #F{ margin-top: 3em; font-weight: bold; padding-left: 5em; font-size: 0.9em; text-transform: uppercase; color: #B4B4B4; }


Expand Down
1 change: 1 addition & 0 deletions htdocs/js/mikevalstar.js
Expand Up @@ -97,6 +97,7 @@ $(function(){
&& href.substring(href.length - 4) != '.jpg' && href.substring(href.length - 4) != '.jpg'
&& href.substring(href.length - 5) != '.jpeg' && href.substring(href.length - 5) != '.jpeg'
&& href.substring(href.length - 4) != '.gif' && href.substring(href.length - 4) != '.gif'
&& href.substring(0,7) != '/Admin/'
&& !(href.indexOf('usrimg') > 0) && !(href.indexOf('usrimg') > 0)
&& !(href.indexOf('usrfiles') > 0) && !(href.indexOf('usrfiles') > 0)
){ ){
Expand Down
155 changes: 151 additions & 4 deletions lib/AdminPages.js
Expand Up @@ -18,10 +18,18 @@ AdminPages.prototype = {
this.db = db; this.db = db;
var self = this; var self = this;


// login related
app.get ('/Admin/Login', function(req, res) { self.pageLogin(req, res); } ); app.get ('/Admin/Login', function(req, res) { self.pageLogin(req, res); } );
app.post('/Admin/Login', function(req, res) { self.pageLoginPost(req, res); } ); app.post('/Admin/Login', function(req, res) { self.pageLoginPost(req, res); } );
app.get ('/Admin/Logout', function(req, res) { self.pageLogout(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); } ); app.get ('/Admin', function(req, res) { self.pageIndex(req, res); } );
} }


Expand All @@ -40,6 +48,11 @@ AdminPages.prototype = {
}); });
} }


, pageLogout: function(req, res){
delete req.session.loggedIn;
res.redirect('/Admin/Login');
}

, pageLoginPost: function(req, res){ , pageLoginPost: function(req, res){
if(req.body && req.body.password && req.body.email){ if(req.body && req.body.password && req.body.email){
var adminuser = this.db.model('adminUser'); var adminuser = this.db.model('adminUser');
Expand All @@ -57,7 +70,7 @@ AdminPages.prototype = {
}else{ }else{
if(row){ if(row){
req.session.loggedIn = true; // register user is logged in req.session.loggedIn = true; // register user is logged in
res.redirect('/Admin') res.redirect('/Admin');
}else{ }else{
res.render('admin/login', { res.render('admin/login', {
title: 'Login', title: 'Login',
Expand Down Expand Up @@ -86,9 +99,143 @@ AdminPages.prototype = {
}); });
} }


, pageLogout: function(req, res){ /* Blog post related */
delete req.session.loggedIn; , pagePostList: function(req, res){ // List of blog posts
res.redirect('/Admin/Login'); 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);
});

});

}
} }


}; };
19 changes: 18 additions & 1 deletion lib/Database.js
Expand Up @@ -10,7 +10,19 @@ Database.prototype = {
adminUser: { adminUser: {
login : String login : String
, password : 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 , _db: null
Expand All @@ -23,12 +35,17 @@ Database.prototype = {
this._schema.adminUser = new Schema(this._collections.adminUser); this._schema.adminUser = new Schema(this._collections.adminUser);
this._model.adminUser = mongoose.model('adminUser', this._schema.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){ , model: function(mod){
switch (mod){ switch (mod){
case 'adminUser': case 'adminUser':
return this._model.adminUser; return this._model.adminUser;
case 'blogPost':
return this._model.blogPost;
} }
} }


Expand Down
6 changes: 5 additions & 1 deletion views/admin/index.jade
@@ -1,3 +1,7 @@
h2 Admin h2 Admin


h3 You are logged in h3 You are logged in

ul
li
a(href="/Admin/PostList") Blog Posts
2 changes: 1 addition & 1 deletion views/admin/login.jade
@@ -1,7 +1,7 @@
h2 Admin - Login h2 Admin - Login


div.loginform div.loginform
form(method="post") form(method="post", action="/Admin/Login")
h3 Login h3 Login


- if(typeof(error_text) != 'undefined') - if(typeof(error_text) != 'undefined')
Expand Down
21 changes: 21 additions & 0 deletions 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")
24 changes: 24 additions & 0 deletions 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
2 changes: 1 addition & 1 deletion views/error.jade
Expand Up @@ -48,7 +48,7 @@ body#mikevalstar
#CC #CC
h2 500 Error h2 500 Error


- if(stack) - if(typeof(stack) != 'undefined')
pre: code.stack!=stack pre: code.stack!=stack
- else - else
There was an error rendering this page. Sorry for the inconvenience. There was an error rendering this page. Sorry for the inconvenience.
Expand Down
43 changes: 43 additions & 0 deletions 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.